1. 模块摘要 (Executive Summary)
状态管理层管理画布元素数据、选中状态、工具状态、剪贴板数据等核心业务数据,是整个画布应用的数据核心,负责维护所有画布元素的状态信息和用户交互相关的全局状态。它采用了 Zustand 作为状态管理库,实现了数据的集中管理和状态变更的响应式更新
项目结构树:
1 2 3
| src/ └── stores/ └── canvasStore.ts
|
Zustand:轻量级状态管理库,用于管理全局状态
nanoid:用于生成唯一 ID
structuredClone:用于深拷贝状态数据
2. Props 和相关类型定义
2.1 useStore 参数
状态管理模块通过 useStore Hook 提供状态访问和更新功能。
| 参数名 |
类型 |
必填 |
默认值 |
描述 |
| setTool |
Function |
是 |
无 |
设置当前使用的工具类型 |
| addElement |
Function |
是 |
无 |
添加新元素到画布 |
| updateElement |
Function |
是 |
无 |
更新指定元素的属性 |
| removeElements |
Function |
是 |
无 |
从画布中移除指定元素 |
| setSelected |
Function |
是 |
无 |
设置当前选中的元素 |
| setEditingId |
Function |
是 |
无 |
设置当前正在编辑的元素 |
| copyElements |
Function |
是 |
无 |
复制指定元素到剪贴板 |
| pasteElements |
Function |
是 |
无 |
从剪贴板粘贴元素到画布 |
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| useStore.getState().setTool("rect");
useStore.getState().addElement({ id: "element1", type: "rect", x: 100, y: 100, width: 200, height: 150, fill: "#ff0000", stroke: "#000000", strokeWidth: 2, });
useStore.getState().updateElement("element1", { fill: "#00ff00" });
useStore.getState().removeElements(["element1"]);
|
2.2 核心类型定义
CanvasElement 类型:
定义了画布上所有元素的基本属性和可选属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| interface CanvasElement { id: string; type: ToolType; x: number; y: number; width: number; height: number; fill: string; stroke: string; strokeWidth: number; alpha?: number; points?: number[][]; rotation?: number; text?: string; fontSize?: number; fontFamily?: string; textAlign?: "left" | "center" | "right"; imageUrl?: string; filter?: "none" | "blur" | "brightness" | "grayscale"; radius?: number; }
|
ToolType 类型:
定义了用户可选择的工具类型。
1 2 3 4 5 6 7 8 9 10 11 12 13
| type ToolType = | "select" | "hand" | "rect" | "circle" | "triangle" | "diamond" | "line" | "arrow" | "pencil" | "text" | "image" | "eraser";
|
3. 核心状态管理 (State Architecture)
状态管理层维护以下内部状态:
| 状态名 |
类型 |
描述 |
| tool |
ToolType |
当前选中的工具类型 |
| elements |
Record<string, [CanvasElement](/src/pages/canvas/Pixi_STM_modules/core/types.ts#L15-L15)> |
所有画布元素的集合 |
| selectedIds |
string[] |
当前选中的元素 ID 数组 |
| editingId |
string \ |
null |
当前正在编辑的元素 ID |
| clipboard |
CanvasElement[] \ |
null |
剪贴板数据 |
| pasteOffset |
number |
粘贴偏移计数 |
| currentStyle |
Object |
当前样式设置 |
3.3 状态同步机制
1 2 3 4 5 6 7 8 9 10
| graph TD A[Zustand Store 状态变更] --> B{订阅者监听} B --> C[StageManager 订阅] B --> D[UI 组件订阅] C --> E[触发渲染层更新] D --> F[触发 UI 更新] style A fill:#e1f5fe style E fill:#e8f5e8 style F fill:#fff3e0
|
4. 逻辑流程 (Logic Flow)
4.1 交互时序图 (Mermaid)
1 2 3 4 5 6 7 8 9 10 11 12
| sequenceDiagram participant U as 用户 participant C as CanvasStore participant SM as StageManager participant R as 渲染层 U->>C: 调用 Action (如 addElement) C->>C: 更新内部状态 C->>SM: 通知状态变更 SM->>R: 触发重新渲染 R->>R: 更新 PIXI 对象 R->>U: 显示更新结果
|
4.2 核心函数
addElement 函数:当用户创建新元素时调用,创建新元素并添加到 elements 集合中
1 2 3 4
| addElement: (el) => originalSet((state) => ({ elements: { ...state.elements, [el.id]: el }, }));
|
updateElement 函数:当用户修改元素属性时调用,更新指定元素的属性并保持其他元素不变
1 2 3 4 5 6 7 8 9 10
| updateElement: (id, attrs) => originalSet((state) => { if (!state.elements[id]) return state; return { elements: { ...state.elements, [id]: { ...state.elements[id], ...attrs }, }, }; });
|
状态管理层作为纯数据层,不直接涉及 UI 和样式实现,但为上层 UI 提供了必要的状态支持,通过状态结构支持上层组件的布局逻辑和状态中的样式属性支持上层组件的样式实现