2025-12-17-前端画布设计Vol.1 实现基础元素渲染和状态控制

1263 个字
6 分钟
2025-12-17-前端画布设计Vol.1 实现基础元素渲染和状态控制

PixiJS 实现基础元素渲染和状态控制#

PixiJS 是一个强大的 2D 渲染引擎,它使用 WebGL 和 Canvas 技术来高效地渲染图形,主要通过  ElementRenderer  类实现。

基本图形渲染实现#

设计的画布中,基本图形是通过 PixiJS 的 Graphics 类绘制的,支持以下基本图形类型:

  1. 矩形 (rect):

    g.rect(0, 0, data.width, data.height);
    g.fill({ color: fillColor, alpha });
    g.stroke({ width: strokeWidth, color: strokeColor });
  2. 圆角矩形 (rounded rectangle):

    g.roundRect(0, 0, data.width, data.height, data.radius);
    g.fill({ color: fillColor, alpha });
    g.stroke({ width: strokeWidth, color: strokeColor });
  3. 圆形 (circle):

    g.ellipse(data.width / 2, data.height / 2, data.width / 2, data.height / 2);
    g.fill({ color: fillColor, alpha });
    g.stroke({ width: strokeWidth, color: strokeColor });
  4. 菱形 (diamond):

    g.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  接口定义,支持以下属性:

  1. 背景色 (background):

    • 通过  fill  属性实现
    • 例如:g.fill({ color: fillColor, alpha })
    • 使用 PIXI.Color 类处理颜色值
  2. 边框宽度 (border-width):

    • 通过  strokeWidth  属性实现
    • 例如:g.stroke({ width: strokeWidth, color: strokeColor })
  3. 边框颜色 (border-color):

    • 通过  stroke  属性实现
    • 例如:g.stroke({ width: strokeWidth, color: strokeColor })
    • 同样使用 PIXI.Color 类处理颜色值
  4. 透明度 (alpha):

    • 通过 alpha 属性实现
    • 例如:g.fill({ color: fillColor, alpha })

在  ElementRenderer  类中,图形渲染的过程包括以下步骤:

  1. 首先清空之前的图形绘制:g.clear()

  2. 设置绘制样式(边框宽度、边框颜色、填充颜色、透明度):

    const strokeWidth = data.strokeWidth ?? 2;
    const strokeColor = new PIXI.Color(data.stroke);
    const fillColor = new PIXI.Color(data.fill);
    const alpha = data.alpha ?? 1;
  3. 根据图形类型绘制对应的形状

  4. 设置图形的位置和旋转:

    g.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;

特殊功能#

  1. 旋转功能: 通过设置  pivot  点和  rotation  属性实现
  2. 圆角矩形: 使用  g.roundRect(x, y, width, height, radius)  方法
  3. 纹理缓存: 对图像元素使用纹理缓存以提高性能
  4. 动态加载: 图像元素支持异步加载纹理

状态管理机制#

状态管理由  zustand  库实现,通过  CanvasStore  集中管理所有画布元素的状态。状态管理包含以下几个核心部分:

1. 状态结构#

  • elements: 一个记录对象,包含所有画布元素
  • selectedIds: 当前选中的元素 ID 数组
  • tool: 当前使用的工具类型
  • currentStyle: 当前绘制样式(填充色、边框色、边框宽度等)

2. 状态更新机制#

状态更新通过以下方法实现:

  • addElement: 添加元素
  • updateElement: 更新元素属性
  • removeElements: 删除元素
  • setSelected: 设置选中的元素
  • batchUpdateElements: 批量更新元素(用于提高性能)

元素渲染机制#

元素渲染通过  ElementRenderer  类实现,它与状态管理紧密结合:

1. 状态-渲染同步#

在  Core_StageManager.ts  中,有一个关键的订阅机制:

useStore.subscribe( (state) => ({ elements: state.elements, selectedIds: state.selectedIds, tool: state.tool }), (state) => { if (!this.state.destroyed) { this.elementRenderer.renderElements(state.elements, this.elementLayer, this.state.destroyed) this.transformerRenderer.renderTransformer( state.elements, state.selectedIds, this.elementRenderer.getSpriteMap(), this.onHandleDown, this.viewport.scale.x, ) // ...
//
}
}, { equalityFn: stateEqualityFn }, )

每当状态发生变化时,就会触发渲染更新。

2. 渲染过程#

ElementRenderer.renderElements  方法遍历所有元素并执行以下操作:

  1. 元素映射管理:使用  spriteMap  记录已渲染的元素
  2. 类型处理:根据元素类型(矩形、圆形、文本、图像等)进行相应渲染
  3. 属性应用:将状态中的属性(位置、大小、颜色等)应用到渲染对象

3. 状态与渲染的实时同步#

当状态变化时,例如:

  • 用户拖动元素时,updateElement  更新元素的  x  和  y  坐标
  • 用户改变填充颜色时,updateElement  更新  fill  属性
  • 选择元素时,setSelected  更新  selectedIds

这些状态变更会立即触发渲染更新,确保 UI 与状态保持同步。

状态控制机制#

1. 撤销/重做#

项目集成了撤销/重做功能,通过  UndoRedoManager  和命令模式实现:

  • 每个操作(添加、删除、更新)都创建一个命令对象
  • 命令对象包含执行和撤销操作的逻辑
  • undo  和  redo  方法控制历史记录栈

2. 选择状态管理#

  • selectedIds  数组跟踪当前选中的元素
  • 选择变化会触发渲染更新,显示选择框和控制点
  • TransformerRenderer 负责渲染选择框和调整手柄

3. 工具状态管理#

  • tool  属性跟踪当前使用的工具
  • 工具变化会影响交互行为和光标样式
  • 不同工具对相同的用户输入(如鼠标点击)会有不同的响应

4. 实时协作#

项目使用 Yjs 实现实时协作功能:

  • 状态变化通过 Yjs 同步到其他用户
  • Yjs 的 observe 机制确保本地状态与共享状态同步
  • 使用事务(transact)保证操作的原子性

性能优化#

  1. 状态比较优化:使用  stateEqualityFn  减少不必要的重渲染
  2. 批量更新:batchUpdateElements  方法用于批量更新元素,减少渲染次数
  3. 精灵映射:ElementRenderer  保留精灵映射以避免重复创建/销毁
  4. 防抖机制:虽然代码中注释掉了防抖,但设计中考虑了性能优化

分享到社交平台

将本文分享给你的朋友们

2025-12-17-前端画布设计Vol.1 实现基础元素渲染和状态控制
https://firefly.cuteleaf.cn/posts/2025-12-27-前端画布设计vol-1-实现基础元素渲染和状态控制/
作者
Zhongye
发布于
2025-12-28
版权声明
CC BY-NC-SA 4.0

评论

Profile Image of the Author
Zhongye
南漂中
公告
新的博客站!旧站点传送门 zhongye1.github.io/Arknight-notes
音乐
专辑封面

音乐

暂无播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章数
142
分类数
14
标签数
214
总字数
339,690
运行天数
0
最后更新
0 天前

目录