@inweb/viewer-visualize 25.3.22 → 25.3.24

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.
@@ -14950,6 +14950,10 @@
14950
14950
  });
14951
14951
  this._canvasImage.onload = () => {
14952
14952
  this._ref.image(this._canvasImage);
14953
+ if (this._ref.height() === 0)
14954
+ this._ref.height(this._canvasImage.height);
14955
+ if (this._ref.width() === 0)
14956
+ this._ref.width(this._canvasImage.width);
14953
14957
  this._ratio = this._ref.height() === 0 || this._ref.width() === 0 ? 1 : this._ref.height() / this._ref.width();
14954
14958
  };
14955
14959
  this._canvasImage.src = params.src;
@@ -15256,6 +15260,7 @@
15256
15260
  .concat(`oda-cursor-${draggerName.toLowerCase()}`)
15257
15261
  .join(" ");
15258
15262
  this.removeTextInput();
15263
+ this.removeImageInput();
15259
15264
  const markupMode = MarkupMode[draggerName];
15260
15265
  const konvaMode = MarkupMode2Konva.get(markupMode);
15261
15266
  if (konvaMode) {
@@ -15325,6 +15330,7 @@
15325
15330
  }
15326
15331
  clearOverlay() {
15327
15332
  this.removeTextInput();
15333
+ this.removeImageInput();
15328
15334
  this._konvaTransformer.nodes([]);
15329
15335
  Object.values(MarkupMode).forEach((mode) => this.konvaLayerFind(mode).forEach((x) => x.destroy()));
15330
15336
  }
@@ -15345,6 +15351,14 @@
15345
15351
  });
15346
15352
  this._konvaLayer.draw();
15347
15353
  }
