Files
freedakgmail a550d6d0fd feat: Heritage Globe - 中国文物全球分布地图
- Next.js + MapLibre GL 3D 地球
- CARTO dark-matter vector 底图
- 动态星空背景(闪烁、漂移、流星)
- 经纬网格线(graticule)
- 文物数据图层与朝代/类别筛选
- 中国风信息弹窗
- 中英双语 i18n
- LayerPanel + MapControls 浮动面板
2026-07-01 01:37:18 +08:00

9.9 KiB
Raw Permalink Blame History

Heritage Globe - 中国文物全球分布地图

项目概述

基于 OpenGridWorks 技术架构,构建一个展示中国流散文物全球分布的交互式地图系统。

技术栈

核心框架

  • Next.js 15 - React 服务端渲染框架
  • TypeScript - 类型安全
  • Tailwind CSS - 样式系统

地图引擎

  • MapLibre GL JS 4.x - 开源矢量地图引擎(Mapbox GL 的开源替代)
  • PMTiles - 云原生瓦片格式,支持按需加载

数据层

  • GeoJSON - 文物坐标数据格式
  • Tippecanoe - GeoJSON → PMTiles 转换工具

UI 组件

  • Radix UI - 无障碍组件库(对话框、下拉菜单等)
  • Lucide React - 图标库

国际化

  • next-intl - Next.js 国际化解决方案
  • 支持中文(简体)/ English 双语切换
  • URL 路径自动添加语言前缀(/zh、/en)

项目结构

heritage-globe/
├── app/                      # Next.js App Router
│   ├── [locale]/            # 国际化路由
│   │   ├── layout.tsx       # 语言布局
│   │   └── page.tsx         # 首页(地图页)
│   ├── layout.tsx           # 根布局
│   └── globals.css          # 全局样式
├── messages/                # 翻译文件
│   ├── zh.json              # 中文翻译
│   └── en.json              # 英文翻译
├── components/              # React 组件
│   ├── map/                 # 地图相关组件
│   │   ├── MapContainer.tsx # 地图容器
│   │   ├── LayerControl.tsx # 图层控制
│   │   └── RelicMarker.tsx  # 文物标记
│   ├── sidebar/             # 侧边栏组件
│   │   ├── Sidebar.tsx      # 侧边栏容器
│   │   ├── FilterPanel.tsx  # 筛选面板
│   │   └── SearchBox.tsx    # 搜索框
│   └── ui/                  # 通用 UI 组件
├── lib/                     # 工具函数
│   ├── map-utils.ts        # 地图工具函数
│   ├── pmtiles-loader.ts   # PMTiles 加载器
│   └── data-processor.ts   # 数据处理
├── public/                  # 静态资源
│   ├── tiles/              # PMTiles 瓦片文件
│   └── icons/              # 自定义图标
├── data/                    # 原始数据
│   └── relics.geojson      # 文物 GeoJSON 数据
└── types/                   # TypeScript 类型定义
    └── relic.ts

搭建步骤

阶段 1: 项目初始化

# 创建 Next.js 项目
npx create-next-app@latest . --typescript --tailwind --app --no-src-dir --import-alias "@/*"

# 安装核心依赖
npm install maplibre-gl pmtiles

# 安装 UI 组件
npm install @radix-ui/react-dialog @radix-ui/react-select @radix-ui/react-slider
npm install lucide-react

# 安装国际化
npm install next-intl

# 安装开发工具
npm install -D @types/geojson

阶段 2: 国际化配置

2.1 创建翻译文件

messages/zh.json:

{
  "nav": {
    "title": "中国文物全球分布",
    "search": "搜索文物或博物馆"
  },
  "map": {
    "layers": "图层",
    "filters": "筛选器",
    "reset": "重置"
  },
  "dynasty": {
    "shang": "商周",
    "qin": "秦汉",
    "tang": "隋唐",
    "song": "宋元",
    "ming": "明清"
  },
  "category": {
    "bronze": "青铜器",
    "porcelain": "瓷器",
    "painting": "书画",
    "jade": "玉器"
  }
}

messages/en.json:

{
  "nav": {
    "title": "Chinese Cultural Relics Worldwide",
    "search": "Search relics or museums"
  },
  "map": {
    "layers": "Layers",
    "filters": "Filters",
    "reset": "Reset"
  },
  "dynasty": {
    "shang": "Shang-Zhou",
    "qin": "Qin-Han",
    "tang": "Sui-Tang",
    "song": "Song-Yuan",
    "ming": "Ming-Qing"
  },
  "category": {
    "bronze": "Bronze",
    "porcelain": "Porcelain",
    "painting": "Painting",
    "jade": "Jade"
  }
}

2.2 配置 next-intl

i18n.ts:

import { getRequestConfig } from 'next-intl/server';

export default getRequestConfig(async ({ locale }) => ({
  messages: (await import(`./messages/${locale}.json`)).default
}));

middleware.ts:

import createMiddleware from 'next-intl/middleware';

export default createMiddleware({
  locales: ['zh', 'en'],
  defaultLocale: 'zh',
  localeDetection: true
});

export const config = {
  matcher: ['/', '/(zh|en)/:path*']
};

阶段 3: 地图基础设施

3.1 配置 MapLibre GL CSS

  • app/[locale]/layout.tsx 中引入 maplibre-gl/dist/maplibre-gl.css

