microboard-temp 0.4.41 → 0.4.43

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/esm/index.js CHANGED
@@ -19486,433 +19486,6 @@ class NoOpCommand {
19486
19486
  }
19487
19487
  }
19488
19488
 
19489
- // src/isSafari.ts
19490
- function isSafari() {
19491
- if (typeof navigator === "undefined") {
19492
- return false;
19493
- }
19494
- const agent = navigator.userAgent;
19495
- const vendor = navigator.vendor;
19496
- const is = vendor !== undefined && vendor.includes("Apple") && agent !== undefined && !agent.includes("CriOS") && !agent.includes("FxiOS");
19497
- return is;
19498
- }
19499
-
19500
- // src/Items/Drawing/Drawing.ts
19501
- class Drawing extends BaseItem {
19502
- points;
19503
- events;
19504
- itemType = "Drawing";
19505
- parent = "Board";
19506
- transformation;
19507
- path2d = new conf.path2DFactory;
19508
- subject = new Subject;
19509
- untransformedMbr = new Mbr;
19510
- lines = [];
19511
- linkTo;
19512
- strokeWidth = 1;
19513
- borderStyle = "solid";
19514
- linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
19515
- borderOpacity = 1;
19516
- transformationRenderBlock = undefined;
19517
- constructor(board, points, events, id = "") {
19518
- super(board, id);
19519
- this.points = points;
19520
- this.events = events;
19521
- this.transformation = new Transformation(id, events);
19522
- this.linkTo = new LinkTo(this.id, this.events);
19523
- this.transformation.subject.subscribe(() => {
19524
- this.updateMbr();
19525
- this.updateLines();
19526
- this.subject.publish(this);
19527
- });
19528
- this.linkTo.subject.subscribe(() => {
19529
- this.updateMbr();
19530
- this.updateLines();
19531
- this.subject.publish(this);
19532
- });
19533
- this.updateLines();
19534
- }
19535
- serialize() {
19536
- this.optimizePoints();
19537
- const points = [];
19538
- for (const point3 of this.points) {
19539
- points.push({ x: point3.x, y: point3.y });
19540
- }
19541
- return {
19542
- itemType: "Drawing",
19543
- points,
19544
- transformation: this.transformation.serialize(),
19545
- strokeStyle: this.borderColor,
19546
- strokeWidth: this.strokeWidth,
19547
- linkTo: this.linkTo.serialize()
19548
- };
19549
- }
19550
- deserialize(data) {
19551
- this.points = [];
19552
- for (const point3 of data.points) {
19553
- this.points.push(new Point(point3.x, point3.y));
19554
- }
19555
- this.linkTo.deserialize(data.linkTo);
19556
- this.optimizePoints();
19557
- this.transformation.deserialize(data.transformation);
19558
- this.borderColor = data.strokeStyle;
19559
- this.strokeWidth = data.strokeWidth;
19560
- this.updateGeometry();
19561
- return this;
19562
- }
19563
- updateGeometry() {
19564
- this.updatePath2d();
19565
- this.updateLines();
19566
- this.updateMbr();
19567
- }
19568
- updateMbr() {
19569
- const offset = this.getStrokeWidth() / 2;
19570
- const untransformedMbr = this.untransformedMbr.copy();
19571
- untransformedMbr.left -= offset;
19572
- untransformedMbr.top -= offset;
19573
- untransformedMbr.right += offset;
19574
- untransformedMbr.bottom += offset;
19575
- const mbr = untransformedMbr.getTransformed(this.transformation.matrix);
19576
- this.left = mbr.left;
19577
- this.top = mbr.top;
19578
- this.right = mbr.right;
19579
- this.bottom = mbr.bottom;
19580
- }
19581
- updatePath2d() {
19582
- this.path2d = new conf.path2DFactory;
19583
- const context = this.path2d;
19584
- const points = this.points;
19585
- if (points.length < 3) {
19586
- context.arc(points[0].x, points[0].y, 0.5, 0, Math.PI * 2, true);
19587
- context.closePath();
19588
- } else {
19589
- context.moveTo(points[0].x, points[0].y);
19590
- let j = 1;
19591
- for (;j < points.length - 2; j++) {
19592
- const cx = (points[j].x + points[j + 1].x) / 2;
19593
- const cy = (points[j].y + points[j + 1].y) / 2;
19594
- context.quadraticCurveTo(points[j].x, points[j].y, cx, cy);
19595
- }
19596
- const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
19597
- const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
19598
- context.quadraticCurveTo(points[j].x, points[j].y, x, y);
19599
- }
19600
- let left = Number.MAX_SAFE_INTEGER;
19601
- let right = Number.MIN_SAFE_INTEGER;
19602
- let top = Number.MAX_SAFE_INTEGER;
19603
- let bottom = Number.MIN_SAFE_INTEGER;
19604
- for (const { x, y } of this.points) {
19605
- if (x < left) {
19606
- left = x;
19607
- }
19608
- if (x > right) {
19609
- right = x;
19610
- }
19611
- if (y < top) {
19612
- top = y;
19613
- }
19614
- if (y > bottom) {
19615
- bottom = y;
19616
- }
19617
- }
19618
- this.untransformedMbr = new Mbr(left, top, right, bottom);
19619
- }
19620
- updateLines() {
19621
- this.lines = [];
19622
- const matrix = this.transformation.matrix;
19623
- if (this.points.length < 2) {
19624
- return;
19625
- }
19626
- for (let i = 0;i < this.points.length - 2; i++) {
19627
- const p1 = this.points[i];
19628
- const p2 = this.points[i + 1];
19629
- const line = new Line(p1.copy(), p2.copy());
19630
- line.transform(matrix);
19631
- this.lines.push(line);
19632
- }
19633
- }
19634
- optimizePoints() {
19635
- const dp = douglasPeucker(this.points, 1);
19636
- dp.push(this.points[this.points.length - 1]);
19637
- this.points = dp;
19638
- }
19639
- addPoint(point3) {
19640
- const previous2 = this.points[this.points.length - 1];
19641
- if (previous2) {
19642
- const distance = point3.getDistance(previous2);
19643
- if (distance >= 2) {
19644
- this.points.push(point3);
19645
- }
19646
- } else {
19647
- this.points.push(point3);
19648
- }
19649
- this.updateGeometry();
19650
- }
19651
- setId(id) {
19652
- this.id = id;
19653
- this.transformation.setId(id);
19654
- this.linkTo.setId(id);
19655
- return this;
19656
- }
19657
- getId() {
19658
- return this.id;
19659
- }
19660
- render(context) {
19661
- if (this.transformationRenderBlock) {
19662
- return;
19663
- }
19664
- const ctx = context.ctx;
19665
- ctx.save();
19666
- ctx.strokeStyle = this.borderColor;
19667
- ctx.lineWidth = this.strokeWidth;
19668
- ctx.lineCap = "round";
19669
- ctx.setLineDash(this.linePattern);
19670
- this.transformation.matrix.applyToContext(ctx);
19671
- ctx.stroke(this.path2d.nativePath);
19672
- ctx.restore();
19673
- if (this.getLinkTo()) {
19674
- const { top, right } = this.getMbr();
19675
- this.linkTo.render(context, top, right, this.board.camera.getScale());
19676
- }
19677
- }
19678
- renderHTML(documentFactory) {
19679
- const div = documentFactory.createElement("drawing-item");
19680
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
19681
- const mbr = this.getMbr();
19682
- const width = mbr.getWidth();
19683
- const height = mbr.getHeight();
19684
- const unscaledWidth = width / scaleX;
19685
- const unscaledHeight = height / scaleY;
19686
- const svg = documentFactory.createElementNS("http://www.w3.org/2000/svg", "svg");
19687
- svg.setAttribute("width", `${unscaledWidth}px`);
19688
- svg.setAttribute("height", `${unscaledHeight}px`);
19689
- svg.setAttribute("viewBox", `0 0 ${unscaledWidth} ${unscaledHeight}`);
19690
- svg.setAttribute("style", "position: absolute; overflow: visible;");
19691
- const pathElement = documentFactory.createElementNS("http://www.w3.org/2000/svg", "path");
19692
- pathElement.setAttribute("d", this.getPathData());
19693
- pathElement.setAttribute("stroke", this.borderColor);
19694
- pathElement.setAttribute("stroke-width", `${this.strokeWidth}`);
19695
- pathElement.setAttribute("fill", "none");
19696
- svg.appendChild(pathElement);
19697
- div.appendChild(svg);
19698
- div.id = this.getId();
19699
- div.style.width = unscaledWidth + "px";
19700
- div.style.height = unscaledHeight + "px";
19701
- div.style.transformOrigin = "left top";
19702
- div.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
19703
- div.style.position = "absolute";
19704
- div.setAttribute("data-link-to", this.linkTo.serialize() || "");
19705
- if (this.getLinkTo()) {
19706
- const linkElement = this.linkTo.renderHTML(documentFactory);
19707
- scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
19708
- translateElementBy(linkElement, (width - parseInt(linkElement.style.width)) / scaleX, 0);
19709
- div.appendChild(linkElement);
19710
- }
19711
- return div;
19712
- }
19713
- getPathData() {
19714
- const points = this.points;
19715
- if (points.length < 2) {
19716
- return "";
19717
- }
19718
- let pathData = `M ${points[0].x} ${points[0].y}`;
19719
- if (points.length < 3) {
19720
- pathData += ` L ${points[0].x + 0.5} ${points[0].y}`;
19721
- } else {
19722
- let j = 1;
19723
- for (;j < points.length - 2; j++) {
19724
- const cx = (points[j].x + points[j + 1].x) / 2;
19725
- const cy = (points[j].y + points[j + 1].y) / 2;
19726
- pathData += ` Q ${points[j].x} ${points[j].y} ${cx} ${cy}`;
19727
- }
19728
- const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
19729
- const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
19730
- pathData += ` Q ${points[j].x} ${points[j].y} ${x} ${y}`;
19731
- }
19732
- return pathData;
19733
- }
19734
- getPath() {
19735
- const { left, top, right, bottom } = this.getMbr();
19736
- const leftTop = new Point(left, top);
19737
- const rightTop = new Point(right, top);
19738
- const rightBottom = new Point(right, bottom);
19739
- const leftBottom = new Point(left, bottom);
19740
- return new Path([
19741
- new Line(leftTop, rightTop),
19742
- new Line(rightTop, rightBottom),
19743
- new Line(rightBottom, leftBottom),
19744
- new Line(leftBottom, leftTop)
19745
- ], true);
19746
- }
19747
- getSnapAnchorPoints() {
19748
- const mbr = this.getMbr();
19749
- const width = mbr.getWidth();
19750
- const height = mbr.getHeight();
19751
- return [
19752
- new Point(mbr.left + width / 2, mbr.top),
19753
- new Point(mbr.left + width / 2, mbr.bottom),
19754
- new Point(mbr.left, mbr.top + height / 2),
19755
- new Point(mbr.right, mbr.top + height / 2)
19756
- ];
19757
- }
19758
- getLines() {
19759
- return this.lines;
19760
- }
19761
- isClosed() {
19762
- return true;
19763
- }
19764
- isEnclosedOrCrossedBy(rect) {
19765
- for (const line of this.lines) {
19766
- if (line.isEnclosedOrCrossedBy(rect)) {
19767
- return true;
19768
- }
19769
- }
19770
- return false;
19771
- }
19772
- emit(operation) {
19773
- if (this.events) {
19774
- const command = new DrawingCommand([this], operation);
19775
- command.apply();
19776
- this.events.emit(operation, command);
19777
- } else {
19778
- this.apply(operation);
19779
- }
19780
- }
19781
- apply(op) {
19782
- switch (op.class) {
19783
- case "Drawing":
19784
- switch (op.method) {
19785
- case "setStrokeColor":
19786
- this.borderColor = op.color;
19787
- break;
19788
- case "setStrokeWidth":
19789
- this.strokeWidth = op.width;
19790
- this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
19791
- break;
19792
- case "setStrokeOpacity":
19793
- this.borderOpacity = op.opacity;
19794
- break;
19795
- case "setStrokeStyle":
19796
- this.borderStyle = op.style;
19797
- this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
19798
- break;
19799
- }
19800
- this.updateMbr();
19801
- break;
19802
- case "Transformation":
19803
- this.transformation.apply(op);
19804
- break;
19805
- case "LinkTo":
19806
- this.linkTo.apply(op);
19807
- break;
19808
- default:
19809
- return;
19810
- }
19811
- this.subject.publish(this);
19812
- }
19813
- setStrokeOpacity(opacity) {
19814
- this.emit({
19815
- class: "Drawing",
19816
- method: "setStrokeOpacity",
19817
- item: [this.id],
19818
- opacity
19819
- });
19820
- return this;
19821
- }
19822
- getStrokeOpacity() {
19823
- return this.borderOpacity;
19824
- }
19825
- setBorderStyle(style) {
19826
- this.emit({
19827
- class: "Drawing",
19828
- method: "setStrokeStyle",
19829
- item: [this.id],
19830
- style
19831
- });
19832
- return this;
19833
- }
19834
- getBorderStyle() {
19835
- return this.borderStyle;
19836
- }
19837
- setStrokeColor(color) {
19838
- this.emit({
19839
- class: "Drawing",
19840
- method: "setStrokeColor",
19841
- item: [this.id],
19842
- color
19843
- });
19844
- return this;
19845
- }
19846
- getStrokeColor() {
19847
- return this.borderColor;
19848
- }
19849
- setStrokeWidth(width) {
19850
- this.emit({
19851
- class: "Drawing",
19852
- method: "setStrokeWidth",
19853
- item: [this.id],
19854
- width,
19855
- prevWidth: this.strokeWidth
19856
- });
19857
- return this;
19858
- }
19859
- getLinkTo() {
19860
- return this.linkTo.link;
19861
- }
19862
- getStrokeWidth() {
19863
- return this.strokeWidth;
19864
- }
19865
- getRichText() {
19866
- return null;
19867
- }
19868
- isPointNearLine(point3, threshold = 10) {
19869
- const transformedMouseX = (point3.x - this.transformation.matrix.translateX) / this.transformation.matrix.scaleX;
19870
- const transformedMouseY = (point3.y - this.transformation.matrix.translateY) / this.transformation.matrix.scaleY;
19871
- const transformedMouse = new Point(transformedMouseX, transformedMouseY);
19872
- for (let i = 0;i < this.points.length - 1; i++) {
19873
- const p1 = this.points[i];
19874
- const p2 = this.points[i + 1];
19875
- const distance = getPerpendicularDistance(transformedMouse, p1, p2);
19876
- if (distance < threshold) {
19877
- return true;
19878
- }
19879
- }
19880
- return false;
19881
- }
19882
- }
19883
- function getPerpendicularDistance(point3, lineStart, lineEnd) {
19884
- const { x: px, y: py } = point3;
19885
- const { x: sx, y: sy } = lineStart;
19886
- const { x: ex, y: ey } = lineEnd;
19887
- const numerator = Math.abs((ey - sy) * px - (ex - sx) * py + ex * sy - ey * sx);
19888
- const denominator = Math.sqrt(Math.pow(ey - sy, 2) + Math.pow(ex - sx, 2));
19889
- return numerator / denominator;
19890
- }
19891
- function douglasPeucker(points, epsilon2) {
19892
- if (points.length < 3) {
19893
- return points;
19894
- }
19895
- const start = points[0];
19896
- const end = points[points.length - 1];
19897
- let maxDistance = 0;
19898
- let maxIndex = 0;
19899
- for (let i = 1;i < points.length - 1; i++) {
19900
- const distance = getPerpendicularDistance(points[i], start, end);
19901
- if (distance > maxDistance) {
19902
- maxDistance = distance;
19903
- maxIndex = i;
19904
- }
19905
- }
19906
- if (maxDistance > epsilon2) {
19907
- const leftSubPoints = points.slice(0, maxIndex + 1);
19908
- const rightSubPoints = points.slice(maxIndex);
19909
- const leftRecursiveResult = douglasPeucker(leftSubPoints, epsilon2);
19910
- const rightRecursiveResult = douglasPeucker(rightSubPoints, epsilon2);
19911
- return leftRecursiveResult.slice(0, -1).concat(rightRecursiveResult);
19912
- } else {
19913
- return [start, end];
19914
- }
19915
- }
19916
19489
  // src/SpatialIndex/LayeredIndex/Layers.ts
