@inweb/markup 25.9.0 → 25.9.2

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.
@@ -46,7 +46,7 @@ export interface IMarkup {
46
46
  */
47
47
  initialize(container: HTMLElement, containerEvents?: string[], viewer?: IEventEmitter, worldTransformer?: IWorldTransform): void;
48
48
  /**
49
- * Releases all resources allocated by this markup instance.
49
+ * Releases resources allocated in the {@link initialize | initialize()}.
50
50
  */
51
51
  dispose(): void;
52
52
  /**
@@ -1,5 +1,5 @@
1
1
  import { IEventEmitter } from "@inweb/eventemitter2";
2
- import { ChangeActiveDraggerEvent, IViewpoint, PanEvent } from "@inweb/viewer-core";
2
+ import { ChangeActiveDraggerEvent, IViewpoint, PanEvent, ZoomAtEvent } from "@inweb/viewer-core";
3
3
  import { IMarkup, MarkupMode } from "../IMarkup";
4
4
  import { IWorldTransform } from "../IWorldTransform";
5
5
  import { IMarkupObject } from "../IMarkupObject";
@@ -36,6 +36,7 @@ export declare class KonvaMarkup implements IMarkup {
36
36
  changeActiveDragger: (event: ChangeActiveDraggerEvent) => void;
37
37
  resizeContainer: (entries: ResizeObserverEntry[]) => void;
38
38
  pan: (event: PanEvent) => void;
39
+ zoomAt: (event: ZoomAtEvent) => void;
39
40
  redirectToViewer: (event: any) => void;
40
41
  syncOverlay(): void;
41
42
  clearOverlay(): void;
@@ -57,6 +58,8 @@ export declare class KonvaMarkup implements IMarkup {
57
58
  clearSelected(): void;
58
59
  private addObject;
59
60
  private konvaLayerFind;
61
+ private getRelativePointPosition;
62
+ private getRelativePointerPosition;
60
63
  private initializeKonva;
61
64
  private destroyKonva;
62
65
  private getMarkupLines;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inweb/markup",
3
- "version": "25.9.0",
3
+ "version": "25.9.2",
4
4
  "description": "JavaScript 2D markups",
5
5
  "homepage": "https://cloud.opendesign.com/docs/index.html",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -26,13 +26,13 @@
26
26
  "docs": "typedoc"
27
27
  },
28
28
  "dependencies": {
29
- "@inweb/eventemitter2": "~25.9.0",
30
- "@inweb/viewer-core": "~25.9.0"
29
+ "@inweb/eventemitter2": "~25.9.2",
30
+ "@inweb/viewer-core": "~25.9.2"
31
31
  },
32
32
  "devDependencies": {
33
33
  "konva": "^9.3.14"
34
34
  },
35
35
  "peerDependencies": {
36
- "konva": "^9.2.0"
36
+ "konva": "^9.3.14"
37
37
  }
38
38
  }
@@ -80,7 +80,7 @@ export interface IMarkup {
80
80
  ): void;
81
81
 
82
82
  /**
83
- * Releases all resources allocated by this markup instance.
83
+ * Releases resources allocated in the {@link initialize | initialize()}.
84
84
  */
85
85
  dispose(): void;
86
86
 
@@ -34,14 +34,15 @@ import {
34
34
  IText,
35
35
  IViewpoint,
36
36
  PanEvent,
37
+ ZoomAtEvent,
37
38
  } from "@inweb/viewer-core";
38
39
 
39
40
  import { IMarkup, MarkupMode } from "../IMarkup";
40
41
  import { IWorldTransform } from "../IWorldTransform";
42
+ import { WorldTransform } from "../WorldTransform";
41
43
  import { IMarkupObject } from "../IMarkupObject";
42
44
  import { MarkupLineType } from "../IMarkupLine";
43
45
  import { MarkupColor } from "./MarkupColor";
44
- import { WorldTransform } from "../WorldTransform";
45
46
  import { KonvaLine } from "./KonvaLine";
46
47
  import { KonvaText } from "./KonvaText";
47
48
  import { KonvaRectangle } from "./KonvaRectangle";
@@ -153,11 +154,13 @@ export class KonvaMarkup implements IMarkup {
153
154
  this._containerEvents.forEach((x) => this._markupContainer.addEventListener(x, this.redirectToViewer));
154
155
  this._viewer.addEventListener("changeactivedragger", this.changeActiveDragger);
155
156
  this._viewer.addEventListener("pan", this.pan);
157
+ this._viewer.addEventListener("zoomat", this.zoomAt);
156
158
  }
157
159
  }