15354
+ colorizeSelectedMarkups(r, g, b) {
15355
+ this.getSelectedObjects().forEach((obj) => {
15356
+ const colorable = obj;
15357
+ if (colorable && colorable.setColor) {
15358
+ colorable.setColor(new MarkupColor(r, g, b).HexColor);
15359
+ }
15360
+ });
15361
+ }
15348
15362
  setViewpoint(viewpoint) {
15349
15363
  const markupColor = viewpoint.custom_fields.markup_color || { r: 255, g: 0, b: 0 };
15350
15364
  this.setMarkupColor(markupColor.r, markupColor.g, markupColor.b);
@@ -15551,37 +15565,53 @@
15551
15565
  layer.add(transformer);
15552
15566
  let isPaint = false;
15553
15567
  let lastLine;
15568
+ let mouseDownPos;
15569
+ let lastObj;
15554
15570
  stage.on("mousedown touchstart", (e) => {
15555
15571
  // do nothing if we mousedown on any shape
15556
- if (!this._markupIsActive || e.target !== stage || this._markupMode === MarkupMode.Text)
15572
+ if (!this._markupIsActive ||
15573
+ e.target !== stage ||
15574
+ this._markupMode === MarkupMode.Text ||
15575
+ this._markupMode === MarkupMode.Image)
15557
15576
  return;
15558
15577
  if (e.target === stage && transformer.nodes().length > 0) {
15559
15578
  transformer.nodes([]);
15560
15579
  return;
15561
15580
  }
15562
15581
  const pos = stage.getPointerPosition();
15582
+ mouseDownPos = pos;
15583
+ isPaint = [MarkupMode.Arrow, MarkupMode.Cloud, MarkupMode.Ellipse, MarkupMode.Line, MarkupMode.Rectangle].some((m) => m === this._markupMode);
15563
15584
  if (this._markupMode === MarkupMode.Line) {
15564
15585
  // add point twice, so we have some drawings even on a simple click
15565
15586
  lastLine = this.addLine([pos.x, pos.y, pos.x, pos.y]);
15566
- isPaint = true;
15567
- }
15568
- // 25.2 - currently only for debug purposes:
15569
- else if (this._markupMode === MarkupMode.Rectangle) {
15570
- this.addRectangle({ x: pos.x, y: pos.y }, 50, 50);
15571
- }
15572
- else if (this._markupMode === MarkupMode.Ellipse) {
15573
- this.addEllipse({ x: pos.x, y: pos.y }, { x: 50, y: 50 });
15574
- }
15575
- else if (this._markupMode === MarkupMode.Arrow) {
15576
- this.addArrow({ x: pos.x, y: pos.y }, { x: pos.x + 50, y: pos.y + 50 });
15577
- }
15578
- else if (this._markupMode === MarkupMode.Cloud) {
15579
- this.addCloud({ x: pos.x, y: pos.y }, 200, 400);
15580
15587
  }
15581
15588
  });
15582
15589
  stage.on("mouseup touchend", (e) => {
15583
15590
  if (!this._markupIsActive)
15584
15591
  return;
15592
+ if (isPaint) {
15593
+ const pos = stage.getPointerPosition();
15594
+ const defParams = mouseDownPos && pos.x === mouseDownPos.x && pos.y === mouseDownPos.y;
15595
+ const startX = defParams ? mouseDownPos.x : Math.min(mouseDownPos.x, pos.x);
15596
+ const startY = defParams ? mouseDownPos.y : Math.min(mouseDownPos.y, pos.y);
15597
+ const dX = defParams ? 200 : Math.abs(mouseDownPos.x - pos.x);
15598
+ const dY = defParams ? 200 : Math.abs(mouseDownPos.y - pos.y);
15599
+ if (defParams) {
15600
+ if (this._markupMode === MarkupMode.Rectangle) {
15601
+ this.addRectangle({ x: startX, y: startY }, dX, dY);
15602
+ }
15603
+ else if (this._markupMode === MarkupMode.Ellipse) {
15604
+ this.addEllipse({ x: startX, y: startY }, { x: dX / 2, y: dY / 2 });
15605
+ }
15606
+ else if (this._markupMode === MarkupMode.Arrow) {
15607
+ this.addArrow({ x: mouseDownPos.x, y: mouseDownPos.y }, { x: defParams ? mouseDownPos.x + 200 : pos.x, y: defParams ? startY : pos.y });
15608
+ }
15609
+ else if (this._markupMode === MarkupMode.Cloud) {
15610
+ this.addCloud({ x: startX, y: startY }, Math.max(100, dX), Math.max(100, dY));
15611
+ }
15612
+ }
15613
+ }
15614
+ lastObj = undefined;
15585
15615
  isPaint = false;
15586
15616
  });
15587
15617
  stage.on("mousemove touchmove", (e) => {
@@ -15593,8 +15623,47 @@
15593
15623
  // prevent scrolling on touch devices
15594
15624
  //e.evt.preventDefault();
15595
15625
  const pos = stage.getPointerPosition();
15596
- const newPoints = lastLine.points().concat([pos.x, pos.y]);
15597
- lastLine.points(newPoints);
15626
+ const defParams = mouseDownPos && pos.x === mouseDownPos.x && pos.y === mouseDownPos.y;
15627
+ const startX = defParams ? mouseDownPos.x : Math.min(mouseDownPos.x, pos.x);
15628
+ const startY = defParams ? mouseDownPos.y : Math.min(mouseDownPos.y, pos.y);
15629
+ const dX = defParams ? 200 : Math.abs(mouseDownPos.x - pos.x);
15630
+ const dY = defParams ? 200 : Math.abs(mouseDownPos.y - pos.y);
15631
+ if (this._markupMode === MarkupMode.Line) {
15632
+ lastLine.addPoints([{ x: pos.x, y: pos.y }]);
15633
+ }
15634
+ else if (this._markupMode === MarkupMode.Arrow) {
15635
+ if (lastObj)
15636
+ lastObj.setEndPoint(pos.x, pos.y);
15637
+ else
15638
+ lastObj = this.addArrow({ x: mouseDownPos.x, y: mouseDownPos.y }, { x: pos.x, y: pos.y });
15639
+ }
15640
+ else if (this._markupMode === MarkupMode.Rectangle) {
15641
+ if (lastObj) {
15642
+ lastObj.setPosition(startX, startY);
15643
+ lastObj.setWidth(dX);
15644
+ lastObj.setHeight(dY);
15645
+ }
15646
+ else
15647
+ lastObj = this.addRectangle({ x: startX, y: startY }, dX, dY);
15648
+ }
15649
+ else if (this._markupMode === MarkupMode.Ellipse) {
15650
+ if (lastObj) {
15651
+ lastObj.setPosition(startX, startY);
15652
+ lastObj.setRadiusX(dX);
15653
+ lastObj.setRadiusY(dY);
15654
+ }
15655
+ else
15656
+ lastObj = this.addEllipse({ x: startX, y: startY }, { x: dX, y: dY });
15657
+ }
15658
+ else if (this._markupMode === MarkupMode.Cloud) {
15659
+ if (lastObj) {
15660
+ lastObj.setPosition(startX, startY);
15661
+ lastObj.setWidth(Math.max(100, dX));
15662
+ lastObj.setHeight(Math.max(100, dY));
15663
+ }
15664
+ else
15665
+ lastObj = this.addCloud({ x: startX, y: startY }, dX, dY);
15666
+ }
15598
15667
  });
15599
15668
  // clicks should select/deselect shapes
15600
15669
  stage.on("click tap", (e) => {
@@ -15603,18 +15672,26 @@
15603
15672
  // if click on empty area - remove all selections
15604
15673
  if (e.target === stage) {
15605
15674
  if (this._markupMode === MarkupMode.Text) {
15606
- if (this._textInputRef)
15675
+ if (this._textInputRef && this._textInputRef.value)
15607
15676
  this.addText(this._textInputRef.value, this._textInputPos, this._textInputAngle);
15608
15677
  else if (transformer.nodes().length === 0) {
15609
15678
  const pos = stage.getPointerPosition();
15610
15679
  this.createTextInput(pos, e.evt.pageX, e.evt.pageY, 0, null);
15611
15680
  }
15612
15681
  }
15682
+ else if (this._markupMode === MarkupMode.Image) {
15683
+ if (this._imageInputRef && this._imageInputRef.value)
15684
+ this.addImage({ x: this._imageInputPos.x, y: this._imageInputPos.y }, this._imageInputRef.value, 0, 0, this._imageInputRef.value);
15685
+ else if (transformer.nodes().length === 0) {
15686
+ const pos = stage.getPointerPosition();
15687
+ this.createImageInput(pos);
15688
+ }
15689
+ }
15613
15690
  transformer.nodes([]);
15614
15691
  return;
15615
15692
  }
15616
15693
  if (e.target.className === "Text" && transformer.nodes().length === 1 && transformer.nodes()[0] === e.target) {
15617
- if (this._textInputRef)
15694
+ if (this._textInputRef && this._textInputRef.value)
15618
15695
  this.addText(this._textInputRef.value, this._textInputPos, this._textInputAngle);
15619
15696
  else
15620
15697
  this.createTextInput({ x: e.target.attrs.x, y: e.target.attrs.y }, e.evt.pageX, e.evt.pageY, e.target.attrs.rotation, e.target.attrs.text);
@@ -15623,6 +15700,16 @@
15623
15700
  else {
15624
15701
  this.removeTextInput();
15625
15702
  }
15703
+ if (e.target.className === "Image" && transformer.nodes().length === 1 && transformer.nodes()[0] === e.target) {
15704
+ if (this._imageInputRef && this._imageInputRef.value)
15705
+ this.addImage(this._imageInputPos, this._imageInputRef.value, 0, 0);
15706
+ else
15707
+ this.createImageInput({ x: e.target.attrs.x, y: e.target.attrs.y });
15708
+ return;
15709
+ }
15710
+ else {
15711
+ this.removeImageInput();
15712
+ }
15626
15713
  if (transformer.nodes().filter((x) => x.className === "Cloud").length > 0 || e.target.className === "Cloud") {
15627
15714
  transformer.rotateEnabled(false);
15628
15715
  }
@@ -15898,7 +15985,7 @@
15898
15985
  });
15899
15986
  const obj = konvaLine.ref();
15900
15987
  this._konvaLayer.add(obj);
15901
- return obj;
15988
+ return konvaLine;
15902
15989
  }
15903
15990
  createTextInput(pos, inputX, inputY, angle, text) {
15904
15991
  if (!this._textInputRef) {
@@ -15938,6 +16025,48 @@
15938
16025
  this._textInputPos = null;
15939
16026
  this._textInputAngle = 0;
15940
16027
  }
16028
+ createImageInput(pos) {
16029
+ if (!this._imageInputRef) {
16030
+ const convertBase64 = (file) => {
16031
+ return new Promise((resolve, reject) => {
16032
+ const fileReader = new FileReader();
16033
+ fileReader.readAsDataURL(file);
16034
+ fileReader.onload = () => {
16035
+ resolve(fileReader.result);
16036
+ };
16037
+ fileReader.onerror = (error) => {
16038
+ reject(error);
16039
+ };
16040
+ });
16041
+ };
16042
+ this._imageInputPos = pos;
16043
+ this._imageInputRef = document.createElement("input");
16044
+ this._imageInputRef.style.display = "none";
16045
+ this._imageInputRef.type = "file";
16046
+ this._imageInputRef.accept = "image/png, image/jpeg";
16047
+ this._imageInputRef.onchange = async (event) => {
16048
+ const file = event.target.files[0];
16049
+ const base64 = await convertBase64(file);
16050
+ this.addImage({ x: this._imageInputPos.x, y: this._imageInputPos.y }, base64.toString(), 0, 0);
16051
+ };
16052
+ this._imageInputRef.oncancel = (event) => {
16053
+ this.removeImageInput();
16054
+ };
16055
+ document.body.appendChild(this._imageInputRef);
16056
+ setTimeout(() => {
16057
+ this._imageInputRef.click();
16058
+ }, 50);
16059
+ }
16060
+ else {
16061
+ this.removeImageInput();
16062
+ }
16063
+ }
16064
+ removeImageInput() {
16065
+ var _a;
16066
+ (_a = this._imageInputRef) === null || _a === void 0 ? void 0 : _a.remove();
16067
+ this._imageInputRef = null;
16068
+ this._imageInputPos = null;
16069
+ }
15941
16070
  addText(specifiedText, position, angle, color, textSize, fontSize, id) {
15942
16071
  if (specifiedText) {
15943
16072
  const tol = 1.0e-6;
@@ -15984,7 +16113,7 @@
15984
16113
  });
15985
16114
  const obj = konvaRectangle.ref();
15986
16115
  this._konvaLayer.add(obj);
15987
- return obj;
16116
+ return konvaRectangle;
15988
16117
  }
15989
16118
  addEllipse(position, radius, lineWidth, color, id) {
15990
16119
  if (!position)
@@ -15998,7 +16127,7 @@
15998
16127
  });
