Skip to content

为什么选择 Rendx

一个类比

如果你用过 Ant Design 再用 shadcn/ui,你会理解 Rendx 在做什么。

Ant Design 给你一个完整的组件库:设计规范、主题系统、国际化、无障碍,开箱即用。代价是——你得接受它的一切决定。想改 DatePicker 的交互行为?在几千行源码里找到干预点。想换掉 Modal 的动画?先理解它的 CSSMotion 系统。组件越"完整",你偏离默认行为的成本越高。

shadcn/ui 换了个思路:把组件源码直接复制到你的项目里,你拥有它、修改它、删掉你不需要的部分。它不是一个"库",而是一组可以自由组合的模板。底层用的是 Radix Primitives 这些无样式原语——你在 shadcn/ui 里写的代码和不用 shadcn/ui 写的代码,调用的是同一层 API。

在 2D 可视化领域,AntV(G2/G6/X6)走的是 Ant Design 的路。Rendx 走的是 shadcn/ui 的路。

框架兜售选择,基建赋予自由

D3 在统计图表领域存活了 15 年。在这期间,ECharts、Highcharts、Chart.js、Recharts 轮番更迭,每一代都声称自己"更好用"。但它们底层都在复用 D3 的原语——d3-scale 做映射、d3-shape 造路径、d3-interpolate 做插值。

框架来了又走,基建永远在。

D3 难用,但它活得最久。不是因为 API 好,是因为它占据了正确的抽象层级:不替用户做决定,只提供做决定的工具。

G2 用声明式 spec 描述图表——几行配置就能出一张柱状图,demo 阶段很爽。但当你想做一个非标准 tooltip、在饼图上叠自定义标注、或者让两个图表共享坐标轴联动时,你得钻进 G2 内部几十个中间层去找干预点。"声明式"意味着框架替你做了 100 个决定,你想改第 73 个时,前 72 个都成了障碍。

X6 替你做好了端口模型、边路由、对齐线、快捷键、剪贴板。开箱即用的代价是——当你的业务需求偏离 X6 的预设 5% 时,你要花 50% 的精力去跟框架搏斗。

Rendx 不兜售仓库,不替你做决定。它给你选择权。

设计哲学

1. 同一套 API,从底层到业务

Rendx 的核心只有 5 个概念:AppSceneLayerGroupNode

插件不会发明新概念。graph-plugin 内部用 Node.createGroup.addselection-pluginLayer 画选框。drag-plugintranslate 移动节点。你在插件内部写的代码和不用插件写的代码,调用的是同一层 API——就像 shadcn/ui 里的组件代码和你自己手写的 React 代码没有区别。

这意味着:

  • 不存在"引擎能做但插件不让做"的能力壁垒
  • 理解了引擎 API 就理解了所有插件的实现
  • 你可以复制一个插件的源码,改成你要的样子,成本很低

2. 原语 > 框架

D3 在统计可视化领域证明了:基建比框架更持久。Rendx 在渲染领域做同样的事。

12 个包,每个职责单一,独立可用:

rendx-path       生成 SVG 路径字符串,零依赖
rendx-shape      几何形状生成器,不绑定渲染器
rendx-curve      12 种曲线插值,不绑定场景图
rendx-ease       20+ 种缓动函数,纯数学
rendx-interpolate 数值/颜色/向量/矩阵插值
rendx-bounding   包围盒计算
rendx-gradient   渐变解析

你可以只用 rendx-path 生成路径字符串给 SVG 用,不引入任何渲染逻辑。也可以只用 rendx-shape + rendx-canvas 做轻量绑定,跳过场景图。每个包都能脱离 Rendx 体系独立存活——这才是基建。

3. 透明 > 方便

javascript
// Rendx — 你知道发生了什么
const rect = Node.create('rect', {fill: '#f00'});
rect.shape.from(0, 0, 100, 50);
layer.add(rect);
app.render();

// AntV/G — 你不知道发生了什么
const rect = new Rect({style: {x: 0, y: 0, width: 100, height: 50, fill: '#f00'}});
// 背后:属性解析 → CSS 继承计算 → 脏标记 → 动画检测 → 布局计算 → ...

D3 难用但透明。jQuery 好用但不透明。jQuery 死了,D3 还在。

"方便"是一个危险的设计目标。你花 5 分钟用配置搞定了 demo,然后花 5 天去对抗配置当你的需求偏离框架预设。Rendx 选择让前 5 分钟稍微慢一点,换取后 5 天不存在。

4. 尊重 Canvas 的本质

Canvas 是即时模式渲染接口。调一次 fillRect() 就画一个矩形,没有 DOM 节点、没有样式继承。

一些引擎试图在 Canvas 上重建 DOM——CSS 属性计算、querySelector 查询、样式继承链。这是用 JavaScript 重写浏览器内核中 C++ 优化了 20 年的能力——不可能更快,只会更重。

Rendx 保留 Canvas 的即时模式本质。场景图只管渲染顺序和变换传播,事件系统只管交互,不模拟 DOM。

5. 插件是模板,不是黑箱

Rendx 的插件系统和 shadcn/ui 的组件一样:插件是被约束的代码组织方式,不是被封装的能力壁垒。