158
160
 
159
161
  dispose(): void {
160
162
  if (this._viewer) {
163
+ this._viewer.removeEventListener("zoomat", this.zoomAt);
161
164
  this._viewer.removeEventListener("pan", this.pan);
162
165
  this._viewer.removeEventListener("changeactivedragger", this.changeActiveDragger);
163
166
  this._containerEvents.forEach((x) => this._markupContainer.removeEventListener(x, this.redirectToViewer));
@@ -205,9 +208,42 @@ export class KonvaMarkup implements IMarkup {
205
208
  };
206
209
 
207
210
  pan = (event: PanEvent) => {
208
- const dX = event.dX / window.devicePixelRatio;
209
- const dY = event.dY / window.devicePixelRatio;
210
- this.getObjects().forEach((obj) => obj.ref().move({ x: dX, y: dY }));
211
+ const pointer = this._konvaStage.getPointerPosition();
212
+
213
+ const pointTo = {
214
+ x: (pointer.x - this._konvaStage.x()) / this._konvaStage.scaleX(),
215
+ y: (pointer.y - this._konvaStage.y()) / this._konvaStage.scaleX(),
216
+ };
217
+
218
+ const newPos = {
219
+ x: pointer.x - pointTo.x * this._konvaStage.scale().x + event.dX,
220
+ y: pointer.y - pointTo.y * this._konvaStage.scale().x + event.dY,
221
+ };
222
+
223
+ this._konvaStage.position(newPos);
224
+ };
225
+
226
+ zoomAt = (event: ZoomAtEvent) => {
227
+ const oldScale = this._konvaStage.scaleX();
228
+ const pointer = this._konvaStage.getPointerPosition();
229
+
230
+ const mousePointTo = {
231
+ x: (pointer.x - this._konvaStage.x()) / oldScale,
232
+ y: (pointer.y - this._konvaStage.y()) / oldScale,
233
+ };
234
+
235
+ // how to scale? Zoom in? Or zoom out?
236
+ let direction = event.data > 0 ? 1 : -1;
237
+
238
+ const newScale = direction > 0 ? oldScale * event.data : oldScale / event.data;
239
+
240
+ this._konvaStage.scale({ x: newScale, y: newScale });
241
+
242
+ const newPos = {
243
+ x: pointer.x - mousePointTo.x * newScale,
244
+ y: pointer.y - mousePointTo.y * newScale,
245
+ };
246
+ this._konvaStage.position(newPos);
211
247
  };
212
248
 
213
249
  redirectToViewer = (event: any) => {
@@ -245,6 +281,8 @@ export class KonvaMarkup implements IMarkup {
245
281
  this.clearSelected();
246
282
  this.removeTextInput();
247
283
  this.removeImageInput();
284
+ this._konvaStage.scale({ x: 1, y: 1 });
285
+ this._konvaStage.position({ x: 0, y: 0 });
248
286
 
249
287
  const markupColor = viewpoint.custom_fields?.markup_color || { r: 255, g: 0, b: 0 };
250
288
  this.setMarkupColor(markupColor.r, markupColor.g, markupColor.b);
@@ -390,6 +428,20 @@ export class KonvaMarkup implements IMarkup {
390
428
  );
391
429
  }
392
430
 
431
+ private getRelativePointPosition = (point, node) => {
432
+ // the function will return pointer position relative to the passed node
433
+ const transform = node.getAbsoluteTransform().copy();
434
+ // to detect relative position we need to invert transform
435
+ transform.invert();
436
+ // get pointer (say mouse or touch) position
437
+ // now we find relative point
438
+ return transform.point(point);
439
+ };
440
+
441
+ private getRelativePointerPosition = (node) => {
442
+ return this.getRelativePointPosition(node.getStage().getPointerPosition(), node);
443
+ };
444
+
393
445
  private initializeKonva(): any {
394
446
  // first we need Konva core things: stage and layer
395
447
  const stage = new Konva.Stage({
@@ -434,7 +486,7 @@ export class KonvaMarkup implements IMarkup {
434
486
  return;
435
487
  }
436
488
 
437
- const pos = stage.getPointerPosition();
489
+ const pos = this.getRelativePointerPosition(stage);
438
490
  mouseDownPos = pos;
439
491
 
440
492
  isPaint = ["Arrow", "Cloud", "Ellipse", "Line", "Rectangle"].some((m) => m === this._markupMode);
@@ -448,7 +500,7 @@ export class KonvaMarkup implements IMarkup {
448
500
  if (!this._markupIsActive) return;
449
501
 
450
502
  if (isPaint) {
451
- const pos = stage.getPointerPosition();
503
+ const pos = this.getRelativePointerPosition(stage);
452
504
  const defParams = mouseDownPos && pos.x === mouseDownPos.x && pos.y === mouseDownPos.y;
453
505
  const startX = defParams ? mouseDownPos.x : Math.min(mouseDownPos.x, pos.x);
454
506
  const startY = defParams ? mouseDownPos.y : Math.min(mouseDownPos.y, pos.y);
@@ -483,7 +535,7 @@ export class KonvaMarkup implements IMarkup {
483
535
  // prevent scrolling on touch devices
484
536
  //e.evt.preventDefault();
485
537
 
486
- const pos = stage.getPointerPosition();
538
+ const pos = this.getRelativePointerPosition(stage);
487
539
  const defParams = mouseDownPos && pos.x === mouseDownPos.x && pos.y === mouseDownPos.y;
488
540
  const startX = defParams ? mouseDownPos.x : Math.min(mouseDownPos.x, pos.x);
489
541
  const startY = defParams ? mouseDownPos.y : Math.min(mouseDownPos.y, pos.y);
@@ -526,7 +578,7 @@ export class KonvaMarkup implements IMarkup {
526
578
  if (this._textInputRef && this._textInputRef.value)
527
579
  this.addText(this._textInputRef.value, this._textInputPos, this._textInputAngle);
528
580
  else if (transformer.nodes().length === 0) {
529
- const pos = stage.getPointerPosition();
581
+ const pos = this.getRelativePointerPosition(stage);
530
582
  this.createTextInput(pos, e.evt.pageX, e.evt.pageY, 0, null);
531
583
  }
532
584
  } else if (this._markupMode === "Image") {
@@ -539,7 +591,7 @@ export class KonvaMarkup implements IMarkup {
539
591
  this._imageInputRef.value
540
592
  );
541
593
  else if (transformer.nodes().length === 0) {
542
- const pos = stage.getPointerPosition();
594
+ const pos = this.getRelativePointerPosition(stage);
543
595
  this.createImageInput(pos);
544
596
  }
545
597
  }
@@ -683,11 +735,11 @@ export class KonvaMarkup implements IMarkup {
683
735
  const textSize = 0.02;
684
736
  const textScale = this._worldTransformer.getScale();
685
737
 
686
- const position = {
687
- x: ref.x(),
688
- y: ref.y(),
689
- };
690
- const worldPoint = this._worldTransformer.screenToWorld(position);
738
+ const position = ref.position();
739
+ const stageAbsoluteTransform = this._konvaStage.getAbsoluteTransform();
740
+ const atPoint = stageAbsoluteTransform.point({ x: position.x, y: position.y });
741
+
742
+ const worldPoint = this._worldTransformer.screenToWorld(atPoint);
691
743
 
692
744
  const shape = new KonvaText(null, ref);
693
745
  const text: IText = {
@@ -697,7 +749,7 @@ export class KonvaMarkup implements IMarkup {
697
749
  text_size: textSize * textScale.y,
698
750
  angle: shape.getRotation(),
699
751
  color: shape.getColor(),
700
- font_size: shape.getFontSize(),
752
+ font_size: shape.getFontSize() * stageAbsoluteTransform.getMatrix()[0],
701
753
  };
702
754
 
703
755
  texts.push(text);
@@ -711,14 +763,17 @@ export class KonvaMarkup implements IMarkup {
711
763
 
712
764
  this.konvaLayerFind("Rectangle").forEach((ref) => {
713
765
  const position = ref.position();
714
- const worldPoint = this._worldTransformer.screenToWorld(position);
766
+ const stageAbsoluteTransform = this._konvaStage.getAbsoluteTransform();
767
+ const atPoint = stageAbsoluteTransform.point({ x: position.x, y: position.y });
768
+ const worldPoint = this._worldTransformer.screenToWorld(atPoint);
769
+ const scale = stageAbsoluteTransform.getMatrix()[0];
715
770
 
716
771
  const shape = new KonvaRectangle(null, ref);
717
772
  const rectangle: IRectangle = {
718
773
  id: shape.id(),
719
774
  position: worldPoint,
720
- width: shape.getWidth(),
721
- height: shape.getHeigth(),
775
+ width: shape.getWidth() * scale,
776
+ height: shape.getHeigth() * scale,
722
777
  line_width: shape.getLineWidth(),
723
778
  color: shape.getColor(),
724
779
  };
@@ -734,13 +789,19 @@ export class KonvaMarkup implements IMarkup {
734
789
 
735
790
  this.konvaLayerFind("Ellipse").forEach((ref) => {
736
791
  const position = ref.position();
737
- const worldPoint = this._worldTransformer.screenToWorld(position);
792
+ const stageAbsoluteTransform = this._konvaStage.getAbsoluteTransform();
793
+ const atPoint = stageAbsoluteTransform.point({ x: position.x, y: position.y });
794
+ const worldPoint = this._worldTransformer.screenToWorld(atPoint);
795
+ const scale = stageAbsoluteTransform.getMatrix()[0];
738
796
 
739
797
  const shape = new KonvaEllipse(null, ref);
740
798
  const ellipse: IEllipse = {
741
799
  id: shape.id(),
742
800
  position: worldPoint,
743
- radius: { x: ref.getRadiusX(), y: ref.getRadiusY() },
801
+ radius: {
802
+ x: ref.getRadiusX() * scale,
803
+ y: ref.getRadiusY() * scale,
804
+ },
744
805
  line_width: shape.getLineWidth(),
745
806
  color: shape.getColor(),
746
807
  };
@@ -789,15 +850,18 @@ export class KonvaMarkup implements IMarkup {
789
850
 
790
851
  this.konvaLayerFind("Image").forEach((ref) => {
791
852
  const position = ref.position();
792
- const worldPoint = this._worldTransformer.screenToWorld(position);
853
+ const stageAbsoluteTransform = this._konvaStage.getAbsoluteTransform();
854
+ const atPoint = stageAbsoluteTransform.point({ x: position.x, y: position.y });
855
+ const worldPoint = this._worldTransformer.screenToWorld(atPoint);
856
+ const scale = stageAbsoluteTransform.getMatrix()[0];
793
857
 
794
858
  const shape = new KonvaImage(null, ref);
795
859
  const image: IImage = {
796
860
  id: shape.id(),
797
861
  position: worldPoint,
798
862
  src: shape.getSrc(),
799
- width: shape.getWidth(),
800
- height: shape.getHeight(),
863
+ width: shape.getWidth() * scale,
864
+ height: shape.getHeight() * scale,
801
865
  };
802
866
 
803
867
  images.push(image);
@@ -811,14 +875,17 @@ export class KonvaMarkup implements IMarkup {
811
875
 
812
876
  this.konvaLayerFind("Cloud").forEach((ref) => {
813
877
  const position = ref.position();
814
- const worldPoint = this._worldTransformer.screenToWorld(position);
878
+ const stageAbsoluteTransform = this._konvaStage.getAbsoluteTransform();
879
+ const atPoint = stageAbsoluteTransform.point({ x: position.x, y: position.y });
880
+ const worldPoint = this._worldTransformer.screenToWorld(atPoint);
881
+ const scale = stageAbsoluteTransform.getMatrix()[0];
815
882
 
816
883
  const shape = new KonvaCloud(null, ref);
817
884
  const cloud: ICloud = {
818
885
  id: shape.id(),
819
886
  position: worldPoint,
820
- width: shape.getWidth(),
821
- height: shape.getHeigth(),
887
+ width: shape.getWidth() * scale,
888
+ height: shape.getHeigth() * scale,
822
889
  line_width: shape.getLineWidth(),
823
890
  color: shape.getColor(),
824
891
  };