kfb-view 2.1.18 → 2.2.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kfb-view",
3
3
  "description": "一个在线kfb的阅片软件",
4
- "version": "2.1.18",
4
+ "version": "2.2.0",
5
5
  "author": "qifeng.fan <qifeng.fan@hzztai.com>",
6
6
  "license": "MIT",
7
7
  "main": "lib/kfb-view.js",
@@ -12,9 +12,10 @@ import {
12
12
  baseNumber, getAngle, getDistance, getPoint,
13
13
  getRectPoint,
14
14
  isPointInMatrix,
15
- pointInOtherPoint, isPointInPolygon, pointsToRegion,
15
+ pointInOtherPoint, isPointInPolygon, pointsToRegion, isPointInLine,
16
16
  } from '../../util/calculate';
17
17
  import {
18
+ EVENT_ADD_POLYGON_POINT,
18
19
  EVENT_AREA_MOVE_END,
19
20
  EVENT_AREA_MOVE_START, EVENT_AREA_MOVING, EVENT_CANCEL_SELECT_LABEL,
20
21
  EVENT_DB_CLICK_LABEL,
@@ -48,12 +49,19 @@ export class Area extends ViewerCommon {
48
49
  /**
49
50
  * 画点
50
51
  * @param {Object} point
51
- * @param {Object=} config 参数,参见thumb
52
+ * @param {Boolean=} active 是否是激活状态
52
53
  */
53
- drawPoint(point, config) {
54
+ drawPoint(point, active) {
54
55
  this.thumb.draw(point, {
55
- ...config,
56
- strokeStyle: this.options.thumbColor,
56
+ radius: !active ?
57
+ this.options.thumb.radius :
58
+ this.options.thumb.activeRadius,
59
+ strokeStyle: !active ?
60
+ this.options.thumb.color :
61
+ this.options.thumb.activeColor,
62
+ fillStyle: !active ?
63
+ this.options.thumb.bgColor :
64
+ this.options.thumb.activeBgColor,
57
65
  });
58
66
  }
59
67
 
@@ -78,7 +86,11 @@ export class Area extends ViewerCommon {
78
86
  this.draging = false;
79
87
  let selectList = [];
80
88
  let selectLabel;
89
+ let prevSelectLabel = undefined;
81
90
  this.labelList.forEach((item) => {
91
+ if (item.select) {
92
+ prevSelectLabel = item;
93
+ }
82
94
  item.select = false;
83
95
  // 如果有可移动的点了,不做操作
84
96
  if (this.movePoint) {
@@ -202,13 +214,39 @@ export class Area extends ViewerCommon {
202
214
  }
203
215
  selectLabel ?
204
216
  this.$emit(EVENT_SELECT_LABEL, selectLabel) :
205
- !this.movePoint ? this.$emit(EVENT_CANCEL_SELECT_LABEL) : '';
217
+ !this.movePoint && prevSelectLabel ?
218
+ this.$emit(EVENT_CANCEL_SELECT_LABEL, prevSelectLabel) : '';
206
219
  this.change();
207
220
  }
208
221
 
209
222
  onCanvasDblClick({x, y}) {
210
223
  setTimeout(() => {
211
- this.$emit(EVENT_DB_CLICK_LABEL);
224
+ const label = this.labelList.find((item) => item.select);
225
+ if (label?.tool === POLYGON) {
226
+ const points = this.imageToViewerElementPoints(label.points);
227
+ let index = -1;
228
+ for (let i = 0, l = points.length, j = l - 1; i < l; j = i, i++) {
229
+ const s = points[i];
230
+ const t = points[j];
231
+ if (isPointInLine({x, y}, [s, t])) {
232
+ index = i;
233
+ break;
234
+ }
235
+ }
236
+ if (index > -1) {
237
+ const p = this.viewerElementToImageCoordinates(x, y);
238
+ label.points.splice(index, 0, {
239
+ ...p,
240
+ canMove: true,
241
+ });
242
+ this.$emit(EVENT_ADD_POLYGON_POINT, label);
243
+ this.change();
244
+ } else {
245
+ this.$emit(EVENT_DB_CLICK_LABEL, label);
246
+ }
247
+ } else {
248
+ this.$emit(EVENT_DB_CLICK_LABEL, label);
249
+ }
212
250
  });
213
251
  }
214
252
 
@@ -231,11 +269,12 @@ export class Area extends ViewerCommon {
231
269
 
232
270
  /**
233
271
  * 监听鼠标拖动事件
272
+ * @param {Object} position
273
+ * @param {number} position.x
274
+ * @param {number} position.y
234
275
  * @param {Object} e
235
- * @param {number} e.x
236
- * @param {number} e.y
237
276
  */
238
- onCanvasDrag({x, y}) {
277
+ onCanvasDrag({x, y}, e) {
239
278
  if (this.options.drag === false) return;
240
279
  if (!this.lastPoint) this.lastPoint = {x, y};
241
280
  const label = this.movePoint.label;
@@ -245,6 +284,7 @@ export class Area extends ViewerCommon {
245
284
  if (!isMove && !isResize) return;
246
285
  if (position === 4 && !isMove) return;
247
286
  if (position !== 4 && !isResize) return;
287
+ e.preventDefaultAction = true;
248
288
  const scale = this.getImageZoom(true) / label.scale;
249
289
  const tool = label.tool;
250
290
  const region = label.region;
@@ -422,53 +462,42 @@ export class Area extends ViewerCommon {
422
462
  this.lastPoint = {x, y};
423
463
  }
424
464
 
425
- /**
426
- * 监听鼠标按钮事件
427
- * @param {Object} e
428
- */
429
- onCanvasKey(e) {
430
- const {originalEvent} = e;
431
- if (originalEvent.code === 'Escape') {
432
- this.$emit(EVENT_CANCEL_SELECT_LABEL);
433
- this.change();
434
- }
435
- }
436
-
437
465
  /**
438
466
  * 绘制点
439
467
  * @param {Object} points
440
468
  * @param {string} type
441
469
  */
442
- drawThumbPoint(points, type) {
443
- if (this.options.thumb === false) {
470
+ drawThumbPoints(points, type) {
471
+ if (this.options.thumb.show === false) {
444
472
  return;
445
473
  }
446
- const thumbRadius = this.options.thumbRadius ?? 5;
474
+ const position = this.movePoint?.position;
447
475
  if (LINE_TYPES.includes(type)) {
448
- this.drawPoint(points[0], {thumbRadius});
476
+ this.drawPoint(points[0], position === 1);
449
477
  this.drawPoint({
450
478
  x: (points[0].x + points[1].x) / 2,
451
479
  y: (points[0].y + points[1].y) / 2,
452
- }, {thumbRadius: thumbRadius + 2});
453
- this.drawPoint(points[1], {thumbRadius});
480
+ }, position === 4);
481
+ this.drawPoint(points[1], position === 7);
454
482
  } else if (REGION_TYPES.includes(type)) {
455
- getRectPoint(points[0], points[1]).forEach((point) => {
456
- this.drawPoint(point, {thumbRadius});
483
+ getRectPoint(points[0], points[1]).forEach((point, i) => {
484
+ this.drawPoint(point, position === i);
457
485
  });
458
486
  } else if (type === POLYGON) {
459
- points.forEach((point) => {
487
+ points.forEach((point, i) => {
460
488
  if (point.canMove) {
461
- this.drawPoint(point, {thumbRadius});
489
+ this.drawPoint(point, position === i);
462
490
  }
463
491
  });
464
492
  } else if (type === FONT || type === DOT) {
465
- this.drawPoint(points[0], {thumbRadius});
493
+ this.drawPoint(points[0], position === 4);
466
494
  } else if (type === STAR || type === FLAG) {
467
495
  getRectPoint(points[0], points[1]).
468
- filter((item, index) => index === 0 || index === 2 || index === 4 ||
469
- index === 6 || index === 8).
470
- forEach((point) => {
471
- this.drawPoint(point, {thumbRadius});
496
+ forEach((point, index) => {
497
+ if (index === 0 || index === 2 || index === 4 ||
498
+ index === 6 || index === 8) {
499
+ this.drawPoint(point, position === index);
500
+ }
472
501
  });
473
502
  }
474
503
  }
@@ -489,17 +518,17 @@ export class Area extends ViewerCommon {
489
518
  region.x + region.width, region.y + region.height);
490
519
  const scale = this.getImageZoom(true) / label.scale;
491
520
  if (!NO_NORMAL_REGION_TYPES.includes(label.tool)) {
492
- this.drawThumbPoint([startPoint, endPoint], label.tool);
521
+ this.drawThumbPoints([startPoint, endPoint], label.tool);
493
522
  } else if (label.tool === FONT) {
494
523
  const fontWidth = this.getFontWidth(label.text, label.fontSize);
495
524
  const pt = getPoint(startPoint, {
496
525
  x: startPoint.x + fontWidth / 2 * scale,
497
526
  y: startPoint.y - label.fontSize / 2 * scale + 4,
498
527
  }, label.angle);
499
- this.drawThumbPoint([pt], label.tool);
528
+ this.drawThumbPoints([pt], label.tool);
500
529
  } else if (label.tool === STAR) {
501
530
  const dist = label.lineWidth * scale;
502
- this.drawThumbPoint([
531
+ this.drawThumbPoints([
503
532
  {
504
533
  x: startPoint.x - dist,
505
534
  y: startPoint.y - dist,
@@ -508,14 +537,14 @@ export class Area extends ViewerCommon {
508
537
  y: startPoint.y + dist,
509
538
  }], label.tool);
510
539
  } else if (label.tool === DOT) {
511
- this.drawThumbPoint([
540
+ this.drawThumbPoints([
512
541
  {
513
542
  x: startPoint.x,
514
543
  y: startPoint.y,
515
544
  }], label.tool);
516
545
  } else if (label.tool === FLAG) {
517
546
  const dist = label.lineWidth * scale;
518
- this.drawThumbPoint([
547
+ this.drawThumbPoints([
519
548
  {
520
549
  x: startPoint.x,
521
550
  y: startPoint.y - dist,
@@ -526,10 +555,10 @@ export class Area extends ViewerCommon {
526
555
  } else if (label.tool === POLYGON) {
527
556
  if (this.draging) {
528
557
  const points = this.imageToViewerElementPoints(label.points);
529
- this.drawThumbPoint(points, label.tool);
558
+ this.drawThumbPoints(points, label.tool);
530
559
  } else {
531
560
  const points = this.setPointsMove(label);
532
- this.drawThumbPoint(points, label.tool);
561
+ this.drawThumbPoints(points, label.tool);
533
562
  }
534
563
  }
535
564
  this[label.tool].setContent(this.canvas, {...label});
@@ -552,7 +581,7 @@ export class Area extends ViewerCommon {
552
581
  label.points[index].canMove = false;
553
582
  if (index === 0 || (!pointInOtherPoint(lastPoint, point, 30) &&
554
583
  !pointInOtherPoint(movePoints[0], point, 30)) ||
555
- (!label.isClose && index === movePoints.length - 1)) {
584
+ (index === movePoints.length - 1)) {
556
585
  lastPoint = point;
557
586
  point.canMove = true;
558
587
  label.points[index].canMove = true;
@@ -48,6 +48,7 @@ export class Board extends ViewerCommon {
48
48
  * @param {boolean} [options.measure=true] 绘画时显示信息
49
49
  * @param {boolean} [options.clear=true] 是否结束绘画时清空画布
50
50
  * @param {boolean} [options.isClose=true] 是否自动闭合曲线
51
+ * @param {boolean} [options.enableDbClickClose=true] 是否双击结束曲线绘制
51
52
  * @param {boolean} [options.once=false] 是否绘画一次后自动结束
52
53
  * @param {boolean} [options.isROI=false] 是否是感性区域
53
54
  * @param {boolean} [options.move=true] 是否可移动
@@ -74,6 +75,7 @@ export class Board extends ViewerCommon {
74
75
  measure: true,
75
76
  clear: true,
76
77
  isClose: true,
78
+ enableDbClickClose: true,
77
79
  ...options,
78
80
  lineWidth: !options.lineWidth ?
79
81
  (this.tool === STAR ? 15 :
@@ -103,6 +105,8 @@ export class Board extends ViewerCommon {
103
105
  text: '',
104
106
  measure: true,
105
107
  clear: true,
108
+ isClose: true,
109
+ enableDbClickClose: true,
106
110
  ...options,
107
111
  lineWidth: !options.lineWidth ?
108
112
  (this.tool === STAR ? 15 :
@@ -141,8 +145,16 @@ export class Board extends ViewerCommon {
141
145
  }
142
146
  this.clearCanvas();
143
147
  this[tool].startDraw();
144
- this[tool].draw(this.imageToViewerElementPoints(this.points));
148
+ const points = this.imageToViewerElementPoints(this.points);
149
+ this[tool].draw(points);
145
150
  this[tool].endDraw();
151
+ if (tool === POLYGON) {
152
+ this[tool].drawPoints(points, {
153
+ radius: this.options.thumb.radius,
154
+ strokeStyle: this.options.thumb.color,
155
+ fillStyle: this.options.thumb.bgColor,
156
+ });
157
+ }
146
158
  this.$emit(EVENT_START_PAINTING, this.getPaintOptions());
147
159
  }
148
160
 
@@ -164,13 +176,22 @@ export class Board extends ViewerCommon {
164
176
  this.points = [this.points[0] || point, point];
165
177
  } else if (tool === POLYGON) {
166
178
  this.points.push(point);
179
+ this.setEnablePoints(false);
167
180
  } else if (POINT_TYPES.includes(tool)) {
168
181
  this.points = [point, point];
169
182
  }
170
183
  this.clearCanvas();
171
184
  this[tool].startDraw();
172
- this[tool].draw(this.imageToViewerElementPoints(this.points));
185
+ const points = this.imageToViewerElementPoints(this.points);
186
+ this[tool].draw(points);
173
187
  this[tool].endDraw();
188
+ if (tool === POLYGON) {
189
+ this[tool].drawPoints(points, {
190
+ radius: this.options.thumb.radius,
191
+ strokeStyle: this.options.thumb.color,
192
+ fillStyle: this.options.thumb.bgColor,
193
+ });
194
+ }
174
195
  this.$emit(EVENT_IN_PAINTING, this.getPaintOptions());
175
196
  }
176
197
 
@@ -195,30 +216,60 @@ export class Board extends ViewerCommon {
195
216
  } else if (POINT_TYPES.includes(tool)) {
196
217
  this.points = [point, point];
197
218
  } else if (tool === POLYGON) {
198
- const points = this.imageToViewerElementPoints(this.points);
199
- let firstPoint = points[0];
200
- // 是否是闭合曲线
201
- const isClose = this[this.tool].options.isClose;
202
- if (isClose) {
203
- // 绘制曲线时,点小于5个,或者曲线不是闭合的
204
- if (points.length < 5 || !pointInOtherPoint(firstPoint, {x, y})) {
219
+ const firstPoint = this.imageToViewerElementCoordinates(this.points[0].x,
220
+ this.points[0].y);
221
+ const enableDbClickClose = this[this.tool].options.enableDbClickClose; // 是否启用双击结束绘制
222
+ const isClose = this[this.tool].options.isClose; // 是否自动关闭
223
+ if (enableDbClickClose) {
224
+ if (isClose && pointInOtherPoint(firstPoint, {x, y})) {
225
+ this.setEnablePoints();
226
+ if (this.points.length < 5) {
227
+ return;
228
+ }
229
+ } else {
205
230
  return;
206
231
  }
207
- } else if (points.length < 5) {
232
+ } else {
233
+ this.setEnablePoints();
234
+ // 如果点小于5个,任务标注不符合规范
235
+ if (this.points.length < 5) {
236
+ this.points = [];
237
+ this.clearCanvas();
238
+ return;
239
+ }
240
+ }
241
+ }
242
+ this.$emit(EVENT_END_PAINTING, this.getPaintOptions());
243
+ // 是否只绘制一次
244
+ if (this[this.tool].options.once) {
245
+ this.endDraw();
246
+ } else if (this[this.tool].options.clear) { // 是否结束绘画时清空画布
247
+ this.points = [];
248
+ this.clearCanvas();
249
+ }
250
+ }
251
+
252
+ /**
253
+ * 监听鼠标双击事件
254
+ * @param {Object} e
255
+ * @param {number} e.x
256
+ * @param {number} e.y
257
+ */
258
+ onCanvasDblClick({x, y}) {
259
+ const point = this.viewerElementToImageCoordinates(x, y);
260
+ if (!this.isInROI(point) || this.points.length === 0) {
261
+ this.points = [];
262
+ this.clearCanvas();
263
+ return;
264
+ }
265
+ if (this.tool === POLYGON) {
266
+ this.setEnablePoints();
267
+ // 如果点小于5个,任务标注不符合规范
268
+ if (this.points.length < 5) {
269
+ this.points = [];
270
+ this.clearCanvas();
208
271
  return;
209
272
  }
210
- // 过滤曲线的点,点之间的距离小于10默认为一个点,取第一个
211
- this.points = this.points.filter((p, index) => {
212
- const _p = this.imageToViewerElementCoordinates(p.x, p.y);
213
- if (index === 0) return true;
214
- if (!isClose && index === this.points.length - 1) return true;
215
- if (pointInOtherPoint(firstPoint, _p)) {
216
- return false;
217
- } else {
218
- firstPoint = _p;
219
- return true;
220
- }
221
- });
222
273
  }
223
274
  this.$emit(EVENT_END_PAINTING, this.getPaintOptions());
224
275
  // 是否只绘制一次
@@ -245,12 +296,22 @@ export class Board extends ViewerCommon {
245
296
  }
246
297
  const tool = this.tool;
247
298
  if (tool === POLYGON && this.points.length > 0) {
248
- this.points.pop();
299
+ if (this.points.length > 1) {
300
+ this.points.pop();
301
+ }
249
302
  this.points.push(point);
250
303
  this.clearCanvas();
251
304
  this[tool].startDraw();
252
- this[tool].draw(this.imageToViewerElementPoints(this.points));
305
+ const points = this.imageToViewerElementPoints(this.points);
306
+ this[tool].draw(points);
253
307
  this[tool].endDraw();
308
+ if (tool === POLYGON) {
309
+ this[tool].drawPoints(points, {
310
+ radius: this.options.thumb.radius,
311
+ strokeStyle: this.options.thumb.color,
312
+ fillStyle: this.options.thumb.bgColor,
313
+ });
314
+ }
254
315
  this.$emit(EVENT_IN_PAINTING, this.getPaintOptions());
255
316
  }
256
317
  }
@@ -261,10 +322,43 @@ export class Board extends ViewerCommon {
261
322
  */
262
323
  onCanvasKey(e) {
263
324
  const {originalEvent} = e;
264
- e.preventDefaultAction = true;
265
- if (originalEvent.code === 'Escape') {
325
+ if (originalEvent.key === 'Escape') {
266
326
  this.endDraw();
267
327
  }
328
+ if (originalEvent.key === 'Delete' || originalEvent.key ===
329
+ 'Backspace') {
330
+ // 曲线绘制中,按删除键,删除上一个标注点
331
+ if (this.tool === POLYGON && this.points.length > 1) {
332
+ this.points.splice(this.points.length - 2, 1);
333
+ this.change();
334
+ }
335
+ }
336
+ }
337
+
338
+ setEnablePoints(end = true) {
339
+ const points = this.imageToViewerElementPoints(this.points);
340
+ let firstPoint = points[0];
341
+ // 过滤曲线的点,点之间的距离小于10默认为一个点,取第一个
342
+ this.points = this.points.filter((p, index) => {
343
+ const _p = points[index];
344
+ if (index === 0) return true;
345
+ if (index === this.points.length - 1) return true;
346
+ if (pointInOtherPoint(firstPoint, _p, 30)) {
347
+ return false;
348
+ } else {
349
+ firstPoint = _p;
350
+ return true;
351
+ }
352
+ });
353
+ if (end && this.points.length > 1) {
354
+ const lastPoint = this.points[this.points.length - 1];
355
+ const lastTwoPoint = this.points[this.points.length - 2];
356
+ if (pointInOtherPoint(
357
+ this.imageToViewerElementCoordinates(lastPoint.x, lastPoint.y),
358
+ this.imageToViewerElementCoordinates(lastTwoPoint.x, lastTwoPoint.y))) {
359
+ this.points.splice(this.points.length - 2, 1);
360
+ }
361
+ }
268
362
  }
269
363
 
270
364
  getPaintOptions() {
@@ -328,6 +422,13 @@ export class Board extends ViewerCommon {
328
422
  this[this.tool].startDraw();
329
423
  this[this.tool].draw(points);
330
424
  this[this.tool].endDraw();
425
+ if (this.tool === POLYGON) {
426
+ this[this.tool].drawPoints(points, {
427
+ radius: this.options.thumb.radius,
428
+ strokeStyle: this.options.thumb.color,
429
+ fillStyle: this.options.thumb.bgColor,
430
+ });
431
+ }
331
432
  this.$emit(EVENT_IN_PAINTING, this.getPaintOptions());
332
433
  }
333
434
  }
@@ -91,7 +91,7 @@ class Rotation extends ViewerCommon {
91
91
  this.drawPoint({
92
92
  x: point.x,
93
93
  y: point.y,
94
- }, {thumbRadius: 5});
94
+ }, {radius: 5});
95
95
  });
96
96
  }
97
97
 
@@ -152,8 +152,7 @@ class Rotation extends ViewerCommon {
152
152
  */
153
153
  onCanvasKey(e) {
154
154
  const {originalEvent} = e;
155
- e.preventDefaultAction = true;
156
- if (originalEvent.code === 'Escape') {
155
+ if (originalEvent.key === 'Escape') {
157
156
  this.viewport.setRotation(0);
158
157
  this.stopRotation();
159
158
  }
@@ -5,6 +5,8 @@ import {
5
5
  import {ViewerCommon} from '../common/common';
6
6
  import * as Tools from '../../tool';
7
7
  import {Combination} from '../../tool/Combination';
8
+ import {EVENT_CANCEL_SELECT_LABEL} from '../../const/event';
9
+ import * as EVENTS from '../../const/event';
8
10
 
9
11
  /**
10
12
  * 用来显示标注线的canvas
@@ -25,6 +27,7 @@ export class Shape extends ViewerCommon {
25
27
  this[mark] = new Tools[mark];
26
28
  });
27
29
  this.combination = new Combination();
30
+ this.delaytimer = [];
28
31
  }
29
32
 
30
33
  /**
@@ -32,15 +35,6 @@ export class Shape extends ViewerCommon {
32
35
  * @param {Object} e
33
36
  */
34
37
  onCanvasKey(e) {
35
- const {originalEvent} = e;
36
- e.preventDefaultAction = true;
37
- if (originalEvent.code === 'Escape') {
38
- this.labelList.forEach((item) => {
39
- item.select = false;
40
- item.show = true;
41
- });
42
- this.change();
43
- }
44
38
  }
45
39
 
46
40
  /**
@@ -59,29 +53,24 @@ export class Shape extends ViewerCommon {
59
53
  this.clearCanvas();
60
54
  // 区域标注列表
61
55
  const regionLabelList = [];
62
- this.labelList.forEach(
63
- (item) => {
64
- if (REGION_TYPES.includes(item.tool) || item.isClose && item.tool ===
65
- POLYGON) {
66
- regionLabelList.push({
67
- ...item,
68
- child: [],
69
- self: item,
70
- });
71
- }
72
- });
56
+ const labelList = this.labelList.filter((item) => {
57
+ if (item.show === false) return false;
58
+ if (!this[item.tool]) return false;
59
+ if (!this.isInCanvas(item.region)) return false;
60
+ if (REGION_TYPES.includes(item.tool) || item.isClose && item.tool ===
61
+ POLYGON && item.fillStyle) {
62
+ regionLabelList.push({
63
+ ...item,
64
+ child: [],
65
+ self: item,
66
+ });
67
+ }
68
+ return true;
69
+ });
73
70
  // strokeStyle, lineWidth, fillStyle 相同认为是一个路径下的图形,一起绘制,优化性能
74
71
  const sameFixWidthLabel = {}; // star, flag, star, font lineWidth固定为2
75
72
  const sameNormalLabel = {};
76
- this.labelList.forEach((item) => {
77
- if (item.show === false) return;
78
- if (!this[item.tool]) return;
79
- if (!this.isInCanvas(item.region)) return;
80
- /* const point = this.imageToViewerElementCoordinates(item.points[0].x,
81
- item.points[0].y);
82
- if ((point.x > this.canvas.width ||
83
- point.y > this.canvas.height ||
84
- point.x < 0 || point.y < 0)) return;*/
73
+ labelList.forEach((item) => {
85
74
  const key = `${item.strokeStyle ?? ''}_${item.lineWidth ??
86
75
  ''}_${item.fillStyle ?? ''}`;
87
76
  const regionKey = `${item.strokeStyle ?? ''}_${item.lineWidth ?? ''}`;
@@ -106,11 +95,41 @@ export class Shape extends ViewerCommon {
106
95
  parent.child.push(item);
107
96
  }
108
97
  });
98
+ if (this.delaytimer) {
99
+ clearTimeout(this.delaytimer);
100
+ this.delaytimer = undefined;
101
+ }
102
+ this.deepDrawLabel(sameFixWidthLabel, sameNormalLabel, 1);
103
+ regionLabelList.forEach((item) => {
104
+ this.combination.setContent(this.canvas, item);
105
+ this.combination.draw({
106
+ points: this.imageToViewerElementPoints(item.points),
107
+ tool: item.tool,
108
+ }, item.child.map(({points, tool}) => ({
109
+ points: this.imageToViewerElementPoints(points),
110
+ tool,
111
+ })), this.viewport.getRotation());
112
+ });
113
+ }
114
+
115
+ deepDrawLabel(sameFixWidthLabel, sameNormalLabel, count) {
116
+ let currentDrawCount = 0; // 当前已绘制数量
109
117
  const ctx = this.canvas.getContext('2d');
110
- Object.values(sameFixWidthLabel).forEach((labels) => {
118
+ const remainFixLabel = {};
119
+ Object.keys(sameFixWidthLabel).forEach((key) => {
120
+ const labels = sameFixWidthLabel[key];
111
121
  ctx.beginPath();
112
122
  labels.forEach((item) => {
113
- this.drawLabel(item);
123
+ if (currentDrawCount >= 5000) { // 一次最多绘制5000个标注,多余标注延迟绘制
124
+ if (remainFixLabel[key]) {
125
+ remainFixLabel[key].push(item);
126
+ } else {
127
+ remainFixLabel[key] = [item];
128
+ }
129
+ } else {
130
+ this.drawLabel(item);
131
+ }
132
+ currentDrawCount++;
114
133
  });
115
134
  const firstLabel = labels?.[0];
116
135
  if (firstLabel?.fillStyle) {
@@ -120,35 +139,36 @@ export class Shape extends ViewerCommon {
120
139
  ctx.strokeStyle = firstLabel.strokeStyle;
121
140
  ctx.stroke();
122
141
  });
123
- Object.values(sameNormalLabel).forEach((labels) => {
142
+ const remainNormalLabel = {};
143
+ Object.keys(sameNormalLabel).forEach((key) => {
144
+ const labels = sameNormalLabel[key];
124
145
  ctx.beginPath();
125
146
  labels.forEach((item) => {
126
- this.drawLabel(item);
147
+ if (currentDrawCount >= 5000) { // 一次最多绘制5000个标注,多余标注延迟绘制
148
+ if (remainNormalLabel[key]) {
149
+ remainNormalLabel[key].push(item);
150
+ } else {
151
+ remainNormalLabel[key] = [item];
152
+ }
153
+ } else {
154
+ this.drawLabel(item);
155
+ }
156
+ currentDrawCount++;
127
157
  });
128
158
  const firstLabel = labels?.[0];
129
159
  ctx.lineWidth = firstLabel.lineWidth;
130
160
  ctx.strokeStyle = firstLabel.strokeStyle;
131
161
  ctx.stroke();
132
162
  });
133
-
134
- regionLabelList.forEach((item) => {
135
- if (item.show === false) return;
136
- if (!this[item.tool]) return;
137
- if (!this.isInCanvas(item.region)) return;
138
- /* const point = this.imageToViewerElementCoordinates(item.points[0].x,
139
- item.points[0].y);
140
- if ((point.x > this.canvas.width ||
141
- point.y > this.canvas.height ||
142
- point.x < 0 || point.y < 0)) return;*/
143
- this.combination.setContent(this.canvas, item);
144
- this.combination.draw({
145
- points: this.imageToViewerElementPoints(item.points),
146
- tool: item.tool,
147
- }, item.child.map(({points, tool}) => ({
148
- points: this.imageToViewerElementPoints(points),
149
- tool,
150
- })), this.viewport.getRotation());
151
- });
163
+ if (Object.keys(remainFixLabel).length === 0 &&
164
+ Object.keys(remainNormalLabel).length === 0) {
165
+ console.log(`end deep draw label, draw count: ${count}`);
166
+ this.delaytimer = undefined;
167
+ } else {
168
+ this.delaytimer = setTimeout(() => {
169
+ this.deepDrawLabel(remainFixLabel, remainNormalLabel, count + 1);
170
+ }, 100);
171
+ }
152
172
  }
153
173
 
154
174
  drawLabel(item) {
@@ -220,8 +220,7 @@ export class Tailoring extends ViewerCommon {
220
220
  */
221
221
  onCanvasKey(e) {
222
222
  const {originalEvent} = e;
223
- e.preventDefaultAction = true;
224
- if (originalEvent.code === 'Escape') {
223
+ if (originalEvent.key === 'Escape') {
225
224
  this.stopTailoring();
226
225
  }
227
226
  }