2026年10月28日

同一张地图,三种方式:SVG、Rust 和 Flutter

同一张地图,三种方式:SVG、Rust 和 Flutter

EVnSteven 已经达到了一个舒适的状态。平台稳定,不需要太多维护,这正是我们一开始想要的:一个安静地持续运行的小系统。这留出了一些实验的空间,也让我们的创始人有时间启动其他几个项目,你可以在结尾处找到它们。

所以我们做了一个实验。我们将主页上的地图重建了两次:一次用 Rust 编译成 WebAssembly,另一次用 Flutter。本文将这三种版本放在同一页面进行比较。

1. 原版:SVG、CSS 和少量 JavaScript

简单来说: 这就是我们主页上的地图。它的构建方式和网页的其他部分一样:由浏览器已知如何显示和动画的形状组成的绘图。它是三者中最简单的,也是大多数访客看到的版本。

Vancouver, CanadaLos Angeles, United StatesSan Diego, United StatesCalgary, CanadaVictoria, CanadaToronto, CanadaPortland, United StatesSeattle, United StatesSan Francisco, United StatesNew York, United StatesSydney, AustraliaBoston, United StatesMontreal, CanadaAustin, United StatesChicago, United StatesOttawa, CanadaLondon, United KingdomBengaluru, IndiaEdmonton, CanadaHalifax, CanadaMelbourne, AustraliaEdinburgh, United KingdomMexico City, MexicoBerlin, GermanyMunich, GermanyBarcelona, SpainParis, FranceManchester, United KingdomOsaka, JapanTokyo, JapanAuckland, New ZealandStockholm, SwedenBrisbane, AustraliaMilan, ItalySeoul, South KoreaOslo, NorwayCape Town, South AfricaSão Paulo, BrazilLagos, NigeriaAmsterdam, NetherlandsKarachi, PakistanDenver, United StatesMiami, United StatesRaleigh, United States

Ready Charging Check in Check out

⚠️ 技术部分即将开始。 不感兴趣?跳转到 Rust →

它是一个 SVG 绘图。浏览器通过 CSS 运行大部分动画,剩下的由一个小脚本处理。

优点是:没有构建步骤,只需一个 Hugo 模板即可。它是矢量图,因此在任何尺寸下都保持清晰。所有 44 个点都可以通过键盘访问,每个点都有屏幕阅读器标签。少量文字已翻译成我们所有的语言。

代价是页面体积较大。地图的标记约为 107 KB(压缩后约 30 KB),运行时约有 670 个元素和约 200 个 CSS 动画。逻辑也难以测试:时间控制存在于 CSS 关键帧和页面中的脚本里,因此唯一的测试方式就是观察它。

2. Rust 与 WebAssembly

简单来说: Rust 是一种以速度快且能在程序运行前捕捉许多错误而闻名的编程语言。这里我们用 Rust 编写了地图的“核心”,将其打包成浏览器可运行的紧凑形式(称为 WebAssembly),让它自己绘制整个地图,就像画家每秒多次重绘同一画布一样。对你来说看起来是一样的。

⚠️ 技术部分来啦。 不感兴趣?跳到 Flutter →

整个地图由编译成 WebAssembly 的 Rust 在单个画布上绘制。Rust 代码掌控地图的所有行为,并且每一帧都重新绘制所有内容。

我们喜欢的部分是逻辑完全是纯 Rust,没有任何浏览器相关的内容:计算元素位置和变化时机的数学,以及读取陆地轮廓的解析器。它有 13 个测试,运行时间不到一秒,如果循环的时序不对,测试会失败,而不是让人注意到画面看起来怪怪的。大约三分之一的约 1,070 行 Rust 代码是经过测试的核心(包含测试);剩下的负责绘制画布和处理鼠标事件。

页面最终非常轻量:只有一个 canvas 元素。但下载体积较大。编译后的模块约 254 KB(压缩后约 92 KB),加上构建工具生成的约 28 KB JavaScript 粘合代码。使用时我们也感受到一些成本:

  • 工具链。 构建需要 Rust、WebAssembly 目标以及一个命令行工具,其版本必须与库完全匹配。我们的构建脚本首先运行测试,如果有一个失败则停止。
  • 无法通过键盘或屏幕阅读器访问单个城市。 画布就是一张图片。SVG 版本中的 44 个可聚焦点消失了。
  • 仅支持英语。 标签写入程序中。
  • 模糊。 软阴影边缘使用画布模糊滤镜,但并非所有浏览器都支持。我们没有测试 Safari,那里边缘可能是硬的。

3. Flutter

简单来说: Flutter 是 Google 提供的一个工具包,用于从一套代码构建可在手机、电脑和网页上运行的应用。它不使用网页自身的构建块,而是自己绘制所有内容。这里的地图是一个小应用,显示在此页面内,使用的是驱动我们充电计算器的同一工具包。

⚠️ 技术部分开始。 不感兴趣?跳到我们的发现 →

它用自定义绘制器绘制地图,并在这里以框架形式展示。Flutter 还可以用同一套代码构建手机和桌面应用,这是它的主要优势:写一次地图,多个地方运行。

