@netless/appliance-plugin 1.1.1 → 1.1.3-4.beta.0

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.
Files changed (154) hide show
  1. package/READMA.zh-CN.md +993 -0
  2. package/README.md +963 -176
  3. package/cdn/cdn.js +1 -1
  4. package/cdn/fullWorker-Dwf7nY.js +486 -0
  5. package/cdn/subWorker-DXBnNm.js +486 -0
  6. package/dist/ObserverMap-BudneEfB.mjs +58 -0
  7. package/dist/ObserverMap-DTz9zucn.js +1 -0
  8. package/dist/appliance-plugin.js +1 -1
  9. package/dist/appliance-plugin.mjs +27 -18
  10. package/dist/cdn.d.ts +2 -2
  11. package/dist/collector/base.d.ts +3 -1
  12. package/dist/collector/collector.d.ts +57 -15
  13. package/dist/collector/index.d.ts +4 -4
  14. package/dist/collector/types.d.ts +49 -16
  15. package/dist/component/autoDraw/index.d.ts +0 -0
  16. package/dist/component/miniMap/index.d.ts +1 -0
  17. package/dist/component/miniMap/manager.d.ts +37 -0
  18. package/dist/component/miniMap/view.d.ts +14 -0
  19. package/dist/component/svg/base.d.ts +30 -0
  20. package/dist/component/svg/manager.d.ts +44 -0
  21. package/dist/component/svg/markmap.d.ts +41 -0
  22. package/dist/component/svg/mermaid-check.d.ts +18 -0
  23. package/dist/component/svg/mermaid-loader.d.ts +29 -0
  24. package/dist/component/svg/mermaid.d.ts +109 -0
  25. package/dist/component/svg/snapshot.d.ts +31 -0
  26. package/dist/component/svg/svgElemt.d.ts +43 -0
  27. package/dist/component/svg/svgToImageLoader.d.ts +25 -0
  28. package/dist/component/svg/types.d.ts +10 -0
  29. package/dist/component/svg/utils.d.ts +9 -0
  30. package/dist/component/svg/vNodeManager.d.ts +28 -0
  31. package/dist/component/textEditor/index.d.ts +2 -2
  32. package/dist/component/textEditor/manager.d.ts +22 -3
  33. package/dist/component/textEditor/types.d.ts +5 -4
  34. package/dist/component/textEditor/utils.d.ts +1 -0
  35. package/dist/component/textEditor/view.d.ts +28 -48
  36. package/dist/core/autoShape/index.d.ts +12 -0
  37. package/dist/core/autoShape/mapper.d.ts +3 -0
  38. package/dist/core/autoShape/recognizer.d.ts +8 -0
  39. package/dist/core/autoShape/registry.d.ts +2 -0
  40. package/dist/core/autoShape/templates.d.ts +2 -0
  41. package/dist/core/autoShape/types.d.ts +78 -0
  42. package/dist/core/backGroundThread/index.d.ts +35 -0
  43. package/dist/core/backGroundThread/types.d.ts +12 -0
  44. package/dist/core/enum.d.ts +74 -13
  45. package/dist/core/index.d.ts +3 -3
  46. package/dist/core/mainEngine.d.ts +101 -27
  47. package/dist/core/mainThread/base.d.ts +10 -6
  48. package/dist/core/mainThread/index.d.ts +2 -2
  49. package/dist/core/mainThread/snapshotThread.d.ts +8 -4
  50. package/dist/core/mainThread/subLocalThread.d.ts +21 -16
  51. package/dist/core/mainThread/subServiceThread.d.ts +2 -2
  52. package/dist/core/mainThread/subTopThread.d.ts +2 -2
  53. package/dist/core/msgEvent/base.d.ts +1 -0
  54. package/dist/core/msgEvent/baseForBackgroundThread.d.ts +9 -0
  55. package/dist/core/msgEvent/baseForWorker.d.ts +2 -1
  56. package/dist/core/msgEvent/copyNode/forBackgroundThread.d.ts +8 -0
  57. package/dist/core/msgEvent/copyNode/forMain.d.ts +2 -2
  58. package/dist/core/msgEvent/forBackgroundThread.d.ts +12 -0
  59. package/dist/core/msgEvent/forMainThread.d.ts +4 -4
  60. package/dist/core/msgEvent/forWorker.d.ts +4 -4
  61. package/dist/core/msgEvent/index.d.ts +4 -4
  62. package/dist/core/msgEvent/rotateNode/forMain.d.ts +2 -2
  63. package/dist/core/msgEvent/scaleNode/forMain.d.ts +2 -2
  64. package/dist/core/msgEvent/setColor/forMain.d.ts +2 -2
  65. package/dist/core/msgEvent/setPoint/forMain.d.ts +2 -2
  66. package/dist/core/msgEvent/setZIndex/forMain.d.ts +7 -0
  67. package/dist/core/msgEvent/translateNode/forMain.d.ts +2 -2
  68. package/dist/core/plugin.d.ts +49 -0
  69. package/dist/core/renderCotrol.d.ts +15 -28
  70. package/dist/core/tools/arrow.d.ts +10 -22
  71. package/dist/core/tools/base.d.ts +52 -9
  72. package/dist/core/tools/ellipse.d.ts +10 -22
  73. package/dist/core/tools/image.d.ts +9 -7
  74. package/dist/core/tools/index.d.ts +14 -13
  75. package/dist/core/tools/laserPen.d.ts +1 -1
  76. package/dist/core/tools/pencil.d.ts +18 -8
  77. package/dist/core/tools/pencilEraser.d.ts +36 -41
  78. package/dist/core/tools/pencilEraserBitMap.d.ts +20 -27
  79. package/dist/core/tools/polygon.d.ts +10 -22
  80. package/dist/core/tools/rectangle.d.ts +10 -22
  81. package/dist/core/tools/selector.d.ts +42 -24
  82. package/dist/core/tools/shadowSvg.d.ts +36 -0
  83. package/dist/core/tools/speechBalloon.d.ts +10 -22
  84. package/dist/core/tools/star.d.ts +10 -22
  85. package/dist/core/tools/straight.d.ts +10 -22
  86. package/dist/core/tools/text.d.ts +2 -1
  87. package/dist/core/tools/utils.d.ts +11 -12
  88. package/dist/core/types.d.ts +98 -18
  89. package/dist/core/utils/ObserverMap.d.ts +19 -0
  90. package/dist/core/utils/clipper.d.ts +8 -0
  91. package/dist/core/utils/getSvgPathFromPoints.d.ts +1 -1
  92. package/dist/core/utils/index.d.ts +6 -5
  93. package/dist/core/utils/indexDB.d.ts +17 -0
  94. package/dist/core/utils/math.d.ts +1 -0
  95. package/dist/core/utils/polygonUtils.d.ts +8 -0
  96. package/dist/core/utils/primitives/Box2d.d.ts +4 -4
  97. package/dist/core/utils/proxy.d.ts +3 -4
  98. package/dist/core/utils/spriteNode.d.ts +8 -1
  99. package/dist/core/vNodeManager.d.ts +13 -9
  100. package/dist/core/worker/base.d.ts +43 -21
  101. package/dist/core/worker/fullWorkerLocal.d.ts +29 -25
  102. package/dist/core/worker/fullWorkerService.d.ts +9 -9
  103. package/dist/core/worker/simpleWorker.d.ts +28 -0
  104. package/dist/core/worker/snapshotWork.d.ts +27 -0
  105. package/dist/core/worker/subWorkerLocal.d.ts +2 -3
  106. package/dist/core/worker/subWorkerTopLayer.d.ts +2 -2
  107. package/dist/core/worker/workerManager.d.ts +52 -36
  108. package/dist/cursors/index.d.ts +9 -11
  109. package/dist/displayer/const.d.ts +1 -0
  110. package/dist/displayer/cursor/index.d.ts +1 -0
  111. package/dist/displayer/floatBar/dragBox/index.d.ts +9 -3
  112. package/dist/displayer/floatBar/index.d.ts +2 -1
  113. package/dist/displayer/floatBtns/index.d.ts +2 -0
  114. package/dist/displayer/utils.d.ts +1 -0
  115. package/dist/extend.d.ts +1 -0
  116. package/dist/fullWorker.js +242 -195
  117. package/dist/index-BCI9ZJly.mjs +9884 -0
  118. package/dist/index-CRWsZj1z.mjs +16601 -0
  119. package/dist/index-D2XqHUO-.js +1 -0
  120. package/dist/index-Dfujq78k.js +3 -0
  121. package/dist/index-TQPJgovl.mjs +1263 -0
  122. package/dist/index-ZvQrVWzu.js +1 -0
  123. package/dist/index.d.ts +1 -0
  124. package/dist/plugin/applianceMultiPlugin.d.ts +2 -3
  125. package/dist/plugin/applianceSinglePlugin.d.ts +3 -4
  126. package/dist/plugin/baseApplianceManager.d.ts +58 -14
  127. package/dist/plugin/baseViewContainerManager.d.ts +72 -73
  128. package/dist/plugin/const.d.ts +2 -22
  129. package/dist/plugin/displayerView.d.ts +18 -4
  130. package/dist/plugin/index.d.ts +1 -0
  131. package/dist/plugin/multi/applianceMultiManager.d.ts +0 -1
  132. package/dist/plugin/multi/containerManager.d.ts +8 -1
  133. package/dist/plugin/multi/displayer/appViewDisplayerManager.d.ts +3 -2
  134. package/dist/plugin/multi/displayer/mainViewDisplayerManager.d.ts +4 -2
  135. package/dist/plugin/single/displayer/mainViewDisplayerManager.d.ts +4 -3
  136. package/dist/plugin/types.d.ts +393 -32
  137. package/dist/style.css +1 -1
  138. package/dist/subWorker.js +242 -195
  139. package/dist/svgToImageLoader-DPRAAhwW.js +1 -0
  140. package/dist/svgToImageLoader-mXH53h-l.mjs +18 -0
  141. package/dist/undo/index.d.ts +25 -31
  142. package/dist/undo/proxyArray.d.ts +37 -0
  143. package/package.json +31 -9
  144. package/cdn/fullWorker-BOTjIN.js +0 -439
  145. package/cdn/subWorker-CiM9eF.js +0 -439
  146. package/dist/collector/eventCollector.d.ts +0 -31
  147. package/dist/collector/magixEventCollector.d.ts +0 -31
  148. package/dist/core/mainThread/workerMainThread.d.ts +0 -99
  149. package/dist/core/msgEvent/deleteNode/forMainThread.d.ts +0 -6
  150. package/dist/core/msgEvent/deleteNode/forWorker.d.ts +0 -6
  151. package/dist/index-AeMVHd25.mjs +0 -2497
  152. package/dist/index-BJ92LABo.mjs +0 -14958
  153. package/dist/index-CjuLwRGu.js +0 -1
  154. package/dist/index-DqtwzzbR.js +0 -1
