Pinia 适合管理图形编辑器画布的缩放与平移状态,因其具备全局性、多组件读写需求及一致性要求;通过 useCanvasViewStore 统一维护 viewport 和 zoom 状态,提供 setZoom、panBy、zoomAt 等 action 实现安全更新,并与渲染层协同完成坐标转换与变换应用。

Pinia 适合管理图形编辑器中画布的缩放与平移状态,因为这类状态具有全局性、需被多个组件(如工具栏、画布、坐标显示区)读写,且需要持久化或跨操作保持一致性。核心思路是:把 视口偏移(viewport.x / viewport.y) 和 缩放比例(zoom) 抽象为 store 的 state,并通过 actions 提供安全、可追踪的更新方式。
定义画布视图状态 Store
创建一个独立的 store(例如 useCanvasViewStore),集中管理缩放和平移数据:
- state 中声明
viewport: { x: number; y: number }和zoom: number,初始值通常为{ x: 0, y: 0, zoom: 1 } - getters 可提供计算属性,比如
isZoomedIn(zoom > 1)、inverseZoom(用于反向转换坐标) - actions 封装所有变更逻辑:不直接暴露
store.zoom = 1.5,而是用setZoom(newZoom)、panBy(dx, dy)、zoomAt(x, y, factor)等方法
支持以鼠标光标为中心缩放
这是图形编辑器的关键交互体验。Pinia 本身不处理事件,但 store 的 actions 可接收坐标参数并更新 state:
- 在画布的
wheel事件处理器中,获取鼠标相对于画布的 clientX/clientY - 调用
store.zoomAt(clientX, clientY, delta),该 action 内部执行:- 将屏幕坐标转为当前场景坐标(利用
viewport和zoom反算) - 更新
zoom值 - 调整
viewport.x和viewport.y,使原光标位置在缩放后仍对应同一场景点
- 将屏幕坐标转为当前场景坐标(利用
与绘图逻辑和渲染层协同
Pinia store 是状态中枢,不是渲染引擎。实际 Canvas 或 SVG 渲染需消费这些状态:
- 在画布组件 setup 中调用
const view = useCanvasViewStore(),响应式读取view.zoom和view.viewport - Canvas 渲染时按顺序应用变换:
ctx.translate(-view.viewport.x, -view.viewport.y); ctx.scale(view.zoom, view.zoom); - 拖拽平移时,监听
mousedown → mousemove,在mousemove中持续调用view.panBy(dx, dy) - 若使用 d3-zoom,可将其
transform事件解构为 zoom 和 translate,再同步到 Pinia store,实现双向绑定
配合其他模块保持一致性
缩放平移状态常影响其他功能,Pinia 让这种联动更清晰:
- 栅格对齐:当
zoom变化时,栅格线密度可能需重算,相关 getter 可依赖zoom - 元素选中框:选中区域的视图坐标需用
zoom和viewport转换,避免缩放后框体错位 - 历史记录:缩放/平移操作可作为“视图命令”存入 undo stack,复用同一套 action 接口


