插件存在的目的是降低使用成本——给你一个"基础可用的模板",省去从头搭建的时间。但你随时可以:

  • 看源码理解它做了什么(因为用的是同一套 API)
  • 复制出来按需修改(因为没有私有魔法)
  • 只用其中两三个,把其余的扔掉(因为零耦合)
  • 自己写一个替代品(因为不存在"插件专用 API")

这和 X6 的插件截然不同。X6 的 Port 系统、边路由、Stencil 面板是框架的一部分,你不能绕过它们,也很难替换它们。

6. 一个引擎,覆盖多个领域

AntV 生态里,X6 做图编辑、G6 做图分析、G2 做图表、S2 做表格。四个框架、四套概念体系、四种插件协议、四种主题系统。你在项目里同时需要图编辑和图表?引两个框架,学两套 API。

Rendx 用一个引擎覆盖所有 Canvas 2D 可视化场景:

rendx-engine (统一渲染层)
├── graph-plugin     → 图编辑
├── selection-plugin → 选中交互
├── drag-plugin      → 拖拽
├── connect-plugin   → 连线
├── grid-plugin      → 网格
├── history-plugin   → 撤销重做
├── minimap-plugin   → 小地图
└── (未来) chart-plugin / table-plugin / ...

所有插件共享同一个 App、同一个 Scene、同一套事件系统。图编辑器节点内嵌一个迷你图表,只需要在同一个场景图里多加几个 Node——不需要引入第二个框架、不需要跨框架通信、不需要协调两套渲染循环。

7. 性能来自正确的架构

  • 多 Canvas 分层 — 每个 Layer 独立 Canvas,互不干扰。overlay 更新不触发数据层重绘
  • 三级脏标记dirty(结构变化)→ needUpdate(局部矩阵)→ worldMatrixNeedUpdate(传播标记),精确控制更新粒度
  • 视口裁剪 — 画布外的节点不进入渲染管线
  • 惰性 EventEmitter — 不监听事件的节点不创建 emitter

这些不是"黑魔法优化",是正确的架构选择——不做不需要做的事。

8. 知道自己不做什么

Canvas 2D 适合几千个节点。超过万级,正确做法是换 WebGL 引擎,而不是在 Canvas 2D 上硬优化。Rendx 不提供 WebGL 后端,不做滤镜,不做富文本——这些在图表/图编辑场景中使用率极低,但实现成本极高。

不跨界,才能在自己的区间做到极致的效率比。

9. 面向 AI 时代的可预测性

当 AI 辅助编程成为常态,代码库的可预测性功能丰富度更重要:

  • 5 个核心概念,无 DI 容器、无 CSS 继承树、无虚拟 DOM diff
  • Node.create('rect', { fill: '#f00' }) — 没有隐式行为,输入/输出确定
  • TypeScript strict 模式,所有 API 类型完备
  • 插件间 app.getPlugin() 运行时软感知,无 import 硬依赖

AI 能通过类型签名推断出正确调用方式的 API,生产力远高于需要阅读大量文档才能理解隐式约定的 API。

横向对比

架构对比

维度RendxAntV (G/G2/G6/X6)
渲染节点模型轻量 Graphics(无 CSS)模拟 DOM(CSS 属性计算 + 样式继承)
插件与引擎关系同一套 API,源码即模板框架内部 API,替换成本高
跨领域一个引擎覆盖图编辑/图表/表格X6/G6/G2/S2 四个独立框架
定制成本低(复制插件源码直接改)高(需理解框架内部抽象层)
包组合方式12 个独立原语包,按需引用捆绑在 @antv/g 体系内
概念密度5 个核心概念20+ 概念(Shape/Display/Style/Plugin/...)

代码量 vs 能力覆盖

引擎源码行数核心能力
Rendx~7,800 行场景图 + 双渲染后端 + 动画 + 事件 + 序列化 + 插件
Konva~30,000 行场景图 + Canvas + 动画 + 事件
ZRender~40,000 行场景图 + Canvas/SVG + 动画 + 事件
AntV/G~50,000+ 行场景图 + Canvas/SVG/WebGL + CSS 兼容 + 动画
Fabric.js~60,000 行Canvas + 对象编辑 + 序列化 + SVG 导出

能力矩阵

能力RendxKonvaAntV/GPixiJS
Canvas 2D
SVG
多 Canvas 分层
三阶段事件流
视口裁剪
序列化
包级别 Tree-shake

动画系统

Transform用途同类引擎
GraphicsTransformtranslate / rotate / scale各引擎均有
AttributeTransformopacity / fill / stroke 插值Konva Tween 等
ClipBoxTransform裁剪框揭露动效 (lr/rl/tb/bt)Rendx 独有
ArcTransform弧线角度动画需手动实现
SectorTransform扇形角度 + 半径动画需手动实现

总结

Rendx 不是一个更好的 X6,也不是一个更好的 G2。

它是一组可自由组合的 2D 可视化渲染原语——底层提供干净的基建(path、shape、curve、ease、interpolate),中层提供完整的渲染引擎(场景图、事件、动画、分层渲染),上层提供可拆可改的插件模板(图编辑、选中、拖拽、连线、网格、撤销)。

每一层都用同一套 API。插件不是黑箱,是模板。你可以全用、部分用、改着用、或者只用底层原语自己搭。

框架让你快速开始,然后在你偏离预设时阻止你。基建让你自己开始,然后在你走多远时都支撑你。

Rendx 选择做基建。