@haoxin-web/excalidraw 1.0.21 → 1.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,170 @@
1
+ # Remote Annotation Integration Guide
2
+
3
+ 本文档用于说明“白板端”和“控制端”完全隔离时,如何通过命令实现远程注释控制。
4
+
5
+ ## 目标
6
+
7
+ - 白板端只负责渲染 `Excalidraw` 并执行命令
8
+ - 控制端只负责发送工具命令(不直接操作白板实例)
9
+ - 两端通过 `socket`(或其他消息通道)通信
10
+
11
+ ---
12
+
13
+ ## 一、白板端如何接入
14
+
15
+ 白板端核心职责:
16
+
17
+ 1. 挂载 `Excalidraw`,拿到 `excalidrawAPI`
18
+ 2. 监听远端命令消息
19
+ 3. 收到命令后执行 `excalidrawAPI.leftToolbar.dispatch(command)`
20
+
21
+ ### 示例(React + socket)
22
+
23
+ ```tsx
24
+ import { useEffect, useState } from "react";
25
+ import Excalidraw from "@excalidraw/excalidraw";
26
+ import type {
27
+ ExcalidrawImperativeAPI,
28
+ LeftToolbarCommand,
29
+ } from "@excalidraw/excalidraw";
30
+
31
+ type SocketLike = {
32
+ on: (event: string, cb: (data: unknown) => void) => void;
33
+ off: (event: string, cb: (data: unknown) => void) => void;
34
+ };
35
+
36
+ const isLeftToolbarCommand = (v: unknown): v is LeftToolbarCommand => {
37
+ if (!v || typeof v !== "object") return false;
38
+ const type = (v as { type?: unknown }).type;
39
+ return (
40
+ typeof type === "string" &&
41
+ [
42
+ "selectSelection",
43
+ "selectFreedraw",
44
+ "selectLine",
45
+ "selectShape",
46
+ "selectText",
47
+ "selectEraser",
48
+ "updateStyle",
49
+ ].includes(type)
50
+ );
51
+ };
52
+
53
+ export default function WhiteboardPage({ socket }: { socket: SocketLike }) {
54
+ const [api, setApi] = useState<ExcalidrawImperativeAPI | null>(null);
55
+
56
+ useEffect(() => {
57
+ const handler = (data: unknown) => {
58
+ if (!isLeftToolbarCommand(data)) return;
59
+ api?.leftToolbar.dispatch(data);
60
+ };
61
+
62
+ socket.on("toolbar-command", handler);
63
+ return () => socket.off("toolbar-command", handler);
64
+ }, [socket, api]);
65
+
66
+ return (
67
+ <Excalidraw
68
+ excalidrawAPI={setApi}
69
+ showToolBar={false}
70
+ // 透明叠加在 PPT 场景可按需开启:
71
+ // viewModeEnabled={false}
72
+ />
73
+ );
74
+ }
75
+ ```
76
+
77
+ ### 白板端注意事项
78
+
79
+ - 建议对命令先做类型校验再执行
80
+ - 退出注释模式时及时解绑 socket 监听
81
+ - 若需“只读观看模式”,可以结合 `viewModeEnabled`
82
+
83
+ ---
84
+
85
+ ## 二、控制端如何调用命令
86
+
87
+ 控制端核心职责:
88
+
89
+ 1. 监听本地工具条交互(按钮、颜色、线宽、形状等)
90
+ 2. 将操作转换成 `LeftToolbarCommand`
91
+ 3. 通过 socket 发给白板端
92
+
93
+ ### 示例(发送命令)
94
+
95
+ ```ts
96
+ import type { LeftToolbarCommand } from "@excalidraw/excalidraw";
97
+
98
+ type SocketLike = {
99
+ emit: (event: string, data: unknown) => void;
100
+ };
101
+
102
+ const sendToolbarCommand = (
103
+ socket: SocketLike,
104
+ command: LeftToolbarCommand,
105
+ ) => {
106
+ socket.emit("toolbar-command", command);
107
+ };
108
+
109
+ // 切换到荧光笔
110
+ sendToolbarCommand(socket, {
111
+ type: "selectFreedraw",
112
+ payload: { variant: "highlighter", strokeWidth: 6, strokeColor: "#ffcc00" },
113
+ });
114
+
115
+ // 切换到线条:空心双箭头
116
+ sendToolbarCommand(socket, {
117
+ type: "selectLine",
118
+ payload: { variant: "outlineDoubleArrow", strokeWidth: 2, strokeColor: "#1677ff" },
119
+ });
120
+
121
+ // 切换到形状:椭圆
122
+ sendToolbarCommand(socket, {
123
+ type: "selectShape",
124
+ payload: { shape: "ellipse", strokeWidth: 3, strokeColor: "#1f1f1f" },
125
+ });
126
+
127
+ // 仅更新样式(不切工具)
128
+ sendToolbarCommand(socket, {
129
+ type: "updateStyle",
130
+ payload: { currentItemStrokeWidth: 4, currentItemStrokeColor: "#ff4d4f" },
131
+ });
132
+ ```
133
+
134
+ ---
135
+
136
+ ## 三、推荐事件约定
137
+
138
+ 建议统一使用一个事件名:
139
+
140
+ - `toolbar-command`
141
+
142
+ 消息体直接使用 `LeftToolbarCommand` JSON。
143
+
144
+ 这样控制端和白板端都容易调试,也便于后续扩展(录制/回放命令流)。
145
+
146
+ ---
147
+
148
+ ## 四、常见问题
149
+
150
+ ### 1) 为什么控制端不能直接调用白板方法?
151
+
152
+ 因为是跨端隔离部署,控制端拿不到白板实例。必须通过消息通道转发命令。
153
+
154
+ ### 2) 一定要用 socket 吗?
155
+
156
+ 不是。只要能传 JSON 的通道都可以:`WebSocket`、`postMessage`、Electron IPC 等。
157
+
158
+ ### 3) 如何保证命令安全?
159
+
160
+ - 白板端做类型校验
161
+ - 只允许白名单命令类型
162
+ - 必要时增加鉴权和房间隔离
163
+
164
+ ---
165
+
166
+ ## 五、下一步建议
167
+
168
+ - 接入日志:记录每次命令时间戳,方便排查问题
169
+ - 接入回放:按命令时间线回放注释过程
170
+ - 接入权限:区分“可控白板”的角色与“只读观众”角色
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haoxin-web/excalidraw",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "type": "module",
5
5
  "types": "./dist/types/excalidraw/index.d.ts",
6
6
  "main": "./dist/prod/index.js",
@@ -33,7 +33,8 @@
33
33
  }
34
34
  },
35
35
  "files": [
36
- "dist/*"
36
+ "dist/*",
37
+ "docs/*"
37
38
  ],
38
39
  "publishConfig": {
39
40
  "access": "public"
@@ -1 +0,0 @@
1
- import{X as a,Y as b,Z as c}from"../chunk-MGDE5ZMU.js";import"../chunk-UB3N3ODO.js";import"../chunk-SRAX5OIU.js";export{c as decodePngMetadata,b as encodePngMetadata,a as getTEXtChunk};