Workspace
<Workspace /> 是 Ydesign 编辑器里承载 Fabric 画布的 React 组件,也是整个界面中用户真正"画图"的区域。它做的事情其实只有几件:
- 在挂载时创建一个
@ydesign/core的Editor实例(绑定 store) - 把 Fabric canvas 插入到容器里,并监听尺寸变化
- 负责透明背景的棋盘格渲染、工作区阴影
- 在组件卸载时销毁 Editor,彻底清理 Fabric 的事件与 DOM
画布的一切业务行为(缩放、选中、图层、裁剪、导入导出等)都不在这个组件里,而是通过 Store API 和 @ydesign/core Handlers 暴露。
基本用法
import { createStore } from '@ydesign/react-editor';
import Workspace from '@ydesign/react-editor/canvas/workspace';
const store = createStore({
key: 'YOUR_API_KEY',
token: 'user-token',
});
export default function App() {
return (
<div style={{ height: '100vh' }}>
<Workspace store={store} />
</div>
);
}
<Workspace /> 会自动占满父容器的宽高,你不需要给它手动指定尺寸,只要父级 <div> 有明确的 width / height(或 flex: 1)即可。
⚠️ Workspace 内部通过
id="canvas"挂载 Fabric Canvas,同一个页面目前只能有一个<Workspace />实例。如果你有"多画布对比"这类需求,请通过路由切换或条件渲染来实现。
初始化配置
Workspace 的尺寸和工作区默认值来自 store 的字段:
const store = createStore({ key: 'YOUR_API_KEY' });
// 初始工作区尺寸
store.width; // => 1080(默认)
store.height; // => 1080(默认)
// 初始画布背景
store.backgroundColor; // => '#fff'
// 初始单位 / DPI
store.unit; // => 'px'
store.dpi; // => 72
想在挂载前调整这些默认值,用 createStore 之后立刻调用对应 action 即可:
const store = createStore({ key: 'YOUR_API_KEY' });
store.setSize({ width: 1200, height: 800 });
store.setUnit({ unit: 'mm', dpi: 300 });
store.setBackgroundColor('#f0f0f0');
// ...然后再挂载 <Workspace store={store} />
修改画布尺寸
// 设置画布工作区尺寸
store.setSize({ width: 1600, height: 900 });
// 也可以从 handler 直接调
store.editor?.workareaHandler.setSize({ width: 1600, height: 900 });
尺寸变化会触发:
workareaHandler重建工作区矩形zoomHandler.auto()自动适配屏幕workarea:changed事件,store.width/store.height自动同步- 历史栈写入(支持撤销回原尺寸)
单位换算
store.setUnit({ unit: 'mm', dpi: 300 });
// 1080px @ 72dpi → 381mm @ 72dpi → 4500px @ 300dpi
详细见 Store 总览 · 画布尺寸 / 单位 / 背景。
修改画布背景
// 纯色
store.setBackgroundColor('#f5f5f5');
// 透明(会自动显示棋盘格)
store.setBackgroundColor('rgba(255, 255, 255, 0)');
store.setBackgroundColor('transparent');
// 线性渐变
store.setBackgroundColor({
type: 'linear',
coords: { x1: 0, y1: 0, x2: 1, y2: 1 },
colorStops: [
{ offset: 0, color: '#ff6a00' },
{ offset: 1, color: '#2253eb' },
],
});
当背景色包含透明度(rgba(..., <1) 或 transparent),Workspace 会在工作区下方自动渲染棋盘格,视觉上提示"这是透明区域":
┌─────────────────────────┐
│ ▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦ │
│ ▦▦▦▦▦ workarea ▦▦▦▦▦▦▦▦ │
│ ▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦ │
└─────────────────────────┘
缩放与视口
缩放由 ZoomHandler 管理,不在 Workspace 组件上。常用 API:
const zoom = store.editor?.zoomHandler;
zoom?.zoomIn(); // 放大一档
zoom?.zoomOut(); // 缩小一档
zoom?.zoomToOne(); // 回到 100%
zoom?.zoomToFit(); // 适配屏幕
zoom?.zoomToRatio(1.5); // 缩放到 150%
zoom?.centerViewport(); // 视口回到画布中央
// 当前缩放比可以从 store 读
console.log(store.scale);
Ydesign 内置了一套缩放控件:<ZoomButtons />(右下角)。如果你想自己做缩放 UI,直接调上面的 handler 方法即可。
标尺 · 出血位 · 参考线
标尺
// 显示 / 隐藏标尺
store.rulesVisible = true; // 通过 action 设置
出血位(印刷场景)
const workarea = store.editor?.workareaHandler;
workarea?.setBleed?.(3); // 3mm 出血
store.bleedVisible = true; // 显示红色出血线
智能参考线 / 吸附
开箱即用,由 GuidelinesHandler 管理:
store.editor?.guidelinesHandler.enable();
store.editor?.guidelinesHandler.disable();
拖动对象时会自动显示居中 / 等距 / 对齐辅助线。
快捷键
Workspace 自带一套画布常用快捷键(在 @ydesign/core 的 HotkeyHandler 里注册):
| 快捷键 | 功能 |
|---|---|
Ctrl/⌘ + Z | 撤销 |
Ctrl/⌘ + Shift + Z | 重做 |
Ctrl/⌘ + C / V / X | 复制 / 粘贴 / 剪切 |
Ctrl/⌘ + D | 克隆 |
Ctrl/⌘ + A | 全选 |
Ctrl/⌘ + G / Shift + G | 组合 / 拆分 |
Delete / Backspace | 删除选中 |
方向键 | 微移 1px |
Shift + 方向键 | 微移 10px |
Ctrl/⌘ + = / - / 0 | 放大 / 缩小 / 回到 100% |
自定义快捷键
通过 HotkeyHandler.bind 追加自己的快捷键:
store.editor?.hotkeyHandler.bind({
'ctrl+s, command+s': e => {
e.preventDefault();
saveToServer();
},
'ctrl+shift+d, command+shift+d': () => {
store.editor?.objectsHandler.duplicate();
},
});
你传入的快捷键会与内置快捷键叠加,不会覆盖默认行为。想要真正替换某个键的行为,可以在回调里重新调对应 handler 来控制。
右键菜单
画布右键菜单(<ContextMenu />)即将推出,详见 ContextMenu 右键菜单(规划中)。
在它正式发布之前,如果你急需右键菜单,可以监听容器的 contextmenu 事件,event.preventDefault() 后弹出自己的菜单,并在菜单项里调用 store.editor.xxxHandler 触发动作。完整示例请看 context-menu 文档中的"替代方案"段落。
容器样式与外观
Workspace 根节点带有固定的类名和深浅色背景:
<div id="canvas_container" className="bg-[#ecf0f1] dark:bg-[#92969d]">
{/* 内部 canvas */}
</div>
想覆盖背景,用全局 CSS 直接针对这个 id 覆盖即可:
#canvas_container {
background: #1e1e1e !important;
}
#canvas_container .inside-shadow {
/* 内阴影 */
box-shadow: inset 0 0 40px rgba(0, 0, 0, 0.15);
}
如果想配合 Tailwind 自定义颜色,可以直接改这个类(需要在自建壳里自己渲染 Workspace 的场景),或者用 [data-theme="dark"] 覆盖。
销毁 & 卸载
<Workspace /> 在 useEffect 卸载阶段会:
- 取消 Fabric canvas 的
after:render监听 - 调用
editor.destroy()清理全部 handler 与 DOM
所以你只需要正常让 React 卸载组件(路由切换、条件渲染 {show && <Workspace />}),不需要手动销毁。
如果 Workspace 是通过 createDesignEditorApp 挂载的,销毁时用 React root 的 root.unmount():
const { root } = createDesignEditorApp({ container, key: 'YOUR_API_KEY' });
// 卸载
root.unmount();
调试:拿到底层 Editor 实例
Workspace 初始化完成后,会在 window._c 上挂一个 Editor 实例,方便你在浏览器控制台里临时调试:
// 浏览器控制台
window._c.zoomHandler.zoomToFit();
window._c.objectsHandler.clear();
window._c.historyHandler.getStatus();
⚠️ 这是开发期调试用的后门,生产代码里请不要依赖
window._c。正式业务代码请统一走store.editor.xxxHandler。
与 Polotno Workspace 的区别
如果你曾经在 Polotno 里用过 <Workspace />,有几点差异需要注意:
| 能力 | Polotno | Ydesign |
|---|---|---|
components.PageControls 自定义页面操作条 | ✅ | ❌(没有 Page 概念,见 Scenes) |
components.NoPages 空状态 UI | ✅ | ❌(单画布场景,无需此 UI) |
backgroundColor / pageBorderColor / paddingX / paddingY prop | ✅ | ❌(用 CSS / store.setBackgroundColor 代替) |
onKeyDown 自定义键盘处理 | ✅ | 用 store.editor.hotkeyHandler.bind({ ... }) 代替 |
setTransformerStyle / setHighlighterStyle(Konva) | ✅ | ❌(基于 Fabric,通过 Fabric 的选中态样式配置) |
| 画布右键菜单 | ✅ | 🚧 规划中(见 ContextMenu) |
| 透明背景自动棋盘格 | 无 | ✅ 自动显示 |
底层渲染引擎不同:Polotno 基于 Konva,Ydesign 基于 Fabric.js v6。两者坐标系和事件模型不一样,API 并不能直接互相迁移。
下一步
- 👉 Toolbar 顶部工具栏
- 👉 Tooltip 浮动工具栏(规划中)
- 👉 Store 总览 —— 用 store 控制画布
- 👉 元素操作
- 👉 场景 & 导入导出
- 👉 定制化 · 画布行为