跳到主要内容

Workspace

<Workspace /> 是 Ydesign 编辑器里承载 Fabric 画布的 React 组件,也是整个界面中用户真正"画图"的区域。它做的事情其实只有几件:

  • 在挂载时创建一个 @ydesign/coreEditor 实例(绑定 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 });

尺寸变化会触发:

  1. workareaHandler 重建工作区矩形
  2. zoomHandler.auto() 自动适配屏幕
  3. workarea:changed 事件,store.width / store.height 自动同步
  4. 历史栈写入(支持撤销回原尺寸)

单位换算

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/coreHotkeyHandler 里注册):

快捷键功能
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 卸载阶段会:

  1. 取消 Fabric canvas 的 after:render 监听
  2. 调用 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 />,有几点差异需要注意:

能力PolotnoYdesign
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 并不能直接互相迁移。


下一步