@realsee/dnalogel 2.0.0-alpha.32 → 2.0.0-alpha.34

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 (123) hide show
  1. package/components/index.js +1450 -0
  2. package/dist/ModelChassisCompassPlugin/index.js +5 -3
  3. package/dist/PanoSpatialTagPlugin/index.js +13 -11
  4. package/dist/components/PaintBrush/Controller.d.ts +43 -0
  5. package/dist/components/PaintBrush/Subscribe.d.ts +76 -0
  6. package/dist/components/PaintBrush/index.d.ts +27 -0
  7. package/dist/components/PaintBrush/style.d.ts +2 -0
  8. package/dist/components/PaintBrush/tween.d.ts +62 -0
  9. package/dist/components/PaintBrush/typings.d.ts +58 -0
  10. package/dist/components/PaintBrush/utils.d.ts +26 -0
  11. package/dist/components/index.d.ts +2 -0
  12. package/dist/floorplan/ModelFloorplanPlugin/index.js +7 -6
  13. package/dist/floorplan/TopviewFloorplanPlugin/index.js +7 -6
  14. package/dist/index.es.js +25 -20
  15. package/dist/index.js +25 -20
  16. package/dist/index.umd.js +25 -20
  17. package/dist/shared-utils/uuid.d.ts +1 -0
  18. package/docs/classes/Magnifier.html +4 -4
  19. package/docs/classes/ModelRoomLabelController.html +4 -4
  20. package/docs/classes/PanoFloorplanRadarPluginController.html +2 -2
  21. package/docs/enums/CameraMovementEffect.html +2 -2
  22. package/docs/enums/DIRECTION.html +1 -1
  23. package/docs/enums/DISPLAY_STRATEGY_TYPE.html +1 -1
  24. package/docs/enums/FLOOR_PLAN_ATTACHED_TO.html +1 -1
  25. package/docs/enums/ITEM_LABEL_PLUGIN_DISPLAY_STRATEGY_TYPE.html +1 -1
  26. package/docs/enums/ModelFloorplanErrorType.html +1 -1
  27. package/docs/enums/Rotation.html +2 -2
  28. package/docs/index.html +1 -1
  29. package/docs/interfaces/CSS3DRenderPluginExportType.html +2 -2
  30. package/docs/interfaces/CameraMovementPluginExportType.html +2 -2
  31. package/docs/interfaces/FloorplanBounding.html +4 -4
  32. package/docs/interfaces/FloorplanData.html +2 -2
  33. package/docs/interfaces/FloorplanEntrance.html +7 -7
  34. package/docs/interfaces/FloorplanExtraObject.html +3 -3
  35. package/docs/interfaces/FloorplanExtraObject3D.html +2 -2
  36. package/docs/interfaces/FloorplanFloorData.html +2 -2
  37. package/docs/interfaces/FloorplanImagePosition.html +2 -2
  38. package/docs/interfaces/FloorplanObserver.html +2 -2
  39. package/docs/interfaces/FloorplanOutlineItem.html +2 -2
  40. package/docs/interfaces/FloorplanPosition.html +2 -2
  41. package/docs/interfaces/FloorplanRoomItem.html +6 -6
  42. package/docs/interfaces/FloorplanRoomLabelItem.html +3 -3
  43. package/docs/interfaces/FloorplanServerBounding.html +4 -4
  44. package/docs/interfaces/FloorplanServerComputedData.html +1 -1
  45. package/docs/interfaces/FloorplanServerData.html +2 -2
  46. package/docs/interfaces/FloorplanServerEntrance.html +7 -7
  47. package/docs/interfaces/FloorplanServerFloorData.html +2 -2
  48. package/docs/interfaces/FloorplanServerImagePosition.html +2 -2
  49. package/docs/interfaces/FloorplanServerObserver.html +2 -2
  50. package/docs/interfaces/FloorplanServerOutlineItem.html +2 -2
  51. package/docs/interfaces/FloorplanServerPosition.html +2 -2
  52. package/docs/interfaces/FloorplanServerRoomItem.html +7 -7
  53. package/docs/interfaces/FloorplanServerRoomLabelItem.html +3 -3
  54. package/docs/interfaces/ItemLabelPluginData.html +1 -1
  55. package/docs/interfaces/ItemLabelPluginExportReturnsType.html +1 -1
  56. package/docs/interfaces/ItemLabelPluginParametersType.html +1 -1
  57. package/docs/interfaces/LineJson.html +1 -1
  58. package/docs/interfaces/ModelChassisCompassPluginData.html +1 -1
  59. package/docs/interfaces/ModelChassisCompassPluginExportType.html +1 -1
  60. package/docs/interfaces/ModelChassisCompassPluginParameterType.html +1 -1
  61. package/docs/interfaces/ModelEntryDoorGuidePluginData.html +1 -1
  62. package/docs/interfaces/ModelEntryDoorGuidePluginExportType.html +1 -1
  63. package/docs/interfaces/ModelFloorplanParameterType.html +1 -1
  64. package/docs/interfaces/ModelFloorplanViewEvent.html +2 -2
  65. package/docs/interfaces/ModelItemLabelPluginData.html +1 -1
  66. package/docs/interfaces/ModelItemLabelPluginExportReturnsType.html +1 -1
  67. package/docs/interfaces/ModelItemLabelPluginParametersType.html +1 -1
  68. package/docs/interfaces/ModelRoomLabelPluginData.html +1 -1
  69. package/docs/interfaces/ModelTVVideoPluginData.html +1 -1
  70. package/docs/interfaces/ModelTVVideoPluginExportType.html +1 -1
  71. package/docs/interfaces/ModelTVVideoPluginParameterType.html +1 -1
  72. package/docs/interfaces/ModelViewPluginExportType.html +1 -1
  73. package/docs/interfaces/OpenParameter.html +2 -2
  74. package/docs/interfaces/PanoCompassPluginData.html +1 -1
  75. package/docs/interfaces/PanoCompassPluginParameterType.html +1 -1
  76. package/docs/interfaces/PanoCursorRaycasterPluginExportType.html +6 -6
  77. package/docs/interfaces/PanoCursorRaycasterPluginParameterType.html +1 -1
  78. package/docs/interfaces/PanoFloorplanRadarPluginControllerParameter.html +1 -1
  79. package/docs/interfaces/PanoMeasureParameterType.html +1 -1
  80. package/docs/interfaces/PanoRulerPluginExportType.html +1 -1
  81. package/docs/interfaces/PanoRulerPluginOptions.html +1 -1
  82. package/docs/interfaces/PanoRulerPluginParameterType.html +1 -1
  83. package/docs/interfaces/PanoSpatialTagPluginContentEvent.html +1 -1
  84. package/docs/interfaces/PanoSpatialTagPluginContentReplacement.html +1 -1
  85. package/docs/interfaces/PanoSpatialTagPluginData.html +1 -1
  86. package/docs/interfaces/PanoSpatialTagPluginDataElement.html +1 -1
  87. package/docs/interfaces/PanoSpatialTagPluginExportType.html +1 -1
  88. package/docs/interfaces/PanoSpatialTagPluginOriginElement.html +1 -1
  89. package/docs/interfaces/PanoSpatialTagPluginParameterType.html +1 -1
  90. package/docs/interfaces/PanoSpatialTagPluginPointElement.html +1 -1
  91. package/docs/interfaces/PanoSpatialTagPluginTagElement.html +1 -1
  92. package/docs/interfaces/Point.html +1 -1
  93. package/docs/interfaces/PointJson.html +1 -1
  94. package/docs/interfaces/Room.html +1 -1
  95. package/docs/interfaces/RoomInfo.html +1 -1
  96. package/docs/interfaces/RoomLabel.html +7 -7
  97. package/docs/interfaces/RoomRules.html +1 -1
  98. package/docs/interfaces/Rooms.html +1 -1
  99. package/docs/interfaces/TopviewFloorplanPluginParameterType.html +9 -9
  100. package/docs/modules.html +20 -20
  101. package/libs/ModelChassisCompassPlugin/Plugin.js +5 -3
  102. package/libs/PanoSpatialTagPlugin/Components/tag.js +9 -9
  103. package/libs/PanoSpatialTagPlugin/Plugin.js +4 -2
  104. package/libs/components/PaintBrush/Controller.d.ts +43 -0
  105. package/libs/components/PaintBrush/Controller.js +575 -0
  106. package/libs/components/PaintBrush/Subscribe.d.ts +76 -0
  107. package/libs/components/PaintBrush/Subscribe.js +121 -0
  108. package/libs/components/PaintBrush/index.d.ts +27 -0
  109. package/libs/components/PaintBrush/index.js +57 -0
  110. package/libs/components/PaintBrush/style.d.ts +2 -0
  111. package/libs/components/PaintBrush/style.js +102 -0
  112. package/libs/components/PaintBrush/tween.d.ts +62 -0
  113. package/libs/components/PaintBrush/tween.js +15 -0
  114. package/libs/components/PaintBrush/typings.d.ts +58 -0
  115. package/libs/components/PaintBrush/typings.js +6 -0
  116. package/libs/components/PaintBrush/utils.d.ts +26 -0
  117. package/libs/components/PaintBrush/utils.js +51 -0
  118. package/libs/components/index.d.ts +2 -0
  119. package/libs/components/index.js +3 -0
  120. package/libs/floorplan/Components/Compass.js +7 -6
  121. package/libs/shared-utils/uuid.d.ts +1 -0
  122. package/libs/shared-utils/uuid.js +1 -0
  123. package/package.json +4 -2
