2025-12-17-前端画布设计Vol.1 实现基础元素渲染和状态控制
文章发布时间:
最后更新时间:
页面浏览: 加载中...
最后更新时间:
页面浏览: 加载中...
PixiJS 实现基础元素渲染和状态控制
PixiJS 是一个强大的 2D 渲染引擎,它使用 WebGL 和 Canvas 技术来高效地渲染图形,主要通过 ElementRenderer 类实现。
基本图形渲染实现
设计的画布中,基本图形是通过 PixiJS 的 Graphics 类绘制的,支持以下基本图形类型:
矩形 (rect):
1
2
3g.rect(0, 0, data.width, data.height);
g.fill({ color: fillColor, alpha });
g.stroke({ width: strokeWidth, color: strokeColor });圆角矩形 (rounded rectangle):
1
2
3g.roundRect(0, 0, data.width, data.height, data.radius);
g.fill({ color: fillColor, alpha });
g.stroke({ width: strokeWidth, color: strokeColor });圆形 (circle):
1
2
3g.ellipse(data.width / 2, data.height / 2, data.width / 2, data.height / 2);
g.fill({ color: fillColor, alpha });
g.stroke({ width: strokeWidth, color: strokeColor });菱形 (diamond):
1
2
3
4
5
6
7
8
9
10
11
12g.poly([
data.width / 2,
0,
data.width,
data.height / 2,
data.width / 2,
data.height,
0,
data.height / 2,
]);
g.fill({ color: fillColor, alpha });
g.stroke({ width: strokeWidth, color: strokeColor });
图形属性实现
每个图形元素都由 CanvasElement 接口定义,支持以下属性:
背景色 (background):
- 通过 fill 属性实现
- 例如:
g.fill({ color: fillColor, alpha }) - 使用
PIXI.Color类处理颜色值
边框宽度 (border-width):
- 通过 strokeWidth 属性实现
- 例如:
g.stroke({ width: strokeWidth, color: strokeColor })
边框颜色 (border-color):
- 通过 stroke 属性实现
- 例如:
g.stroke({ width: strokeWidth, color: strokeColor }) - 同样使用
PIXI.Color类处理颜色值
透明度 (alpha):
- 通过 alpha 属性实现
- 例如:
g.fill({ color: fillColor, alpha })
在 ElementRenderer 类中,图形渲染的过程包括以下步骤:
- 首先清空之前的图形绘制:
g.clear() 设置绘制样式(边框宽度、边框颜色、填充颜色、透明度):
1
2
3
4const strokeWidth = data.strokeWidth ?? 2;
const strokeColor = new PIXI.Color(data.stroke);
const fillColor = new PIXI.Color(data.fill);
const alpha = data.alpha ?? 1;根据图形类型绘制对应的形状
设置图形的位置和旋转:
1
2
3g.pivot.set(data.width / 2, data.height / 2);
g.position.set(data.x + data.width / 2, data.y + data.height / 2);
g.rotation = data.rotation;
特殊功能
- 旋转功能: 通过设置 pivot 点和 rotation 属性实现
- 圆角矩形: 使用
g.roundRect(x, y, width, height, radius)方法 - 纹理缓存: 对图像元素使用纹理缓存以提高性能
- 动态加载: 图像元素支持异步加载纹理
状态管理机制
状态管理由 zustand 库实现,通过 CanvasStore 集中管理所有画布元素的状态。状态管理包含以下几个核心部分:
1. 状态结构
- elements: 一个记录对象,包含所有画布元素
- selectedIds: 当前选中的元素 ID 数组
- tool: 当前使用的工具类型
- currentStyle: 当前绘制样式(填充色、边框色、边框宽度等)
2. 状态更新机制
状态更新通过以下方法实现:
- addElement: 添加元素
- updateElement: 更新元素属性
- removeElements: 删除元素
- setSelected: 设置选中的元素
- batchUpdateElements: 批量更新元素(用于提高性能)
元素渲染机制
元素渲染通过 ElementRenderer 类实现,它与状态管理紧密结合:
1. 状态-渲染同步
在 Core_StageManager.ts 中,有一个关键的订阅机制:
1 | |
每当状态发生变化时,就会触发渲染更新。
2. 渲染过程
ElementRenderer.renderElements 方法遍历所有元素并执行以下操作:
- 元素映射管理:使用 spriteMap 记录已渲染的元素
- 类型处理:根据元素类型(矩形、圆形、文本、图像等)进行相应渲染
- 属性应用:将状态中的属性(位置、大小、颜色等)应用到渲染对象
3. 状态与渲染的实时同步
当状态变化时,例如:
- 用户拖动元素时,updateElement 更新元素的 x 和 y 坐标
- 用户改变填充颜色时,updateElement 更新 fill 属性
- 选择元素时,setSelected 更新 selectedIds
这些状态变更会立即触发渲染更新,确保 UI 与状态保持同步。
状态控制机制
1. 撤销/重做
项目集成了撤销/重做功能,通过 UndoRedoManager 和命令模式实现:
- 每个操作(添加、删除、更新)都创建一个命令对象
- 命令对象包含执行和撤销操作的逻辑
- undo 和 redo 方法控制历史记录栈
2. 选择状态管理
- selectedIds 数组跟踪当前选中的元素
- 选择变化会触发渲染更新,显示选择框和控制点
- TransformerRenderer 负责渲染选择框和调整手柄
3. 工具状态管理
- tool 属性跟踪当前使用的工具
- 工具变化会影响交互行为和光标样式
- 不同工具对相同的用户输入(如鼠标点击)会有不同的响应
4. 实时协作
项目使用 Yjs 实现实时协作功能:
- 状态变化通过 Yjs 同步到其他用户
- Yjs 的 observe 机制确保本地状态与共享状态同步
- 使用事务(transact)保证操作的原子性
性能优化
- 状态比较优化:使用 stateEqualityFn 减少不必要的重渲染
- 批量更新:batchUpdateElements 方法用于批量更新元素,减少渲染次数
- 精灵映射:ElementRenderer 保留精灵映射以避免重复创建/销毁
- 防抖机制:虽然代码中注释掉了防抖,但设计中考虑了性能优化