这与 Rust 的 map 逻辑相同,移植到 Dart,包含 11 个测试。包括测试在内约有 1,100 行代码。Flutter 将每个城市作为带标签的按钮交给屏幕阅读器,而画布版本缺少这一点(我们还没有检查它在真实屏幕阅读器上的表现如何)。它也是下载量最大的:应用约为 1.8 MB(压缩后约 535 KB)。Flutter 的绘图引擎是额外下载的,但网站已经与计算器共享了一个副本,因此打开过计算器的访客不会再次下载。其文本使用网站的字体 Merriweather,浏览器在运行时获取。

我们发现了什么

SVG + CSS + JSRust + WebAssemblyFlutter
地图下载大小约 107 KB,内嵌页面约 254 KB 模块 + 28 KB 粘合代码约 1.8 MB 应用(绘图引擎共享)
页面中的元素约 670 个,含约 200 个 CSS 动画1 个画布1 个框架
逻辑测试无13 个,本地11 个,本地
键盘可访问城市数是,全部 44 个否向屏幕阅读器暴露(未测试)
是否翻译是否,仅英文否,仅英文
在任意缩放下保持清晰是(矢量)根据屏幕像素密度重绘根据屏幕像素密度重绘
构建所需无Rust 工具链,匹配工具版本Flutter SDK

关于速度的补充说明。在我们的测试中,SVG 地图和 Rust 地图均以屏幕刷新率运行(测试显示器约为 120 帧每秒),因此帧率无法区分它们。我们没有测量 Flutter 的帧率,也没有测量电池或 CPU 使用情况,因此无法判断哪一个对手机更省电。

令我们惊讶的事情

有些细节很容易出错。 我们的第一个克隆版本在地图上以固定比例绘制钥匙和时钟,因此在小屏幕上它们会缩小,看起来比原版小得多。原版使用页面自身的字体单位(rem,会随屏幕宽度变化)来设置大小。克隆版本现在从页面读取该大小。时钟也有所不同:原版的指针以15分钟为步进移动,而Rust和Flutter版本则是连续转动的。

时区未内置。 无论是编译成WebAssembly的Rust还是Dart,都没有携带包含“Asia/Dubai”等时区信息的数据库。它们都通过浏览器内置的Intl服务来获取时区信息,该服务还能正确处理夏令时。

三者共享输入。 Rust和Flutter地图从它们所在的页面读取城市列表和陆地轮廓数据,这与SVG地图使用的数据相同。修改一个城市,三者都会同步变化。这也意味着这些地图只能在提供这些数据的页面上运行。

Flutter web会记忆。 Flutter web安装了自己的缓存,因此在重建后我们一直看到旧版本,直到清除缓存。

我们的结论

SVG地图保留在首页。对于这样大小的绘图,它是最轻量的,易于访问,支持翻译,并且不需要构建。Rust是更有趣的亚军:如果我们需要地图逻辑可被证明是正确的,或者需要在浏览器中进行大量计算,经过测试的Rust核心是一个不错的选择。如果地图需要嵌入Flutter应用中,Flutter则很有意义。

一个实验不必改变产品才有价值。我们最终对每种方法的成本有了更清晰的认识,得到了经过测试的地图行为描述,并且有一个页面可以让你亲自查看这三种版本。

我们的创始人接下来正在打造的项目

一个稳定的平台为其他想法留下了时间。除了EVnSteven,我们的创始人还在开发这些项目:

叫车服务,即将上线 Kimem (opens in a new tab) 由创始人Mekonnen Alemu打造的埃塞俄比亚巴希尔达尔的叫车服务。乘客在预订前可以看到车费估算,在地图上观看最近司机的接近,并在行程结束时以现金支付计价车费。 非营利,开源 StrayCats (opens in a new tab) David发起的一个项目,旨在帮助照顾街猫、流浪猫或任何猫的人,即使那只猫恰好是一只狗。项目仍处于构想阶段,尚无应用程序,David非常欢迎您的想法和反馈。献给Saibo,2010–2026。 现金跟踪,免费,即将上线 Effectivo (opens in a new tab) 带有创新的非完美记账,适合使用现金的人。只需几次点击即可记录购买,统计钱包中的现金,并回顾哪些支出值得。创新之处在于,每个持续使用现金的人都帮助保持现金流通,惠及所有人。免费且无广告,支持Android和iPhone,现已推出测试版和网页版演示。

您的建筑已准备好进行电动车充电。

在您已有的插座为电动汽车充电。司机按使用时间付费。

获取 EVnSteven

订阅 EVnSteven 笔记

我们仅使用您的电子邮件发送这些通知。取消订阅任何电子邮件。 隐私政策

支持与指南

2026年9月10日

需要多少电气工程师来给汽车充电?

足够多到把一个500美元的插座变成一个2万美元的项目。我喜欢工程师——我自己也学过工程。但有时我们把简单的事情弄得太复杂了。 阅读更多 · 1 min


2024年9月4日

每个版本都更出色,就像SpaceX的猛禽发动机

探索EVnSteven代码库如何体现简洁性、动力和可重用性,并与SpaceX猛禽发动机从V1到V3的演进进行对比。 阅读更多 · 1 min