19917
19490
  class Layers {
19918
19491
  getNewLayer;
@@ -21147,6 +20720,7 @@ class SpatialIndex {
21147
20720
  }
21148
20721
  });
21149
20722
  });
20723
+ console.log([...items, ...children]);
21150
20724
  return [...items, ...children];
21151
20725
  }
21152
20726
  getEnclosedOrCrossed(left, top, right, bottom) {
@@ -21161,6 +20735,7 @@ class SpatialIndex {
21161
20735
  }
21162
20736
  });
21163
20737
  });
20738
+ console.log([...items, ...children]);
21164
20739
  return [...items, ...children];
21165
20740
  }
21166
20741
  getUnderPoint(point3, tolerance = 5) {
@@ -21174,6 +20749,7 @@ class SpatialIndex {
21174
20749
  }
21175
20750
  });
21176
20751
  });
20752
+ console.log([...items, ...children]);
21177
20753
  return [...items, ...children];
21178
20754
  }
21179
20755
  getRectsEnclosedOrCrossed(left, top, right, bottom) {
@@ -21188,6 +20764,7 @@ class SpatialIndex {
21188
20764
  }
21189
20765
  });
21190
20766
  });
20767
+ console.log([...items, ...children]);
21191
20768
  return [...items, ...children];
21192
20769
  }
