AGENTUPDATE 技术博客

1000usdinchina.com开发总结(4)-手画一张交互式 100 城中国 SVG 地图

1000usdinchina.com开发总结(4)-手画一张交互式 100 城中国 SVG 地图
目录

访客在 1000usdinchina.com 第一眼看到的是一张地图 —— 一张中国的 交互式 SVG 地图,每个覆盖城市一个可点的点。没有 Mapbox、没有 Leaflet、没有瓦片服务器。 就是手写 SVG。这篇讲为什么、怎么做,以及那个城市点变黑团的 bug。

这是系列第 4 篇。

目录

为什么用原生 SVG 不用地图库

地图库很棒,但对这活完全不合适:

  • 体积。 Leaflet/Mapbox + 瓦片是几百 KB 到几 MB。这里的地图是一段内联 SVG,gzip 后几 KB, 零运行时依赖。
  • 边缘友好。 没有瓦片请求、没有 API key、没有要经 Worker 代理的东西。它随 HTML 一起 ship, 从缓存秒渲染。
  • 可控。 我不需要街道和卫星图 —— 我要一个风格化轮廓 + 约 100 个精确放置的点。SVG 给我对这件事 的像素级控制,且仅此而已。

中国交互式 SVG 地图,每个覆盖城市一个品牌色点,东部密集、西部稀疏

城市点与交互

每座城是一个按投影坐标定位的 <circle>,接上悬停和点击:

<svg viewBox="0 0 1000 800" class="china-map">
  <path class="china-outline" d="M..." />
  <!-- 每个覆盖城市一个点 -->
  <a href="/en/city/chengdu">
    <circle class="city-dot" cx="486" cy="430" r="4"
            data-city="chengdu" aria-label="Chengdu" />
  </a>
  <!-- ... -->
</svg>
.city-dot { fill: var(--accent); transition: r .15s, fill .15s; cursor: pointer; }
.city-dot:hover { r: 7; fill: var(--accent-strong); }

悬停放大点,点击跳到城市。因为每个点是个锚点,它无需 JavaScript 也能用,且键盘可达 —— 无障碍白送。

黑团 bug

这个坑花了一下午。地图放大时,成簇的城市变成实心黑团

flowchart TD
    A[SVG 里被旧 generator 烤进了 67 个多余 city-dot] --> B[这些点没有 CSS class]
    B --> C[无样式 circle 默认 fill: black]
    C --> D[放大时密集无样式点融成黑团]
    D --> E[修法:给烤进去的点 display:none]
    E --> F[别从 generator 重生 —— 它已漂移]

根因:早期版本的地图 generator 把 67 个无样式 city-dot 元素直接烤进了 SVG。一个没指定 fill 的 SVG <circle> 默认实心黑。正常缩放下它们小、没人注意;一放大,密集黑点融成一团。

修法刻意保守:给烤进去的点 display:none,而不是重生整张 SVG。为什么不直接重跑 generator? 因为 generator 已经和实际在 prod 的手调地图漂移了 —— 重生会「修好」黑团,却悄悄把几十处 手动位置校正回退。当 generator 已和手改产物漂移,别盲目重生。 治标,保住手工成果。

SVG vs canvas vs 瓦片

对一个风格化轮廓上的约 100 个静态点,SVG 赢:

内联 SVG Canvas 瓦片地图(Leaflet/Mapbox)
载荷 几 KB 小 + JS 几百 KB–MB
依赖 库 + 瓦片 + key
无障碍 原生(锚点、ARIA) 手动 部分
边缘友好 完美(内联) 需瓦片请求
适合... 几百个静态要素 几千个动态点 真实地理 / 街道

Canvas 在几千个动画点时才划算;瓦片地图在你需要真街道时。对一张边缘上的风格化 100 点地图, 内联 SVG 是最小、最快、最无障碍的选择。

要点

  • 对约 100 个静态要素,手写内联 SVG 在体积、速度、无障碍上都胜过地图库。
  • 锚点包裹的点,无需 JavaScript 就给你导航和键盘支持。
  • 放大变实心黑团是无样式 SVG circle 的典型症状(默认 fill: black)。
  • 若 generator 已和手改产物漂移,治标 —— 别重生丢掉手工活。

常见问题

不用地图库能做交互地图吗? 能。对一张点位固定的风格化地图,内联 SVG + 锚点包裹的 circle 就给你交互、导航和无障碍,零依赖。

我的 SVG circle 为什么变黑? 没有 fill 的 SVG <circle> 默认实心黑。加个 CSS class 或 fill 属性;密集的无样式 circle 放大时会融成一团。

什么时候该改用 canvas 或瓦片地图? 几千个动态/动画点用 canvas;需要真街道、卫星图或真实地理投影时用瓦片地图(Leaflet/Mapbox)。


下一篇 → 我如何用 Claude Code 单人 ship 这个应用:prompt、context、harness、loop engineering