@netless/appliance-plugin 1.1.36-beta.1 → 1.1.36-beta.3
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.
- package/READMA.zh-CN.md +60 -49
- package/README.md +92 -50
- package/dist/appliance-plugin.js +1 -1
- package/dist/appliance-plugin.mjs +1 -1
- package/dist/assets/{fullWorker-B_mvkoeW.js → fullWorker-C5kniG7M.js} +7 -7
- package/dist/assets/{subWorker-CRdsidWT.js → subWorker-Cps_t9fu.js} +7 -7
- package/dist/{bridge-enxPG6qf.js → bridge-DeN8jJgs.js} +1 -1
- package/dist/bridge-DvqpopG1.mjs +67 -0
- package/dist/bridge.js +1 -1
- package/dist/bridge.mjs +1 -1
- package/dist/component/textEditor/manager.d.ts +0 -1
- package/dist/fullWorker.js +2 -2
- package/dist/{index-D8SnD90W.mjs → index-B3MjbDsW.mjs} +1 -1
- package/dist/{index-2On9v0Ff.mjs → index-B7jKsOvs.mjs} +4089 -4324
- package/dist/{index-BZql6xgR.mjs → index-C-mmzWhD.mjs} +1 -1
- package/dist/{index-CcS9cKSp.js → index-C5LkBIDy.js} +1 -1
- package/dist/{index-D4z0hSjm.js → index-CGUukLaV.js} +1 -1
- package/dist/{index-Bm90lQii.js → index-CR9y5tMJ.js} +1 -1
- package/dist/{index-CIjmeY9J.js → index-ChEzLTlY.js} +1 -1
- package/dist/{index-K9QVPOhV.mjs → index-CobMH-xU.mjs} +14 -21
- package/dist/index-D9xjZ07S.js +1 -0
- package/dist/index-DJpL2E5_.js +1 -0
- package/dist/{index-DbI0V6BY.mjs → index-Dllr4Im3.mjs} +3937 -4172
- package/dist/{index-BrJL-fin.mjs → index-v6moTe3J.mjs} +14 -21
- package/dist/plugin/selectorApi.d.ts +4 -1
- package/dist/plugin/types.d.ts +8 -3
- package/dist/subWorker.js +2 -2
- package/dist/undo/index.d.ts +0 -1
- package/package.json +2 -4
- package/cdn/cdn.js +0 -1
- package/cdn/fullWorker-uAwmRi.js +0 -486
- package/cdn/subWorker-BVNpAC.js +0 -486
- package/dist/bridge-DYkH1J6p.mjs +0 -67
- package/dist/index-BSD0B_eV.js +0 -1
- package/dist/index-W9Jz9E04.js +0 -1
package/READMA.zh-CN.md
CHANGED
|
@@ -63,34 +63,13 @@ import { ApplianceMultiPlugin } from '@netless/appliance-plugin';
|
|
|
63
63
|
import { ApplianceSinglePlugin } from '@netless/appliance-plugin';
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
> **worker.js 文件与 CDN / 静态资源**
|
|
67
|
-
>
|
|
68
|
-
> 我们采用双 worker 并发来提高绘制效率,比主线程效率提高 40% 以上。两个 worker 文件的公共依赖重复,直接打进包体会显著增加体积,因此推荐通过 `options.cdn` 指定 worker 地址,有两种常见方式:
|
|
69
|
-
>
|
|
70
|
-
> 1. **CDN 方式**:将 `@netless/appliance-plugin/cdn` 下的 `fullWorker.js`、`subWorker.js` 部署到 CDN,在插件的 `getInstance` 的第二个参数 `options.cdn` 中传入这两个文件的 CDN 地址(`fullWorkerUrl`、`subWorkerUrl`)。
|
|
71
|
-
> ***注意***:CDN 配置的 URL 必须同源,否则 worker 线程会无法加载。
|
|
72
|
-
>
|
|
73
|
-
> 2. **静态资源方式**:将 `fullWorker.js`、`subWorker.js` 放到项目的静态目录(如 Vite 的 `public/`),不参与打包。在代码中基于 `import.meta.env.BASE_URL`(或等效的 publicPath)拼出完整 URL,传入 `options.cdn`。同源请求、不占打包体积,也无需 Blob 内联,内存占用更小。
|
|
74
|
-
>
|
|
75
|
-
> 若需控制包体积,请使用上述任一方式配置 `options.cdn`。
|
|
76
|
-
|
|
77
66
|
### 接入方式参考
|
|
78
67
|
|
|
79
|
-
####
|
|
68
|
+
#### 准备 worker URL
|
|
80
69
|
```js
|
|
81
|
-
// 引入 worker 方式三选一:
|
|
82
|
-
// 方式一:静态资源(推荐)- 将 fullWorker.js、subWorker.js 放到 public 等静态目录,同源请求、不占打包体积
|
|
83
|
-
const workerBase = (import.meta.env.BASE_URL || '/').replace(/\/?$/, '/');
|
|
84
|
-
const fullWorkerUrl = workerBase + 'fullWorker.js';
|
|
85
|
-
const subWorkerUrl = workerBase + 'subWorker.js';
|
|
86
|
-
|
|
87
|
-
// 方式二:CDN - 将 @netless/appliance-plugin/cdn 下文件部署到 CDN 后,此处写 CDN 地址、不占打包体积 注意: 域名一定要同源
|
|
88
|
-
const fullWorkerUrl = 'https://your-cdn.com/fullWorker.js';
|
|
89
|
-
const subWorkerUrl = 'https://your-cdn.com/subWorker.js';
|
|
90
|
-
|
|
91
|
-
// 方式三:从 dist 以 ?raw 内联为 Blob(需打包器支持 ?raw,如 Vite / webpack raw-loader)这种方式会占用一定内存.
|
|
92
70
|
import fullWorkerString from '@netless/appliance-plugin/dist/fullWorker.js?raw';
|
|
93
71
|
import subWorkerString from '@netless/appliance-plugin/dist/subWorker.js?raw';
|
|
72
|
+
|
|
94
73
|
const fullWorkerUrl = URL.createObjectURL(new Blob([fullWorkerString], { type: 'text/javascript' }));
|
|
95
74
|
const subWorkerUrl = URL.createObjectURL(new Blob([subWorkerString], { type: 'text/javascript' }));
|
|
96
75
|
```
|
|
@@ -103,7 +82,7 @@ const subWorkerUrl = URL.createObjectURL(new Blob([subWorkerString], { type: 'te
|
|
|
103
82
|
// 分包引用
|
|
104
83
|
import { useFastboard, Fastboard } from "@netless/fastboard-react";
|
|
105
84
|
|
|
106
|
-
//
|
|
85
|
+
// 按上文方式准备 worker URL:
|
|
107
86
|
const fullWorkerUrl = ...;
|
|
108
87
|
const subWorkerUrl = ...;
|
|
109
88
|
|
|
@@ -134,7 +113,7 @@ const app = useFastboard(() => ({
|
|
|
134
113
|
// 分包引用
|
|
135
114
|
import { createFastboard, createUI } from "@netless/fastboard";
|
|
136
115
|
|
|
137
|
-
//
|
|
116
|
+
// 按上文方式准备 worker URL:
|
|
138
117
|
const fullWorkerUrl = ...;
|
|
139
118
|
const subWorkerUrl = ...;
|
|
140
119
|
|
|
@@ -173,7 +152,7 @@ import { WhiteWebSdk } from "white-web-sdk";
|
|
|
173
152
|
import { WindowManager } from "@netless/window-manager";
|
|
174
153
|
import { ApplianceMultiPlugin } from '@netless/appliance-plugin';
|
|
175
154
|
|
|
176
|
-
//
|
|
155
|
+
// 按上文方式准备 worker URL:
|
|
177
156
|
const fullWorkerUrl = ...;
|
|
178
157
|
const subWorkerUrl = ...;
|
|
179
158
|
|
|
@@ -211,7 +190,7 @@ import '@netless/appliance-plugin/dist/style.css';
|
|
|
211
190
|
import { WhiteWebSdk } from "white-web-sdk";
|
|
212
191
|
import { ApplianceSinglePlugin, ApplianceSigleWrapper } from '@netless/appliance-plugin';
|
|
213
192
|
|
|
214
|
-
//
|
|
193
|
+
// 按上文方式准备 worker URL:
|
|
215
194
|
const fullWorkerUrl = ...;
|
|
216
195
|
const subWorkerUrl = ...;
|
|
217
196
|
|
|
@@ -338,20 +317,26 @@ injectMethodToObject(windowmanager.mainView,'setMemberState');
|
|
|
338
317
|
|
|
339
318
|
6. Selector / Element 扩展接口
|
|
340
319
|
- `getSelectedElements(viewId?)` - 获取当前 selector 选中快照
|
|
320
|
+
- `isElementPropertySupported(toolsType, field)` - 判断指定教具类型是否支持某个属性字段,适合自定义 floatbar 按钮显隐
|
|
341
321
|
- `blurSelector(viewId?)` - 取消当前 selector 选中
|
|
342
322
|
- `updateSelectedElements(viewId?, changes)` - 更新当前 selector 选中集的属性
|
|
343
323
|
- `copySelectedElements(viewId?)` - 复制当前 selector 选中集
|
|
344
324
|
- `deleteSelectedElements(viewId?)` - 删除当前 selector 选中集
|
|
345
325
|
- `updateElement(elementId, scenePath, viewId, updateElementInfo, useUndoRedoStack?)` - 单元素最终态更新接口,返回 `Promise<boolean>`
|
|
326
|
+
- `getFloatbarContainer(viewId?)` - 获取当前 view 内置的自定义 floatbar 挂载容器
|
|
327
|
+
- `getViewOffsetToContainer(container, viewId?)` - 计算当前 view 到外部容器的坐标偏移,用于挂载到业务 overlay root
|
|
346
328
|
|
|
347
329
|
其中需要注意:
|
|
348
330
|
|
|
349
331
|
- `updateSelectedElements(...)` 是 selector-only 能力,只处理当前选中的 selector 集合
|
|
332
|
+
- `blurSelector(...)`、`updateSelectedElements(...)`、`copySelectedElements(...)`、`deleteSelectedElements(...)`、`updateElement(...)` 都要求在可写权限下调用
|
|
350
333
|
- `updateElement(...)` 是 storage-first 的单元素最终态更新通知接口
|
|
351
334
|
- `updateElement(...)` 不表达调用返回时已经渲染完成
|
|
352
335
|
- `updateElement(...)` 不支持 selector
|
|
353
336
|
- `updateElementInfo` 需要显式携带 `toolsType`,并按教具类型声明对应字段
|
|
354
337
|
- `updateElement(...)` 返回 `Promise<boolean>`,仅表示本次调用是否通过基础校验并成功发起
|
|
338
|
+
- `getFloatbarContainer(...)` 是推荐的自定义 floatbar 挂载方式;挂到该容器下时,`selectorGeometryChange.viewRect` 可直接用于定位
|
|
339
|
+
- 如果业务必须挂到外部容器,请配合 `getViewOffsetToContainer(...)` 做坐标换算
|
|
355
340
|
|
|
356
341
|
7. Selector 扩展事件
|
|
357
342
|
- `selectedElementsChange`
|
|
@@ -366,7 +351,14 @@ injectMethodToObject(windowmanager.mainView,'setMemberState');
|
|
|
366
351
|
- `remoteSelectorChange`
|
|
367
352
|
- 表示远端 / 被同步端 selector 的同步结果变化
|
|
368
353
|
|
|
369
|
-
|
|
354
|
+
8. Selector / Floatbar 自定义能力
|
|
355
|
+
- 支持关闭内置 floatbar,仅保留 selector 选中、拖拽、缩放、旋转等交互能力
|
|
356
|
+
- 支持基于 `selectedElementsChange`、`selectorGeometryChange`、`selectorTransformChange`、`remoteSelectorChange` 事件渲染业务自定义 UI
|
|
357
|
+
- 支持通过 `overwriteSelectorStyles` 覆盖 selector 外框、控制点、端点和锁态图标样式
|
|
358
|
+
- 支持将自定义 floatbar 挂到 plugin 内部容器,或挂到业务自己的外部 overlay 容器
|
|
359
|
+
- 推荐结合 [customer-custom-selector-floatbar-integration.zh-CN.md](https://github.com/user-attachments/files/29439912/customer-custom-selector-floatbar-integration.zh-CN.md) 接入
|
|
360
|
+
|
|
361
|
+
9. 不兼容接口
|
|
370
362
|
- [`exportScene`](https://doc.shengwang.cn/api-ref/whiteboard/javascript/interfaces/room#exportScene) - appliance-plugin 开启后,笔记不能按 room 的方式导出
|
|
371
363
|
- [服务端截图](https://doc.shengwang.cn/doc/whiteboard/restful/fastboard-sdk/restful-wb/operations/post-v5-rooms-uuid-screenshots) - appliance-plugin 开启后,笔记不能通过调用服务端截图方式获取截图,而需要改用 `screenshotToCanvasAsync` 获取
|
|
372
364
|
|
|
@@ -408,6 +400,41 @@ room.setMemberState({
|
|
|
408
400
|
- 闭合绘制矩形、圆/椭圆、三角形、五角星
|
|
409
401
|
- 箭头和直线保持单笔非闭合
|
|
410
402
|
|
|
403
|
+
##### 自定义 Selector / Floatbar 与 Selector 扩展 API (Version >=1.1.36-beta.2)
|
|
404
|
+
|
|
405
|
+
当前版本新增了一套围绕 selector 的事件与命令式 API,方便业务在 `white-web-sdk` / `@netless/window-manager` 场景下自定义 selector UI、floatbar UI 和选中属性面板。
|
|
406
|
+
|
|
407
|
+
新增事件:
|
|
408
|
+
|
|
409
|
+
- `selectedElementsChange` - 只表示最终选中集合变化
|
|
410
|
+
- `selectorGeometryChange` - 只表示最终几何结果变化,坐标统一输出 `viewRect`
|
|
411
|
+
- `selectorTransformChange` - 只表示拖拽、拉伸、旋转、端点编辑等过程态
|
|
412
|
+
- `remoteSelectorChange` - 表示远端 / 被同步端 selector 的同步结果变化
|
|
413
|
+
|
|
414
|
+
新增 API:
|
|
415
|
+
|
|
416
|
+
- `getSelectedElements(viewId?)`
|
|
417
|
+
- `isElementPropertySupported(toolsType, field)`
|
|
418
|
+
- `blurSelector(viewId?)`
|
|
419
|
+
- `updateSelectedElements(viewId?, changes)`
|
|
420
|
+
- `copySelectedElements(viewId?)`
|
|
421
|
+
- `deleteSelectedElements(viewId?)`
|
|
422
|
+
- `updateElement(elementId, scenePath, viewId, updateElementInfo, useUndoRedoStack?)`
|
|
423
|
+
- `getFloatbarContainer(viewId?)`
|
|
424
|
+
- `getViewOffsetToContainer(container, viewId?)`
|
|
425
|
+
|
|
426
|
+
典型用途:
|
|
427
|
+
|
|
428
|
+
- 关闭内置 floatbar,自己渲染按钮、色板、字号和文本样式 UI
|
|
429
|
+
- 通过 `getSelectedElements()` 获取当前选中快照
|
|
430
|
+
- 通过 `updateSelectedElements()` 批量更新当前选中元素属性
|
|
431
|
+
- 通过 `updateElement()` 更新某个非当前选中的单元素
|
|
432
|
+
- 通过 `getFloatbarContainer()` 或 `getViewOffsetToContainer()` 决定自定义 floatbar 挂载位置
|
|
433
|
+
- 通过 `overwriteSelectorStyles` 统一覆盖 selector 视觉样式
|
|
434
|
+
|
|
435
|
+
详细设计与接入示例请参考:
|
|
436
|
+
- [customer-custom-selector-floatbar-integration.zh-CN.md](https://github.com/user-attachments/files/29439912/customer-custom-selector-floatbar-integration.zh-CN.md)
|
|
437
|
+
|
|
411
438
|
##### 扩展教具 (Version >=1.1.1)
|
|
412
439
|
在原来的[白板教具](https://doc.shengwang.cn/api-ref/whiteboard/javascript/globals.html#memberstate)类型上,增加了一些扩展功能属性,如下:
|
|
413
440
|
|
|
@@ -796,10 +823,10 @@ plugin.insertBackgroundImage(viewId, {
|
|
|
796
823
|
`getInstance(wm: WindowManager | Room | Player, adaptor: ApplianceAdaptor)`
|
|
797
824
|
- `wm`: `WindowManager | Room | Player`。多窗口模式下传入的是 `WindowManager`,单窗口模式下传入的是 `Room` 或者 `Player`(白板回放模式)。
|
|
798
825
|
- `adaptor`: 配置适配器。
|
|
799
|
-
- `options: AppliancePluginOptions` - 必须配置,其中 `cdn`
|
|
826
|
+
- `options: AppliancePluginOptions` - 必须配置,其中 `cdn` 用于传入 worker URL。
|
|
800
827
|
```js
|
|
801
828
|
export type AppliancePluginOptions = {
|
|
802
|
-
/**
|
|
829
|
+
/** worker URL 配置项 */
|
|
803
830
|
cdn: CdnOpt;
|
|
804
831
|
/** 额外配置项 */
|
|
805
832
|
extras?: ExtrasOptions;
|
|
@@ -874,19 +901,9 @@ appliancePlugin.currentManager.consoleWorkerInfo() // 可以查看到 worker
|
|
|
874
901
|
import { ApplianceSinglePlugin } from '@netless/appliance-plugin';
|
|
875
902
|
import '@netless/appliance-plugin/dist/style.css';
|
|
876
903
|
|
|
877
|
-
// 方式1: 使用 CDN(推荐生产环境)
|
|
878
|
-
const plugin = await ApplianceSinglePlugin.getInstance(room, {
|
|
879
|
-
options: {
|
|
880
|
-
cdn: {
|
|
881
|
-
fullWorkerUrl: 'https://your-cdn.com/fullWorker.js',
|
|
882
|
-
subWorkerUrl: 'https://your-cdn.com/subWorker.js',
|
|
883
|
-
},
|
|
884
|
-
},
|
|
885
|
-
});
|
|
886
|
-
|
|
887
|
-
// 方式2: 使用本地 worker 文件(适合开发环境)
|
|
888
904
|
import fullWorkerString from '@netless/appliance-plugin/dist/fullWorker.js?raw';
|
|
889
905
|
import subWorkerString from '@netless/appliance-plugin/dist/subWorker.js?raw';
|
|
906
|
+
|
|
890
907
|
const fullWorkerBlob = new Blob([fullWorkerString], {type: 'text/javascript'});
|
|
891
908
|
const fullWorkerUrl = URL.createObjectURL(fullWorkerBlob);
|
|
892
909
|
const subWorkerBlob = new Blob([subWorkerString], {type: 'text/javascript'});
|
|
@@ -992,19 +1009,13 @@ const canRedo = plugin.canRedoSteps() > 0;
|
|
|
992
1009
|
- **多窗口场景**:如果需要多窗口功能,使用 `ApplianceMultiPlugin`
|
|
993
1010
|
- **单白板场景**:如果只需要单白板功能,使用 `ApplianceSinglePlugin`
|
|
994
1011
|
|
|
995
|
-
### 2.
|
|
996
|
-
|
|
997
|
-
- **CDN 部署**(推荐):适合生产环境,可以减少主包体积(主包约 400kB,两个 worker 各约 800kB)
|
|
998
|
-
- **本地打包**:适合开发环境或对包体积不敏感的场景
|
|
999
|
-
|
|
1000
|
-
### 3. 性能优化建议
|
|
1012
|
+
### 2. 性能优化建议
|
|
1001
1013
|
|
|
1002
|
-
- 使用 CDN 部署 worker 文件,减少主包体积
|
|
1003
1014
|
- 合理配置 `bufferSize`,根据设备性能调整画布缓存大小
|
|
1004
1015
|
- 在移动端或低性能设备上,可以考虑使用 `useSimple: true` 简单模式
|
|
1005
1016
|
- 如有非必要的功能, 可以不用开启 `useBackgroundThread: true`
|
|
1006
1017
|
|
|
1007
|
-
###
|
|
1018
|
+
### 3. 兼容性说明
|
|
1008
1019
|
|
|
1009
1020
|
- 支持现代浏览器(Chrome、Firefox、Safari、Edge)
|
|
1010
1021
|
- 移动端浏览器支持情况取决于 OffscreenCanvas 支持情况
|
package/README.md
CHANGED
|
@@ -63,35 +63,13 @@ import { ApplianceMultiPlugin } from '@netless/appliance-plugin';
|
|
|
63
63
|
import { ApplianceSinglePlugin } from '@netless/appliance-plugin';
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
> **worker.js files: CDN & static assets**
|
|
67
|
-
>
|
|
68
|
-
> We use dual workers for higher drawing efficiency (40%+ over the main thread). The two worker files share duplicated dependencies, so bundling them would significantly increase package size. We recommend providing worker URLs via `options.cdn`. Two common approaches:
|
|
69
|
-
>
|
|
70
|
-
> 1. **CDN**: Deploy `fullWorker.js` and `subWorker.js` from `@netless/appliance-plugin/cdn` to your CDN, then pass their URLs as `fullWorkerUrl` and `subWorkerUrl` in the plugin’s `getInstance` second argument `options.cdn`.
|
|
71
|
-
> ***Note***: CDN URLs must be same-origin with your app, or the workers will fail to load.
|
|
72
|
-
>
|
|
73
|
-
> 2. **Static assets**: Put `fullWorker.js` and `subWorker.js` in your project’s static directory (e.g. Vite’s `public/`), so they are not bundled. In code, build full URLs from `import.meta.env.BASE_URL` (or your publicPath) and pass them to `options.cdn`. Same-origin, no bundle bloat, no Blob inline, lower memory use.
|
|
74
|
-
>
|
|
75
|
-
> To keep bundle size down, configure `options.cdn` using one of the above.
|
|
76
|
-
|
|
77
66
|
### Access Mode Reference
|
|
78
67
|
|
|
79
|
-
####
|
|
68
|
+
#### Preparing worker URLs
|
|
80
69
|
```js
|
|
81
|
-
// Choose one of three ways to provide worker URLs:
|
|
82
|
-
|
|
83
|
-
// Option 1: Static assets (recommended) — put fullWorker.js & subWorker.js in public (or similar); same-origin, no bundle cost
|
|
84
|
-
const workerBase = (import.meta.env.BASE_URL || '/').replace(/\/?$/, '/');
|
|
85
|
-
const fullWorkerUrl = workerBase + 'fullWorker.js';
|
|
86
|
-
const subWorkerUrl = workerBase + 'subWorker.js';
|
|
87
|
-
|
|
88
|
-
// Option 2: CDN — after deploying files from @netless/appliance-plugin/cdn to your CDN, set URLs here. Note: must be same-origin
|
|
89
|
-
const fullWorkerUrl = 'https://your-cdn.com/fullWorker.js';
|
|
90
|
-
const subWorkerUrl = 'https://your-cdn.com/subWorker.js';
|
|
91
|
-
|
|
92
|
-
// Option 3: Inline via ?raw as Blob (requires ?raw support, e.g. Vite or webpack raw-loader). Uses more memory.
|
|
93
70
|
import fullWorkerString from '@netless/appliance-plugin/dist/fullWorker.js?raw';
|
|
94
71
|
import subWorkerString from '@netless/appliance-plugin/dist/subWorker.js?raw';
|
|
72
|
+
|
|
95
73
|
const fullWorkerUrl = URL.createObjectURL(new Blob([fullWorkerString], { type: 'text/javascript' }));
|
|
96
74
|
const subWorkerUrl = URL.createObjectURL(new Blob([subWorkerString], { type: 'text/javascript' }));
|
|
97
75
|
```
|
|
@@ -104,7 +82,7 @@ const subWorkerUrl = URL.createObjectURL(new Blob([subWorkerString], { type: 'te
|
|
|
104
82
|
// Subpackage reference
|
|
105
83
|
import { useFastboard, Fastboard } from "@netless/fastboard-react";
|
|
106
84
|
|
|
107
|
-
//
|
|
85
|
+
// Prepare worker URLs as shown above:
|
|
108
86
|
const fullWorkerUrl = ...;
|
|
109
87
|
const subWorkerUrl = ...;
|
|
110
88
|
|
|
@@ -135,7 +113,7 @@ const app = useFastboard(() => ({
|
|
|
135
113
|
// Subpackage reference
|
|
136
114
|
import { createFastboard, createUI } from "@netless/fastboard";
|
|
137
115
|
|
|
138
|
-
//
|
|
116
|
+
// Prepare worker URLs as shown above:
|
|
139
117
|
const fullWorkerUrl = ...;
|
|
140
118
|
const subWorkerUrl = ...;
|
|
141
119
|
|
|
@@ -174,7 +152,7 @@ import { WhiteWebSdk } from "white-web-sdk";
|
|
|
174
152
|
import { WindowManager } from "@netless/window-manager";
|
|
175
153
|
import { ApplianceMultiPlugin } from '@netless/appliance-plugin';
|
|
176
154
|
|
|
177
|
-
//
|
|
155
|
+
// Prepare worker URLs as shown above:
|
|
178
156
|
const fullWorkerUrl = ...;
|
|
179
157
|
const subWorkerUrl = ...;
|
|
180
158
|
|
|
@@ -211,7 +189,7 @@ import '@netless/appliance-plugin/dist/style.css';
|
|
|
211
189
|
|
|
212
190
|
import { WhiteWebSdk } from "white-web-sdk";
|
|
213
191
|
import { ApplianceSinglePlugin, ApplianceSigleWrapper } from '@netless/appliance-plugin';
|
|
214
|
-
//
|
|
192
|
+
// Prepare worker URLs as shown above:
|
|
215
193
|
const fullWorkerUrl = ...;
|
|
216
194
|
const subWorkerUrl = ...;
|
|
217
195
|
|
|
@@ -329,7 +307,51 @@ The following interfaces are involved:
|
|
|
329
307
|
- `updateMarkmap` - Update markdown text in whiteboard (Version >=1.1.32) **This method requires enabling extras.useBackgroundThread**
|
|
330
308
|
- `insertBackgroundImage` - Insert whiteboard background image (Version >=1.1.32) **This method requires enabling extras.useBackgroundThread**
|
|
331
309
|
|
|
332
|
-
5.
|
|
310
|
+
5. Selector / Element extension APIs
|
|
311
|
+
- `getSelectedElements(viewId?)` - Get the current selector snapshot
|
|
312
|
+
- `isElementPropertySupported(toolsType, field)` - Check whether a property field is supported by a specific tools type, useful for custom floatbar button visibility
|
|
313
|
+
- `blurSelector(viewId?)` - Clear the current selector selection
|
|
314
|
+
- `updateSelectedElements(viewId?, changes)` - Update properties of the current selector selection set
|
|
315
|
+
- `copySelectedElements(viewId?)` - Copy the current selector selection set
|
|
316
|
+
- `deleteSelectedElements(viewId?)` - Delete the current selector selection set
|
|
317
|
+
- `updateElement(elementId, scenePath, viewId, updateElementInfo, useUndoRedoStack?)` - Single-element final-state update API, returns `Promise<boolean>`
|
|
318
|
+
- `getFloatbarContainer(viewId?)` - Get the built-in custom floatbar mount container for the current view
|
|
319
|
+
- `getViewOffsetToContainer(container, viewId?)` - Convert coordinates from the current view to an external container, useful when mounting to a business overlay root
|
|
320
|
+
|
|
321
|
+
Notes:
|
|
322
|
+
|
|
323
|
+
- `updateSelectedElements(...)` is selector-only and only operates on the current selection set
|
|
324
|
+
- `blurSelector(...)`, `updateSelectedElements(...)`, `copySelectedElements(...)`, `deleteSelectedElements(...)`, and `updateElement(...)` should be called only when the room is writable
|
|
325
|
+
- `updateElement(...)` is a storage-first single-element final-state update API
|
|
326
|
+
- `updateElement(...)` does not imply rendering has finished when the Promise resolves
|
|
327
|
+
- `updateElement(...)` does not support selector itself
|
|
328
|
+
- `updateElementInfo` must explicitly include `toolsType`, and fields must match that tools type
|
|
329
|
+
- `updateElement(...)` returning `Promise<boolean>` only means the call passed validation and the update flow was started successfully
|
|
330
|
+
- `getFloatbarContainer(...)` is the recommended mount point for a custom floatbar; when mounted there, `selectorGeometryChange.viewRect` can be used directly for positioning
|
|
331
|
+
- If you must mount to an external container, use `getViewOffsetToContainer(...)` to convert coordinates
|
|
332
|
+
|
|
333
|
+
6. Selector extension events
|
|
334
|
+
- `selectedElementsChange`
|
|
335
|
+
- Fires only when `selectedIds` change
|
|
336
|
+
- Represents only the final selection set change
|
|
337
|
+
- `selectorGeometryChange`
|
|
338
|
+
- Represents only the final geometry change
|
|
339
|
+
- Coordinates are unified as `viewRect`
|
|
340
|
+
- `selectorTransformChange`
|
|
341
|
+
- Represents only transform process states such as drag, resize, rotate, and endpoint editing
|
|
342
|
+
- Exposes only `viewId + emitEventType + workState`
|
|
343
|
+
- `remoteSelectorChange`
|
|
344
|
+
- Represents selector sync result changes from remote / synced clients
|
|
345
|
+
|
|
346
|
+
7. Custom selector / floatbar capability
|
|
347
|
+
- You can disable the built-in floatbar while keeping selector selection, drag, resize, rotate, and endpoint-edit interactions
|
|
348
|
+
- You can render your own custom UI based on `selectedElementsChange`, `selectorGeometryChange`, `selectorTransformChange`, and `remoteSelectorChange`
|
|
349
|
+
- You can override selector visuals such as the highlight box, control points, endpoint dots, and locked icon through `overwriteSelectorStyles`
|
|
350
|
+
- You can mount your custom floatbar into the plugin-provided internal container or your own external overlay container
|
|
351
|
+
- Recommended reading:
|
|
352
|
+
- [customer-custom-selector-floatbar-integration.zh-CN.md](https://github.com/user-attachments/files/29439912/customer-custom-selector-floatbar-integration.zh-CN.md)
|
|
353
|
+
|
|
354
|
+
8. Incompatible interfaces
|
|
333
355
|
- [`exportScene`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#exportscene) - After appliance-plugin is enabled, notes cannot be exported in room mode
|
|
334
356
|
- [Server-side screenshot](https://docs.agora.io/en/interactive-whiteboard/reference/whiteboard-api/screenshots?platform=web#screenshot-a-scene-post) - After appliance-plugin is enabled, notes cannot be obtained by calling server-side screenshot, but need to use `screenshotToCanvasAsync` to obtain the screenshot
|
|
335
357
|
|
|
@@ -371,6 +393,42 @@ Recommendations:
|
|
|
371
393
|
- Draw `Rectangle`, `Ellipse / Circle`, `Triangle`, and `Five-point Star` as closed strokes
|
|
372
394
|
- Draw `Arrow` and `Straight` as open single strokes
|
|
373
395
|
|
|
396
|
+
##### Custom Selector / Floatbar and Selector Extension APIs (Version >=1.1.36-beta.2)
|
|
397
|
+
|
|
398
|
+
This version adds a selector-focused event and imperative API set so that integrators can build custom selector UI, floatbar UI, and selected-element property panels in `white-web-sdk` / `@netless/window-manager` scenarios.
|
|
399
|
+
|
|
400
|
+
New events:
|
|
401
|
+
|
|
402
|
+
- `selectedElementsChange` - final selection set changes only
|
|
403
|
+
- `selectorGeometryChange` - final geometry changes only, with unified `viewRect`
|
|
404
|
+
- `selectorTransformChange` - process states for drag, resize, rotate, and endpoint editing
|
|
405
|
+
- `remoteSelectorChange` - selector sync result changes from remote / synced clients
|
|
406
|
+
|
|
407
|
+
New APIs:
|
|
408
|
+
|
|
409
|
+
- `getSelectedElements(viewId?)`
|
|
410
|
+
- `isElementPropertySupported(toolsType, field)`
|
|
411
|
+
- `blurSelector(viewId?)`
|
|
412
|
+
- `updateSelectedElements(viewId?, changes)`
|
|
413
|
+
- `copySelectedElements(viewId?)`
|
|
414
|
+
- `deleteSelectedElements(viewId?)`
|
|
415
|
+
- `updateElement(elementId, scenePath, viewId, updateElementInfo, useUndoRedoStack?)`
|
|
416
|
+
- `getFloatbarContainer(viewId?)`
|
|
417
|
+
- `getViewOffsetToContainer(container, viewId?)`
|
|
418
|
+
|
|
419
|
+
Typical usage:
|
|
420
|
+
|
|
421
|
+
- Disable the built-in floatbar and render your own buttons, palettes, font-size, and text-style UI
|
|
422
|
+
- Use `getSelectedElements()` to read the current selector snapshot
|
|
423
|
+
- Use `updateSelectedElements()` to batch-update the current selection
|
|
424
|
+
- Use `updateElement()` to update a specific element outside the current selection
|
|
425
|
+
- Use `getFloatbarContainer()` or `getViewOffsetToContainer()` to decide where custom floatbar UI should be mounted
|
|
426
|
+
- Use `overwriteSelectorStyles` to customize selector visuals
|
|
427
|
+
|
|
428
|
+
For design details and integration examples, see:
|
|
429
|
+
|
|
430
|
+
- [customer-custom-selector-floatbar-integration.zh-CN.md](https://github.com/user-attachments/files/29439912/customer-custom-selector-floatbar-integration.zh-CN.md)
|
|
431
|
+
|
|
374
432
|
##### Extended Tools (Version >=1.1.1)
|
|
375
433
|
On the original [whiteboard tools](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/globals.html#memberstate) type, some extended function attributes have been added, as follows:
|
|
376
434
|
|
|
@@ -780,10 +838,10 @@ plugin.usePlugin(autoDrawPlugin);
|
|
|
780
838
|
`getInstance(wm: WindowManager | Room | Player, adaptor: ApplianceAdaptor)`
|
|
781
839
|
- `wm`: `WindowManager | Room | Player`. In multi-window mode, pass `WindowManager`, in single-window mode, pass `Room` or `Player` (whiteboard playback mode).
|
|
782
840
|
- `adaptor`: Configuration adapter.
|
|
783
|
-
- `options: AppliancePluginOptions` - Must be configured, where `cdn`
|
|
841
|
+
- `options: AppliancePluginOptions` - Must be configured, where `cdn` contains worker URLs.
|
|
784
842
|
```js
|
|
785
843
|
export type AppliancePluginOptions = {
|
|
786
|
-
/**
|
|
844
|
+
/** Worker URL configuration item */
|
|
787
845
|
cdn: CdnOpt;
|
|
788
846
|
/** Additional configuration items */
|
|
789
847
|
extras?: ExtrasOptions;
|
|
@@ -856,19 +914,9 @@ appliancePlugin.currentManager.consoleWorkerInfo() // Can view drawing informat
|
|
|
856
914
|
import { ApplianceSinglePlugin } from '@netless/appliance-plugin';
|
|
857
915
|
import '@netless/appliance-plugin/dist/style.css';
|
|
858
916
|
|
|
859
|
-
// Method 1: Using CDN (recommended for production)
|
|
860
|
-
const plugin = await ApplianceSinglePlugin.getInstance(room, {
|
|
861
|
-
options: {
|
|
862
|
-
cdn: {
|
|
863
|
-
fullWorkerUrl: 'https://your-cdn.com/fullWorker.js',
|
|
864
|
-
subWorkerUrl: 'https://your-cdn.com/subWorker.js',
|
|
865
|
-
},
|
|
866
|
-
},
|
|
867
|
-
});
|
|
868
|
-
|
|
869
|
-
// Method 2: Using local worker files (suitable for development)
|
|
870
917
|
import fullWorkerString from '@netless/appliance-plugin/dist/fullWorker.js?raw';
|
|
871
918
|
import subWorkerString from '@netless/appliance-plugin/dist/subWorker.js?raw';
|
|
919
|
+
|
|
872
920
|
const fullWorkerBlob = new Blob([fullWorkerString], {type: 'text/javascript'});
|
|
873
921
|
const fullWorkerUrl = URL.createObjectURL(fullWorkerBlob);
|
|
874
922
|
const subWorkerBlob = new Blob([subWorkerString], {type: 'text/javascript'});
|
|
@@ -974,19 +1022,13 @@ const canRedo = plugin.canRedoSteps() > 0;
|
|
|
974
1022
|
- **Multi-window scenario**: If you need multi-window functionality, use `ApplianceMultiPlugin`
|
|
975
1023
|
- **Single whiteboard scenario**: If you only need single whiteboard functionality, use `ApplianceSinglePlugin`
|
|
976
1024
|
|
|
977
|
-
### 2.
|
|
978
|
-
|
|
979
|
-
- **CDN deployment** (recommended): Suitable for production environments, can reduce main package size (main package ~400kB, two workers ~800kB each)
|
|
980
|
-
- **Local packaging**: Suitable for development environments or scenarios where package size is not a concern
|
|
981
|
-
|
|
982
|
-
### 3. Performance optimization recommendations
|
|
1025
|
+
### 2. Performance optimization recommendations
|
|
983
1026
|
|
|
984
|
-
- Use CDN deployment for worker files to reduce main package size
|
|
985
1027
|
- Reasonably configure `bufferSize` to adjust canvas cache size according to device performance
|
|
986
1028
|
- On mobile or low-performance devices, consider using `useSimple: true` simple mode
|
|
987
1029
|
- If there are unnecessary features, you can avoid enabling `useBackgroundThread: true`
|
|
988
1030
|
|
|
989
|
-
###
|
|
1031
|
+
### 3. Compatibility notes
|
|
990
1032
|
|
|
991
1033
|
- Supports modern browsers (Chrome, Firefox, Safari, Edge)
|
|
992
1034
|
- Mobile browser support depends on OffscreenCanvas support
|
package/dist/appliance-plugin.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-D9xjZ07S.js");exports.ActiveContainerType=e.ActiveContainerType;exports.ApplianceMultiPlugin=e.ApplianceMultiPlugin;exports.ApplianceNames=e.ApplianceNames;exports.ApplianceSigleWrapper=e.ApplianceSigleWrapper;exports.ApplianceSinglePlugin=e.ApplianceSinglePlugin;exports.Cursor_Hover_Id=e.Cursor_Hover_Id;exports.ECanvasShowType=e.ECanvasShowType;exports.EDataType=e.EDataType;exports.EForceStopReason=e.EForceStopReason;exports.EImageType=e.EImageType;exports.EMatrixrRelationType=e.EMatrixrRelationType;exports.EOperationType=e.EOperationType;exports.EPostMessageType=e.EPostMessageType;exports.ERenderFilterType=e.ERenderFilterType;exports.ESVGType=e.ESVGType;exports.EScaleType=e.EScaleType;exports.EStrokeType=e.EStrokeType;exports.EToolsKey=e.EToolsKey;exports.ElayerType=e.ElayerType;exports.EmitEventType=e.EmitEventType;exports.EventMessageType=e.EventMessageType;exports.EventWorkState=e.EventWorkState;exports.EvevtWorkState=e.EventWorkState;exports.InternalMsgEmitterType=e.InternalMsgEmitterType;exports.Main_View_Id=e.Main_View_Id;exports.Plugin=e.Plugin;exports.ShapeType=e.ShapeType;exports.Task_Time_Interval=e.Task_Time_Interval;exports.fullWorkerUrl=e.fullWorker;exports.subWorkerUrl=e.subWorker;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a7 as s, a8 as p, a9 as r, aa as t, ab as i, a4 as l, Z as n, b as E, ac as o, t as T, j as y, ad as v, a as g, ae as S, d as c, u, w as k, c as m, af as M, E as _, ag as d, v as A, v as I, ah as W, Y as P, ai as b, aj as f, a6 as h, ak as w, al as C } from "./index-
|
|
1
|
+
import { a7 as s, a8 as p, a9 as r, aa as t, ab as i, a4 as l, Z as n, b as E, ac as o, t as T, j as y, ad as v, a as g, ae as S, d as c, u, w as k, c as m, af as M, E as _, ag as d, v as A, v as I, ah as W, Y as P, ai as b, aj as f, a6 as h, ak as w, al as C } from "./index-Dllr4Im3.mjs";
|
|
2
2
|
export {
|
|
3
3
|
s as ActiveContainerType,
|
|
4
4
|
p as ApplianceMultiPlugin,
|