21193
20770
  getItemsEnclosedOrCrossed(left, top, right, bottom) {
@@ -21207,9 +20784,11 @@ class SpatialIndex {
21207
20784
  distance: point3.getDistance(item.getMbr().getCenter())
21208
20785
  })).filter(({ distance }) => distance <= maxDistance);
21209
20786
  withDistance.sort((a, b) => a.distance - b.distance);
20787
+ console.log(withDistance.slice(0, maxItems).map(({ item }) => item));
21210
20788
  return withDistance.slice(0, maxItems).map(({ item }) => item);
21211
20789
  }
21212
20790
  list() {
20791
+ console.log("list", this.getItemsWithIncludedChildren(this.itemsArray).concat());
21213
20792
  return this.getItemsWithIncludedChildren(this.itemsArray).concat();
21214
20793
  }
21215
20794
  getZIndex(item) {
@@ -21302,12 +20881,12 @@ class Items {
21302
20881
  if (enclosed.length === 0) {
21303
20882
  enclosed = underPointer;
21304
20883
  }
21305
- if (underPointer.some((item) => item instanceof Drawing)) {
20884
+ if (underPointer.some((item) => item.itemType === "Drawing")) {
21306
20885
  enclosed = [...underPointer, ...enclosed];
21307
20886
  }
21308
20887
  const { nearest } = enclosed.reduce((acc, item) => {
21309
20888
  const area = item.getMbr().getHeight() * item.getMbr().getWidth();
21310
- if (item instanceof Drawing && !item.isPointNearLine(this.pointer.point)) {
20889
+ if (item.itemType === "Drawing" && !item.isPointNearLine(this.pointer.point)) {
21311
20890
  return acc;
21312
20891
  }
21313
20892
  const isItemTransparent = item instanceof Shape && item?.getBackgroundColor() === "none";
@@ -21580,6 +21159,7 @@ class SimpleSpatialIndex {
21580
21159
  items.push(item);
21581
21160
  }
21582
21161
  });
21162
+ console.log("simple", items);
21583
21163
  return items;
21584
21164
  }
21585
21165
  getEnclosedOrCrossed(left, top, right, bottom) {
@@ -21590,6 +21170,7 @@ class SimpleSpatialIndex {
21590
21170
  items.push(item);
21591
21171
  }
21592
21172
  });
21173
+ console.log("simple", items);
21593
21174
  return items;
21594
21175
  }
21595
21176
  getUnderPoint(point3, tolerace = 5) {
@@ -21599,12 +21180,14 @@ class SimpleSpatialIndex {
21599
21180
  items.push(item);
21600
21181
  }
21601
21182
  });
21183
+ console.log("simple", items);
21602
21184
  return items;
21603
21185
  }
21604
21186
  getMbr() {
21605
21187
  return this.Mbr;
21606
21188
  }
21607
21189
  list() {
21190
+ console.log("simple list", this.itemsArray.concat());
21608
21191
  return this.itemsArray.concat();
21609
21192
  }