package/README.md CHANGED
@@ -1,122 +1,237 @@
1
- # appliance-plugin
2
-
3
- [中文文档](https://github.com/duty-os/appliance-plugin/blob/master/READMA.zh-CN.md)
4
-
5
- The plug-in is attached to the plug-in mechanism of white-web-sdk to achieve a set of whiteboard teaching AIDS, state synchronization, playback, scene switching and other functions still rely on white-web-sdk or window-manager.
6
-
7
- ## Introduction
8
-
9
- A whiteboard pencil drawing plugin based on SpriteJS as a rendering engine.
10
-
11
- The following two demos are implemented in the example folder for reference only.
12
- | scenario | demo path | depends on |
13
- | :-- | :----: | :-- |
14
- | multi-window | [example/src/multi.ts](https://github.com/hqer927/appliance-plugin/blob/master/example/src/multi.ts) | @netless/window-manager、white-web-sdk |
15
- | white-board | [example/src/single.ts](https://github.com/hqer927/appliance-plugin/blob/master/example/src/single.ts) | white-web-sdk |
16
- <!-- | fastboard | todo | todo | -->
17
-
18
- ## Principle
19
-
20
- 1. The plugin is mainly based on the 2D functionality of SpriteJS, supports webgl2 rendering, and is backward compatible with downgrades to webgl and canvas2d
21
- 2. The plugin uses the dual webWorker+offscreenCanvas mechanism to process the drawing calculation + rendering logic in a separate worker thread. Does not occupy cpu tasks of the main thread.
22
-
23
- ## Plugin usage
24
-
25
- ### Install
26
-
27
- ```bash
28
- npm install @netless/appliance-plugin
29
- ```
30
-
31
- ### Sign up for plugins
32
-
33
- Plug-ins can support two scenarios, their access plug-in names are different:
34
- - Multi-window 'ApplianceMultiPlugin'
35
- ```js
36
- import { ApplianceMultiPlugin } from '@netless/appliance-plugin';
37
- ```
38
- - Single whiteboard 'ApplianceSinglePlugin'
39
- ```js
40
- import { ApplianceSinglePlugin } from '@netless/appliance-plugin';
41
- ```
42
-
43
- > workerjs file cdn deployment
44
- >
45
- > We used two-worker concurrency to improve drawing efficiency, which improved it by more than 40% over single-thread efficiency. However, the common dependencies on the two worker files are repeated, so building directly into the package will greatly increase the package size. So we allow the workerjs file cdn deployment by simply deploying the file under @netless/appliance-plugin/cdn into the cdn and then configuring the c of the last two workerjs via the second parameter of getInstance in the plug-in, options.cdn The dn address is fine. This solves the problem of excessive package size
46
- >
47
- > - **The total package is about 300kB, and the two wokerjs are 600kB each** If you need to consider the size of the package you are building, select Configure cdn.
48
-
49
- ### Access mode reference
50
-
51
- #### Multi-window mode (Interconnecting with window-manager)
52
- ```js
53
- import '@netless/window-manager/dist/style.css';
54
- import '@netless/appliance-plugin/dist/style.css';
55
- import { WhiteWebSdk } from "white-web-sdk";
56
- import { WindowManager } from "@netless/window-manager";
57
- // All bundled
58
- import { ApplianceMultiPlugin } from '@netless/appliance-plugin';
59
- // cdn
60
- // The following steps are optional. If you use cdn, you do not need to import from dist. If you import from dist, you need to import resources and configure them to options.cdn in bolb inline form. Such as? raw, this requires packaging support,vite default support? raw,webpack needs to be configured.
1
+ # appliance-plugin
2
+
3
+ [中文文档](https://github.com/netless-io/fastboard/blob/main/docs/zh/appliance-plugin.md)
4
+
5
+ This plugin is based on the plugin mechanism of white-web-sdk, and realizes a set of whiteboard teaching AIDS drawing tools. At the same time, it is also based on @netless/window-manager, which can be used on multiple Windows.
6
+
7
+ ## Introduction
8
+
9
+ appliance-plugin is a high-performance whiteboard drawing plugin that depends on [white-web-sdk](https://www.npmjs.com/package/white-web-sdk) and [@netless/window-manager](https://www.npmjs.com/package/@netless/window-manager), and is based on Web API support for [OffscreenCanvas](https://developer.mozilla.org/zh-CN/docs/Web/API/OffscreenCanvas).
10
+
11
+ ### Key Features
12
+
13
+ - 🎨 **Rich Drawing Tools**: Supports pencil, eraser, shape tools, text, images, and more
14
+ - **High Performance Rendering**: Uses dual WebWorker + OffscreenCanvas mechanism, improving drawing efficiency by more than 40% compared to the main thread
15
+ - 🖼️ **Multi-window Support**: Supports multi-window scenarios, can be used independently on different windows
16
+ - 🎯 **Laser Pen Tool**: Supports laser pen functionality, suitable for presentation scenarios
17
+ - 📝 **Text Editing**: Supports text insertion, editing, and style settings
18
+ - 🗺️ **Minimap Function**: Provides minimap navigation for viewing overall content
19
+ - 🔄 **Undo/Redo**: Supports global undo/redo functionality
20
+ - 🎭 **Custom Styles**: Supports custom brush styles, text styles, etc.
21
+ - 🔌 **Plugin Extension**: Supports extending functionality through plugin mechanism (e.g., autoDraw handwriting graphics auto-association)
22
+
23
+ ## Principle
24
+
25
+ 1. **Rendering Engine**: The plugin is mainly based on SpriteJS's 2D functionality, supports WebGL2 rendering, and is backward compatible with downgrades to WebGL and Canvas2D.
26
+ 2. **Multi-threaded Architecture**: The plugin uses the dual WebWorker + OffscreenCanvas mechanism to process drawing calculations and rendering logic in independent worker threads, not occupying the CPU tasks of the main thread.
27
+ - **Full Worker**: Thread responsible for drawing complete data
28
+ - **Sub Worker**: Thread responsible for drawing one frame of data
29
+ 3. **Compatibility Handling**: For mobile terminals that do not support OffscreenCanvas, it will automatically downgrade to main thread processing.
30
+
31
+ ### Supported Drawing Tools
32
+
33
+ The plugin supports the following drawing tools:
34
+
35
+ - **Basic Tools**: Pencil, eraser, partial eraser, bitmap eraser, selector tool, hand tool
36
+ - **Shape Tools**: Straight line, arrow, rectangle, circle, triangle, diamond, polygon, star, speech balloon
37
+ - **Text Tool**: Supports text input, editing, and style settings
38
+ - **Image Tool**: Supports image insertion and editing
39
+ - **Special Tools**: Laser pen, background SVG
40
+ - **Interactive Tools**: Click interactive tool (for plugin custom behavior)
41
+
42
+ ## Plugin usage
43
+
44
+ ### Install
45
+
46
+ ```bash
47
+ npm install @netless/appliance-plugin
48
+ ```
49
+
50
+ ### Register Plugin
51
+
52
+ Plugins can support two scenarios, they have different plugin names:
53
+ - Multi-window `ApplianceMultiPlugin`
54
+ ```js
55
+ import { ApplianceMultiPlugin } from '@netless/appliance-plugin';
56
+ ```
57
+ - Single whiteboard `ApplianceSinglePlugin`
58
+ ```js
59
+ import { ApplianceSinglePlugin } from '@netless/appliance-plugin';
60
+ ```
61
+
62
+ > **worker.js files: CDN & static assets**
63
+ >
64
+ > 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:
65
+ >
66
+ > 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`.
67
+ > ***Note***: CDN URLs must be same-origin with your app, or the workers will fail to load.
68
+ >
69
+ > 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.
70
+ >
71
+ > To keep bundle size down, configure `options.cdn` using one of the above.
72
+
73
+ ### Access Mode Reference
74
+
75
+ #### Introducing worker.js
76
+ ```js
77
+ // Choose one of three ways to provide worker URLs:
78
+
79
+ // Option 1: Static assets (recommended) — put fullWorker.js & subWorker.js in public (or similar); same-origin, no bundle cost
80
+ const workerBase = (import.meta.env.BASE_URL || '/').replace(/\/?$/, '/');
81
+ const fullWorkerUrl = workerBase + 'fullWorker.js';
82
+ const subWorkerUrl = workerBase + 'subWorker.js';
83
+
84
+ // Option 2: CDN — after deploying files from @netless/appliance-plugin/cdn to your CDN, set URLs here. Note: must be same-origin
85
+ const fullWorkerUrl = 'https://your-cdn.com/fullWorker.js';
86
+ const subWorkerUrl = 'https://your-cdn.com/subWorker.js';
87
+
88
+ // Option 3: Inline via ?raw as Blob (requires ?raw support, e.g. Vite or webpack raw-loader). Uses more memory.
61
89
  import fullWorkerString from '@netless/appliance-plugin/dist/fullWorker.js?raw';
62
90
  import subWorkerString from '@netless/appliance-plugin/dist/subWorker.js?raw';
63
- const fullWorkerBlob = new Blob([fullWorkerString], {type: 'text/javascript'});
64
- const fullWorkerUrl = URL.createObjectURL(fullWorkerBlob);
65
- const subWorkerBlob = new Blob([subWorkerString], {type: 'text/javascript'});
66
- const subWorkerUrl = URL.createObjectURL(subWorkerBlob);
67
-
68
- const whiteWebSdk = new WhiteWebSdk(...)
69
- const room = await whiteWebSdk.joinRoom({
70
- ...
71
- invisiblePlugins: [WindowManager, ApplianceMultiPlugin],
72
- useMultiViews: true,
73
- })
74
- const manager = await WindowManager.mount({ room , container:elm, chessboard: true, cursor: true, supportAppliancePlugin: true});
75
- if (manager) {
76
- // await manager.switchMainViewToWriter();
77
- await ApplianceMultiPlugin.getInstance(manager,
91
+ const fullWorkerUrl = URL.createObjectURL(new Blob([fullWorkerString], { type: 'text/javascript' }));
92
+ const subWorkerUrl = URL.createObjectURL(new Blob([subWorkerString], { type: 'text/javascript' }));
93
+ ```
94
+
95
+ #### fastboard (Direct integration with fastboard)
96
+ ```js
97
+ // Integration with fastboard-react
98
+ // Full package mode reference
99
+ // import { useFastboard, Fastboard } from "@netless/fastboard-react/full";
100
+ // Subpackage reference
101
+ import { useFastboard, Fastboard } from "@netless/fastboard-react";
102
+
103
+ // Use one of the three worker options from "Introducing worker.js" above:
104
+ const fullWorkerUrl = ...;
105
+ const subWorkerUrl = ...;
106
+
107
+ const app = useFastboard(() => ({
108
+ sdkConfig: {
109
+ ...
110
+ },
111
+ joinRoom: {
112
+ ...
113
+ },
114
+ managerConfig: {
115
+ cursor: true,
116
+ enableAppliancePlugin: true,
117
+ ...
118
+ },
119
+ enableAppliancePlugin: {
120
+ cdn: {
121
+ fullWorkerUrl,
122
+ subWorkerUrl,
123
+ }
124
+ ...
125
+ }
126
+ }));
127
+
128
+ // Integration with fastboard
129
+ // Full package mode reference
130
+ // import { createFastboard, createUI } from "@netless/fastboard/full";
131
+ // Subpackage reference
132
+ import { createFastboard, createUI } from "@netless/fastboard";
133
+
134
+ // Use one of the three worker options from "Introducing worker.js" above:
135
+ const fullWorkerUrl = ...;
136
+ const subWorkerUrl = ...;
137
+
138
+ const fastboard = await createFastboard({
139
+ sdkConfig: {
140
+ ...
141
+ },
142
+ joinRoom: {
143
+ ...
144
+ },
145
+ managerConfig: {
146
+ cursor: true,
147
+ supportAppliancePlugin: true,
148
+ ...
149
+ },
150
+ enableAppliancePlugin: {
151
+ cdn: {
152
+ fullWorkerUrl,
153
+ subWorkerUrl,
154
+ }
155
+ ...
156
+ }
157
+ });
158
+ ```
159
+
160
+ #### Multi-window (Direct integration with window-manager)
161
+
162
+ ```js
163
+
164
+ import '@netless/window-manager/dist/style.css';
165
+ import '@netless/appliance-plugin/dist/style.css';
166
+
167
+ import { WhiteWebSdk } from "white-web-sdk";
168
+ import { WindowManager } from "@netless/window-manager";
169
+ import { ApplianceMultiPlugin } from '@netless/appliance-plugin';
170
+
171
+ // Use one of the three worker options from "Introducing worker.js" above:
172
+ const fullWorkerUrl = ...;
173
+ const subWorkerUrl = ...;
174
+
175
+ const whiteWebSdk = new WhiteWebSdk(...)
176
+ const room = await whiteWebSdk.joinRoom({
177
+ ...
178
+ invisiblePlugins: [WindowManager, ApplianceMultiPlugin],
179
+ useMultiViews: true,
180
+ })
181
+ const manager = await WindowManager.mount({ room, container: elm, chessboard: true, cursor: true, supportAppliancePlugin: true});
182
+ if (manager) {
183
+ await manager.switchMainViewToWriter();
184
+ await ApplianceMultiPlugin.getInstance(manager,
78
185
  {
79
186
  options: {
80
187
  cdn: {
81
188
  fullWorkerUrl,
82
189
  subWorkerUrl,
83
- }
190
+ },
191
+ ...
84
192
  }
85
193
  }
86
- );
87
- }
88
- ```
89
- #### Single whiteboard (interconnection with white-web-sdk)
90
- ```js
91
- import { WhiteWebSdk } from "white-web-sdk";
92
- // All bundled
93
- import { ApplianceSinglePlugin, ApplianceSigleWrapper } from '@netless/appliance-plugin';
94
- // The following steps are optional. If you use cdn, you do not need to import from dist. If you import from dist, you need to import resources and configure them to options.cdn in bolb inline form. Such as? raw, this requires packaging support,vite default support? raw,webpack needs to be configured.
95
- import fullWorkerString from '@netless/appliance-plugin/dist/fullWorker.js?raw';
96
- import subWorkerString from '@netless/appliance-plugin/dist/subWorker.js?raw';
97
- const fullWorkerBlob = new Blob([fullWorkerString], {type: 'text/javascript'});
98
- const fullWorkerUrl = URL.createObjectURL(fullWorkerBlob);
99
- const subWorkerBlob = new Blob([subWorkerString], {type: 'text/javascript'});
100
- const subWorkerUrl = URL.createObjectURL(subWorkerBlob);
101
-
102
- const whiteWebSdk = new WhiteWebSdk(...)
103
- const room = await whiteWebSdk.joinRoom({
104
- ...
105
- invisiblePlugins: [ApplianceSinglePlugin],
106
- wrappedComponents: [ApplianceSigleWrapper]
107
- })
108
- await ApplianceSinglePlugin.getInstance(room,
194
+ );
195
+ }
196
+ ```
197
+
198
+ > **Note** The project needs to import the CSS file `import '@netless/appliance-plugin/dist/style.css';`
199
+
200
+ #### Single whiteboard (Direct integration with white-web-sdk)
201
+
202
+ ```js
203
+
204
+ import '@netless/appliance-plugin/dist/style.css';
205
+
206
+ import { WhiteWebSdk } from "white-web-sdk";
207
+ import { ApplianceSinglePlugin, ApplianceSigleWrapper } from '@netless/appliance-plugin';
208
+ // Use one of the three worker options from "Introducing worker.js" above:
209
+ const fullWorkerUrl = ...;
210
+ const subWorkerUrl = ...;
211
+
212
+ const whiteWebSdk = new WhiteWebSdk(...)
213
+ const room = await whiteWebSdk.joinRoom({
214
+ ...
215
+ invisiblePlugins: [ApplianceSinglePlugin],
216
+ wrappedComponents: [ApplianceSigleWrapper]
217
+ })
218
+ await ApplianceSinglePlugin.getInstance(room,
109
219
  {
110
220
  options: {
111
221
  cdn: {
112
222
  fullWorkerUrl,
113
223
  subWorkerUrl,
114
224
  }
225
+ ...
115
226
  }
116
227
  }
117
- );
228
+ );
118
229
  ```
119
- #### About ’?raw‘ webpack configuration
230
+
231
+ > **Note** The project needs to import the CSS file `import '@netless/appliance-plugin/dist/style.css';`
232
+
233
+ #### About ?raw webpack configuration
234
+
120
235
  ```js
121
236
  module: {
122
237
  rules: [
@@ -132,84 +247,756 @@ module: {
132
247
  }
133
248
  ]
134
249
  },
135
- ```
136
-
137
- ## Call introduction
138
- ### api introduction
139
- The plugin re-implements some of the interfaces of the same name on room or Windows Manager, but internally we have re-injected them back into the original object via injectMethodToObject. No changes are required for external users. As follows:
140
- ```js
141
- // Internal hack
142
- injectMethodToObject(windowmanager, 'undo');
143
- injectMethodToObject(windowmanager, 'redo');
144
- injectMethodToObject(windowmanager,'cleanCurrentScene');
145
- injectMethodToObject(windowmanager,'insertImage');
146
- injectMethodToObject(windowmanager,'completeImageUpload');
147
- injectMethodToObject(windowmanager,'lockImage');
148
- injectMethodToObject(room,'getImagesInformation');
149
- injectMethodToObject(room,'callbacks');
150
- injectMethodToObject(room,'screenshotToCanvasAsync');
151
- injectMethodToObject(room,'getBoundingRectAsync');
152
- injectMethodToObject(room,'scenePreviewAsync');
153
- injectMethodToObject(windowmanager.mainView,'setMemberState');
154
- // These we can see the call behavior through the front-end log, for example:
155
- // [ApplianceMultiPlugin] setMemberState
156
- // [ApplianceMultiPlugin] cleanCurrentScene
250
+ ```
251
+
252
+ ## API Introduction
253
+
254
+ #### Optimize Original Interfaces
255
+
256
+ The plugin re-implements some interfaces with the same name on room or windowmanager, but we have internally re-injected them back into the original object through `injectMethodToObject`. Therefore, external users do not need to make any changes. As follows:
257
+ ```js
258
+ // Internal hack
259
+ injectMethodToObject(windowmanager, 'undo');
260
+ injectMethodToObject(windowmanager, 'redo');
261
+ injectMethodToObject(windowmanager,'cleanCurrentScene');
262
+ injectMethodToObject(windowmanager,'insertImage');
263
+ injectMethodToObject(windowmanager,'completeImageUpload');
264
+ injectMethodToObject(windowmanager,'lockImage');
265
+ injectMethodToObject(room,'getImagesInformation');
266
+ injectMethodToObject(room,'callbacks');
267
+ injectMethodToObject(room,'screenshotToCanvasAsync');
268
+ injectMethodToObject(room,'getBoundingRectAsync');
269
+ injectMethodToObject(room,'scenePreviewAsync');
270
+ injectMethodToObject(windowmanager.mainView,'setMemberState');
271
+ // These we can see the call behavior through the front-end log, for example:
272
+ // [ApplianceMultiPlugin] setMemberState
273
+ // [ApplianceMultiPlugin] cleanCurrentScene
157
274
  ```
158
275
  The following interfaces are involved:
159
276
 
160
- 1. Interface on room
161
- - `setMemberState`
162
- - `undo`
163
- - `redo`
164
- - `callbacks`
165
- - `insertImage`
166
- - `lockImage`
167
- - `completeImageUpload`
168
- - `getImagesInformation`
169
- - `cleanCurrentScene`
170
-
171
- 2. windowmanager upper interface
172
- - `cleanCurrentScene`
173
-
174
- 3. The mainview interface of windowmanager
175
- - `setMemberState`
176
- - `undo`
177
- - `redo`
178
- - `callbacks`
179
- - `insertImage`
180
- - `lockImage`
181
- - `completeImageUpload`
182
- - `getImagesInformation`
183
- - `cleanCurrentScene`
184
-
185
- 4. Customize
186
- - `getBoundingRectAsync`
187
- - `screenshotToCanvasAsync`
188
- - `scenePreviewAsync`
189
- - `destroy`
190
-
191
- ### Configure parameters
192
- ``getInstance(wm: WindowManager, adaptor: ApplianceAdaptor)``
193
- - wm: WindowManager\room\player. In multi-window mode, you pass WindowManager, and in single-window mode, you pass room or player(whiteboard playback mode).
194
- - adaptor: configures the adapter.
195
- - options: ``AppliancePluginOptions``; The cdn addresses of both workers must be configured.
196
- ```js
197
- export type AppliancePluginOptions = {
198
- /** cdn Configuration item */
199
- cdn: CdnOpt;
200
- /** Synchronize data configuration items */
201
- syncOpt? : SyncOpt;
202
- /** Canvas configuration item */
203
- canvasOpt? : CanvasOpt;
204
- }
277
+ 1. Interfaces on room
278
+ - [`setMemberState`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#setmemberstate)
279
+ - [`undo`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#undo)
280
+ - [`redo`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#redo)
281
+ - [`callbacks`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#callbacks)
282
+ - [`insertImage`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#insertimage)
283
+ - [`lockImage`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#lockimage)
284
+ - [`completeImageUpload`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#completeimageupload)
285
+ - `getImagesInformation`
286
+ - [`cleanCurrentScene`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#cleancurrentscene)
287
+
288
+ 2. WindowManager interfaces
289
+ - [`cleanCurrentScene`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#cleancurrentscene)
290
+ - [`canUndoSteps`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#canundosteps)
291
+ - [`canRedoSteps`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#canredosteps)
292
+
293
+ 3. Interfaces on WindowManager's mainView
294
+ - [`setMemberState`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#setmemberstate)
295
+ - [`undo`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#undo)
296
+ - [`redo`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#redo)
297
+ - [`callbacks`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#callbacks)
298
+ - [`insertImage`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#insertimage)
299
+ - [`lockImage`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#lockimage)
300
+ - [`completeImageUpload`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#completeimageupload)
301
+ - `getImagesInformation`
302
+ - [`cleanCurrentScene`](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#cleancurrentscene)
303
+
304
+ 4. Custom interfaces
305
+ - `getBoundingRectAsync` - Replace interface `room.getBoundingRect`
306
+ - `screenshotToCanvasAsync` - Replace interface [room.screenshotToCanvasAsync](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#screenshottocanvasasync)
307
+ - `scenePreviewAsync` - Replace interface [room.scenePreview](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#scenepreview)
308
+ - `fillSceneSnapshotAsync` - Replace interface [room.fillSceneSnapshot](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#fillscenesnapshot)
309
+ - `destroy` - Destroy the instance of appliance-plugin
310
+ - `addListener` - Add appliance-plugin internal event listener
311
+ - `removeListener` - Remove appliance-plugin internal event listener
312
+ - `disableDeviceInputs` - Replace interface [room.disableDeviceInputs](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#disabledeviceinputs)
313
+ - `disableEraseImage` - Replace interface [room.disableEraseImage](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#disableeraseimage) **This method only prohibits the eraser that erases the entire image from erasing images, partial eraser is invalid**
314
+ - `disableCameraTransform` - Replace interface [room.disableCameraTransform](https://api-ref.agora.io/en/interactive-whiteboard-sdk/web/2.x/interfaces/room.html#disablecameratransform) (Version >=1.1.17)
315
+ - `insertText` - Insert text at the specified position (Version >=1.1.18)
316
+ - `updateText` - Edit the content of the specified text (Version >=1.1.18)
317
+ - `blurText` - Remove text focus (Version >=1.1.19)
318
+ - `hasElements` - Check if there are elements in the specified scene (Version >=1.1.19)
319
+ - `getElements` - Get all elements in the specified scene (Version >=1.1.19)
320
+ - `stopDraw` - Stop Draw event (Version >=1.1.19)
321
+ - `setViewLocalScenePathChange` - Set the local scene path change for the whiteboard view (Version >=1.1.27)
322
+ - `insertMarkmap` - Insert markdown text to whiteboard (Version >=1.1.32) **This method requires enabling extras.useBackgroundThread**
323
+ - `updateMarkmap` - Update markdown text in whiteboard (Version >=1.1.32) **This method requires enabling extras.useBackgroundThread**
324
+ - `insertBackgroundImage` - Insert whiteboard background image (Version >=1.1.32) **This method requires enabling extras.useBackgroundThread**
325
+
326
+ 5. Incompatible interfaces
327
+ - [`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
328
+ - [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
329
+
330
+ #### New Features
331
+ ##### Laser Pen Tool (Version >=1.1.1)
332
+ ```js
333
+ import { EStrokeType, ApplianceNames } from '@netless/appliance-plugin';
334
+ room.setMemberState({currentApplianceName: ApplianceNames.laserPen, strokeType: EStrokeType.Normal});
335
+ ```
336
+ ![Image](https://github.com/user-attachments/assets/3cd10c3a-b17b-4c01-b9d4-868c69116d96)
337
+
338
+ ##### Auto Shape: One-stroke Quick Shape Drawing (Version >=1.1.33)
339
+ When enabled, users still draw with the `Pencil` tool. On pointer up, the plugin tries to recognize the completed stroke as a regular shape and outputs the corresponding shape instead of a normal pencil path.
340
+
341
+ ```js
342
+ import { ApplianceNames, EStrokeType } from '@netless/appliance-plugin';
343
+
344
+ room.setMemberState({
345
+ currentApplianceName: ApplianceNames.pencil,
346
+ autoShape: true,
347
+ strokeType: EStrokeType.Normal,
348
+ });
349
+ ```
350
+
351
+ The current version supports single-stroke recognition for:
352
+
353
+ - `Straight`
354
+ - `Arrow`
355
+ - `Rectangle`
356
+ - `Ellipse / Circle`
357
+ - `Triangle`
358
+ - `Rhombus`
359
+ - `Five-point Star`
360
+
361
+ Recommendations:
362
+
363
+ - Use the `Pencil` tool
364
+ - Complete the gesture in one stroke
365
+ - Draw `Rectangle`, `Ellipse / Circle`, `Triangle`, and `Five-point Star` as closed strokes
366
+ - Draw `Arrow` and `Straight` as open single strokes
367
+
368
+ ##### Extended Tools (Version >=1.1.1)
369
+ 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:
370
+
371
+ ```js
372
+ export enum EStrokeType {
373
+ /** Solid line */
374
+ Normal = 'Normal',
375
+ /** Line with pen edge */
376
+ Stroke = 'Stroke',
377
+ /** Dotted line */
378
+ Dotted = 'Dotted',
379
+ /** Long dotted line */
380
+ LongDotted = 'LongDotted'
381
+ };
382
+ export type ExtendMemberState = {
383
+ /** The tool selected by the current user */
384
+ currentApplianceName: ApplianceNames;
385
+ /** Whether to enable pen edge */
386
+ strokeType?: EStrokeType;
387
+ /** Whether to delete the entire line segment */
388
+ isLine?: boolean;
389
+ /** Stroke transparency */
390
+ strokeOpacity?: number;
391
+ /** Whether to enable laser pointer */
392
+ useLaserPen?: boolean;
393
+ /** Whether to enable one-stroke auto shape recognition */
394
+ autoShape?: boolean;
395
+ /** Laser pointer holding time, second */
396
+ duration?: number;
397
+ /** Fill style */
398
+ fillColor?: Color;
399
+ /** Fill transparency */
400
+ fillOpacity?: number;
401
+ /** The specific type of graph to draw when using ``shape`` tool */
402
+ shapeType?: ShapeType;
403
+ /** Number of polygon vertices */
404
+ vertices?:number;
405
+ /** Inner vertex step length of polygon */
406
+ innerVerticeStep?:number;
407
+ /** Ratio of inner vertex radius to outer vertex radius of polygon */
408
+ innerRatio?: number;
409
+ /** Text transparency */
410
+ textOpacity?: number;
411
+ /** Text background color */
412
+ textBgColor?: Color;
413
+ /** Text background color transparency */
414
+ textBgOpacity?: number;
415
+ /** Placement */
416
+ placement?: SpeechBalloonPlacement;
417
+ };
418
+ import { ExtendMemberState, ApplianceNames } from '@netless/appliance-plugin';
419
+ /** Set tool state */
420
+ room.setMemberState({ ... } as ExtendMemberState);
421
+ manager.mainView.setMemberState({ ... } as ExtendMemberState);
422
+ appliance.setMemberState({ ... } as ExtendMemberState);
423
+ ```
424
+ 1. Set stroke type:
425
+ ```js
426
+ // Solid line
427
+ setMemberState({strokeType: EStrokeType.Normal });
428
+ // Line with pen edge
429
+ setMemberState({strokeType: EStrokeType.Stroke });
430
+ // Dotted line
431
+ setMemberState({strokeType: EStrokeType.Dotted });
432
+ // Long dotted line
433
+ setMemberState({strokeType: EStrokeType.LongDotted });
434
+ ```
435
+ ![Image](https://github.com/user-attachments/assets/fabe4ea7-db42-4c31-a751-10df4dd82807)
436
+
437
+ 2. Set stroke and shape border opacity (marker):
438
+ ```js
439
+ setMemberState({strokeOpacity: 0.5 });
440
+ ```
441
+ ![Image](https://github.com/user-attachments/assets/1aac265d-9643-4858-bcc6-a43af94ed73e)
442
+
443
+ 3. Set text color, opacity, background color, and opacity
444
+ ```js
445
+ setMemberState({textOpacity: 0.5, textBgOpacity: 0.5, textBgColor:[0, 0, 0]});
446
+ ```
447
+ ![Image](https://github.com/user-attachments/assets/b59a9864-8f3f-4700-abee-2ccbe264cc86)
448
+
449
+ 4. Set shape fill color and opacity
450
+ ```js
451
+ setMemberState({fillOpacity: 0.5, fillColor:[0, 0, 0]});
452
+ ```
453
+ ![Image](https://github.com/user-attachments/assets/468b930c-3db0-4355-87be-6b55af764799)
454
+
455
+ 5. Custom regular polygon
456
+ ```js
457
+ // Regular pentagon
458
+ setMemberState({currentApplianceName: ApplianceNames.shape, shapeType: ShapeType.Polygon, vertices: 5});
459
+ ```
460
+ ![Image](https://github.com/user-attachments/assets/f34540f5-d779-42f9-bb8a-91250fcfe4e1)
461
+
462
+ 6. Custom star shape
463
+ ```js
464
+ // Fat hexagonal star
465
+ setMemberState({currentApplianceName: ApplianceNames.shape, shapeType: ShapeType.Star, vertices: 12, innerVerticeStep: 2, innerRatio: 0.8});
466
+ ```
467
+ ![Image](https://github.com/user-attachments/assets/49215362-722a-47d3-998f-cc933a2b5126)
468
+
469
+ 7. Custom speech balloon placement
470
+ ```js
471
+ // Speech balloon in the lower left corner
472
+ setMemberState({currentApplianceName: ApplianceNames.shape, shapeType: ShapeType.SpeechBalloon, placement: 'bottomLeft'});
473
+ ```
474
+ ![Image](https://github.com/user-attachments/assets/6d52dedf-ca21-406d-a353-d801273b98bf)
475
+
476
+ ##### Split screen display notes (little whiteboard feature), need to combine [`@netless/app-little-white-board`](https://github.com/netless-io/app-little-white-board) (Version >=1.1.3)
477
+ ![Image](https://github.com/user-attachments/assets/20810ea6-7d85-4e72-b75f-185599fffaf8)
478
+
479
+ ##### Minimap function (Version >=1.1.6)
480
+ ```js
481
+ /** Create a minimap
482
+ * @param viewId ID of the whiteboard under multi-whiteboard, the main whiteboard ID is `mainView`, other whiteboard IDs are the appID returned by addApp()
483
+ * @param div Minimap DOM container
484
+ */
485
+ createMiniMap(viewId: string, div: HTMLElement): Promise<void>;
486
+ /** Destroy minimap */
487
+ destroyMiniMap(viewId: string): Promise<boolean>;
488
+ ```
489
+ ![Image](https://github.com/user-attachments/assets/8888dc2f-ba66-4807-aa12-16530b3b8a3c)
490
+
491
+ ##### Text editing API (Version >=1.1.18)
492
+ ```js
493
+ /** Insert text at the specified position
494
+ * @param x The x coordinate of the left edge midpoint of the first character in the world coordinate system
495
+ * @param y The y coordinate of the left edge midpoint of the first character in the world coordinate system
496
+ * @param textContent Initial text content, empty if not provided
497
+ * @returns The identifier of the text
498
+ */
499
+ insertText(x: number, y: number, textContent?: string): string | undefined;
500
+
501
+ /** Edit the content of the specified text
502
+ * @param identifier The identifier of the text, returned by insertText()
503
+ * @param textContent The new content of the text
504
+ */
505
+ updateText(identifier: string, textContent: string): void;
506
+
507
+ /** Remove text focus */
508
+ blurText(): void;
509
+ ```
510
+
511
+ ##### Element query API (Version >=1.1.19)
512
+ ```js
513
+ /** Check if there are elements in the specified scene
514
+ * @param scenePath Scene path, defaults to the currently focused scene
515
+ * @param filter Filter condition
516
+ * @returns Whether elements exist
517
+ */
518
+ hasElements(
519
+ scenePath?: string,
520
+ filter?: (toolsType: EToolsKey) => boolean,
521
+ ): boolean;
522
+
523
+ /** Get all elements in the specified scene
524
+ * @param scenePath Scene path, defaults to the currently focused scene
525
+ * @param filter Filter condition
526
+ * @returns All elements
527
+ */
528
+ getElements(
529
+ scenePath?: string,
530
+ filter?: (toolsType: EToolsKey) => boolean,
531
+ ): BaseCollectorReducerAction[];
532
+ ```
533
+
534
+ ##### Filter notes (Version >=1.1.6)
535
+ ```js
536
+ /** Filter notes
537
+ * @param viewId ID of the whiteboard under multi-whiteboard, the main whiteboard ID is `mainView`, other whiteboard IDs are the appID returned by addApp()
538
+ * @param filter Filter condition
539
+ * render: Whether notes can be rendered, [uid1, uid2, ...] or true. true means all will be rendered; [uid1, uid2, ...] is the specified set of user uids to render
540
+ * hide: Whether notes are hidden, [uid1, uid2, ...] or true. true means all will be hidden; [uid1, uid2, ...] is the specified set of user uids to hide
541
+ * clear: Whether notes can be erased, [uid1, uid2, ...] or true. true means all can be erased; [uid1, uid2, ...] is the specified set of user uids that can be erased
542
+ * @param isSync Whether to synchronize to the whiteboard room, default is true, meaning the setting will be synchronized to all users
543
+ */
544
+ filterRenderByUid(viewId: string, filter: { render?: _ArrayTrue, hide?: _ArrayTrue, clear?: _ArrayTrue}, isSync?:boolean): void;
545
+ /** Cancel filter notes
546
+ * @param viewId ID of the whiteboard under multi-whiteboard, the main whiteboard ID is `mainView`, other whiteboard IDs are the appID returned by addApp()
547
+ * @param isSync Whether to synchronize to the whiteboard room, default is true, meaning it will be synchronized to other users. Please keep it consistent with the filterRenderByUid setting
548
+ */
549
+ cancelFilterRender(viewId: string, isSync?:boolean): void;
550
+ ```
551
+ ![Image](https://github.com/user-attachments/assets/7952ee1d-4f9c-4e86-802a-bac8e4ae6a51)
552
+
553
+ ##### Set whiteboard local scene path change (Version >=1.1.27)
554
+ ```js
555
+ /** Set whiteboard local scene path change
556
+ * @param viewId ID of the whiteboard under multi-whiteboard, the main whiteboard ID is `mainView`, other whiteboard IDs are the appID returned by addApp()
557
+ * @param scenePath The scene path to set
558
+ */
559
+ setViewLocalScenePathChange(viewId: string, scenePath: string): Promise<void>;
560
+ ```
561
+
562
+ ##### ExtrasOption custom tool configuration
563
+ 1. Custom stroke styles
564
+ - Short dotted line style
565
+ ```ts
566
+ export type DottedOpt = {
567
+ /** Dotted line endpoint style, square: flat, round: round, default is round */
568
+ lineCap: "square" | "round";
569
+ /** Dotted line, single segment length, default is 1, meaning single segment length is 1 */
570
+ segment: number;
571
+ /** Dotted line, single segment gap, default is 2, meaning single segment gap is 2 * thickness */
572
+ gap: number;
573
+ };
574
+ /** Short dotted line style */
575
+ dottedStroke: {
576
+ lineCap: "round",
577
+ segment: 1,
578
+ gap: 2,
579
+ },
580
+ ```
581
+ ![Image](https://github.com/user-attachments/assets/5dc7e2bf-c285-45f0-89d2-849b4792dc7e)
582
+ - Long dotted line style
583
+ ```ts
584
+ export type LongDottedOpt = {
585
+ /** Long dotted line endpoint style, square: flat, round: round, default is round */
586
+ lineCap: "square" | "round";
587
+ /** Long dotted line, single segment length, default is 1, meaning single segment length is 1 * thickness */
588
+ segment: number;
589
+ /** Long dotted line, single segment gap, default is 2, meaning single segment gap is 2 * thickness */
590
+ gap: number;
591
+ };
592
+ /** Long dotted line style */
593
+ longDottedStroke: {
594
+ lineCap: "round",
595
+ segment: 2,
596
+ gap: 3,
597
+ },
598
+ ```
599
+ ![Image](https://github.com/user-attachments/assets/a305c1a1-b366-444a-ace6-3e0ecbf5ad19)
600
+ - Normal stroke style
601
+ ```ts
602
+ export type NormalOpt = {
603
+ /** Endpoint style, square: flat, round: round, default is round */
604
+ lineCap: "square" | "round";
605
+ };
606
+ /** Normal stroke style */
607
+ normalStroke: {
608
+ lineCap: "round",
609
+ }
610
+ ```
611
+ ![Image](https://github.com/user-attachments/assets/23979f81-057a-408f-8302-de228ef00b4f)
612
+
613
+ 2. Text custom styles
614
+ ```ts
615
+ export type TextEditorOpt = {
616
+ /** Whether to show float bar */
617
+ showFloatBar?: boolean;
618
+ /** Whether can switch by selector tool */
619
+ canSelectorSwitch?: boolean;
620
+ /** Whether right boundary auto wrap */
621
+ rightBoundBreak?: boolean;
622
+ /** Extended font list */
623
+ extendFontFaces?: { fontFamily: string; src: string }[];
624
+ /** Font loading timeout, unit: milliseconds */
625
+ loadFontFacesTimeout?: number;
626
+ };
627
+ // For example: set unified font library
628
+ textEditor: {
629
+ showFloatBar: false,
630
+ canSelectorSwitch: false,
631
+ rightBoundBreak: true,
632
+ extendFontFaces: [
633
+ {
634
+ fontFamily: "Noto Sans SC",
635
+ src: "https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-mu0SC55I.woff2",
636
+ },
637
+ ],
638
+ loadFontFacesTimeout: 20000,
639
+ },
640
+ ```
641
+ Need to combine CSS style implementation
642
+ ```css
643
+ @font-face {
644
+ font-family: "Noto Sans SC";
645
+ src: url("https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-mu0SC55I.woff2")
646
+ format("woff2");
647
+ font-display: swap;
648
+ }
649
+ html {
650
+ font-family: "Noto Sans SC";
651
+ }
652
+ ```
653
+
654
+ ##### Insert Mind Map (requires markdown text) (Version >=1.1.32)
655
+ ```ts
656
+ import { ApplianceMultiPlugin } from '@netless/appliance-plugin';
657
+ const plugin = await ApplianceMultiPlugin.getInstance(manager, {
658
+ options: {
659
+ cdn: {...}
660
+ extras: {
661
+ ...,
662
+ useBackgroundThread: true,
663
+ }
664
+ },
665
+ });
666
+ const markId = await plugin.insertMarkmap(viewId, {
667
+ data: `# First Level Title
668
+ ## Second Level Title 1
669
+ ### Third Level Title 1
670
+ ### Third Level Title 2
671
+ #### Fourth Level Title 1
672
+ #### Fourth Level Title 2
673
+ #### Fourth Level Title 3
674
+ ## Second Level Title 2
675
+ ### Third Level Title 1
676
+ ### Third Level Title 2`,
677
+ uuid: 'unique identifier',
678
+ centerX: 0,
679
+ centerY: 0,
680
+ width: 200,
681
+ height: 200,
682
+ locked: false,
683
+ });
684
+ plugin.updateMarkmap(viewId, markId, {
685
+ data: `# First Level Title
686
+ ## Second Level Title 1
687
+ ## Second Level Title 2
688
+ ### Third Level Title 1
689
+ ### Third Level Title 2`,
690
+ uuid: 'unique identifier',
691
+ centerX: 0,
692
+ centerY: 0,
693
+ width: 200,
694
+ height: 200,
695
+ locked: false,
696
+ } )
697
+
698
+ ```
699
+ ![Image](https://github.com/user-attachments/assets/0d278bd5-1cc7-413f-881c-8a43ef1429e3)
700
+ ##### Insert Background Image (Version >=1.1.32)
701
+ ```ts
702
+ import { ApplianceMultiPlugin } from '@netless/appliance-plugin';
703
+ const plugin = await ApplianceMultiPlugin.getInstance(manager, {
704
+ options: {
705
+ cdn: {...}
706
+ extras: {
707
+ ...,
708
+ useBackgroundThread: true,
709
+ }
710
+ },
711
+ });
712
+ plugin.insertBackgroundImage(viewId, {
713
+ src: 'https://example.com/background.png'
714
+ uuid: 'unique identifier',
715
+ centerX: 0,
716
+ centerY: 0,
717
+ width: 200,
718
+ height: 200,
719
+ locked: true,
720
+ })
721
+ ```
722
+
723
+ ##### Handwriting graphics automatic association function:`autoDraw`, need to combine [@netless/appliance-extend-auto-draw-plugin](https://www.npmjs.com/package/@netless/appliance-extend-auto-draw-plugin)
724
+ ```js
725
+ export interface AutoDrawOptions {
726
+ /** API key for accessing all OpenRouter models */
727
+ apiKey?: string;
728
+ /** Custom model to use */
729
+ customModel?: string;
730
+ /** Container for rendering icons */
731
+ container: HTMLDivElement;
732
+ /** Delay time for rendering icons, default is 2000ms */
733
+ delay?: number;
734
+ /**
735
+ * Upload file to OSS server and return URL address, if returns undefined then this feature will not be used
736
+ * @param file File object
737
+ * @returns Image URL string
738
+ */
739
+ uploadFile?: (file: File) => Promise<string | undefined>;
740
+ }
741
+ import { ApplianceMultiPlugin } from '@netless/appliance-plugin';
742
+ import { AutoDrawPlugin } from '@netless/appliance-extend-auto-draw-plugin';
743
+ const plugin = await ApplianceMultiPlugin.getInstance(...);
744
+ const autoDrawPlugin = new AutoDrawPlugin({
745
+ container: topBarDiv,
746
+ delay: 2000
747
+ });
748
+ plugin.usePlugin(autoDrawPlugin);
749
+ ```
750
+ ![Image](https://github.com/user-attachments/assets/c388691c-ae72-44ec-bbb7-e92c3a73c9c7)
751
+
752
+ <!-- 9. Handwriting graphics automatic association function: 'autoDraw' (version >=1.1.7)
753
+ ```js
754
+ export type AutoDrawOptions = {
755
+ /** Automatically associate rest api addresses */
756
+ hostServer: string;
757
+ /** A container that holds a list of associated icons */
758
+ container: HTMLDivElement;
759
+ /** How long does the drawing end start activating the association */
760
+ delay?: number;
761
+ };
762
+ import { ApplianceMultiPlugin, AutoDrawPlugin } from '@netless/appliance-plugin';
763
+ const plugin = await ApplianceMultiPlugin.getInstance(...);
764
+ const autoDrawPlugin = new AutoDrawPlugin({
765
+ container: topBarDiv,
766
+ hostServer: 'https://autodraw-white-backup-hk-hkxykbfofr.cn-hongkong.fcapp.run',
767
+ delay: 2000
768
+ });
769
+ plugin.usePlugin(autoDrawPlugin);
770
+ ```
771
+ ![Image](https://github.com/user-attachments/assets/c388691c-ae72-44ec-bbb7-e92c3a73c9c7) -->
772
+
773
+ ### Configuration Parameters
774
+ `getInstance(wm: WindowManager | Room | Player, adaptor: ApplianceAdaptor)`
775
+ - `wm`: `WindowManager | Room | Player`. In multi-window mode, pass `WindowManager`, in single-window mode, pass `Room` or `Player` (whiteboard playback mode).
776
+ - `adaptor`: Configuration adapter.
777
+ - `options: AppliancePluginOptions` - Must be configured, where `cdn` is required.
778
+ ```js
779
+ export type AppliancePluginOptions = {
780
+ /** CDN configuration item */
781
+ cdn: CdnOpt;
782
+ /** Additional configuration items */
783
+ extras?: ExtrasOptions;
784
+ };
785
+ export type CdnOpt = {
786
+ /** Full worker URL address, thread for drawing complete data */
787
+ fullWorkerUrl?: string;
788
+ /** Sub worker URL address, thread for drawing one frame of data */
789
+ subWorkerUrl?: string;
790
+ };
791
+ export type ExtrasOptions = {
792
+ /** Whether to use simple mode, default value is ``false``
793
+ * true: Simple mode:
794
+ 1. Drawing will use single worker, bezier smoothing cannot be used during drawing.
795
+ 2. Remove some new features: minimap, pointerPen (laser pen), autoDraw plugin.
796
+ */
797
+ useSimple: boolean;
798
+ /** Whether to use worker, default value is ``auto``
799
+ * auto: Automatically select (use webWorker if browser supports offscreenCanvas, otherwise use main thread)
800
+ * mainThread: Use main thread, canvas drawing data.
801
+ */
802
+ useWorker?: UseWorkerType;
803
+ /** Whether to use backgroundThread, default value is ``false``
804
+ * true: Use backgroundThread, can call ``insertMarkmap``, ``updateMarkmap``, ``insertBackgroundImage``
805
+ * false: Do not use backgroundThread
806
+ */
807
+ useBackgroundThread?: boolean;
808
+ /** Synchronization data configuration item */
809
+ syncOpt?: SyncOpt;
810
+ /** Canvas configuration item */
811
+ canvasOpt?: CanvasOpt;
812
+ /** Pointer configuration item */
813
+ cursor?: CursorOpt;
814
+ /** Canvas cache configuration item */
815
+ bufferSize?: BufferSizeOpt;
816
+ /** Bezier optimization configuration item */
817
+ bezier?: BezierOpt;
818
+ /** Partial eraser configuration item */
819
+ pencilEraser?: PencilEraserOpt;
820
+ /** Stroke width range configuration item */
821
+ strokeWidth?: StrokeWidthOpt,
822
+ /** Text editor configuration item */
823
+ textEditor?: TextEditorOpt;
824
+ /** Undo redo configuration item */
825
+ undoRedo?: {
826
+ /** Whether to enable global undo redo, default value is false (Version >=1.1.27) */
827
+ enableGlobal?: boolean;
828
+ /** Maximum stack length for undo redo, default value is 20 */
829
+ maxStackLength?: number;
830
+ };
831
+ }
205
832
  ```
206
- - cursorAdapter? : ``CursorAdapter``; This parameter is optional. In single whiteboard mode, customize the mouse style.
833
+ - `cursorAdapter?: CursorAdapter` - Optional, in single whiteboard mode, configure custom mouse style.
834
+ - `logger?: Logger` - Optional, configure log printer object. If not provided, defaults to local console output. If logs need to be uploaded to a specified server, manual configuration is required.
835
+ > If you need to upload to the whiteboard log server, you can configure `room.logger` to this item.
836
+
837
+ ### Front-end Debugging
838
+ During the integration process, if you want to understand and track the internal status of the plugin, you can view internal data through the following console commands.
839
+ ```js
840
+ const appliancePlugin = await ApplianceSinglePlugin.getInstance(...)
841
+ appliancePlugin.currentManager // Can view package version number, internal status, etc.
842
+ appliancePlugin.currentManager.consoleWorkerInfo() // Can view drawing information on worker
843
+ ```
844
+
845
+ ## Usage Examples
846
+
847
+ ### Basic Usage Example
848
+
849
+ ```js
850
+ import { ApplianceSinglePlugin } from '@netless/appliance-plugin';
851
+ import '@netless/appliance-plugin/dist/style.css';
852
+
853
+ // Method 1: Using CDN (recommended for production)
854
+ const plugin = await ApplianceSinglePlugin.getInstance(room, {
855
+ options: {
856
+ cdn: {
857
+ fullWorkerUrl: 'https://your-cdn.com/fullWorker.js',
858
+ subWorkerUrl: 'https://your-cdn.com/subWorker.js',
859
+ },
860
+ },
861
+ });
862
+
863
+ // Method 2: Using local worker files (suitable for development)
864
+ import fullWorkerString from '@netless/appliance-plugin/dist/fullWorker.js?raw';
865
+ import subWorkerString from '@netless/appliance-plugin/dist/subWorker.js?raw';
866
+ const fullWorkerBlob = new Blob([fullWorkerString], {type: 'text/javascript'});
867
+ const fullWorkerUrl = URL.createObjectURL(fullWorkerBlob);
868
+ const subWorkerBlob = new Blob([subWorkerString], {type: 'text/javascript'});
869
+ const subWorkerUrl = URL.createObjectURL(subWorkerBlob);
870
+
871
+ const plugin = await ApplianceSinglePlugin.getInstance(room, {
872
+ options: {
873
+ cdn: {
874
+ fullWorkerUrl,
875
+ subWorkerUrl,
876
+ },
877
+ },
878
+ });
879
+ ```
880
+
881
+ ### Switch Drawing Tools
882
+
883
+ ```js
884
+ import { ApplianceNames, EStrokeType } from '@netless/appliance-plugin';
885
+
886
+ // Switch to pencil tool
887
+ room.setMemberState({ currentApplianceName: ApplianceNames.pencil });
888
+
889
+ // Switch to rectangle tool
890
+ room.setMemberState({ currentApplianceName: ApplianceNames.rectangle });
891
+
892
+ // Switch to laser pen tool
893
+ room.setMemberState({
894
+ currentApplianceName: ApplianceNames.laserPen,
895
+ strokeType: EStrokeType.Normal
896
+ });
897
+
898
+ // Switch to text tool
899
+ room.setMemberState({ currentApplianceName: ApplianceNames.text });
900
+ ```
901
+
902
+ ### Custom Style Example
903
+
904
+ ```js
905
+ // Set brush style to dotted line
906
+ room.setMemberState({
907
+ strokeType: EStrokeType.Dotted,
908
+ strokeOpacity: 0.8
909
+ });
910
+
911
+ // Set shape fill
912
+ room.setMemberState({
913
+ fillColor: [255, 0, 0], // Red
914
+ fillOpacity: 0.5
915
+ });
916
+
917
+ // Set text style
918
+ room.setMemberState({
919
+ textOpacity: 0.9,
920
+ textBgColor: [255, 255, 0], // Yellow background
921
+ textBgOpacity: 0.3
922
+ });
923
+ ```
924
+
925
+ ### Text Editing Example
926
+
927
+ ```js
928
+ // Insert text at specified position
929
+ const textId = plugin.insertText(100, 100, 'Hello World');
930
+
931
+ // Edit text content
932
+ plugin.updateText(textId, 'Updated Text');
933
+
934
+ // Remove text focus
935
+ plugin.blurText();
936
+ ```
937
+
938
+ ### Minimap Function Example
939
+
940
+ ```js
941
+ // Create minimap
942
+ const minimapDiv = document.getElementById('minimap');
943
+ await plugin.createMiniMap('mainView', minimapDiv);
944
+
945
+ // Destroy minimap
946
+ await plugin.destroyMiniMap('mainView');
947
+ ```
948
+
949
+ ### Undo/Redo Example
950
+
951
+ ```js
952
+ // Undo operation
953
+ const undoSteps = plugin.undo();
954
+
955
+ // Redo operation
956
+ const redoSteps = plugin.redo();
957
+
958
+ // Check if undo/redo is possible
959
+ const canUndo = plugin.canUndoSteps() > 0;
960
+ const canRedo = plugin.canRedoSteps() > 0;
961
+ ```
962
+
963
+ ## FAQ
964
+
965
+ ### 1. How to choose the right integration method?
966
+
967
+ - **fastboard**: If you are using the fastboard framework, it is recommended to use fastboard's integration method, which has the simplest configuration
968
+ - **Multi-window scenario**: If you need multi-window functionality, use `ApplianceMultiPlugin`
969
+ - **Single whiteboard scenario**: If you only need single whiteboard functionality, use `ApplianceSinglePlugin`
970
+
971
+ ### 2. Worker file deployment method selection?
972
+
973
+ - **CDN deployment** (recommended): Suitable for production environments, can reduce main package size (main package ~400kB, two workers ~800kB each)
974
+ - **Local packaging**: Suitable for development environments or scenarios where package size is not a concern
975
+
976
+ ### 3. Performance optimization recommendations
977
+
978
+ - Use CDN deployment for worker files to reduce main package size
979
+ - Reasonably configure `bufferSize` to adjust canvas cache size according to device performance
980
+ - On mobile or low-performance devices, consider using `useSimple: true` simple mode
981
+ - If there are unnecessary features, you can avoid enabling `useBackgroundThread: true`
982
+
983
+ ### 4. Compatibility notes
984
+
985
+ - Supports modern browsers (Chrome, Firefox, Safari, Edge)
986
+ - Mobile browser support depends on OffscreenCanvas support
987
+ - Devices that do not support OffscreenCanvas will automatically downgrade to main thread mode
988
+
989
+ ## Version History
990
+
991
+ For detailed version update records, please refer to [CHANGELOG.md](./CHANGELOG.md)
992
+
993
+ ## License
994
+
995
+ MIT License
207
996
 
208
- ### Front-end debugging introduction
209
- During the interconnection process, if you want to understand and track the internal status of the plug-in, you can view the internal data through the following console commands.
997
+ ## Related Links
210
998
 
211
- ```js
212
- const applianPlugin = await ApplianceSinglePlugin.getInstance(...)
213
- applianPlugin.CurrentManager // can see the package version number, internal state, etc
214
- applianPlugin.CurrentManager.ConsoleWorkerInfo () // can check information to draw on the worker
215
- ```
999
+ - [white-web-sdk](https://www.npmjs.com/package/white-web-sdk)
1000
+ - [@netless/window-manager](https://www.npmjs.com/package/@netless/window-manager)
1001
+ - [fastboard](https://github.com/netless-io/fastboard)
1002
+ - [Official Documentation](https://doc.shengwang.cn/)