R2 CDN — maps.worldmonitor.app
所有大型静态地图文件均通过 Cloudflare R2 提供,而不是 Vercel。R2 存储桶 worldmonitor-maps 由 CF 代理的自定义域名提供服务:
为什么选择 R2 而不是 Vercel?
- Cloudflare 带宽免费;Vercel 在大规模使用时按 GB 计费
- CF 缓存规则在边缘节点缓存
/data/、/assets/、/textures/等路径 30 天 - 大型文件(GeoJSON、PMTiles)不会膨胀 Vercel 部署
R2 上的文件
上传到 R2
CORS
R2 不支持通配符子域名(https://*.example.com)。每个源都必须在 CORS 规则中显式列出。使用 r2 bucket cors set 或直接对 R2 API 发起 curl -X PUT(Wrangler 4.31 可能报错 “not well formed”)。
国家几何服务
文件:src/services/country-geometry.ts
该服务提供所有国家级别的地理编码:点对多边形查找、ISO 代码解析、名称匹配、边界框和质心计算。它在首次使用时加载一次国家边界并建立索引以供快速查询。
数据流
countries.geojson— 带有 ISO 代码和名称的基础多边形,从/data/提供(Vercel)country-boundary-overrides.geojson— 来自 Natural Earth 的可选更高分辨率多边形,从 R2 CDN(maps.worldmonitor.app)提供。通过ISO3166-1-Alpha-2(或ISO_A2)代码匹配;匹配到的要素替换基础几何数据- 基础文件先加载并立即构建国家索引(服务变为可用)。覆盖文件随后获取,带 3 秒超时 — 失败会被静默忽略。覆盖查找使用
Map<code, Feature>实现 O(1) 匹配
索引数据结构
关键导出
名称别名
常见别名在NAME_ALIASES 中映射:
政治覆盖
POLITICAL_OVERRIDES 将子国家代码映射到主权代码,当应用将它们视为独立实体时(例如 CN-TW → TW)。
国家边界覆盖
覆盖机制允许我们在不替换整个countries.geojson 的情况下改进单个国家的边界。这是解决争议边界问题的基础(参见 #1044)。
工作原理
- 加载基础
countries.geojson后,应用从 R2 CDN 获取country-boundary-overrides.geojson,带 3 秒超时 - 对于覆盖文件中的每个要素,按 ISO Alpha-2 代码匹配
countries.geojson中的国家(使用Map进行 O(1) 查找) - 覆盖几何数据替换基础几何数据(在用于地图渲染的原始 GeoJSON 和索引的点对多边形数据中都会替换)
- 覆盖文件可以包含任意数量的国家 — 只有匹配的代码会被应用
添加新的国家覆盖
- 从 Natural Earth 50m Admin 0 获取边界(描绘的是事实边界 — 实际领土控制 — 而非外交主张)
- 按 ISO 代码提取国家要素并保存为 GeoJSON
- 合并到或替换
country-boundary-overrides.geojson - 上传到 R2:
- 无需代码更改 — 应用会自动获取新的几何数据
scripts/fetch-country-boundary-overrides.mjs 下载完整的 Natural Earth 50m 数据集(~24 MB),提取国家要素(当前为巴基斯坦和印度),并写入覆盖文件。
地缘政治敏感性
- Natural Earth 显示的是事实边界(谁实际控制该领土),而非外交主张
- 这是大多数地图平台使用的相同标准
- 为争议领土添加覆盖时,请在 PR 描述中记录来源和理由
- 覆盖系统不会增加或减少领土 — 它用来自同一权威来源的更高分辨率轮廓替换低分辨率轮廓
回退边界
对于可能未加载完整多边形几何的区域,country-geometry.ts 中的 ME_STRIKE_BOUNDS 为中东国家提供了矩形边界框。resolveCountryFromBounds() 将这些作为快速首轮筛选,在多个边界框重叠时回退到精确的点对多边形。
底图切片
底图切片配置位于src/config/basemap.ts。有关切片提供商(PMTiles、OpenFreeMap、CARTO)、主题和回退行为的完整详情,请参见地图引擎。
PMTiles 也通过 maps.worldmonitor.app 从 R2 提供,通过 VITE_PMTILES_URL 配置。