21610
21193
  getZIndex(item) {
@@ -42192,202 +41775,455 @@ class Placeholder extends BaseItem {
42192
41775
  renderHTML(documentFactory) {
42193
41776
  return documentFactory.createElement("div");
42194
41777
  }
42195
- getLinkTo() {
42196
- return;
41778
+ getLinkTo() {
41779
+ return;
41780
+ }
41781
+ getRichText() {
41782
+ return null;
41783
+ }
41784
+ }
41785
+ // src/Items/Image/Image.ts
41786
+ function getPlaceholderImage(board, imageDimension) {
41787
+ const placeholderCanvas = conf.documentFactory.createElement("canvas");
41788
+ const placeholderContext = placeholderCanvas.getContext("2d");
41789
+ const context = new DrawingContext(board.camera, placeholderContext);
41790
+ const placeholder = new Placeholder(board);
41791
+ if (imageDimension) {
41792
+ placeholderCanvas.width = imageDimension.width;
41793
+ placeholderCanvas.height = imageDimension.height;
41794
+ placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
41795
+ } else {
41796
+ placeholderCanvas.width = 250;
41797
+ placeholderCanvas.height = 50;
41798
+ placeholder.transformation.scaleTo(250 / 100, 50 / 100);
41799
+ }
41800
+ const placeholderImage = new Image;
41801
+ placeholderImage.src = placeholderCanvas.toDataURL();
41802
+ return placeholderImage;
41803
+ }
41804
+
41805
+ class ImageItem extends BaseItem {
41806
+ events;
41807
+ itemType = "Image";
41808
+ parent = "Board";
41809
+ image;
41810
+ transformation;
41811
+ linkTo;
41812
+ subject = new Subject;
41813
+ loadCallbacks = [];
41814
+ beforeLoadCallbacks = [];
41815
+ transformationRenderBlock = undefined;
41816
+ storageLink;
41817
+ imageDimension;
41818
+ board;
41819
+ constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
41820
+ super(board, id);
41821
+ this.events = events;
41822
+ this.linkTo = new LinkTo(this.id, events);
41823
+ this.board = board;
41824
+ this.setStorageLink(storageLink);
41825
+ this.imageDimension = imageDimension;
41826
+ this.transformation = new Transformation(id, events);
41827
+ this.image = new Image;
41828
+ this.image.crossOrigin = "anonymous";
41829
+ this.image.onload = this.onLoad;
41830
+ this.image.onerror = this.onError;
41831
+ if (typeof base64 === "string") {
41832
+ this.image.src = base64;
41833
+ }
41834
+ this.linkTo.subject.subscribe(() => {
41835
+ this.updateMbr();
41836
+ this.subject.publish(this);
41837
+ });
41838
+ this.transformation.subject.subscribe(this.onTransform);
41839
+ }
41840
+ setStorageLink(link2) {
41841
+ try {
41842
+ const url = new URL(link2);
41843
+ this.storageLink = `${window?.location.origin}${url.pathname}`;
41844
+ } catch (_) {}
41845
+ }
41846
+ getStorageId() {
41847
+ return this.storageLink.split("/").pop();
41848
+ }
41849
+ handleError = () => {
41850
+ console.error("Invalid dataUrl or image failed to load.");
41851
+ this.image = getPlaceholderImage(this.board);
41852
+ this.updateMbr();
41853
+ this.subject.publish(this);
41854
+ this.shootLoadCallbacks();
41855
+ };
41856
+ onLoad = async () => {
41857
+ this.shootBeforeLoadCallbacks();
41858
+ this.updateMbr();
41859
+ this.subject.publish(this);
41860
+ this.shootLoadCallbacks();
41861
+ };
41862
+ onError = (_error) => {
41863
+ this.image = getPlaceholderImage(this.board);
41864
+ this.updateMbr();
41865
+ this.subject.publish(this);
41866
+ this.shootLoadCallbacks();
41867
+ };
41868
+ onTransform = () => {
41869
+ this.updateMbr();
41870
+ this.subject.publish(this);
41871
+ };
41872
+ updateMbr() {
41873
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
41874
+ this.left = translateX;
41875
+ this.top = translateY;
41876
+ this.right = this.left + this.image.width * scaleX;
41877
+ this.bottom = this.top + this.image.height * scaleY;
41878
+ }
41879
+ doOnceBeforeOnLoad = (callback) => {
41880
+ this.loadCallbacks.push(callback);
41881
+ };
41882
+ doOnceOnLoad = (callback) => {
41883
+ this.loadCallbacks.push(callback);
41884
+ };
41885
+ setId(id) {
41886
+ this.id = id;
41887
+ this.transformation.setId(id);
41888
+ this.linkTo.setId(id);
41889
+ return this;
41890
+ }
41891
+ getId() {
41892
+ return this.id;
41893
+ }
41894
+ serialize() {
41895
+ return {
41896
+ itemType: "Image",
41897
+ storageLink: this.storageLink,
41898
+ imageDimension: this.imageDimension,
41899
+ transformation: this.transformation.serialize(),
41900
+ linkTo: this.linkTo.serialize()
41901
+ };
41902
+ }
41903
+ setCoordinates() {
41904
+ this.left = this.transformation.matrix.translateX;
41905
+ this.top = this.transformation.matrix.translateY;
41906
+ this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
41907
+ this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
41908
+ this.subject.publish(this);
41909
+ }
41910
+ shootBeforeLoadCallbacks() {
41911
+ while (this.beforeLoadCallbacks.length > 0) {
41912
+ this.beforeLoadCallbacks.shift()(this);
41913
+ }
41914
+ }
41915
+ shootLoadCallbacks() {
41916
+ while (this.loadCallbacks.length > 0) {
41917
+ this.loadCallbacks.shift()(this);
41918
+ }
41919
+ }
41920
+ deserialize(data) {
41921
+ if (data.transformation) {
41922
+ this.transformation.deserialize(data.transformation);
41923
+ }
41924
+ this.linkTo.deserialize(data.linkTo);
41925
+ this.image.onload = () => {
41926
+ this.setCoordinates();
41927
+ this.shootLoadCallbacks();
41928
+ };
41929
+ if (data.storageLink) {
41930
+ this.setStorageLink(data.storageLink);
41931
+ }
41932
+ if (this.image.src) {
41933
+ return this;
41934
+ }
41935
+ this.image = getPlaceholderImage(this.board, data.imageDimension);
41936
+ const storageImage = new Image;
41937
+ storageImage.onload = () => {
41938
+ this.image = storageImage;
41939
+ this.onLoad();
41940
+ };
41941
+ storageImage.onerror = this.onError;
41942
+ storageImage.src = this.storageLink;
41943
+ return this;
41944
+ }
41945
+ emit(operation) {
41946
+ if (this.events) {
41947
+ const command = new ImageCommand([this], operation);
41948
+ command.apply();
41949
+ this.events.emit(operation, command);
41950
+ } else {
41951
+ this.apply(operation);
41952
+ }
41953
+ }
41954
+ setDimensions(dim) {
41955
+ this.imageDimension = dim;
41956
+ }
41957
+ apply(op) {
41958
+ switch (op.class) {
41959
+ case "Transformation":
41960
+ this.transformation.apply(op);
41961
+ break;
41962
+ case "LinkTo":
41963
+ this.linkTo.apply(op);
41964
+ break;
41965
+ case "Image":
41966
+ if (op.data.base64) {
41967
+ this.image.src = op.data.base64;
41968
+ }
41969
+ this.setStorageLink(op.data.storageLink);
41970
+ this.setDimensions(op.data.imageDimension);
41971
+ this.subject.publish(this);
41972
+ break;
41973
+ }
41974
+ }
41975
+ render(context) {
41976
+ if (this.transformationRenderBlock) {
41977
+ return;
41978
+ }
41979
+ const ctx = context.ctx;
41980
+ ctx.save();
41981
+ this.transformation.matrix.applyToContext(ctx);
41982
+ ctx.drawImage(this.image, 0, 0);
41983
+ ctx.restore();
41984
+ if (this.getLinkTo()) {
41985
+ const { top, right } = this.getMbr();
41986
+ this.linkTo.render(context, top, right, this.board.camera.getScale());
41987
+ }
41988
+ }
41989
+ renderHTML(documentFactory) {
41990
+ const div = documentFactory.createElement("image-item");
41991
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
41992
+ const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
41993
+ div.style.backgroundImage = `url(${this.storageLink})`;
41994
+ div.id = this.getId();
41995
+ div.style.width = `${this.imageDimension.width}px`;
41996
+ div.style.height = `${this.imageDimension.height}px`;
41997
+ div.style.transformOrigin = "top left";
41998
+ div.style.transform = transform;
41999
+ div.style.position = "absolute";
42000
+ div.style.backgroundSize = "cover";
42001
+ div.setAttribute("data-link-to", this.linkTo.serialize() || "");
42002
+ if (this.getLinkTo()) {
42003
+ const linkElement = this.linkTo.renderHTML(documentFactory);
42004
+ scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
42005
+ translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
42006
+ div.appendChild(linkElement);
42007
+ }
42008
+ return div;
42009
+ }
42010
+ getPath() {
42011
+ const { left, top, right, bottom } = this.getMbr();
42012
+ const leftTop = new Point(left, top);
42013
+ const rightTop = new Point(right, top);
42014
+ const rightBottom = new Point(right, bottom);
42015
+ const leftBottom = new Point(left, bottom);
42016
+ return new Path([
42017
+ new Line(leftTop, rightTop),
42018
+ new Line(rightTop, rightBottom),
42019
+ new Line(rightBottom, leftBottom),
42020
+ new Line(leftBottom, leftTop)
42021
+ ], true);
42022
+ }
42023
+ getSnapAnchorPoints() {
42024
+ const mbr = this.getMbr();
42025
+ const width2 = mbr.getWidth();
42026
+ const height2 = mbr.getHeight();
42027
+ return [
42028
+ new Point(mbr.left + width2 / 2, mbr.top),
42029
+ new Point(mbr.left + width2 / 2, mbr.bottom),
42030
+ new Point(mbr.left, mbr.top + height2 / 2),
42031
+ new Point(mbr.right, mbr.top + height2 / 2)
42032
+ ];
42033
+ }
42034
+ isClosed() {
42035
+ return true;
42197
42036
  }
42198
42037
  getRichText() {
42199
42038
  return null;
42200
42039
  }
42040
+ getLinkTo() {
42041
+ return this.linkTo.link;
42042
+ }
42043
+ download() {
42044
+ const linkElem = document.createElement("a");
42045
+ linkElem.href = this.storageLink;
42046
+ linkElem.setAttribute("download", "");
42047
+ linkElem.click();
42048
+ }
42049
+ onRemove() {
42050
+ const storageId = this.getStorageId();
42051
+ if (storageId) {
42052
+ conf.hooks.beforeMediaRemove([storageId], this.board.getBoardId());
42053
+ }
42054
+ super.onRemove();
42055
+ }
42201
42056
  }
42202
- // src/Items/Image/Image.ts
42203
- function getPlaceholderImage(board, imageDimension) {
42204
- const placeholderCanvas = conf.documentFactory.createElement("canvas");
42205
- const placeholderContext = placeholderCanvas.getContext("2d");
42206
- const context = new DrawingContext(board.camera, placeholderContext);
42207
- const placeholder = new Placeholder(board);
42208
- if (imageDimension) {
42209
- placeholderCanvas.width = imageDimension.width;
42210
- placeholderCanvas.height = imageDimension.height;
42211
- placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
42212
- } else {
42213
- placeholderCanvas.width = 250;
42214
- placeholderCanvas.height = 50;
42215
- placeholder.transformation.scaleTo(250 / 100, 50 / 100);
42057
+ // src/isSafari.ts
42058
+ function isSafari() {
42059
+ if (typeof navigator === "undefined") {
42060
+ return false;
42216
42061
  }
42217
- const placeholderImage = new Image;
42218
- placeholderImage.src = placeholderCanvas.toDataURL();
42219
- return placeholderImage;
42062
+ const agent = navigator.userAgent;
42063
+ const vendor = navigator.vendor;
42064
+ const is2 = vendor !== undefined && vendor.includes("Apple") && agent !== undefined && !agent.includes("CriOS") && !agent.includes("FxiOS");
42065
+ return is2;
42220
42066
  }
42221
42067
 
42222
- class ImageItem extends BaseItem {
42068
+ // src/Items/Drawing/Drawing.ts
42069
+ class Drawing extends BaseItem {
42070
+ points;
42223
42071
  events;
42224
- itemType = "Image";
42072
+ itemType = "Drawing";
42225
42073
  parent = "Board";
42226
- image;
42227
42074
  transformation;
42228
- linkTo;
42075
+ path2d = new conf.path2DFactory;
42229
42076
  subject = new Subject;
42230
- loadCallbacks = [];
42231
- beforeLoadCallbacks = [];
42077
+ untransformedMbr = new Mbr;
42078
+ lines = [];
42079
+ linkTo;
42080
+ strokeWidth = 1;
42081
+ borderStyle = "solid";
42082
+ linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
42083
+ borderOpacity = 1;
42232
42084
  transformationRenderBlock = undefined;
42233
- storageLink;
42234
- imageDimension;
42235
- board;
42236
- constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
42085
+ constructor(board, points, events, id = "") {
42237
42086
  super(board, id);
42087
+ this.points = points;
42238
42088
  this.events = events;
42239
- this.linkTo = new LinkTo(this.id, events);
42240
- this.board = board;
42241
- this.setStorageLink(storageLink);
42242
- this.imageDimension = imageDimension;
42243
42089
  this.transformation = new Transformation(id, events);
42244
- this.image = new Image;
42245
- this.image.crossOrigin = "anonymous";
42246
- this.image.onload = this.onLoad;
42247
- this.image.onerror = this.onError;
42248
- if (typeof base64 === "string") {
42249
- this.image.src = base64;
42250
- }
42090
+ this.linkTo = new LinkTo(this.id, this.events);
42091
+ this.transformation.subject.subscribe(() => {
42092
+ this.updateMbr();
42093
+ this.updateLines();
42094
+ this.subject.publish(this);
42095
+ });
42251
42096
  this.linkTo.subject.subscribe(() => {
42252
42097
  this.updateMbr();
42098
+ this.updateLines();
42253
42099
  this.subject.publish(this);
42254
42100
  });
42255
- this.transformation.subject.subscribe(this.onTransform);
42256
- }
42257
- setStorageLink(link2) {
42258
- try {
42259
- const url = new URL(link2);
42260
- this.storageLink = `${window?.location.origin}${url.pathname}`;
42261
- } catch (_) {}
42262
- }
42263
- getStorageId() {
42264
- return this.storageLink.split("/").pop();
42265
- }
42266
- handleError = () => {
42267
- console.error("Invalid dataUrl or image failed to load.");
42268
- this.image = getPlaceholderImage(this.board);
42269
- this.updateMbr();
42270
- this.subject.publish(this);
42271
- this.shootLoadCallbacks();
42272
- };
42273
- onLoad = async () => {
42274
- this.shootBeforeLoadCallbacks();
42275
- this.updateMbr();
42276
- this.subject.publish(this);
42277
- this.shootLoadCallbacks();
42278
- };
42279
- onError = (_error) => {
42280
- this.image = getPlaceholderImage(this.board);
42281
- this.updateMbr();
42282
- this.subject.publish(this);
42283
- this.shootLoadCallbacks();
42284
- };
42285
- onTransform = () => {
42286
- this.updateMbr();
42287
- this.subject.publish(this);
42288
- };
42289
- updateMbr() {
42290
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42291
- this.left = translateX;
42292
- this.top = translateY;
42293
- this.right = this.left + this.image.width * scaleX;
42294
- this.bottom = this.top + this.image.height * scaleY;
42295
- }
42296
- doOnceBeforeOnLoad = (callback) => {
42297
- this.loadCallbacks.push(callback);
42298
- };
42299
- doOnceOnLoad = (callback) => {
42300
- this.loadCallbacks.push(callback);
42301
- };
42302
- setId(id) {
42303
- this.id = id;
42304
- this.transformation.setId(id);
42305
- this.linkTo.setId(id);
42306
- return this;
42307
- }
42308
- getId() {
42309
- return this.id;
42101
+ this.updateLines();
42310
42102
  }
42311
42103
  serialize() {
42104
+ this.optimizePoints();
42105
+ const points = [];
42106
+ for (const point5 of this.points) {
42107
+ points.push({ x: point5.x, y: point5.y });
42108
+ }
42312
42109
  return {
42313
- itemType: "Image",
42314
- storageLink: this.storageLink,
42315
- imageDimension: this.imageDimension,
42110
+ itemType: "Drawing",
42111
+ points,
42316
42112
  transformation: this.transformation.serialize(),
42113
+ strokeStyle: this.borderColor,
42114
+ strokeWidth: this.strokeWidth,
42317
42115
  linkTo: this.linkTo.serialize()
42318
42116
  };
42319
42117
  }
42320
- setCoordinates() {
42321
- this.left = this.transformation.matrix.translateX;
42322
- this.top = this.transformation.matrix.translateY;
42323
- this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
42324
- this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
42325
- this.subject.publish(this);
42326
- }
42327
- shootBeforeLoadCallbacks() {
42328
- while (this.beforeLoadCallbacks.length > 0) {
42329
- this.beforeLoadCallbacks.shift()(this);
42118
+ deserialize(data) {
42119
+ this.points = [];
42120
+ for (const point5 of data.points) {
42121
+ this.points.push(new Point(point5.x, point5.y));
42330
42122
  }
42123
+ this.linkTo.deserialize(data.linkTo);
42124
+ this.optimizePoints();
42125
+ this.transformation.deserialize(data.transformation);
42126
+ this.borderColor = data.strokeStyle;
42127
+ this.strokeWidth = data.strokeWidth;
42128
+ this.updateGeometry();
42129
+ return this;
42331
42130
  }
42332
- shootLoadCallbacks() {
42333
- while (this.loadCallbacks.length > 0) {
42334
- this.loadCallbacks.shift()(this);
42335
- }
42131
+ updateGeometry() {
42132
+ this.updatePath2d();
42133
+ this.updateLines();
42134
+ this.updateMbr();
42336
42135
  }
42337
- deserialize(data) {
42338
- if (data.transformation) {
42339
- this.transformation.deserialize(data.transformation);
42136
+ updateMbr() {
42137
+ const offset = this.getStrokeWidth() / 2;
42138
+ const untransformedMbr = this.untransformedMbr.copy();
42139
+ untransformedMbr.left -= offset;
42140
+ untransformedMbr.top -= offset;
42141
+ untransformedMbr.right += offset;
42142
+ untransformedMbr.bottom += offset;
42143
+ const mbr = untransformedMbr.getTransformed(this.transformation.matrix);
42144
+ this.left = mbr.left;
42145
+ this.top = mbr.top;
42146
+ this.right = mbr.right;
42147
+ this.bottom = mbr.bottom;
42148
+ }
42149
+ updatePath2d() {
42150
+ this.path2d = new conf.path2DFactory;
42151
+ const context = this.path2d;
42152
+ const points = this.points;
42153
+ if (points.length < 3) {
42154
+ context.arc(points[0].x, points[0].y, 0.5, 0, Math.PI * 2, true);
42155
+ context.closePath();
42156
+ } else {
42157
+ context.moveTo(points[0].x, points[0].y);
42158
+ let j = 1;
42159
+ for (;j < points.length - 2; j++) {
42160
+ const cx = (points[j].x + points[j + 1].x) / 2;
42161
+ const cy = (points[j].y + points[j + 1].y) / 2;
42162
+ context.quadraticCurveTo(points[j].x, points[j].y, cx, cy);
42163
+ }
42164
+ const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
42165
+ const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
42166
+ context.quadraticCurveTo(points[j].x, points[j].y, x, y);
42340
42167
  }
42341
- this.linkTo.deserialize(data.linkTo);
42342
- this.image.onload = () => {
42343
- this.setCoordinates();
42344
- this.shootLoadCallbacks();
42345
- };
42346
- if (data.storageLink) {
42347
- this.setStorageLink(data.storageLink);
42168
+ let left = Number.MAX_SAFE_INTEGER;
42169
+ let right = Number.MIN_SAFE_INTEGER;
42170
+ let top = Number.MAX_SAFE_INTEGER;
42171
+ let bottom = Number.MIN_SAFE_INTEGER;
42172
+ for (const { x, y } of this.points) {
42173
+ if (x < left) {
42174
+ left = x;
42175
+ }
42176
+ if (x > right) {
42177
+ right = x;
42178
+ }
42179
+ if (y < top) {
42180
+ top = y;
42181
+ }
42182
+ if (y > bottom) {
42183
+ bottom = y;
42184
+ }
42348
42185
  }
42349
- if (this.image.src) {
42350
- return this;
42186
+ this.untransformedMbr = new Mbr(left, top, right, bottom);
42187
+ }
42188
+ updateLines() {
42189
+ this.lines = [];
42190
+ const matrix = this.transformation.matrix;
42191
+ if (this.points.length < 2) {
42192
+ return;
42193
+ }
42194
+ for (let i = 0;i < this.points.length - 2; i++) {
42195
+ const p1 = this.points[i];
42196
+ const p22 = this.points[i + 1];
42197
+ const line = new Line(p1.copy(), p22.copy());
42198
+ line.transform(matrix);
42199
+ this.lines.push(line);
42351
42200
  }
42352
- this.image = getPlaceholderImage(this.board, data.imageDimension);
42353
- const storageImage = new Image;
42354
- storageImage.onload = () => {
42355
- this.image = storageImage;
42356
- this.onLoad();
42357
- };
42358
- storageImage.onerror = this.onError;
42359
- storageImage.src = this.storageLink;
42360
- return this;
42361
42201
  }
42362
- emit(operation) {
42363
- if (this.events) {
42364
- const command = new ImageCommand([this], operation);
42365
- command.apply();
42366
- this.events.emit(operation, command);
42202
+ optimizePoints() {
42203
+ const dp = douglasPeucker(this.points, 1);
42204
+ dp.push(this.points[this.points.length - 1]);
42205
+ this.points = dp;
42206
+ }
42207
+ addPoint(point5) {
42208
+ const previous2 = this.points[this.points.length - 1];
42209
+ if (previous2) {
42210
+ const distance = point5.getDistance(previous2);
42211
+ if (distance >= 2) {
42212
+ this.points.push(point5);
42213
+ }
42367
42214
  } else {
42368
- this.apply(operation);
42215
+ this.points.push(point5);
42369
42216
  }
42217
+ this.updateGeometry();
42370
42218
  }
42371
- setDimensions(dim) {
42372
- this.imageDimension = dim;
42219
+ setId(id) {
42220
+ this.id = id;
42221
+ this.transformation.setId(id);
42222
+ this.linkTo.setId(id);
42223
+ return this;
42373
42224
  }
42374
- apply(op) {
42375
- switch (op.class) {
42376
- case "Transformation":
42377
- this.transformation.apply(op);
42378
- break;
42379
- case "LinkTo":
42380
- this.linkTo.apply(op);
42381
- break;
42382
- case "Image":
42383
- if (op.data.base64) {
42384
- this.image.src = op.data.base64;
42385
- }
42386
- this.setStorageLink(op.data.storageLink);
42387
- this.setDimensions(op.data.imageDimension);
42388
- this.subject.publish(this);
42389
- break;
42390
- }
42225
+ getId() {
42226
+ return this.id;
42391
42227
  }
42392
42228
  render(context) {
42393
42229
  if (this.transformationRenderBlock) {
@@ -42395,8 +42231,12 @@ class ImageItem extends BaseItem {
42395
42231
  }
42396
42232
  const ctx = context.ctx;
42397
42233
  ctx.save();
42234
+ ctx.strokeStyle = this.borderColor;
42235
+ ctx.lineWidth = this.strokeWidth;
42236
+ ctx.lineCap = "round";
42237
+ ctx.setLineDash(this.linePattern);
42398
42238
  this.transformation.matrix.applyToContext(ctx);
42399
- ctx.drawImage(this.image, 0, 0);
42239
+ ctx.stroke(this.path2d.nativePath);
42400
42240
  ctx.restore();
42401
42241
  if (this.getLinkTo()) {
42402
42242
  const { top, right } = this.getMbr();
@@ -42404,26 +42244,61 @@ class ImageItem extends BaseItem {
42404
42244
  }
42405
42245
  }
42406
42246
  renderHTML(documentFactory) {
42407
- const div = documentFactory.createElement("image-item");
42247
+ const div = documentFactory.createElement("drawing-item");
42408
42248
  const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42409
- const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
42410
- div.style.backgroundImage = `url(${this.storageLink})`;
42249
+ const mbr = this.getMbr();
42250
+ const width2 = mbr.getWidth();
42251
+ const height2 = mbr.getHeight();
42252
+ const unscaledWidth = width2 / scaleX;
42253
+ const unscaledHeight = height2 / scaleY;
42254
+ const svg3 = documentFactory.createElementNS("http://www.w3.org/2000/svg", "svg");
42255
+ svg3.setAttribute("width", `${unscaledWidth}px`);
42256
+ svg3.setAttribute("height", `${unscaledHeight}px`);
42257
+ svg3.setAttribute("viewBox", `0 0 ${unscaledWidth} ${unscaledHeight}`);
42258
+ svg3.setAttribute("style", "position: absolute; overflow: visible;");
42259
+ const pathElement = documentFactory.createElementNS("http://www.w3.org/2000/svg", "path");
42260
+ pathElement.setAttribute("d", this.getPathData());
42261
+ pathElement.setAttribute("stroke", this.borderColor);
42262
+ pathElement.setAttribute("stroke-width", `${this.strokeWidth}`);
42263
+ pathElement.setAttribute("fill", "none");
42264
+ svg3.appendChild(pathElement);
42265
+ div.appendChild(svg3);
42411
42266
  div.id = this.getId();
42412
- div.style.width = `${this.imageDimension.width}px`;
42413
- div.style.height = `${this.imageDimension.height}px`;
42414
- div.style.transformOrigin = "top left";
42415
- div.style.transform = transform;
42267
+ div.style.width = unscaledWidth + "px";
42268
+ div.style.height = unscaledHeight + "px";
42269
+ div.style.transformOrigin = "left top";
42270
+ div.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
42416
42271
  div.style.position = "absolute";
42417
- div.style.backgroundSize = "cover";
42418
42272
  div.setAttribute("data-link-to", this.linkTo.serialize() || "");
42419
42273
  if (this.getLinkTo()) {
42420
42274
  const linkElement = this.linkTo.renderHTML(documentFactory);
42421
42275
  scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
42422
- translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
42276
+ translateElementBy(linkElement, (width2 - parseInt(linkElement.style.width)) / scaleX, 0);
42423
42277
  div.appendChild(linkElement);
42424
42278
  }
42425
42279
  return div;
42426
42280
  }
42281
+ getPathData() {
42282
+ const points = this.points;
42283
+ if (points.length < 2) {
42284
+ return "";
42285
+ }
42286
+ let pathData = `M ${points[0].x} ${points[0].y}`;
42287
+ if (points.length < 3) {
42288
+ pathData += ` L ${points[0].x + 0.5} ${points[0].y}`;
42289
+ } else {
42290
+ let j = 1;
42291
+ for (;j < points.length - 2; j++) {
42292
+ const cx = (points[j].x + points[j + 1].x) / 2;
42293
+ const cy = (points[j].y + points[j + 1].y) / 2;
42294
+ pathData += ` Q ${points[j].x} ${points[j].y} ${cx} ${cy}`;
42295
+ }
42296
+ const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
42297
+ const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
42298
+ pathData += ` Q ${points[j].x} ${points[j].y} ${x} ${y}`;
42299
+ }
42300
+ return pathData;
42301
+ }
42427
42302
  getPath() {
42428
42303
  const { left, top, right, bottom } = this.getMbr();
42429
42304
  const leftTop = new Point(left, top);
@@ -42448,27 +42323,162 @@ class ImageItem extends BaseItem {
42448
42323
  new Point(mbr.right, mbr.top + height2 / 2)
42449
42324
  ];
42450
42325
  }
42326
+ getLines() {
42327
+ return this.lines;
42328
+ }
42451
42329
  isClosed() {
42452
42330
  return true;
42453
42331
  }
42454
- getRichText() {
42455
- return null;
42332
+ isEnclosedOrCrossedBy(rect) {
42333
+ for (const line of this.lines) {
42334
+ if (line.isEnclosedOrCrossedBy(rect)) {
42335
+ return true;
42336
+ }
42337
+ }
42338
+ return false;
42339
+ }
42340
+ emit(operation) {
42341
+ if (this.events) {
42342
+ const command = new DrawingCommand([this], operation);
42343
+ command.apply();
42344
+ this.events.emit(operation, command);
42345
+ } else {
42346
+ this.apply(operation);
42347
+ }
42348
+ }
42349
+ apply(op) {
42350
+ switch (op.class) {
42351
+ case "Drawing":
42352
+ switch (op.method) {
42353
+ case "setStrokeColor":
42354
+ this.borderColor = op.color;
42355
+ break;
42356
+ case "setStrokeWidth":
42357
+ this.strokeWidth = op.width;
42358
+ this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
42359
+ break;
42360
+ case "setStrokeOpacity":
42361
+ this.borderOpacity = op.opacity;
42362
+ break;
42363
+ case "setStrokeStyle":
42364
+ this.borderStyle = op.style;
42365
+ this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
42366
+ break;
42367
+ }
42368
+ this.updateMbr();
42369
+ break;
42370
+ case "Transformation":
42371
+ this.transformation.apply(op);
42372
+ break;
42373
+ case "LinkTo":
42374
+ this.linkTo.apply(op);
42375
+ break;
42376
+ default:
42377
+ return;
42378
+ }
42379
+ this.subject.publish(this);
42380
+ }
42381
+ setStrokeOpacity(opacity) {
42382
+ this.emit({
42383
+ class: "Drawing",
42384
+ method: "setStrokeOpacity",
42385
+ item: [this.id],
42386
+ opacity
42387
+ });
42388
+ return this;
42389
+ }
42390
+ getStrokeOpacity() {
42391
+ return this.borderOpacity;
42392
+ }
42393
+ setBorderStyle(style2) {
42394
+ this.emit({
42395
+ class: "Drawing",
42396
+ method: "setStrokeStyle",
42397
+ item: [this.id],
42398
+ style: style2
42399
+ });
42400
+ return this;
42401
+ }
42402
+ getBorderStyle() {
42403
+ return this.borderStyle;
42404
+ }
42405
+ setStrokeColor(color2) {
42406
+ this.emit({
42407
+ class: "Drawing",
42408
+ method: "setStrokeColor",
42409
+ item: [this.id],
42410
+ color: color2
42411
+ });
42412
+ return this;
42413
+ }
42414
+ getStrokeColor() {
42415
+ return this.borderColor;
42416
+ }
42417
+ setStrokeWidth(width2) {
42418
+ this.emit({
42419
+ class: "Drawing",
42420
+ method: "setStrokeWidth",
42421
+ item: [this.id],
42422
+ width: width2,
42423
+ prevWidth: this.strokeWidth
42424
+ });
42425
+ return this;
42456
42426
  }
42457
42427
  getLinkTo() {
42458
42428
  return this.linkTo.link;
42459
42429
  }
42460
- download() {
42461
- const linkElem = document.createElement("a");
42462
- linkElem.href = this.storageLink;
42463
- linkElem.setAttribute("download", "");
42464
- linkElem.click();
42430
+ getStrokeWidth() {
42431
+ return this.strokeWidth;
42465
42432
  }
42466
- onRemove() {
42467
- const storageId = this.getStorageId();
42468
- if (storageId) {
42469
- conf.hooks.beforeMediaRemove([storageId], this.board.getBoardId());
42433
+ getRichText() {
42434
+ return null;
42435
+ }
42436
+ isPointNearLine(point5, threshold = 10) {
42437
+ const transformedMouseX = (point5.x - this.transformation.matrix.translateX) / this.transformation.matrix.scaleX;
42438
+ const transformedMouseY = (point5.y - this.transformation.matrix.translateY) / this.transformation.matrix.scaleY;
42439
+ const transformedMouse = new Point(transformedMouseX, transformedMouseY);
42440
+ for (let i = 0;i < this.points.length - 1; i++) {
42441
+ const p1 = this.points[i];
42442
+ const p22 = this.points[i + 1];
42443
+ const distance = getPerpendicularDistance(transformedMouse, p1, p22);
42444
+ if (distance < threshold) {
42445
+ return true;
42446
+ }
42470
42447
  }
42471
- super.onRemove();
42448
+ return false;
42449
+ }
42450
+ }
42451
+ function getPerpendicularDistance(point5, lineStart, lineEnd) {
42452
+ const { x: px, y: py } = point5;
42453
+ const { x: sx, y: sy } = lineStart;
42454
+ const { x: ex, y: ey } = lineEnd;
42455
+ const numerator = Math.abs((ey - sy) * px - (ex - sx) * py + ex * sy - ey * sx);
42456
+ const denominator = Math.sqrt(Math.pow(ey - sy, 2) + Math.pow(ex - sx, 2));
42457
+ return numerator / denominator;
42458
+ }
42459
+ function douglasPeucker(points, epsilon2) {
42460
+ if (points.length < 3) {
42461
+ return points;
42462
+ }
42463
+ const start = points[0];
42464
+ const end = points[points.length - 1];
42465
+ let maxDistance = 0;
42466
+ let maxIndex = 0;
42467
+ for (let i = 1;i < points.length - 1; i++) {
42468
+ const distance = getPerpendicularDistance(points[i], start, end);
42469
+ if (distance > maxDistance) {
42470
+ maxDistance = distance;
42471
+ maxIndex = i;
42472
+ }
42473
+ }
42474
+ if (maxDistance > epsilon2) {
42475
+ const leftSubPoints = points.slice(0, maxIndex + 1);
42476
+ const rightSubPoints = points.slice(maxIndex);
42477
+ const leftRecursiveResult = douglasPeucker(leftSubPoints, epsilon2);
42478
+ const rightRecursiveResult = douglasPeucker(rightSubPoints, epsilon2);
42479
+ return leftRecursiveResult.slice(0, -1).concat(rightRecursiveResult);
42480
+ } else {
42481
+ return [start, end];
42472
42482
  }
42473
42483
  }
42474
42484
  // src/Items/Group/Group.ts