15999
16128
  const obj = konvaEllipse.ref();
16000
16129
  this._konvaLayer.add(obj);
16001
- return obj;
16130
+ return konvaEllipse;
16002
16131
  }
16003
16132
  addArrow(start, end, color, id) {
16004
16133
  if (!start || !end)
@@ -16011,7 +16140,7 @@
16011
16140
  });
16012
16141
  const obj = konvaArrow.ref();
16013
16142
  this._konvaLayer.add(obj);
16014
- return obj;
16143
+ return konvaArrow;
16015
16144
  }
16016
16145
  addCloud(position, width, height, lineWidth, color, id) {
16017
16146
  if (!position || !width || !height)
@@ -16026,21 +16155,30 @@
16026
16155
  });
16027
16156
  const obj = konvaCloud.ref();
16028
16157
  this._konvaLayer.add(obj);
16029
- return obj;
16158
+ return konvaCloud;
16030
16159
  }
16031
16160
  addImage(position, src, width, height, id) {
16032
- if (!position || !width || !height)
16161
+ if (!position)
16033
16162
  return;
16034
- const konvaImage = new KonvaImage({
16035
- position,
16036
- src,
16037
- width,
16038
- height,
16039
- id,
16040
- });
16041
- const obj = konvaImage.ref();
16042
- this._konvaLayer.add(obj);
16043
- return obj;
16163
+ if (src) {
16164
+ const konvaImage = new KonvaImage({
16165
+ position,
16166
+ src,
16167
+ width,
16168
+ height,
16169
+ id,
16170
+ });
16171
+ const obj = konvaImage.ref();
16172
+ this._konvaLayer.add(obj);
16173
+ const trNodes = this._konvaTransformer.nodes();
16174
+ if (trNodes.length > 0) {
16175
+ // in case of edit - remove old Image placeholder object
16176
+ trNodes[0].destroy();
16177
+ this._konvaTransformer.nodes([]);
16178
+ }
16179
+ }
16180
+ this.removeImageInput();
16181
+ return;
16044
16182
  }