3.2 创建地图容器组件

  • components/map/MapContainer.tsx
  • 初始化 MapLibre 地图实例
  • 设置中国为初始中心点(北京:116.4074, 39.9042
  • 使用 Carto 深色底图

3.3 创建语言切换器

// components/LanguageSwitcher.tsx
'use client';
import { useLocale } from 'next-intl';
import { useRouter, usePathname } from 'next/navigation';

export function LanguageSwitcher() {
  const locale = useLocale();
  const router = useRouter();
  const pathname = usePathname();

  const toggleLanguage = () => {
    const newLocale = locale === 'zh' ? 'en' : 'zh';
    router.push(pathname.replace(`/${locale}`, `/${newLocale}`));
  };

  return (
    <button onClick={toggleLanguage}>
      {locale === 'zh' ? 'EN' : '中文'}
    </button>
  );
}

3.4 集成 PMTiles

  • lib/pmtiles-loader.ts
  • 实现 PMTiles Protocol 注册
  • 支持本地和远程瓦片加载

阶段 4: 数据层

4.1 定义数据结构(支持双语)

// types/relic.ts
interface Relic {
  id: string;
  name: {
    zh: string;              // 中文名称
    en: string;              // 英文名称
  };
  dynasty: string;           // 朝代(使用 key,如 "tang"
  category: string;          // 类别(使用 key,如 "bronze"
  currentLocation: {
    zh: string;              // 中文地点
    en: string;              // 英文地点
  };
  museum: {
    zh: string;              // 中文机构名
    en: string;              // 英文机构名
  };
  coordinates: [number, number]; // 经纬度
  year?: string;             // 年代
  description?: {
    zh: string;
    en: string;
  };
  imageUrl?: string;         // 图片 URL
  protectionLevel?: string;  // 保护级别
}

4.2 准备示例数据(双语)

  • 创建 data/relics.geojson
  • 至少包含 10-20 个示例文物点位
  • 覆盖英国、法国、美国、日本等主要国家

4.3 生成 PMTiles

# 安装 tippecanoemacOS
brew install tippecanoe

# 转换 GeoJSON → PMTiles
tippecanoe -o public/tiles/relics.pmtiles \
  --minimum-zoom=0 \
  --maximum-zoom=14 \
  --drop-densest-as-needed \
  --extend-zooms-if-still-dropping \
  data/relics.geojson

阶段 5: 图层系统

4.1 朝代图层

  • 根据朝代(商周、秦汉、隋唐、宋元、明清等)分层
  • 不同朝代使用不同颜色标识
  • 支持单独开关

4.2 类别图层

  • 青铜器、瓷器、书画、玉器、石刻等
  • 使用不同图标表示

4.3 气泡样式

  • 根据文物重要性(保护级别)调整大小
  • 聚类显示(缩小时自动聚合)

阶段 6: 交互功能

5.1 侧边栏控制面板

  • 图层树形结构(类似 OpenGridWorks
  • 拖拽排序
  • 开关动画

5.2 筛选器

  • 朝代范围滑块
  • 类别多选
  • 保护级别筛选
  • 国家/地区筛选

5.3 搜索功能

  • 文物名称模糊搜索
  • 收藏机构搜索
  • 搜索结果定位到地图

5.4 详情弹窗

  • 点击文物标记显示详情卡片
  • 展示图片、名称、年代、描述等
  • 提供外部链接(如博物馆官网)

阶段 7: 视觉优化

6.1 主题样式

  • 采用深色主题(类似 OpenGridWorks
  • 定义 CSS 变量统一配色

6.2 响应式设计

  • 桌面端:侧边栏固定
  • 移动端:抽屉式侧边栏

6.3 动画效果

  • 图层切换动画
  • 标记 hover 效果
  • 平滑缩放过渡

阶段 8: 高级功能(可选)

7.1 时间轴

  • 按文物流失年代播放动画
  • 展示流散历程

7.2 统计面板

  • 总文物数量
  • 分布国家统计
  • 朝代占比图表

7.3 分享功能

  • 生成带参数的分享链接
  • 截图导出

7.4 预设视图

  • "丝绸之路文物"
  • "战争掠夺文物"
  • "敦煌流散文物"

核心配置文件

next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config) => {
    // 支持 PMTiles 二进制文件
    config.module.rules.push({
      test: /\.pmtiles$/,
      type: 'asset/resource',
    });
    return config;
  },
};

module.exports = nextConfig;

tailwind.config.ts

import type { Config } from 'tailwindcss';

const config: Config = {
  darkMode: 'class',
  content: [
    './app/**/*.{js,ts,jsx,tsx,mdx}',
    './components/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {
      colors: {
        map: {
          bg: '#0a0e27',
          panel: '#1a1e3a',
          accent: '#3b82f6',
        },
      },
    },
  },
  plugins: [],
};

export default config;

开发流程

  1. 初始化项目 → 安装依赖
  2. 搭建地图 → 验证 MapLibre 正常渲染
  3. 加载数据 → 展示示例文物点位
  4. 实现图层 → 按朝代/类别分层
  5. 添加交互 → 点击、筛选、搜索
  6. 优化样式 → 深色主题、响应式
  7. 测试部署 → Vercel 一键部署

数据来源建议

  • 公开数据集: UNESCO、大英博物馆、卢浮宫等开放数据
  • 研究报告: 流失文物统计报告
  • 众包贡献: 社区上传补充

参考资源

许可证

MIT License - 开源友好


预计开发时间: 2-3 天(核心功能) 扩展功能: 根据需求迭代