@inweb/markup 25.8.2 → 25.8.4
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/dist/markup.js +183 -248
- package/dist/markup.js.map +1 -1
- package/dist/markup.min.js +1 -1
- package/dist/markup.module.js +182 -240
- package/dist/markup.module.js.map +1 -1
- package/lib/markup/Konva/KonvaMarkup.d.ts +0 -4
- package/package.json +3 -3
- package/src/markup/Konva/KonvaMarkup.ts +218 -281
|
@@ -23,12 +23,22 @@
|
|
|
23
23
|
|
|
24
24
|
import Konva from "konva";
|
|
25
25
|
import { IEventEmitter } from "@inweb/eventemitter2";
|
|
26
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
ChangeActiveDraggerEvent,
|
|
28
|
+
IArrow,
|
|
29
|
+
ICloud,
|
|
30
|
+
IEllipse,
|
|
31
|
+
IImage,
|
|
32
|
+
ILine,
|
|
33
|
+
IRectangle,
|
|
34
|
+
IText,
|
|
35
|
+
IViewpoint,
|
|
36
|
+
PanEvent,
|
|
37
|
+
} from "@inweb/viewer-core";
|
|
27
38
|
|
|
28
39
|
import { IMarkup, MarkupMode } from "../IMarkup";
|
|
29
40
|
import { IWorldTransform } from "../IWorldTransform";
|
|
30
41
|
import { IMarkupObject } from "../IMarkupObject";
|
|
31
|
-
import { IMarkupColorable } from "../IMarkupColorable";
|
|
32
42
|
import { MarkupLineType } from "../IMarkupLine";
|
|
33
43
|
import { MarkupColor } from "./MarkupColor";
|
|
34
44
|
import { WorldTransform } from "../WorldTransform";
|
|
@@ -85,11 +95,10 @@ const MarkupMode2Konva = {
|
|
|
85
95
|
* 2D markup core.
|
|
86
96
|
*/
|
|
87
97
|
export class KonvaMarkup implements IMarkup {
|
|
88
|
-
private _isInitialized = false;
|
|
89
98
|
private _viewer: IEventEmitter;
|
|
90
99
|
private _worldTransformer: IWorldTransform;
|
|
91
100
|
private _container: HTMLElement;
|
|
92
|
-
private _pointerEvents: string[];
|
|
101
|
+
private _pointerEvents: string[] = [];
|
|
93
102
|
private _markupIsActive = false;
|
|
94
103
|
private _markupMode: MarkupMode;
|
|
95
104
|
private _markupColor = new MarkupColor(255, 0, 0);
|
|
@@ -106,8 +115,6 @@ export class KonvaMarkup implements IMarkup {
|
|
|
106
115
|
private _resizeObserver: ResizeObserver;
|
|
107
116
|
private _zIndex = 1;
|
|
108
117
|
|
|
109
|
-
private readonly _markupContainerName = "markupContainer";
|
|
110
|
-
|
|
111
118
|
public lineWidth = 4;
|
|
112
119
|
public lineType: MarkupLineType = "solid";
|
|
113
120
|
public fontSize = 34;
|
|
@@ -118,10 +125,12 @@ export class KonvaMarkup implements IMarkup {
|
|
|
118
125
|
viewer?: IEventEmitter,
|
|
119
126
|
worldTransformer?: IWorldTransform
|
|
120
127
|
): void {
|
|
121
|
-
if (!Konva)
|
|
122
|
-
|
|
123
|
-
'Markup:
|
|
128
|
+
if (!Konva) {
|
|
129
|
+
console.error(
|
|
130
|
+
'Markup error: Konva is not initialized. Update node_modules or add to your page <script src="https://unpkg.com/konva@9/konva.min.js"></script>'
|
|
124
131
|
);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
125
134
|
|
|
126
135
|
this._viewer = viewer;
|
|
127
136
|
this._worldTransformer = worldTransformer ?? new WorldTransform();
|
|
@@ -129,7 +138,7 @@ export class KonvaMarkup implements IMarkup {
|
|
|
129
138
|
this._pointerEvents = pointerEvents ?? [];
|
|
130
139
|
|
|
131
140
|
this._markupContainer = document.createElement("div");
|
|
132
|
-
this._markupContainer.id =
|
|
141
|
+
this._markupContainer.id = "markup-container";
|
|
133
142
|
this._markupContainer.style.position = "absolute";
|
|
134
143
|
this._markupContainer.style.top = "0px";
|
|
135
144
|
this._markupContainer.style.left = "0px";
|
|
@@ -151,26 +160,21 @@ export class KonvaMarkup implements IMarkup {
|
|
|
151
160
|
this._viewer.addEventListener("changeactivedragger", this.changeActiveDragger);
|
|
152
161
|
this._viewer.addEventListener("pan", this.pan);
|
|
153
162
|
}
|
|
154
|
-
|
|
155
|
-
this._isInitialized = true;
|
|
156
163
|
}
|
|
157
164
|
|
|
158
165
|
dispose(): void {
|
|
159
|
-
if (!this._isInitialized) return;
|
|
160
|
-
|
|
161
166
|
if (this._viewer) {
|
|
162
167
|
this._viewer.removeEventListener("pan", this.pan);
|
|
163
168
|
this._viewer.removeEventListener("changeactivedragger", this.changeActiveDragger);
|
|
169
|
+
this._pointerEvents.forEach((x) => this._markupContainer.removeEventListener(x, this.redirectToViewer));
|
|
164
170
|
}
|
|
165
171
|
|
|
166
|
-
this._pointerEvents.forEach((x) => this._markupContainer.removeEventListener(x, this.redirectToViewer));
|
|
167
|
-
|
|
168
172
|
this.destroyKonva();
|
|
169
173
|
|
|
170
|
-
this._resizeObserver
|
|
174
|
+
this._resizeObserver?.disconnect();
|
|
171
175
|
this._resizeObserver = undefined;
|
|
172
176
|
|
|
173
|
-
this._markupContainer
|
|
177
|
+
this._markupContainer?.remove();
|
|
174
178
|
this._markupContainer = undefined;
|
|
175
179
|
|
|
176
180
|
this._container = undefined;
|
|
@@ -178,7 +182,6 @@ export class KonvaMarkup implements IMarkup {
|
|
|
178
182
|
this._worldTransformer = undefined;
|
|
179
183
|
|
|
180
184
|
this._markupIsActive = false;
|
|
181
|
-
this._isInitialized = false;
|
|
182
185
|
}
|
|
183
186
|
|
|
184
187
|
changeActiveDragger = (event: ChangeActiveDraggerEvent) => {
|
|
@@ -201,9 +204,10 @@ export class KonvaMarkup implements IMarkup {
|
|
|
201
204
|
const { width, height } = entries[0].contentRect;
|
|
202
205
|
|
|
203
206
|
if (!width || !height) return; // <- invisible container, or container with parent removed
|
|
207
|
+
if (!this._konvaStage) return;
|
|
204
208
|
|
|
205
|
-
this._konvaStage
|
|
206
|
-
this._konvaStage
|
|
209
|
+
this._konvaStage.width(width);
|
|
210
|
+
this._konvaStage.height(height);
|
|
207
211
|
};
|
|
208
212
|
|
|
209
213
|
pan = (event: PanEvent) => {
|
|
@@ -222,7 +226,7 @@ export class KonvaMarkup implements IMarkup {
|
|
|
222
226
|
this.removeTextInput();
|
|
223
227
|
this.removeImageInput();
|
|
224
228
|
this.clearSelected();
|
|
225
|
-
this.getObjects().forEach((obj) => obj.
|
|
229
|
+
this.getObjects().forEach((obj) => obj.delete());
|
|
226
230
|
}
|
|
227
231
|
|
|
228
232
|
getMarkupColor(): { r: number; g: number; b: number } {
|
|
@@ -235,49 +239,73 @@ export class KonvaMarkup implements IMarkup {
|
|
|
235
239
|
|
|
236
240
|
colorizeAllMarkup(r: number, g: number, b: number): void {
|
|
237
241
|
const hexColor = new MarkupColor(r, g, b).HexColor;
|
|
238
|
-
this.getObjects().
|
|
239
|
-
const colorable = obj as unknown as IMarkupColorable;
|
|
240
|
-
if (colorable && colorable.setColor) colorable.setColor(hexColor);
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
this._konvaLayer.draw();
|
|
242
|
+
this.getObjects().filter((obj: any) => obj.setColor?.(hexColor));
|
|
244
243
|
}
|
|
245
244
|
|
|
246
245
|
colorizeSelectedMarkups(r: number, g: number, b: number): void {
|
|
247
246
|
const hexColor = new MarkupColor(r, g, b).HexColor;
|
|
248
|
-
this.getSelectedObjects().
|
|
249
|
-
const colorable = obj as unknown as IMarkupColorable;
|
|
250
|
-
if (colorable && colorable.setColor) colorable.setColor(hexColor);
|
|
251
|
-
});
|
|
247
|
+
this.getSelectedObjects().filter((obj: any) => obj.setColor?.(hexColor));
|
|
252
248
|
}
|
|
253
249
|
|
|
254
250
|
setViewpoint(viewpoint: IViewpoint): void {
|
|
255
|
-
const markupColor = viewpoint.custom_fields
|
|
251
|
+
const markupColor = viewpoint.custom_fields?.markup_color || { r: 255, g: 0, b: 0 };
|
|
256
252
|
this.setMarkupColor(markupColor.r, markupColor.g, markupColor.b);
|
|
257
253
|
|
|
258
|
-
|
|
254
|
+
viewpoint.lines?.forEach((line: ILine) => {
|
|
255
|
+
const linePoints = [];
|
|
256
|
+
line.points.forEach((point) => {
|
|
257
|
+
const screenPoint = this._worldTransformer.worldToScreen(point);
|
|
258
|
+
linePoints.push(screenPoint.x);
|
|
259
|
+
linePoints.push(screenPoint.y);
|
|
260
|
+
});
|
|
261
|
+
this.addLine(linePoints, line.color, line.type as MarkupLineType, line.width, line.id);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
viewpoint.texts?.forEach((text: IText) => {
|
|
265
|
+
const screenPoint = this._worldTransformer.worldToScreen(text.position);
|
|
266
|
+
this.addText(text.text, screenPoint, text.angle, text.color, text.text_size, text.font_size, text.id);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
viewpoint.rectangles?.forEach((rect: IRectangle) => {
|
|
270
|
+
const screenPoint = this._worldTransformer.worldToScreen(rect.position);
|
|
271
|
+
this.addRectangle(screenPoint, rect.width, rect.height, rect.line_width, rect.color, rect.id);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
viewpoint.ellipses?.forEach((ellipse: IEllipse) => {
|
|
275
|
+
const screenPoint = this._worldTransformer.worldToScreen(ellipse.position);
|
|
276
|
+
this.addEllipse(screenPoint, ellipse.radius, ellipse.line_width, ellipse.color, ellipse.id);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
viewpoint.arrows?.forEach((arrow: IArrow) => {
|
|
280
|
+
const startPoint = this._worldTransformer.worldToScreen(arrow.start);
|
|
281
|
+
const endPoint = this._worldTransformer.worldToScreen(arrow.end);
|
|
282
|
+
this.addArrow(startPoint, endPoint, arrow.color, arrow.id);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
viewpoint.clouds?.forEach((cloud: ICloud) => {
|
|
286
|
+
const screenPoint = this._worldTransformer.worldToScreen(cloud.position);
|
|
287
|
+
this.addCloud(screenPoint, cloud.width, cloud.height, cloud.line_width, cloud.color, cloud.id);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
viewpoint.images?.forEach((image: IImage) => {
|
|
291
|
+
const screenPoint = this._worldTransformer.worldToScreen(image.position);
|
|
292
|
+
this.addImage(screenPoint, image.src, image.width, image.height, image.id);
|
|
293
|
+
});
|
|
259
294
|
}
|
|
260
295
|
|
|
261
296
|
getViewpoint(): IViewpoint {
|
|
262
|
-
const viewpoint: IViewpoint = {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
viewpoint.
|
|
273
|
-
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
viewpoint.custom_fields = {
|
|
277
|
-
markup_color: this.getMarkupColor(),
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
this.fillViewpointShapes(viewpoint);
|
|
297
|
+
const viewpoint: IViewpoint = {};
|
|
298
|
+
|
|
299
|
+
viewpoint.lines = this.getMarkupLines();
|
|
300
|
+
viewpoint.texts = this.getMarkupTexts();
|
|
301
|
+
viewpoint.arrows = this.getMarkupArrows();
|
|
302
|
+
viewpoint.clouds = this.getMarkupClouds();
|
|
303
|
+
viewpoint.ellipses = this.getMarkupEllipses();
|
|
304
|
+
viewpoint.images = this.getMarkupImages();
|
|
305
|
+
viewpoint.rectangles = this.getMarkupRectangles();
|
|
306
|
+
|
|
307
|
+
viewpoint.custom_fields = { markup_color: this.getMarkupColor() };
|
|
308
|
+
viewpoint.snapshot = { data: this.combineMarkupWithDrawing() };
|
|
281
309
|
|
|
282
310
|
viewpoint.description = new Date().toDateString();
|
|
283
311
|
return viewpoint;
|
|
@@ -320,6 +348,8 @@ export class KonvaMarkup implements IMarkup {
|
|
|
320
348
|
}
|
|
321
349
|
|
|
322
350
|
getSelectedObjects(): IMarkupObject[] {
|
|
351
|
+
if (!this._konvaTransformer) return [];
|
|
352
|
+
|
|
323
353
|
return this._konvaTransformer
|
|
324
354
|
.nodes()
|
|
325
355
|
.map((ref) => {
|
|
@@ -331,86 +361,39 @@ export class KonvaMarkup implements IMarkup {
|
|
|
331
361
|
}
|
|
332
362
|
|
|
333
363
|
selectObjects(objects: IMarkupObject[]) {
|
|
364
|
+
if (!this._konvaTransformer) return;
|
|
365
|
+
|
|
334
366
|
const selectedObjs = this._konvaTransformer.nodes().concat(objects.map((x) => x.ref()));
|
|
335
367
|
this._konvaTransformer.nodes(selectedObjs);
|
|
336
368
|
}
|
|
337
369
|
|
|
338
370
|
clearSelected(): void {
|
|
339
|
-
this._konvaTransformer.nodes([]);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
private fillViewpointShapes(viewpoint) {
|
|
343
|
-
const markupLines = this.getMarkupLines();
|
|
344
|
-
if (markupLines && markupLines.length > 0) {
|
|
345
|
-
markupLines?.forEach((line) => {
|
|
346
|
-
viewpoint.lines.push(line);
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
const markupTexts = this.getMarkupTexts();
|
|
351
|
-
if (markupTexts && markupTexts.length > 0) {
|
|
352
|
-
markupTexts?.forEach((text) => {
|
|
353
|
-
viewpoint.texts.push(text);
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
const markupRectangles = this.getMarkupRectangles();
|
|
358
|
-
if (markupRectangles && markupRectangles.length > 0) {
|
|
359
|
-
markupRectangles?.forEach((rectangle) => {
|
|
360
|
-
viewpoint.rectangles.push(rectangle);
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const markupEllipses = this.getMarkupEllipses();
|
|
365
|
-
if (markupEllipses && markupEllipses.length > 0) {
|
|
366
|
-
markupEllipses?.forEach((ellipse) => {
|
|
367
|
-
viewpoint.ellipses.push(ellipse);
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const markupArrows = this.getMarkupArrows();
|
|
372
|
-
if (markupArrows && markupArrows.length > 0) {
|
|
373
|
-
markupArrows?.forEach((arrow) => {
|
|
374
|
-
viewpoint.arrows.push(arrow);
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
const markupImages = this.getMarkupImages();
|
|
379
|
-
if (markupImages && markupImages.length > 0) {
|
|
380
|
-
markupImages?.forEach((image) => {
|
|
381
|
-
viewpoint.images.push(image);
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
const markupClouds = this.getMarkupClouds();
|
|
386
|
-
if (markupClouds && markupClouds.length > 0) {
|
|
387
|
-
markupClouds?.forEach((cloud) => {
|
|
388
|
-
viewpoint.clouds.push(cloud);
|
|
389
|
-
});
|
|
390
|
-
}
|
|
371
|
+
if (this._konvaTransformer) this._konvaTransformer.nodes([]);
|
|
391
372
|
}
|
|
392
373
|
|
|
393
374
|
private addObject(object: IMarkupObject): void {
|
|
394
|
-
this._konvaLayer.add(object.ref());
|
|
375
|
+
if (this._konvaLayer) this._konvaLayer.add(object.ref());
|
|
395
376
|
}
|
|
396
377
|
|
|
397
378
|
private konvaLayerFind(type: string): any {
|
|
379
|
+
if (!this._konvaLayer) return [];
|
|
380
|
+
|
|
398
381
|
const konvaShape = MarkupMode2Konva[type];
|
|
399
|
-
if (konvaShape
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
return [];
|
|
382
|
+
if (!konvaShape || !konvaShape.initializer) return [];
|
|
383
|
+
|
|
384
|
+
// for "draggable" Konva uses Rectangles in Transformer. We need only Shapes from layer.
|
|
385
|
+
return this._konvaLayer.find(konvaShape.name).filter((ref) => ref.parent === this._konvaLayer);
|
|
404
386
|
}
|
|
405
387
|
|
|
406
388
|
private initializeKonva(): any {
|
|
407
389
|
// first we need Konva core things: stage and layer
|
|
408
|
-
|
|
409
|
-
container: this.
|
|
390
|
+
const stage = new Konva.Stage({
|
|
391
|
+
container: this._markupContainer,
|
|
410
392
|
width: this._container.clientWidth,
|
|
411
393
|
height: this._container.clientHeight,
|
|
412
394
|
});
|
|
413
|
-
|
|
395
|
+
this._konvaStage = stage;
|
|
396
|
+
|
|
414
397
|
const layer = new Konva.Layer({ pixelRation: window.devicePixelRatio });
|
|
415
398
|
stage.add(layer);
|
|
416
399
|
this._konvaLayer = layer;
|
|
@@ -420,9 +403,8 @@ export class KonvaMarkup implements IMarkup {
|
|
|
420
403
|
keepRatio: false,
|
|
421
404
|
flipEnabled: false,
|
|
422
405
|
});
|
|
423
|
-
|
|
424
|
-
this._konvaTransformer = transformer;
|
|
425
406
|
layer.add(transformer);
|
|
407
|
+
this._konvaTransformer = transformer;
|
|
426
408
|
|
|
427
409
|
let isPaint = false;
|
|
428
410
|
let lastLine;
|
|
@@ -618,12 +600,8 @@ export class KonvaMarkup implements IMarkup {
|
|
|
618
600
|
container.addEventListener("keydown", (e) => {
|
|
619
601
|
if (!this._markupIsActive) return;
|
|
620
602
|
if (e.code === "Delete") {
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
this._konvaTransformer.nodes().forEach((x) => x.destroy());
|
|
624
|
-
this._konvaTransformer.nodes([]);
|
|
625
|
-
}
|
|
626
|
-
layer.draw();
|
|
603
|
+
this.getSelectedObjects().forEach((obj: IMarkupObject) => obj.delete());
|
|
604
|
+
this.clearSelected();
|
|
627
605
|
return;
|
|
628
606
|
}
|
|
629
607
|
e.preventDefault();
|
|
@@ -633,20 +611,22 @@ export class KonvaMarkup implements IMarkup {
|
|
|
633
611
|
private destroyKonva() {
|
|
634
612
|
this.clearOverlay();
|
|
635
613
|
|
|
636
|
-
this._konvaStage
|
|
614
|
+
this._konvaStage?.destroy();
|
|
637
615
|
|
|
638
616
|
this._konvaLayer = undefined;
|
|
639
617
|
this._konvaTransformer = undefined;
|
|
640
618
|
this._konvaStage = undefined;
|
|
641
619
|
}
|
|
642
620
|
|
|
643
|
-
private getMarkupLines() {
|
|
621
|
+
private getMarkupLines(): Array<ILine> {
|
|
644
622
|
const lines = [];
|
|
645
|
-
|
|
646
|
-
|
|
623
|
+
|
|
624
|
+
this.konvaLayerFind("Line").forEach((ref) => {
|
|
625
|
+
const linePoints = ref.points();
|
|
647
626
|
if (!linePoints) return;
|
|
627
|
+
|
|
648
628
|
const worldPoints = [];
|
|
649
|
-
const absoluteTransform =
|
|
629
|
+
const absoluteTransform = ref.getAbsoluteTransform();
|
|
650
630
|
for (let i = 0; i < linePoints.length; i += 2) {
|
|
651
631
|
// we need getAbsoluteTransform because inside Konva position starts from {0, 0}
|
|
652
632
|
// https://stackoverflow.com/a/57641487 - check answer's comments
|
|
@@ -656,33 +636,33 @@ export class KonvaMarkup implements IMarkup {
|
|
|
656
636
|
worldPoints.push(worldPoint);
|
|
657
637
|
}
|
|
658
638
|
|
|
659
|
-
const konvaLine = new KonvaLine(null,
|
|
660
|
-
|
|
639
|
+
const konvaLine = new KonvaLine(null, ref);
|
|
640
|
+
const line: ILine = {
|
|
661
641
|
id: konvaLine.id(),
|
|
662
642
|
points: worldPoints,
|
|
663
643
|
color: konvaLine.getColor() || "#ff0000",
|
|
664
644
|
type: konvaLine.getLineType() || this.lineType,
|
|
665
645
|
width: konvaLine.getLineWidth() || this.lineWidth,
|
|
666
|
-
}
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
lines.push(line);
|
|
667
649
|
});
|
|
668
650
|
|
|
669
651
|
return lines;
|
|
670
652
|
}
|
|
671
653
|
|
|
672
|
-
private getMarkupTexts() {
|
|
654
|
+
private getMarkupTexts(): Array<IText> {
|
|
673
655
|
const texts = [];
|
|
674
656
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
this.konvaLayerFind("Text").forEach((text) => {
|
|
679
|
-
if (!text) return;
|
|
657
|
+
this.konvaLayerFind("Text").forEach((ref) => {
|
|
658
|
+
const textSize = 0.02;
|
|
659
|
+
const textScale = this._worldTransformer.getScale();
|
|
680
660
|
|
|
681
|
-
const position = { x:
|
|
661
|
+
const position = { x: ref.x(), y: ref.y() };
|
|
682
662
|
const worldPoint = this._worldTransformer.screenToWorld(position);
|
|
683
663
|
|
|
684
|
-
const shape = new KonvaText(null,
|
|
685
|
-
|
|
664
|
+
const shape = new KonvaText(null, ref);
|
|
665
|
+
const text: IText = {
|
|
686
666
|
id: shape.id(),
|
|
687
667
|
position: worldPoint,
|
|
688
668
|
text: shape.getText(),
|
|
@@ -690,168 +670,143 @@ export class KonvaMarkup implements IMarkup {
|
|
|
690
670
|
angle: shape.getRotation(),
|
|
691
671
|
color: shape.getColor(),
|
|
692
672
|
font_size: shape.getFontSize(),
|
|
693
|
-
}
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
texts.push(text);
|
|
694
676
|
});
|
|
695
677
|
|
|
696
678
|
return texts;
|
|
697
679
|
}
|
|
698
680
|
|
|
699
|
-
private getMarkupRectangles() {
|
|
681
|
+
private getMarkupRectangles(): Array<IRectangle> {
|
|
700
682
|
const rectangles = [];
|
|
701
|
-
|
|
702
|
-
|
|
683
|
+
|
|
684
|
+
this.konvaLayerFind("Rectangle").forEach((ref) => {
|
|
685
|
+
const position = ref.position();
|
|
703
686
|
const worldPoint = this._worldTransformer.screenToWorld(position);
|
|
704
687
|
|
|
705
|
-
const shape = new KonvaRectangle(null,
|
|
706
|
-
|
|
688
|
+
const shape = new KonvaRectangle(null, ref);
|
|
689
|
+
const rectangle: IRectangle = {
|
|
707
690
|
id: shape.id(),
|
|
708
691
|
position: worldPoint,
|
|
709
692
|
width: shape.getWidth(),
|
|
710
693
|
height: shape.getHeigth(),
|
|
711
694
|
line_width: shape.getLineWidth(),
|
|
712
695
|
color: shape.getColor(),
|
|
713
|
-
}
|
|
696
|
+
};
|
|
697
|
+
|
|
698
|
+
rectangles.push(rectangle);
|
|
714
699
|
});
|
|
715
700
|
|
|
716
701
|
return rectangles;
|
|
717
702
|
}
|
|
718
703
|
|
|
719
|
-
private getMarkupEllipses() {
|
|
704
|
+
private getMarkupEllipses(): Array<IEllipse> {
|
|
720
705
|
const ellipses = [];
|
|
721
|
-
|
|
722
|
-
|
|
706
|
+
|
|
707
|
+
this.konvaLayerFind("Ellipse").forEach((ref) => {
|
|
708
|
+
const position = ref.position();
|
|
723
709
|
const worldPoint = this._worldTransformer.screenToWorld(position);
|
|
724
710
|
|
|
725
|
-
const shape = new KonvaEllipse(null,
|
|
726
|
-
|
|
711
|
+
const shape = new KonvaEllipse(null, ref);
|
|
712
|
+
const ellipse: IEllipse = {
|
|
727
713
|
id: shape.id(),
|
|
728
714
|
position: worldPoint,
|
|
729
|
-
radius: { x:
|
|
715
|
+
radius: { x: ref.getRadiusX(), y: ref.getRadiusY() },
|
|
730
716
|
line_width: shape.getLineWidth(),
|
|
731
717
|
color: shape.getColor(),
|
|
732
|
-
}
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
ellipses.push(ellipse);
|
|
733
721
|
});
|
|
734
722
|
|
|
735
723
|
return ellipses;
|
|
736
724
|
}
|
|
737
725
|
|
|
738
|
-
private getMarkupArrows() {
|
|
726
|
+
private getMarkupArrows(): Array<IArrow> {
|
|
739
727
|
const arrows = [];
|
|
740
|
-
|
|
728
|
+
|
|
729
|
+
this.konvaLayerFind("Arrow").forEach((ref) => {
|
|
741
730
|
// we need getAbsoluteTransform because inside Konva position starts from {0, 0}
|
|
742
|
-
const absoluteTransform =
|
|
731
|
+
const absoluteTransform = ref.getAbsoluteTransform();
|
|
743
732
|
|
|
744
|
-
const atStartPoint = absoluteTransform.point({ x:
|
|
733
|
+
const atStartPoint = absoluteTransform.point({ x: ref.points()[0], y: ref.points()[1] });
|
|
745
734
|
const worldStartPoint = this._worldTransformer.screenToWorld(atStartPoint);
|
|
746
735
|
|
|
747
|
-
const atEndPoint = absoluteTransform.point({ x:
|
|
736
|
+
const atEndPoint = absoluteTransform.point({ x: ref.points()[2], y: ref.points()[3] });
|
|
748
737
|
const worldEndPoint = this._worldTransformer.screenToWorld(atEndPoint);
|
|
749
738
|
|
|
750
|
-
const shape = new KonvaArrow(null,
|
|
751
|
-
|
|
739
|
+
const shape = new KonvaArrow(null, ref);
|
|
740
|
+
const arrow: IArrow = {
|
|
752
741
|
id: shape.id(),
|
|
753
742
|
start: worldStartPoint,
|
|
754
743
|
end: worldEndPoint,
|
|
755
744
|
color: shape.getColor(),
|
|
756
|
-
}
|
|
745
|
+
};
|
|
746
|
+
|
|
747
|
+
arrows.push(arrow);
|
|
757
748
|
});
|
|
758
749
|
|
|
759
750
|
return arrows;
|
|
760
751
|
}
|
|
761
752
|
|
|
762
|
-
private getMarkupImages() {
|
|
753
|
+
private getMarkupImages(): Array<IImage> {
|
|
763
754
|
const images = [];
|
|
764
|
-
|
|
765
|
-
|
|
755
|
+
|
|
756
|
+
this.konvaLayerFind("Image").forEach((ref) => {
|
|
757
|
+
const position = ref.position();
|
|
766
758
|
const worldPoint = this._worldTransformer.screenToWorld(position);
|
|
767
759
|
|
|
768
|
-
const shape = new KonvaImage(null,
|
|
769
|
-
|
|
760
|
+
const shape = new KonvaImage(null, ref);
|
|
761
|
+
const image: IImage = {
|
|
770
762
|
id: shape.id(),
|
|
771
763
|
position: worldPoint,
|
|
772
764
|
src: shape.getSrc(),
|
|
773
765
|
width: shape.getWidth(),
|
|
774
766
|
height: shape.getHeight(),
|
|
775
|
-
}
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
images.push(image);
|
|
776
770
|
});
|
|
777
771
|
|
|
778
772
|
return images;
|
|
779
773
|
}
|
|
780
774
|
|
|
781
|
-
private getMarkupClouds() {
|
|
775
|
+
private getMarkupClouds(): Array<ICloud> {
|
|
782
776
|
const clouds = [];
|
|
783
|
-
|
|
784
|
-
|
|
777
|
+
|
|
778
|
+
this.konvaLayerFind("Cloud").forEach((ref) => {
|
|
779
|
+
const position = ref.position();
|
|
785
780
|
const worldPoint = this._worldTransformer.screenToWorld(position);
|
|
786
781
|
|
|
787
|
-
const shape = new KonvaCloud(null,
|
|
788
|
-
|
|
782
|
+
const shape = new KonvaCloud(null, ref);
|
|
783
|
+
const cloud: ICloud = {
|
|
789
784
|
id: shape.id(),
|
|
790
785
|
position: worldPoint,
|
|
791
786
|
width: shape.getWidth(),
|
|
792
787
|
height: shape.getHeigth(),
|
|
793
788
|
line_width: shape.getLineWidth(),
|
|
794
789
|
color: shape.getColor(),
|
|
795
|
-
}
|
|
796
|
-
});
|
|
797
|
-
|
|
798
|
-
return clouds;
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
private loadMarkup(viewpoint: IViewpoint) {
|
|
802
|
-
viewpoint.lines?.forEach((vpLine) => {
|
|
803
|
-
const linePoints = [];
|
|
804
|
-
vpLine.points.forEach((point) => {
|
|
805
|
-
const screenPoint = this._worldTransformer.worldToScreen(point);
|
|
806
|
-
linePoints.push(screenPoint.x);
|
|
807
|
-
linePoints.push(screenPoint.y);
|
|
808
|
-
});
|
|
809
|
-
|
|
810
|
-
this.addLine(linePoints, vpLine.color, vpLine.type as MarkupLineType, vpLine.width, vpLine.id);
|
|
811
|
-
});
|
|
812
|
-
|
|
813
|
-
viewpoint.texts?.forEach((vpText) => {
|
|
814
|
-
const screenPoint = this._worldTransformer.worldToScreen(vpText.position);
|
|
815
|
-
this.addText(vpText.text, screenPoint, vpText.angle, vpText.color, vpText.text_size, vpText.font_size, vpText.id);
|
|
816
|
-
});
|
|
817
|
-
|
|
818
|
-
viewpoint.rectangles?.forEach((vpRect) => {
|
|
819
|
-
const screenPoint = this._worldTransformer.worldToScreen(vpRect.position);
|
|
820
|
-
this.addRectangle(screenPoint, vpRect.width, vpRect.height, vpRect.line_width, vpRect.color, vpRect.id);
|
|
821
|
-
});
|
|
822
|
-
|
|
823
|
-
viewpoint.ellipses?.forEach((vpEllipse) => {
|
|
824
|
-
const screenPoint = this._worldTransformer.worldToScreen(vpEllipse.position);
|
|
825
|
-
this.addEllipse(screenPoint, vpEllipse.radius, vpEllipse.line_width, vpEllipse.color, vpEllipse.id);
|
|
826
|
-
});
|
|
827
|
-
|
|
828
|
-
viewpoint.arrows?.forEach((vpArrow) => {
|
|
829
|
-
const startPoint = this._worldTransformer.worldToScreen(vpArrow.start);
|
|
830
|
-
const endPoint = this._worldTransformer.worldToScreen(vpArrow.end);
|
|
831
|
-
this.addArrow(startPoint, endPoint, vpArrow.color, vpArrow.id);
|
|
832
|
-
});
|
|
790
|
+
};
|
|
833
791
|
|
|
834
|
-
|
|
835
|
-
const screenPoint = this._worldTransformer.worldToScreen(vpCloud.position);
|
|
836
|
-
this.addCloud(screenPoint, vpCloud.width, vpCloud.height, vpCloud.line_width, vpCloud.color, vpCloud.id);
|
|
792
|
+
clouds.push(cloud);
|
|
837
793
|
});
|
|
838
794
|
|
|
839
|
-
|
|
840
|
-
const screenPoint = this._worldTransformer.worldToScreen(vpImage.position);
|
|
841
|
-
this.addImage(screenPoint, vpImage.src, vpImage.width, vpImage.height, vpImage.id);
|
|
842
|
-
});
|
|
795
|
+
return clouds;
|
|
843
796
|
}
|
|
844
797
|
|
|
845
798
|
private combineMarkupWithDrawing() {
|
|
846
799
|
this.clearSelected();
|
|
847
800
|
|
|
848
801
|
const tempCanvas = document.createElement("canvas");
|
|
849
|
-
|
|
850
|
-
|
|
802
|
+
if (this._konvaStage) {
|
|
803
|
+
tempCanvas.width = this._konvaStage.width();
|
|
804
|
+
tempCanvas.height = this._konvaStage.height();
|
|
851
805
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
806
|
+
const ctx = tempCanvas.getContext("2d");
|
|
807
|
+
if (this._container instanceof HTMLCanvasElement) ctx.drawImage(this._container, 0, 0);
|
|
808
|
+
ctx.drawImage(this._konvaStage.toCanvas({ pixelRatio: window.devicePixelRatio }), 0, 0);
|
|
809
|
+
}
|
|
855
810
|
|
|
856
811
|
return tempCanvas.toDataURL("image/jpeg", 0.25);
|
|
857
812
|
}
|
|
@@ -878,8 +833,7 @@ export class KonvaMarkup implements IMarkup {
|
|
|
878
833
|
id,
|
|
879
834
|
});
|
|
880
835
|
|
|
881
|
-
|
|
882
|
-
this._konvaLayer.add(obj);
|
|
836
|
+
this.addObject(konvaLine);
|
|
883
837
|
return konvaLine;
|
|
884
838
|
}
|
|
885
839
|
|
|
@@ -968,7 +922,7 @@ export class KonvaMarkup implements IMarkup {
|
|
|
968
922
|
}
|
|
969
923
|
|
|
970
924
|
private addText(
|
|
971
|
-
|
|
925
|
+
text: string,
|
|
972
926
|
position: Konva.Vector2d,
|
|
973
927
|
angle?: number,
|
|
974
928
|
color?: string,
|
|
@@ -976,37 +930,33 @@ export class KonvaMarkup implements IMarkup {
|
|
|
976
930
|
fontSize?: number,
|
|
977
931
|
id?: string
|
|
978
932
|
): KonvaText | void {
|
|
979
|
-
|
|
980
|
-
if (trNodes.length > 0) {
|
|
981
|
-
// in case of edit - remove old Konva.Text object
|
|
982
|
-
trNodes[0].destroy();
|
|
983
|
-
this._konvaTransformer.nodes([]);
|
|
984
|
-
}
|
|
933
|
+
if (!text) return;
|
|
985
934
|
|
|
986
|
-
|
|
935
|
+
// in case of edit - remove old Konva.Text object
|
|
936
|
+
this.getSelectedObjects().at(0)?.delete();
|
|
987
937
|
|
|
988
|
-
|
|
989
|
-
|
|
938
|
+
this.clearSelected();
|
|
939
|
+
this.removeTextInput();
|
|
990
940
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
941
|
+
// in case we have old viewpoint without font_size
|
|
942
|
+
const tolerance = 1.0e-6;
|
|
943
|
+
if (textSize && textSize > tolerance && (!fontSize || fontSize < tolerance)) {
|
|
944
|
+
const size = 0.02;
|
|
945
|
+
const scale = this._worldTransformer.getScale();
|
|
946
|
+
fontSize = textSize / (scale.y / size) / 34;
|
|
947
|
+
}
|
|
997
948
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
949
|
+
const konvaText = new KonvaText({
|
|
950
|
+
position: { x: position.x, y: position.y },
|
|
951
|
+
text,
|
|
952
|
+
rotation: angle,
|
|
953
|
+
fontSize: fontSize || this.fontSize,
|
|
954
|
+
color: color || this._markupColor.HexColor,
|
|
955
|
+
id,
|
|
956
|
+
});
|
|
1006
957
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
}
|
|
958
|
+
this.addObject(konvaText);
|
|
959
|
+
return konvaText;
|
|
1010
960
|
}
|
|
1011
961
|
|
|
1012
962
|
private addRectangle(
|
|
@@ -1028,8 +978,7 @@ export class KonvaMarkup implements IMarkup {
|
|
|
1028
978
|
id,
|
|
1029
979
|
});
|
|
1030
980
|
|
|
1031
|
-
|
|
1032
|
-
this._konvaLayer.add(obj);
|
|
981
|
+
this.addObject(konvaRectangle);
|
|
1033
982
|
return konvaRectangle;
|
|
1034
983
|
}
|
|
1035
984
|
|
|
@@ -1050,8 +999,7 @@ export class KonvaMarkup implements IMarkup {
|
|
|
1050
999
|
id,
|
|
1051
1000
|
});
|
|
1052
1001
|
|
|
1053
|
-
|
|
1054
|
-
this._konvaLayer.add(obj);
|
|
1002
|
+
this.addObject(konvaEllipse);
|
|
1055
1003
|
return konvaEllipse;
|
|
1056
1004
|
}
|
|
1057
1005
|
|
|
@@ -1070,8 +1018,7 @@ export class KonvaMarkup implements IMarkup {
|
|
|
1070
1018
|
id,
|
|
1071
1019
|
});
|
|
1072
1020
|
|
|
1073
|
-
|
|
1074
|
-
this._konvaLayer.add(obj);
|
|
1021
|
+
this.addObject(konvaArrow);
|
|
1075
1022
|
return konvaArrow;
|
|
1076
1023
|
}
|
|
1077
1024
|
|
|
@@ -1094,8 +1041,7 @@ export class KonvaMarkup implements IMarkup {
|
|
|
1094
1041
|
id,
|
|
1095
1042
|
});
|
|
1096
1043
|
|
|
1097
|
-
|
|
1098
|
-
this._konvaLayer.add(obj);
|
|
1044
|
+
this.addObject(konvaCloud);
|
|
1099
1045
|
return konvaCloud;
|
|
1100
1046
|
}
|
|
1101
1047
|
|
|
@@ -1106,32 +1052,23 @@ export class KonvaMarkup implements IMarkup {
|
|
|
1106
1052
|
height?: number,
|
|
1107
1053
|
id?: string
|
|
1108
1054
|
): KonvaImage | void {
|
|
1109
|
-
if (!position) return;
|
|
1055
|
+
if (!position || !src) return;
|
|
1110
1056
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
if (src) {
|
|
1114
|
-
konvaImage = new KonvaImage({
|
|
1115
|
-
position,
|
|
1116
|
-
src,
|
|
1117
|
-
width,
|
|
1118
|
-
height,
|
|
1119
|
-
id,
|
|
1120
|
-
});
|
|
1121
|
-
|
|
1122
|
-
const obj = konvaImage.ref();
|
|
1123
|
-
this._konvaLayer.add(obj);
|
|
1124
|
-
|
|
1125
|
-
const trNodes = this._konvaTransformer.nodes();
|
|
1126
|
-
if (trNodes.length > 0) {
|
|
1127
|
-
// in case of edit - remove old Image placeholder object
|
|
1128
|
-
trNodes[0].destroy();
|
|
1129
|
-
this._konvaTransformer.nodes([]);
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1057
|
+
// in case of edit - remove old Image placeholder object
|
|
1058
|
+
this.getSelectedObjects().at(0)?.delete();
|
|
1132
1059
|
|
|
1060
|
+
this.clearSelected();
|
|
1133
1061
|
this.removeImageInput();
|
|
1134
1062
|
|
|
1063
|
+
const konvaImage = new KonvaImage({
|
|
1064
|
+
position,
|
|
1065
|
+
src,
|
|
1066
|
+
width,
|
|
1067
|
+
height,
|
|
1068
|
+
id,
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
this.addObject(konvaImage);
|
|
1135
1072
|
return konvaImage;
|
|
1136
1073
|
}
|
|
1137
1074
|
}
|