16045
16183
  }
16046
16184
 
@@ -16214,6 +16352,9 @@
16214
16352
  itr.delete();
16215
16353
  this._viewer.update();
16216
16354
  }
16355
+ colorizeSelectedMarkups(r = 255, g = 0, b = 0) {
16356
+ throw new Error("Not implemented yet");
16357
+ }
16217
16358
  setViewpoint(viewpoint) {
16218
16359
  function getLogicalPoint3dAsArray(point3d) {
16219
16360
  return [point3d.x, point3d.y, point3d.z];
@@ -16477,10 +16618,11 @@
16477
16618
  canvas.style.touchAction = "none";
16478
16619
  canvas.width = canvas.clientWidth * window.devicePixelRatio;
16479
16620
  canvas.height = canvas.clientHeight * window.devicePixelRatio;
16480
- const visualizeJs = await loadVisualizeJs(this.visualizeJsUrl, (ev) => {
16481
- const { loaded, timeStamp, total, lengthComputable } = ev;
16482
- const event = { loaded, timeStamp, total, lengthComputable, type: "visualizeprogress" };
16483
- onProgress === null || onProgress === void 0 ? void 0 : onProgress(event);
16621
+ const visualizeJs = await loadVisualizeJs(this.visualizeJsUrl, (event) => {
16622
+ const { loaded, total } = event;
16623
+ if (onProgress)
16624
+ onProgress(new ProgressEvent("progress", { lengthComputable: true, loaded, total }));
16625
+ this.emitEvent({ type: "initializeprogress", data: loaded / total, loaded, total });
16484
16626
  });
16485
16627
  this._visualizeJs = visualizeJs;
16486
16628
  this.visualizeJs.canvas = canvas;
@@ -16500,6 +16642,7 @@
16500
16642
  this.syncOptions();
16501
16643
  this._renderTime = performance.now();
16502
16644
  this.render(this._renderTime);
16645
+ this.emitEvent({ type: "initialize" });
16503
16646
  return this;
16504
16647
  }
16505
16648
  /**
@@ -17189,7 +17332,17 @@
17189
17332
  colorizeAllMarkup(r = 255, g = 0, b = 0) {
17190
17333
  this.markup.colorizeAllMarkup(r, g, b);
17191
17334
  }
17192
- /*
17335
+ /**
17336
+ * Colorize all selected markup entities with the specified color.
17337
+ *
17338
+ * @param r - `Red` part of color.
17339
+ * @param g - `Green` part of color.
17340
+ * @param b - `Blue` part of color.
17341
+ */
17342
+ colorizeSelectedMarkups(r = 255, g = 0, b = 0) {
17343
+ this.markup.colorizeSelectedMarkups(r, g, b);
17344
+ }
17345
+ /**
17193
17346
  * Add an empty markup entity to the overlay.
17194
17347
  */
17195
17348
  addMarkupEntity(entityName) {