重新推出 Snap.svg:2025 年形状优先的 D3.js 替代方案(含几何、3D 和 TypeScript)

发布: (2025年12月7日 GMT+8 05:48)
9 min read
原文: Dev.to

Source: Dev.to

简短概述

  • Adobe 上的原始 Snap.svg 仓库已经多年基本冻结。
  • 在过去十年里,我一直在一个 Snap.svg 的分支上添加几何工具、交互原语、UI 构建辅助以及 TypeScript 类型,同时保持原始 API 不变。
  • 此外,现在还有一个不断壮大的工具集,用于非线性扭曲、类 3D 变换以及基于贝塞尔的 3D 投影。

本文是系列文章的第一篇,旨在拆解这些组件并展示实际使用方法。

简史:Snap.svg 以及它为何重要

Snap.svg 最初由 Dmitry Baranovskiy(Raphaël 的作者)创建,并作为 Adobe Web 平台工作的一部分托管:

  • 官方 Adobe 仓库:

Snap.svg 的核心设计假设既简单又强大:如果浏览器已经把 SVG 作为一等的场景图(路径、组、变换、事件等)提供,那么 JavaScript 库应该帮助你直接操作它,而不是用自己的保留模式画布抽象来取代它。

Snap.svg 为你提供的功能

  • 对原生 SVG 元素的轻量包装 – Snap 返回一个 “paper”;你可以直接创建形状、分组、样式化并对 SVG 本身进行动画。
  • 统一的变换与分组 API – 以一致的方式处理组、变换和边界框。
  • 最小的思维模型 – 你仍在使用 SVG;Snap 只让这件事更愉快。

这些特性使 Snap.svg 成为图标、仪表盘、微交互以及 “SVG 作为 UI” 的理想选择,早在 “SVG UI” 流行之前就已经得到广泛使用。然而官方仓库多年停滞:没有现代构建、没有 TypeScript,也没有几何层的演进。核心思想仍然可靠,只是生态系统停止了前进。

为什么在 2025 年选择 Snap.svg(而不是 D3.js)?

显而易见的问题是:既然有 D3.js(以及一大批后继者),为何还要去使用 Snap.svg?

  • D3 是数据优先的。当你拥有复杂的数据模型、需要灵活的布局管线并希望将一切绑定到选择器时,D3 大放异彩。
  • Snap.svg 是形状优先的。当你已经知道想要的形状(图标、部件、图表、控件),并希望使用丰富的几何 API 来操作这些 SVG 基元时,Snap 更合适。

如果你的需求是:

  • 可拖拽的图表编辑器
  • 交互式图标、徽章和小部件
  • 几何密集型 UI(流场、Voronoi 覆盖、凸包、类 3D 曲线)
  • 基于 SVG 的 UI 组件,且希望将其作为设计系统的一部分发布

那么通过 D3 的数据绑定模型去实现往往会带来额外的干扰,此时一个库只需要 “给我一个 <svg> 元素,我会提供有用的几何/动画/交互层” 更贴合需求。这正是本分支的设计立场。

分支:在 Snap.svg 之上加入几何、交互、UI 与类型定义

扩展后的分支位于:

  • Forked + extended Snap.svg:

核心约束是保守的:原始 Snap.svg API 完全保持不变。在此基础上,分支新增了:

贝塞尔 / 多段贝塞尔工具

提供更高级的贝塞尔帮助函数(包括类 3D 曲线)以及用于构建和编辑曲线的实用工具。

多边形操作

凸包与凹包、SAT 风格的重叠检测,以及对多边形区域进行形态学类操作的辅助函数。

稳健的 BBox 与几何帮助函数

在变换下表现良好的边界框扩展,以及在元素和 paper 上暴露的更丰富的几何基元。

Element 与 Paper 扩展

更高层次的绘图与布局帮助(例如网格构建和通用变换)。

交互与 GUI 原语

“智能拖拽”行为、受约束的运动、本地化扭曲场以及贝塞尔控制点编辑,全部基于 SVG 基元实现。

调色板与 UI 实用工具

用于在 SVG 中构建 UI 的实用助手:网格、覆盖层、控制面板、标签等。

完整的 TypeScript 类型

为 Snap API 以及新加入的几何/交互扩展提供正式的类型层,使得在现代开发工具中使用更加可控。

重点并不是把 Snap 变成别的东西,而是让 “形状优先” 的方法在前端开发者当前面临的问题中变得可行。

向 3D 与非线性变换迈进

到目前为止的讨论都比较抽象:几何、交互、 “UI 助手”。为了让概念更具体,我们来看看新的 非线性变换类 3D 工具,因为它们对其他所有功能都是一次压力测试。

非线性变换画廊

非线性演示页面将 Snap 与一组随时间弯曲网格的动画 “场” 结合起来:

  • 某些预设沿对角线扫过正弦波。
  • 其他则表现为悬臂梁,网格围绕一条线 “铰接”。
  • 还有径向涟漪、膨胀以及组合多种效果的复合扭曲。

你可以在这里看到它们:

Non‑linear transforms demo

概念上,每个演示都在 SVG 平面上定义了一个随时间变化的变换,并让 Snap 将其应用到网格的每一个点。许多场内部使用了 3D 变换(深度旋转、透视投影),随后再投影回 2D,这就是它们看起来 “类 3D” 的原因,尽管最终仍在普通 SVG 中渲染。

关键不在于每个 UI 都会使用这些扭曲,而在于扩展层能够在 SVG 平面上描述真正的场,而不仅仅是全局的仿射变换。

本地化扭曲与 “扭曲场”

扭曲演示使用相同的机制,但将其本地化并加入交互:

  • 在舞台上绘制一个圆形 “扭曲场”。
  • 一个更小的 “探针” 网格可以在该场内部拖动。
  • 根据预设(扭转/捏合、膨胀、涟漪、3D 正弦深度),仅在探针与场相交的区域应用局部扭曲。

在这里尝试:

Warp fields (localized non‑linear warps) demo

这正是 Snap.svg 擅长的交互类型:SVG 充当你的场景图,库为其提供可编程的度量。扭曲场以声明式方式定义,拖拽和边界框帮助函数负责 bookkeeping。

3D 贝塞尔投影演示

非线性扭曲是一条扩展路径,另一条是 显式 3D 曲线与投影。贝塞尔投影演示展示了这一点:

  • 通过 Z 坐标滑块以及在多个正投影视图中直接操作控制点来控制 3D 贝塞尔曲线。
  • 同一条曲线同时在 XY、XZ、YZ 正投影、透视相机视图以及自定义的 “等轴投影” 中显示。

观看演示:

3D Bezier projections demo

内部实现上,这条曲线由一个扩展的 Bezier 对象表示,支持 3D 坐标、投影数学以及交互编辑,全部基于原始 Snap.svg 元素模型构建。

Back to Blog

相关文章

阅读更多 »