@@ -0,0 +1,575 @@
1
+ import { queue, execInterval, transformCoords, unTransformCoords, getQuadraticCurvePoint, noop, nextFrame, } from './utils';
2
+ import tween from './tween';
3
+ import { PaintBrushTypeEnum, } from './typings';
4
+ import { Subscribe } from './Subscribe';
5
+ import { uuid } from '../../shared-utils/uuid';
6
+ import PaintBrushStyle from './style';
7
+ export class Controller extends Subscribe {
8
+ constructor(configs) {
9
+ super();
10
+ Object.defineProperty(this, "configs", {
11
+ enumerable: true,
12
+ configurable: true,
13
+ writable: true,
14
+ value: void 0
15
+ });
16
+ Object.defineProperty(this, "clientWidth", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: void 0
21
+ });
22
+ Object.defineProperty(this, "clientHeight", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: void 0
27
+ });
28
+ Object.defineProperty(this, "ready", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: false
33
+ });
34
+ Object.defineProperty(this, "uuid", {
35
+ enumerable: true,
36
+ configurable: true,
37
+ writable: true,
38
+ value: uuid()
39
+ });
40
+ Object.defineProperty(this, "tween", {
41
+ enumerable: true,
42
+ configurable: true,
43
+ writable: true,
44
+ value: void 0
45
+ });
46
+ Object.defineProperty(this, "tweening", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: false
51
+ });
52
+ Object.defineProperty(this, "container", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: void 0
57
+ });
58
+ Object.defineProperty(this, "canvas", {
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ value: void 0
63
+ });
64
+ Object.defineProperty(this, "data", {
65
+ enumerable: true,
66
+ configurable: true,
67
+ writable: true,
68
+ value: {}
69
+ });
70
+ Object.defineProperty(this, "tempLine", {
71
+ enumerable: true,
72
+ configurable: true,
73
+ writable: true,
74
+ value: {}
75
+ });
76
+ this.configs = configs;
77
+ this.clientWidth = document.body.clientWidth;
78
+ this.clientHeight = document.body.clientHeight;
79
+ this.container = this.ifInsertToDOM();
80
+ this.canvas = {};
81
+ this.initCtrl();
82
+ }
83
+ get color() {
84
+ return this.configs.currentColor;
85
+ }
86
+ get state() {
87
+ return this.data;
88
+ }
89
+ get dpr() {
90
+ return this.configs.DPR || 1;
91
+ }
92
+ ifInsertToDOM() {
93
+ if (this.container) {
94
+ return this.container;
95
+ }
96
+ if (this.configs.container) {
97
+ this.configs.container.id = '_gl_paintBrush';
98
+ this.container = this.configs.container;
99
+ }
100
+ else if (!document.getElementById('_gl_paintBrush')) {
101
+ const container = document.createElement('div');
102
+ container.id = '_gl_paintBrush';
103
+ document.body.appendChild(container);
104
+ this.container = container;
105
+ }
106
+ else {
107
+ this.container = document.getElementById('_gl_paintBrush');
108
+ }
109
+ this.container.innerHTML = PaintBrushStyle;
110
+ return this.container;
111
+ }
112
+ /**
113
+ *
114
+ * @param className 初始化画板
115
+ * @returns
116
+ */
117
+ initCanvas(className) {
118
+ const canvas = document.createElement('canvas');
119
+ canvas.className = className;
120
+ canvas.width = this.clientWidth;
121
+ canvas.height = this.clientHeight;
122
+ const ctx = canvas.getContext('2d');
123
+ if (!ctx)
124
+ return;
125
+ ctx.lineWidth = 5 * this.dpr;
126
+ ctx.lineCap = 'round';
127
+ ctx.lineJoin = 'round';
128
+ this.container.appendChild(canvas);
129
+ return canvas;
130
+ }
131
+ /**
132
+ * 初始化操作面板
133
+ * @returns
134
+ */
135
+ initCtrl() {
136
+ const ctrl = document.createElement('div');
137
+ ctrl.className = '_paintBrush-ctrl';
138
+ const ctrl_inner = document.createElement('div');
139
+ ctrl_inner.className = '_paintBrush-ctrlinner';
140
+ const a_undo = document.createElement('a');
141
+ a_undo.className = '_paintBrush-ctrlitem _paintBrush-ctrlitem--undo';
142
+ a_undo.addEventListener('click', (e) => {
143
+ var _a;
144
+ e.stopPropagation();
145
+ // 点击撤回:供埋点使用
146
+ if (this.configs.onClickUndo) {
147
+ this.configs.onClickUndo();
148
+ }
149
+ if (!this.canvas[this.uuid] || !this.data[this.uuid] || this.data[this.uuid].length === 0) {
150
+ return;
151
+ }
152
+ const popState = this.data[this.uuid].pop();
153
+ if (popState) {
154
+ this.emitStateChange({
155
+ type: PaintBrushTypeEnum.Undo,
156
+ color: this.color,
157
+ ready: this.ready,
158
+ state: popState,
159
+ uuid: this.uuid,
160
+ });
161
+ }
162
+ const $ctx = (_a = this.canvas[this.uuid]) === null || _a === void 0 ? void 0 : _a.getContext('2d');
163
+ if (!this.canvas[this.uuid]) {
164
+ return;
165
+ }
166
+ const { width, height } = this.canvas[this.uuid];
167
+ if ($ctx) {
168
+ $ctx.clearRect(0, 0, width, height);
169
+ }
170
+ this.data[this.uuid].forEach((ld) => this.handleDrawLine(this.uuid, ld, { withUndo: true }));
171
+ });
172
+ const a_close = document.createElement('a');
173
+ a_close.className = '_paintBrush-ctrlitem _paintBrush-ctrlitem--close';
174
+ a_close.addEventListener('click', (e) => {
175
+ e.stopPropagation();
176
+ this.closeBrush();
177
+ // 点击关闭:供埋点使用
178
+ if (this.configs.onClickClose) {
179
+ this.configs.onClickClose();
180
+ }
181
+ });
182
+ const $A = [a_undo, a_close];
183
+ $A.forEach(($a) => {
184
+ const $i = document.createElement('i');
185
+ $i.className = 'brush-icon';
186
+ const $span = document.createElement('span');
187
+ $span.className = 'brush-txt';
188
+ $span.innerText = $a.className.endsWith('undo') ? this.configs.onUndoText : this.configs.onExitText;
189
+ $a.appendChild($i);
190
+ $a.appendChild($span);
191
+ });
192
+ ctrl_inner.appendChild(a_undo);
193
+ ctrl_inner.appendChild(a_close);
194
+ ctrl.appendChild(ctrl_inner);
195
+ this.container.appendChild(ctrl);
196
+ return ctrl;
197
+ }
198
+ openBrush() {
199
+ if (this.ready)
200
+ return;
201
+ if (!this.canvas[this.uuid]) {
202
+ this.canvas[this.uuid] = this.initCanvas('_paintBrush-canvas');
203
+ }
204
+ this.container.className = 'brushing';
205
+ const $curCanvas = this.canvas[this.uuid];
206
+ const $ctx = $curCanvas.getContext('2d');
207
+ $ctx.clearRect(0, 0, $curCanvas.width, $curCanvas.height);
208
+ this.openBrushHandle();
209
+ this.ready = true;
210
+ this.emit('readyChange', true);
211
+ }
212
+ closeBrush() {
213
+ if (!this.ready)
214
+ return;
215
+ this.container.className = '';
216
+ this.data = {};
217
+ this.tempLine = {};
218
+ Object.keys(this.canvas).forEach((key) => {
219
+ this.canvas[key].ontouchstart = () => false;
220
+ this.canvas[key].ontouchmove = () => false;
221
+ this.canvas[key].ontouchend = () => false;
222
+ this.canvas[key].ontouchcancel = () => false;
223
+ const $ctx = this.canvas[key].getContext('2d');
224
+ if ($ctx) {
225
+ $ctx.clearRect(0, 0, this.canvas[key].width, this.canvas[key].height);
226
+ }
227
+ });
228
+ this.ready = false;
229
+ this.emit('readyChange', false);
230
+ this.emitStateChange({
231
+ type: PaintBrushTypeEnum.Exit,
232
+ color: this.color,
233
+ ready: false,
234
+ uuid: this.uuid,
235
+ });
236
+ }
237
+ updateCurrentColor(color) {
238
+ const currentCanvas = this.canvas[this.uuid];
239
+ if (!currentCanvas)
240
+ return;
241
+ const currentCtx = currentCanvas.getContext('2d');
242
+ if (!currentCtx)
243
+ return;
244
+ this.configs.currentColor = color;
245
+ currentCtx.strokeStyle = color;
246
+ }
247
+ openBrushHandle() {
248
+ const currentCanvas = this.canvas[this.uuid];
249
+ if (!currentCanvas)
250
+ return;
251
+ const currentCtx = currentCanvas.getContext('2d');
252
+ if (!currentCtx)
253
+ return;
254
+ const color = this.color || '#6D92FF';
255
+ currentCtx.strokeStyle = color;
256
+ let begin = null; // 开始点
257
+ let points = []; // 单次 touch 点位集合
258
+ let move;
259
+ let line = []; // 同步 touch 点位数据
260
+ let startTime = 0; // touch 开始时间
261
+ // 绘制
262
+ const draw = (beginPoint, controlPoint, endPoint) => {
263
+ const color = this.color || '#ff0000';
264
+ currentCtx.strokeStyle = color;
265
+ currentCtx.beginPath();
266
+ currentCtx.moveTo(beginPoint.x, beginPoint.y);
267
+ currentCtx.quadraticCurveTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y);
268
+ currentCtx.stroke();
269
+ };
270
+ // 鼠标按下
271
+ currentCanvas.onmousedown = (e) => {
272
+ e.preventDefault();
273
+ startTime = Date.now();
274
+ const x = e.clientX;
275
+ const y = e.clientY;
276
+ points = [];
277
+ points.push({ x, y });
278
+ begin = { x, y };
279
+ move = transformCoords({ x, y }, this.clientWidth, this.clientHeight);
280
+ line = [];
281
+ };
282
+ // 鼠标移动
283
+ currentCanvas.onmousemove = (e) => {
284
+ e.preventDefault();
285
+ if (!begin)
286
+ return;
287
+ const x = Number(e.clientX);
288
+ const y = Number(e.clientY);
289
+ // 密集点位稀释
290
+ if (Math.abs(x - begin.x) < 5 && Math.abs(y - begin.y) < 5) {
291
+ return;
292
+ }
293
+ points.push({ x, y });
294
+ // 此处应记录折线拟合之前的点
295
+ line.push(transformCoords({ x, y }, this.clientWidth, this.clientHeight));
296
+ // 折线拟合二次贝塞尔曲线至少需要三个点
297
+ if (points.length < 3) {
298
+ return;
299
+ }
300
+ const { control, end } = getQuadraticCurvePoint(points);
301
+ if (!control || !end) {
302
+ return;
303
+ }
304
+ draw(begin, control, end);
305
+ begin = end;
306
+ };
307
+ // 鼠标松开
308
+ currentCanvas.onmouseup = (e) => {
309
+ e.preventDefault();
310
+ begin = null;
311
+ if (points.length < 3)
312
+ return;
313
+ if (!this.data[this.uuid]) {
314
+ this.data[this.uuid] = [];
315
+ }
316
+ const duration = Date.now() - startTime;
317
+ const state = {
318
+ move: Object.assign({}, move),
319
+ uuid: this.uuid,
320
+ line: [...line],
321
+ color: this.color,
322
+ duration: duration < 1280 ? duration : duration < 2000 ? 1280 : 0, // 单次笔迹时长超过2000ms不加动画
323
+ };
324
+ this.data[this.uuid].push(state);
325
+ // 广播数据
326
+ nextFrame(() => {
327
+ this.emitStateChange({
328
+ type: PaintBrushTypeEnum.Drawline,
329
+ color: this.color,
330
+ ready: this.ready,
331
+ state,
332
+ uuid: this.uuid,
333
+ });
334
+ });
335
+ };
336
+ // 手势按压
337
+ currentCanvas.ontouchstart = (e) => {
338
+ e.preventDefault();
339
+ startTime = Date.now();
340
+ const x = e.touches[0].clientX;
341
+ const y = e.touches[0].clientY;
342
+ points = [];
343
+ points.push({ x, y });
344
+ begin = { x, y };
345
+ console.log('ontouchstart', x, y, begin);
346
+ move = transformCoords({ x, y }, this.clientWidth, this.clientHeight);
347
+ line = [];
348
+ };
349
+ // 手势移动
350
+ currentCanvas.ontouchmove = (e) => {
351
+ e.preventDefault();
352
+ if (!begin)
353
+ return;
354
+ const x = Number(e.touches[0].clientX);
355
+ const y = Number(e.touches[0].clientY);
356
+ if (Math.abs(x - begin.x) < 5 && Math.abs(y - begin.y) < 5)
357
+ return; // 密集点位稀释
358
+ points.push({ x, y });
359
+ line.push(transformCoords({ x, y }, this.clientWidth, this.clientHeight)); // 此处应记录折线拟合之前的点
360
+ if (points.length < 3)
361
+ return; // 折线拟合二次贝塞尔曲线至少需要三个点
362
+ const { control, end } = getQuadraticCurvePoint(points);
363
+ if (!control || !end)
364
+ return;
365
+ draw(begin, control, end);
366
+ begin = end;
367
+ };
368
+ // 手势按压离开
369
+ currentCanvas.ontouchend = currentCanvas.ontouchcancel = (e) => {
370
+ e.preventDefault();
371
+ begin = null;
372
+ if (points.length < 3)
373
+ return;
374
+ if (!this.data[this.uuid]) {
375
+ this.data[this.uuid] = [];
376
+ }
377
+ const duration = Date.now() - startTime;
378
+ const state = {
379
+ move: Object.assign({}, move),
380
+ line: [...line],
381
+ uuid: this.uuid,
382
+ color: this.color,
383
+ duration: duration < 1280 ? duration : duration < 2000 ? 1280 : 0, // 单次笔迹时长超过2000ms不加动画
384
+ };
385
+ this.data[this.uuid].push(state);
386
+ // 广播数据
387
+ nextFrame(() => {
388
+ this.emitStateChange({
389
+ type: PaintBrushTypeEnum.Drawline,
390
+ color: this.color,
391
+ ready: this.ready,
392
+ state,
393
+ uuid: this.uuid,
394
+ });
395
+ });
396
+ };
397
+ }
398
+ emitStateChange(action, userAction = true) {
399
+ if (action.type !== PaintBrushTypeEnum.Drawline) {
400
+ this.emit('stateChange', action, userAction);
401
+ return;
402
+ }
403
+ const timestamp = Date.now();
404
+ const state = action.state;
405
+ if (!state)
406
+ return;
407
+ if (!state.line)
408
+ return;
409
+ const sliceCount = Math.ceil(state.line.length / 100);
410
+ for (let i = 0; i < sliceCount; i++) {
411
+ const localityAction = {
412
+ uuid: this.uuid,
413
+ color: this.color,
414
+ ready: this.ready,
415
+ type: action.type,
416
+ state: {
417
+ uuid: this.uuid,
418
+ move: state.move,
419
+ duration: state.duration,
420
+ color: this.color,
421
+ line: state.line.slice(i * 100, (i + 1) * 100),
422
+ },
423
+ timestamp,
424
+ end: i === sliceCount - 1,
425
+ };
426
+ /** 由于单次 ws 传输数据量过大,会导致 ws 断掉,所以分批传数据 */
427
+ execInterval(i, 20, () => {
428
+ this.emit('stateChange', localityAction, userAction);
429
+ });
430
+ }
431
+ }
432
+ action(action) {
433
+ const { ready, type, uuid } = action;
434
+ if (!ready && this.ready) {
435
+ // 关闭面板
436
+ this.closeBrush();
437
+ return;
438
+ }
439
+ if (ready && !this.ready) {
440
+ // 开启面板:首次打开画笔不同步上一次的画线
441
+ this.openBrush();
442
+ return;
443
+ }
444
+ if (!this.ready) {
445
+ return;
446
+ }
447
+ switch (type) {
448
+ case PaintBrushTypeEnum.Drawline:
449
+ const { state, timestamp, end } = action;
450
+ if (!timestamp)
451
+ return;
452
+ if (!state)
453
+ return;
454
+ this.tempLine[timestamp] = [].concat(this.tempLine[timestamp] || [], state.line);
455
+ if (end) {
456
+ Object.assign(state, { line: this.tempLine[timestamp] });
457
+ this.handleDrawLine(uuid, state, {}, () => delete this.tempLine[timestamp]);
458
+ }
459
+ break;
460
+ case PaintBrushTypeEnum.Undo:
461
+ this.handleUndo(uuid);
462
+ break;
463
+ default:
464
+ break;
465
+ }
466
+ }
467
+ handleDrawLine(_uuid, data, { withUndo = false }, callback = noop) {
468
+ if (!data || Object.prototype.toString.call(data) != '[object Object]' || Object.keys(data).length === 0) {
469
+ return;
470
+ }
471
+ console.log('handleDrawLine', data, data.line);
472
+ queue(() => {
473
+ return new Promise((resolve) => {
474
+ if (!withUndo) {
475
+ if (!this.canvas[_uuid]) {
476
+ this.canvas[_uuid] = this.initCanvas('_paintBrush-canvas--sync');
477
+ }
478
+ if (!this.data[_uuid]) {
479
+ this.data[_uuid] = [];
480
+ }
481
+ this.data[_uuid].push(data);
482
+ }
483
+ if (!this.canvas[_uuid]) {
484
+ return;
485
+ }
486
+ const $ctx = this.canvas[_uuid].getContext('2d');
487
+ if (!$ctx)
488
+ return;
489
+ const { line = [], color = 'black', duration = 0, uuid } = data;
490
+ const move = unTransformCoords(data.move || {}, this.clientWidth, this.clientHeight);
491
+ let points = [move];
492
+ $ctx.strokeStyle = color;
493
+ $ctx.beginPath();
494
+ $ctx.moveTo(move.x, move.y);
495
+ if (duration && !withUndo) {
496
+ let drawCache = [];
497
+ const self = this;
498
+ self.tween = tween({ step: 0 }, { step: line.length - 1 }, duration)
499
+ .onUpdate(({ step }) => {
500
+ var _a;
501
+ self.tweening = true;
502
+ if (!self.ready) {
503
+ $ctx.clearRect(0, 0, self.canvas[uuid].width, self.canvas[uuid].height);
504
+ return (_a = self.tween) === null || _a === void 0 ? void 0 : _a.stop();
505
+ }
506
+ const i = Math.floor(step);
507
+ if (!drawCache.find((dc) => dc === i)) {
508
+ drawCache.push(i);
509
+ console.log('__debug__', line, line[i], i);
510
+ points.push(unTransformCoords(line[i], self.clientWidth, self.clientHeight));
511
+ if (points.length < 3)
512
+ return;
513
+ const { control, end } = getQuadraticCurvePoint(points);
514
+ if (!control || !end)
515
+ return;
516
+ $ctx.quadraticCurveTo(control.x, control.y, end.x, end.y);
517
+ $ctx.stroke();
518
+ }
519
+ })
520
+ .onComplete((e) => {
521
+ self.tween = undefined;
522
+ self.tweening = false;
523
+ drawCache = [];
524
+ points = [];
525
+ if (callback)
526
+ callback();
527
+ resolve();
528
+ });
529
+ }
530
+ else {
531
+ for (let i = 0; i < line.length; i++) {
532
+ points.push(unTransformCoords(line[i], this.clientWidth, this.clientHeight));
533
+ if (points.length < 3)
534
+ continue;
535
+ const { control, end } = getQuadraticCurvePoint(points);
536
+ if (!control || !end)
537
+ continue;
538
+ $ctx.quadraticCurveTo(control.x, control.y, end.x, end.y);
539
+ }
540
+ $ctx.stroke();
541
+ points = [];
542
+ if (callback)
543
+ callback();
544
+ resolve();
545
+ }
546
+ });
547
+ });
548
+ }
549
+ handleUndo(uuid) {
550
+ console.log('handleUndo', uuid, this.canvas[uuid]);
551
+ if (!this.canvas[uuid] || !this.data[uuid] || this.data[uuid].length === 0) {
552
+ return;
553
+ }
554
+ this.data[uuid].pop();
555
+ const handle = () => {
556
+ var _a;
557
+ const $ctx = (_a = this.canvas[uuid]) === null || _a === void 0 ? void 0 : _a.getContext('2d');
558
+ if ($ctx) {
559
+ $ctx.clearRect(0, 0, this.canvas[uuid].width, this.canvas[uuid].height);
560
+ }
561
+ this.data[uuid].forEach((ld) => this.handleDrawLine(uuid, ld, { withUndo: true }));
562
+ };
563
+ if (this.tween && this.tweening) {
564
+ this.tween.stop();
565
+ nextFrame(handle, 60);
566
+ return;
567
+ }
568
+ handle();
569
+ }
570
+ destroyBrush() {
571
+ this.closeBrush();
572
+ this.ready = false;
573
+ this.emit('readyChange', true);
574
+ }
575
+ }
@@ -0,0 +1,76 @@
1
+ export declare type EventMap = {
2
+ [name: string]: (...args: any[]) => void | boolean;
3
+ };
4
+ /**
5
+ * 监听者模式
6
+ * @template T 预设的监听回调类型
7
+ * @example
8
+ * ```
9
+ * new Subscribe<{
10
+ * "foo": [arg1: number, arg2: string],
11
+ * "bar": [arg: boolean],
12
+ * }>()
13
+ * ```
14
+ */
15
+ declare class Subscribe<T extends EventMap> {
16
+ /**
17
+ * 判断是否注册了事件
18
+ * @param name 事件类型
19
+ */
20
+ hasListener(name: keyof T): boolean;
21
+ /**
22
+ * 注册事件
23
+ * @param name 事件类型
24
+ * @param callback 事件回调函数
25
+ * @param once 是否只执行一次
26
+ * @returns 解除事件
27
+ * @template K 预设的监听事件名称
28
+ * @template C 回调函数函数上下文
29
+ */
30
+ on<K extends keyof T>(name: K, callback: (...args: Parameters<T[K]>) => ReturnType<T[K]>, once?: boolean): () => void;
31
+ /**
32
+ * 注册事件(是否只执行一次)
33
+ * @param name 事件类型
34
+ * @param callback 事件回调函数
35
+ * @returns 解除事件
36
+ * @template K 预设的监听事件名称
37
+ * @template C 回调函数函数上下文
38
+ */
39
+ once<K extends keyof T>(name: K, callback: (...args: Parameters<T[K]>) => ReturnType<T[K]>): () => void;
40
+ /**
41
+ * 解除事件
42
+ *
43
+ * 如果 name 不传的话解除对应所有事件
44
+ * 如果 name, callback 不传的话解除所有name的所有事件
45
+ * @param name 事件类型
46
+ * @param callback 事件回调函数
47
+ * @template K 预设的监听事件名称
48
+ */
49
+ off<K extends keyof T>(name?: K, callback?: (...args: Parameters<T[K]>) => ReturnType<T[K]>): void;
50
+ /**
51
+ * 触发事件
52
+ * @param name 事件类型
53
+ * @param data 触发事件的数据
54
+ * @returns canceled 是否被触发取消
55
+ * @template K 预设的监听事件名称
56
+ */
57
+ emit<K extends keyof T>(name: K, ...data: Parameters<T[K]>): boolean;
58
+ }
59
+ export declare namespace SubscribeMixinType {
60
+ interface hasListener<T extends EventMap> {
61
+ (name: keyof T): boolean;
62
+ }
63
+ interface on<T extends EventMap> {
64
+ <K extends keyof T>(name: K, callback: (...args: Parameters<T[K]>) => ReturnType<T[K]>, once?: boolean): () => void;
65
+ }
66
+ interface once<T extends EventMap> {
67
+ <K extends keyof T>(name: K, callback: (...args: Parameters<T[K]>) => ReturnType<T[K]>): () => void;
68
+ }
69
+ interface off<T extends EventMap> {
70
+ <K extends keyof T>(names?: K | K[], callback?: (...args: any[]) => any): void;
71
+ }
72
+ interface emit<T extends EventMap> {
73
+ <K extends keyof T>(name: K, ...data: Parameters<T[K]>): boolean;
74
+ }
75
+ }
76
+ export { Subscribe };