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.
@@ -19643,433 +19643,6 @@ class NoOpCommand {
19643
19643
  }
19644
19644
  }
19645
19645
 
19646
- // src/isSafari.ts
19647
- function isSafari() {
19648
- if (typeof navigator === "undefined") {
19649
- return false;
19650
- }
19651
- const agent = navigator.userAgent;
19652
- const vendor = navigator.vendor;
19653
- const is = vendor !== undefined && vendor.includes("Apple") && agent !== undefined && !agent.includes("CriOS") && !agent.includes("FxiOS");
19654
- return is;
19655
- }
19656
-
19657
- // src/Items/Drawing/Drawing.ts
19658
- class Drawing extends BaseItem {
19659
- points;
19660
- events;
19661
- itemType = "Drawing";
19662
- parent = "Board";
19663
- transformation;
19664
- path2d = new conf.path2DFactory;
19665
- subject = new Subject;
19666
- untransformedMbr = new Mbr;
19667
- lines = [];
19668
- linkTo;
19669
- strokeWidth = 1;
19670
- borderStyle = "solid";
19671
- linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
19672
- borderOpacity = 1;
19673
- transformationRenderBlock = undefined;
19674
- constructor(board, points, events, id = "") {
19675
- super(board, id);
19676
- this.points = points;
19677
- this.events = events;
19678
- this.transformation = new Transformation(id, events);
19679
- this.linkTo = new LinkTo(this.id, this.events);
19680
- this.transformation.subject.subscribe(() => {
19681
- this.updateMbr();
19682
- this.updateLines();
19683
- this.subject.publish(this);
19684
- });
19685
- this.linkTo.subject.subscribe(() => {
19686
- this.updateMbr();
19687
- this.updateLines();
19688
- this.subject.publish(this);
19689
- });
19690
- this.updateLines();
19691
- }
19692
- serialize() {
19693
- this.optimizePoints();
19694
- const points = [];
19695
- for (const point3 of this.points) {
19696
- points.push({ x: point3.x, y: point3.y });
19697
- }
19698
- return {
19699
- itemType: "Drawing",
19700
- points,
19701
- transformation: this.transformation.serialize(),
19702
- strokeStyle: this.borderColor,
19703
- strokeWidth: this.strokeWidth,
19704
- linkTo: this.linkTo.serialize()
19705
- };
19706
- }
19707
- deserialize(data) {
19708
- this.points = [];
19709
- for (const point3 of data.points) {
19710
- this.points.push(new Point(point3.x, point3.y));
19711
- }
19712
- this.linkTo.deserialize(data.linkTo);
19713
- this.optimizePoints();
19714
- this.transformation.deserialize(data.transformation);
19715
- this.borderColor = data.strokeStyle;
19716
- this.strokeWidth = data.strokeWidth;
19717
- this.updateGeometry();
19718
- return this;
19719
- }
19720
- updateGeometry() {
19721
- this.updatePath2d();
19722
- this.updateLines();
19723
- this.updateMbr();
19724
- }
19725
- updateMbr() {
19726
- const offset = this.getStrokeWidth() / 2;
19727
- const untransformedMbr = this.untransformedMbr.copy();
19728
- untransformedMbr.left -= offset;
19729
- untransformedMbr.top -= offset;
19730
- untransformedMbr.right += offset;
19731
- untransformedMbr.bottom += offset;
19732
- const mbr = untransformedMbr.getTransformed(this.transformation.matrix);
19733
- this.left = mbr.left;
19734
- this.top = mbr.top;
19735
- this.right = mbr.right;
19736
- this.bottom = mbr.bottom;
19737
- }
19738
- updatePath2d() {
19739
- this.path2d = new conf.path2DFactory;
19740
- const context = this.path2d;
19741
- const points = this.points;
19742
- if (points.length < 3) {
19743
- context.arc(points[0].x, points[0].y, 0.5, 0, Math.PI * 2, true);
19744
- context.closePath();
19745
- } else {
19746
- context.moveTo(points[0].x, points[0].y);
19747
- let j = 1;
19748
- for (;j < points.length - 2; j++) {
19749
- const cx = (points[j].x + points[j + 1].x) / 2;
19750
- const cy = (points[j].y + points[j + 1].y) / 2;
19751
- context.quadraticCurveTo(points[j].x, points[j].y, cx, cy);
19752
- }
19753
- const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
19754
- const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
19755
- context.quadraticCurveTo(points[j].x, points[j].y, x, y);
19756
- }
19757
- let left = Number.MAX_SAFE_INTEGER;
19758
- let right = Number.MIN_SAFE_INTEGER;
19759
- let top = Number.MAX_SAFE_INTEGER;
19760
- let bottom = Number.MIN_SAFE_INTEGER;
19761
- for (const { x, y } of this.points) {
19762
- if (x < left) {
19763
- left = x;
19764
- }
19765
- if (x > right) {
19766
- right = x;
19767
- }
19768
- if (y < top) {
19769
- top = y;
19770
- }
19771
- if (y > bottom) {
19772
- bottom = y;
19773
- }
19774
- }
19775
- this.untransformedMbr = new Mbr(left, top, right, bottom);
19776
- }
19777
- updateLines() {
19778
- this.lines = [];
19779
- const matrix = this.transformation.matrix;
19780
- if (this.points.length < 2) {
19781
- return;
19782
- }
19783
- for (let i = 0;i < this.points.length - 2; i++) {
19784
- const p1 = this.points[i];
19785
- const p2 = this.points[i + 1];
19786
- const line = new Line(p1.copy(), p2.copy());
19787
- line.transform(matrix);
19788
- this.lines.push(line);
19789
- }
19790
- }
19791
- optimizePoints() {
19792
- const dp = douglasPeucker(this.points, 1);
19793
- dp.push(this.points[this.points.length - 1]);
19794
- this.points = dp;
19795
- }
19796
- addPoint(point3) {
19797
- const previous2 = this.points[this.points.length - 1];
19798
- if (previous2) {
19799
- const distance = point3.getDistance(previous2);
19800
- if (distance >= 2) {
19801
- this.points.push(point3);
19802
- }
19803
- } else {
19804
- this.points.push(point3);
19805
- }
19806
- this.updateGeometry();
19807
- }
19808
- setId(id) {
19809
- this.id = id;
19810
- this.transformation.setId(id);
19811
- this.linkTo.setId(id);
19812
- return this;
19813
- }
19814
- getId() {
19815
- return this.id;
19816
- }
19817
- render(context) {
19818
- if (this.transformationRenderBlock) {
19819
- return;
19820
- }
19821
- const ctx = context.ctx;
19822
- ctx.save();
19823
- ctx.strokeStyle = this.borderColor;
19824
- ctx.lineWidth = this.strokeWidth;
19825
- ctx.lineCap = "round";
19826
- ctx.setLineDash(this.linePattern);
19827
- this.transformation.matrix.applyToContext(ctx);
19828
- ctx.stroke(this.path2d.nativePath);
19829
- ctx.restore();
19830
- if (this.getLinkTo()) {
19831
- const { top, right } = this.getMbr();
19832
- this.linkTo.render(context, top, right, this.board.camera.getScale());
19833
- }
19834
- }
19835
- renderHTML(documentFactory) {
19836
- const div = documentFactory.createElement("drawing-item");
19837
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
19838
- const mbr = this.getMbr();
19839
- const width = mbr.getWidth();
19840
- const height = mbr.getHeight();
19841
- const unscaledWidth = width / scaleX;
19842
- const unscaledHeight = height / scaleY;
19843
- const svg = documentFactory.createElementNS("http://www.w3.org/2000/svg", "svg");
19844
- svg.setAttribute("width", `${unscaledWidth}px`);
19845
- svg.setAttribute("height", `${unscaledHeight}px`);
19846
- svg.setAttribute("viewBox", `0 0 ${unscaledWidth} ${unscaledHeight}`);
19847
- svg.setAttribute("style", "position: absolute; overflow: visible;");
19848
- const pathElement = documentFactory.createElementNS("http://www.w3.org/2000/svg", "path");
19849
- pathElement.setAttribute("d", this.getPathData());
19850
- pathElement.setAttribute("stroke", this.borderColor);
19851
- pathElement.setAttribute("stroke-width", `${this.strokeWidth}`);
19852
- pathElement.setAttribute("fill", "none");
19853
- svg.appendChild(pathElement);
19854
- div.appendChild(svg);
19855
- div.id = this.getId();
19856
- div.style.width = unscaledWidth + "px";
19857
- div.style.height = unscaledHeight + "px";
19858
- div.style.transformOrigin = "left top";
19859
- div.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
19860
- div.style.position = "absolute";
19861
- div.setAttribute("data-link-to", this.linkTo.serialize() || "");
19862
- if (this.getLinkTo()) {
19863
- const linkElement = this.linkTo.renderHTML(documentFactory);
19864
- scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
19865
- translateElementBy(linkElement, (width - parseInt(linkElement.style.width)) / scaleX, 0);
19866
- div.appendChild(linkElement);
19867
- }
19868
- return div;
19869
- }
19870
- getPathData() {
19871
- const points = this.points;
19872
- if (points.length < 2) {
19873
- return "";
19874
- }
19875
- let pathData = `M ${points[0].x} ${points[0].y}`;
19876
- if (points.length < 3) {
19877
- pathData += ` L ${points[0].x + 0.5} ${points[0].y}`;
19878
- } else {
19879
- let j = 1;
19880
- for (;j < points.length - 2; j++) {
19881
- const cx = (points[j].x + points[j + 1].x) / 2;
19882
- const cy = (points[j].y + points[j + 1].y) / 2;
19883
- pathData += ` Q ${points[j].x} ${points[j].y} ${cx} ${cy}`;
19884
- }
19885
- const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
19886
- const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
19887
- pathData += ` Q ${points[j].x} ${points[j].y} ${x} ${y}`;
19888
- }
19889
- return pathData;
19890
- }
19891
- getPath() {
19892
- const { left, top, right, bottom } = this.getMbr();
19893
- const leftTop = new Point(left, top);
19894
- const rightTop = new Point(right, top);
19895
- const rightBottom = new Point(right, bottom);
19896
- const leftBottom = new Point(left, bottom);
19897
- return new Path([
19898
- new Line(leftTop, rightTop),
19899
- new Line(rightTop, rightBottom),
19900
- new Line(rightBottom, leftBottom),
19901
- new Line(leftBottom, leftTop)
19902
- ], true);
19903
- }
19904
- getSnapAnchorPoints() {
19905
- const mbr = this.getMbr();
19906
- const width = mbr.getWidth();
19907
- const height = mbr.getHeight();
19908
- return [
19909
- new Point(mbr.left + width / 2, mbr.top),
19910
- new Point(mbr.left + width / 2, mbr.bottom),
19911
- new Point(mbr.left, mbr.top + height / 2),
19912
- new Point(mbr.right, mbr.top + height / 2)
19913
- ];
19914
- }
19915
- getLines() {
19916
- return this.lines;
19917
- }
19918
- isClosed() {
19919
- return true;
19920
- }
19921
- isEnclosedOrCrossedBy(rect) {
19922
- for (const line of this.lines) {
19923
- if (line.isEnclosedOrCrossedBy(rect)) {
19924
- return true;
19925
- }
19926
- }
19927
- return false;
19928
- }
19929
- emit(operation) {
19930
- if (this.events) {
19931
- const command = new DrawingCommand([this], operation);
19932
- command.apply();
19933
- this.events.emit(operation, command);
19934
- } else {
19935
- this.apply(operation);
19936
- }
19937
- }
19938
- apply(op) {
19939
- switch (op.class) {
19940
- case "Drawing":
19941
- switch (op.method) {
19942
- case "setStrokeColor":
19943
- this.borderColor = op.color;
19944
- break;
19945
- case "setStrokeWidth":
19946
- this.strokeWidth = op.width;
19947
- this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
19948
- break;
19949
- case "setStrokeOpacity":
19950
- this.borderOpacity = op.opacity;
19951
- break;
19952
- case "setStrokeStyle":
19953
- this.borderStyle = op.style;
19954
- this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
19955
- break;
19956
- }
19957
- this.updateMbr();
19958
- break;
19959
- case "Transformation":
19960
- this.transformation.apply(op);
19961
- break;
19962
- case "LinkTo":
19963
- this.linkTo.apply(op);
19964
- break;
19965
- default:
19966
- return;
19967
- }
19968
- this.subject.publish(this);
19969
- }
19970
- setStrokeOpacity(opacity) {
19971
- this.emit({
19972
- class: "Drawing",
19973
- method: "setStrokeOpacity",
19974
- item: [this.id],
19975
- opacity
19976
- });
19977
- return this;
19978
- }
19979
- getStrokeOpacity() {
19980
- return this.borderOpacity;
19981
- }
19982
- setBorderStyle(style) {
19983
- this.emit({
19984
- class: "Drawing",
19985
- method: "setStrokeStyle",
19986
- item: [this.id],
19987
- style
19988
- });
19989
- return this;
19990
- }
19991
- getBorderStyle() {
19992
- return this.borderStyle;
19993
- }
19994
- setStrokeColor(color) {
19995
- this.emit({
19996
- class: "Drawing",
19997
- method: "setStrokeColor",
19998
- item: [this.id],
19999
- color
20000
- });
20001
- return this;
20002
- }
20003
- getStrokeColor() {
20004
- return this.borderColor;
20005
- }
20006
- setStrokeWidth(width) {
20007
- this.emit({
20008
- class: "Drawing",
20009
- method: "setStrokeWidth",
20010
- item: [this.id],
20011
- width,
20012
- prevWidth: this.strokeWidth
20013
- });
20014
- return this;
20015
- }
20016
- getLinkTo() {
20017
- return this.linkTo.link;
20018
- }
20019
- getStrokeWidth() {
20020
- return this.strokeWidth;
20021
- }
20022
- getRichText() {
20023
- return null;
20024
- }
20025
- isPointNearLine(point3, threshold = 10) {
20026
- const transformedMouseX = (point3.x - this.transformation.matrix.translateX) / this.transformation.matrix.scaleX;
20027
- const transformedMouseY = (point3.y - this.transformation.matrix.translateY) / this.transformation.matrix.scaleY;
20028
- const transformedMouse = new Point(transformedMouseX, transformedMouseY);
20029
- for (let i = 0;i < this.points.length - 1; i++) {
20030
- const p1 = this.points[i];
20031
- const p2 = this.points[i + 1];
20032
- const distance = getPerpendicularDistance(transformedMouse, p1, p2);
20033
- if (distance < threshold) {
20034
- return true;
20035
- }
20036
- }
20037
- return false;
20038
- }
20039
- }
20040
- function getPerpendicularDistance(point3, lineStart, lineEnd) {
20041
- const { x: px, y: py } = point3;
20042
- const { x: sx, y: sy } = lineStart;
20043
- const { x: ex, y: ey } = lineEnd;
20044
- const numerator = Math.abs((ey - sy) * px - (ex - sx) * py + ex * sy - ey * sx);
20045
- const denominator = Math.sqrt(Math.pow(ey - sy, 2) + Math.pow(ex - sx, 2));
20046
- return numerator / denominator;
20047
- }
20048
- function douglasPeucker(points, epsilon2) {
20049
- if (points.length < 3) {
20050
- return points;
20051
- }
20052
- const start = points[0];
20053
- const end = points[points.length - 1];
20054
- let maxDistance = 0;
20055
- let maxIndex = 0;
20056
- for (let i = 1;i < points.length - 1; i++) {
20057
- const distance = getPerpendicularDistance(points[i], start, end);
20058
- if (distance > maxDistance) {
20059
- maxDistance = distance;
20060
- maxIndex = i;
20061
- }
20062
- }
20063
- if (maxDistance > epsilon2) {
20064
- const leftSubPoints = points.slice(0, maxIndex + 1);
20065
- const rightSubPoints = points.slice(maxIndex);
20066
- const leftRecursiveResult = douglasPeucker(leftSubPoints, epsilon2);
20067
- const rightRecursiveResult = douglasPeucker(rightSubPoints, epsilon2);
20068
- return leftRecursiveResult.slice(0, -1).concat(rightRecursiveResult);
20069
- } else {
20070
- return [start, end];
20071
- }
20072
- }
20073
19646
  // src/SpatialIndex/LayeredIndex/Layers.ts
20074
19647
  class Layers {
20075
19648
  getNewLayer;
@@ -21304,6 +20877,7 @@ class SpatialIndex {
21304
20877
  }
21305
20878
  });
21306
20879
  });
20880
+ console.log([...items, ...children]);
21307
20881
  return [...items, ...children];
21308
20882
  }
21309
20883
  getEnclosedOrCrossed(left, top, right, bottom) {
@@ -21318,6 +20892,7 @@ class SpatialIndex {
21318
20892
  }
21319
20893
  });
21320
20894
  });
20895
+ console.log([...items, ...children]);
21321
20896
  return [...items, ...children];
21322
20897
  }
21323
20898
  getUnderPoint(point3, tolerance = 5) {
@@ -21331,6 +20906,7 @@ class SpatialIndex {
21331
20906
  }
21332
20907
  });
21333
20908
  });
20909
+ console.log([...items, ...children]);
21334
20910
  return [...items, ...children];
21335
20911
  }
21336
20912
  getRectsEnclosedOrCrossed(left, top, right, bottom) {
@@ -21345,6 +20921,7 @@ class SpatialIndex {
21345
20921
  }
21346
20922
  });
21347
20923
  });
20924
+ console.log([...items, ...children]);
21348
20925
  return [...items, ...children];
21349
20926
  }
21350
20927
  getItemsEnclosedOrCrossed(left, top, right, bottom) {
@@ -21364,9 +20941,11 @@ class SpatialIndex {
21364
20941
  distance: point3.getDistance(item.getMbr().getCenter())
21365
20942
  })).filter(({ distance }) => distance <= maxDistance);
21366
20943
  withDistance.sort((a, b) => a.distance - b.distance);
20944
+ console.log(withDistance.slice(0, maxItems).map(({ item }) => item));
21367
20945
  return withDistance.slice(0, maxItems).map(({ item }) => item);
21368
20946
  }
21369
20947
  list() {
20948
+ console.log("list", this.getItemsWithIncludedChildren(this.itemsArray).concat());
21370
20949
  return this.getItemsWithIncludedChildren(this.itemsArray).concat();
21371
20950
  }
21372
20951
  getZIndex(item) {
@@ -21459,12 +21038,12 @@ class Items {
21459
21038
  if (enclosed.length === 0) {
21460
21039
  enclosed = underPointer;
21461
21040
  }
21462
- if (underPointer.some((item) => item instanceof Drawing)) {
21041
+ if (underPointer.some((item) => item.itemType === "Drawing")) {
21463
21042
  enclosed = [...underPointer, ...enclosed];
21464
21043
  }
21465
21044
  const { nearest } = enclosed.reduce((acc, item) => {
21466
21045
  const area = item.getMbr().getHeight() * item.getMbr().getWidth();
21467
- if (item instanceof Drawing && !item.isPointNearLine(this.pointer.point)) {
21046
+ if (item.itemType === "Drawing" && !item.isPointNearLine(this.pointer.point)) {
21468
21047
  return acc;
21469
21048
  }
21470
21049
  const isItemTransparent = item instanceof Shape && item?.getBackgroundColor() === "none";
@@ -21737,6 +21316,7 @@ class SimpleSpatialIndex {
21737
21316
  items.push(item);
21738
21317
  }
21739
21318
  });
21319
+ console.log("simple", items);
21740
21320
  return items;
21741
21321
  }
21742
21322
  getEnclosedOrCrossed(left, top, right, bottom) {
@@ -21747,6 +21327,7 @@ class SimpleSpatialIndex {
21747
21327
  items.push(item);
21748
21328
  }
21749
21329
  });
21330
+ console.log("simple", items);
21750
21331
  return items;
21751
21332
  }
21752
21333
  getUnderPoint(point3, tolerace = 5) {
@@ -21756,12 +21337,14 @@ class SimpleSpatialIndex {
21756
21337
  items.push(item);
21757
21338
  }
21758
21339
  });
21340
+ console.log("simple", items);
21759
21341
  return items;
21760
21342
  }
21761
21343
  getMbr() {
21762
21344
  return this.Mbr;
21763
21345
  }
21764
21346
  list() {
21347
+ console.log("simple list", this.itemsArray.concat());
21765
21348
  return this.itemsArray.concat();
21766
21349
  }
21767
21350
  getZIndex(item) {
@@ -42349,202 +41932,455 @@ class Placeholder extends BaseItem {
42349
41932
  renderHTML(documentFactory) {
42350
41933
  return documentFactory.createElement("div");
42351
41934
  }
42352
- getLinkTo() {
42353
- return;
41935
+ getLinkTo() {
41936
+ return;
41937
+ }
41938
+ getRichText() {
41939
+ return null;
41940
+ }
41941
+ }
41942
+ // src/Items/Image/Image.ts
41943
+ function getPlaceholderImage(board, imageDimension) {
41944
+ const placeholderCanvas = conf.documentFactory.createElement("canvas");
41945
+ const placeholderContext = placeholderCanvas.getContext("2d");
41946
+ const context = new DrawingContext(board.camera, placeholderContext);
41947
+ const placeholder = new Placeholder(board);
41948
+ if (imageDimension) {
41949
+ placeholderCanvas.width = imageDimension.width;
41950
+ placeholderCanvas.height = imageDimension.height;
41951
+ placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
41952
+ } else {
41953
+ placeholderCanvas.width = 250;
41954
+ placeholderCanvas.height = 50;
41955
+ placeholder.transformation.scaleTo(250 / 100, 50 / 100);
41956
+ }
41957
+ const placeholderImage = new Image;
41958
+ placeholderImage.src = placeholderCanvas.toDataURL();
41959
+ return placeholderImage;
41960
+ }
41961
+
41962
+ class ImageItem extends BaseItem {
41963
+ events;
41964
+ itemType = "Image";
41965
+ parent = "Board";
41966
+ image;
41967
+ transformation;
41968
+ linkTo;
41969
+ subject = new Subject;
41970
+ loadCallbacks = [];
41971
+ beforeLoadCallbacks = [];
41972
+ transformationRenderBlock = undefined;
41973
+ storageLink;
41974
+ imageDimension;
41975
+ board;
41976
+ constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
41977
+ super(board, id);
41978
+ this.events = events;
41979
+ this.linkTo = new LinkTo(this.id, events);
41980
+ this.board = board;
41981
+ this.setStorageLink(storageLink);
41982
+ this.imageDimension = imageDimension;
41983
+ this.transformation = new Transformation(id, events);
41984
+ this.image = new Image;
41985
+ this.image.crossOrigin = "anonymous";
41986
+ this.image.onload = this.onLoad;
41987
+ this.image.onerror = this.onError;
41988
+ if (typeof base64 === "string") {
41989
+ this.image.src = base64;
41990
+ }
41991
+ this.linkTo.subject.subscribe(() => {
41992
+ this.updateMbr();
41993
+ this.subject.publish(this);
41994
+ });
41995
+ this.transformation.subject.subscribe(this.onTransform);
41996
+ }
41997
+ setStorageLink(link2) {
41998
+ try {
41999
+ const url = new URL(link2);
42000
+ this.storageLink = `${window?.location.origin}${url.pathname}`;
42001
+ } catch (_) {}
42002
+ }
42003
+ getStorageId() {
42004
+ return this.storageLink.split("/").pop();
42005
+ }
42006
+ handleError = () => {
42007
+ console.error("Invalid dataUrl or image failed to load.");
42008
+ this.image = getPlaceholderImage(this.board);
42009
+ this.updateMbr();
42010
+ this.subject.publish(this);
42011
+ this.shootLoadCallbacks();
42012
+ };
42013
+ onLoad = async () => {
42014
+ this.shootBeforeLoadCallbacks();
42015
+ this.updateMbr();
42016
+ this.subject.publish(this);
42017
+ this.shootLoadCallbacks();
42018
+ };
42019
+ onError = (_error) => {
42020
+ this.image = getPlaceholderImage(this.board);
42021
+ this.updateMbr();
42022
+ this.subject.publish(this);
42023
+ this.shootLoadCallbacks();
42024
+ };
42025
+ onTransform = () => {
42026
+ this.updateMbr();
42027
+ this.subject.publish(this);
42028
+ };
42029
+ updateMbr() {
42030
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42031
+ this.left = translateX;
42032
+ this.top = translateY;
42033
+ this.right = this.left + this.image.width * scaleX;
42034
+ this.bottom = this.top + this.image.height * scaleY;
42035
+ }
42036
+ doOnceBeforeOnLoad = (callback) => {
42037
+ this.loadCallbacks.push(callback);
42038
+ };
42039
+ doOnceOnLoad = (callback) => {
42040
+ this.loadCallbacks.push(callback);
42041
+ };
42042
+ setId(id) {
42043
+ this.id = id;
42044
+ this.transformation.setId(id);
42045
+ this.linkTo.setId(id);
42046
+ return this;
42047
+ }
42048
+ getId() {
42049
+ return this.id;
42050
+ }
42051
+ serialize() {
42052
+ return {
42053
+ itemType: "Image",
42054
+ storageLink: this.storageLink,
42055
+ imageDimension: this.imageDimension,
42056
+ transformation: this.transformation.serialize(),
42057
+ linkTo: this.linkTo.serialize()
42058
+ };
42059
+ }
42060
+ setCoordinates() {
42061
+ this.left = this.transformation.matrix.translateX;
42062
+ this.top = this.transformation.matrix.translateY;
42063
+ this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
42064
+ this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
42065
+ this.subject.publish(this);
42066
+ }
42067
+ shootBeforeLoadCallbacks() {
42068
+ while (this.beforeLoadCallbacks.length > 0) {
42069
+ this.beforeLoadCallbacks.shift()(this);
42070
+ }
42071
+ }
42072
+ shootLoadCallbacks() {
42073
+ while (this.loadCallbacks.length > 0) {
42074
+ this.loadCallbacks.shift()(this);
42075
+ }
42076
+ }
42077
+ deserialize(data) {
42078
+ if (data.transformation) {
42079
+ this.transformation.deserialize(data.transformation);
42080
+ }
42081
+ this.linkTo.deserialize(data.linkTo);
42082
+ this.image.onload = () => {
42083
+ this.setCoordinates();
42084
+ this.shootLoadCallbacks();
42085
+ };
42086
+ if (data.storageLink) {
42087
+ this.setStorageLink(data.storageLink);
42088
+ }
42089
+ if (this.image.src) {
42090
+ return this;
42091
+ }
42092
+ this.image = getPlaceholderImage(this.board, data.imageDimension);
42093
+ const storageImage = new Image;
42094
+ storageImage.onload = () => {
42095
+ this.image = storageImage;
42096
+ this.onLoad();
42097
+ };
42098
+ storageImage.onerror = this.onError;
42099
+ storageImage.src = this.storageLink;
42100
+ return this;
42101
+ }
42102
+ emit(operation) {
42103
+ if (this.events) {
42104
+ const command = new ImageCommand([this], operation);
42105
+ command.apply();
42106
+ this.events.emit(operation, command);
42107
+ } else {
42108
+ this.apply(operation);
42109
+ }
42110
+ }
42111
+ setDimensions(dim) {
42112
+ this.imageDimension = dim;
42113
+ }
42114
+ apply(op) {
42115
+ switch (op.class) {
42116
+ case "Transformation":
42117
+ this.transformation.apply(op);
42118
+ break;
42119
+ case "LinkTo":
42120
+ this.linkTo.apply(op);
42121
+ break;
42122
+ case "Image":
42123
+ if (op.data.base64) {
42124
+ this.image.src = op.data.base64;
42125
+ }
42126
+ this.setStorageLink(op.data.storageLink);
42127
+ this.setDimensions(op.data.imageDimension);
42128
+ this.subject.publish(this);
42129
+ break;
42130
+ }
42131
+ }
42132
+ render(context) {
42133
+ if (this.transformationRenderBlock) {
42134
+ return;
42135
+ }
42136
+ const ctx = context.ctx;
42137
+ ctx.save();
42138
+ this.transformation.matrix.applyToContext(ctx);
42139
+ ctx.drawImage(this.image, 0, 0);
42140
+ ctx.restore();
42141
+ if (this.getLinkTo()) {
42142
+ const { top, right } = this.getMbr();
42143
+ this.linkTo.render(context, top, right, this.board.camera.getScale());
42144
+ }
42145
+ }
42146
+ renderHTML(documentFactory) {
42147
+ const div = documentFactory.createElement("image-item");
42148
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42149
+ const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
42150
+ div.style.backgroundImage = `url(${this.storageLink})`;
42151
+ div.id = this.getId();
42152
+ div.style.width = `${this.imageDimension.width}px`;
42153
+ div.style.height = `${this.imageDimension.height}px`;
42154
+ div.style.transformOrigin = "top left";
42155
+ div.style.transform = transform;
42156
+ div.style.position = "absolute";
42157
+ div.style.backgroundSize = "cover";
42158
+ div.setAttribute("data-link-to", this.linkTo.serialize() || "");
42159
+ if (this.getLinkTo()) {
42160
+ const linkElement = this.linkTo.renderHTML(documentFactory);
42161
+ scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
42162
+ translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
42163
+ div.appendChild(linkElement);
42164
+ }
42165
+ return div;
42166
+ }
42167
+ getPath() {
42168
+ const { left, top, right, bottom } = this.getMbr();
42169
+ const leftTop = new Point(left, top);
42170
+ const rightTop = new Point(right, top);
42171
+ const rightBottom = new Point(right, bottom);
42172
+ const leftBottom = new Point(left, bottom);
42173
+ return new Path([
42174
+ new Line(leftTop, rightTop),
42175
+ new Line(rightTop, rightBottom),
42176
+ new Line(rightBottom, leftBottom),
42177
+ new Line(leftBottom, leftTop)
42178
+ ], true);
42179
+ }
42180
+ getSnapAnchorPoints() {
42181
+ const mbr = this.getMbr();
42182
+ const width2 = mbr.getWidth();
42183
+ const height2 = mbr.getHeight();
42184
+ return [
42185
+ new Point(mbr.left + width2 / 2, mbr.top),
42186
+ new Point(mbr.left + width2 / 2, mbr.bottom),
42187
+ new Point(mbr.left, mbr.top + height2 / 2),
42188
+ new Point(mbr.right, mbr.top + height2 / 2)
42189
+ ];
42190
+ }
42191
+ isClosed() {
42192
+ return true;
42354
42193
  }
42355
42194
  getRichText() {
42356
42195
  return null;
42357
42196
  }
42197
+ getLinkTo() {
42198
+ return this.linkTo.link;
42199
+ }
42200
+ download() {
42201
+ const linkElem = document.createElement("a");
42202
+ linkElem.href = this.storageLink;
42203
+ linkElem.setAttribute("download", "");
42204
+ linkElem.click();
42205
+ }
42206
+ onRemove() {
42207
+ const storageId = this.getStorageId();
42208
+ if (storageId) {
42209
+ conf.hooks.beforeMediaRemove([storageId], this.board.getBoardId());
42210
+ }
42211
+ super.onRemove();
42212
+ }
42358
42213
  }
42359
- // src/Items/Image/Image.ts
42360
- function getPlaceholderImage(board, imageDimension) {
42361
- const placeholderCanvas = conf.documentFactory.createElement("canvas");
42362
- const placeholderContext = placeholderCanvas.getContext("2d");
42363
- const context = new DrawingContext(board.camera, placeholderContext);
42364
- const placeholder = new Placeholder(board);
42365
- if (imageDimension) {
42366
- placeholderCanvas.width = imageDimension.width;
42367
- placeholderCanvas.height = imageDimension.height;
42368
- placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
42369
- } else {
42370
- placeholderCanvas.width = 250;
42371
- placeholderCanvas.height = 50;
42372
- placeholder.transformation.scaleTo(250 / 100, 50 / 100);
42214
+ // src/isSafari.ts
42215
+ function isSafari() {
42216
+ if (typeof navigator === "undefined") {
42217
+ return false;
42373
42218
  }
42374
- const placeholderImage = new Image;
42375
- placeholderImage.src = placeholderCanvas.toDataURL();
42376
- return placeholderImage;
42219
+ const agent = navigator.userAgent;
42220
+ const vendor = navigator.vendor;
42221
+ const is2 = vendor !== undefined && vendor.includes("Apple") && agent !== undefined && !agent.includes("CriOS") && !agent.includes("FxiOS");
42222
+ return is2;
42377
42223
  }
42378
42224
 
42379
- class ImageItem extends BaseItem {
42225
+ // src/Items/Drawing/Drawing.ts
42226
+ class Drawing extends BaseItem {
42227
+ points;
42380
42228
  events;
42381
- itemType = "Image";
42229
+ itemType = "Drawing";
42382
42230
  parent = "Board";
42383
- image;
42384
42231
  transformation;
42385
- linkTo;
42232
+ path2d = new conf.path2DFactory;
42386
42233
  subject = new Subject;
42387
- loadCallbacks = [];
42388
- beforeLoadCallbacks = [];
42234
+ untransformedMbr = new Mbr;
42235
+ lines = [];
42236
+ linkTo;
42237
+ strokeWidth = 1;
42238
+ borderStyle = "solid";
42239
+ linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
42240
+ borderOpacity = 1;
42389
42241
  transformationRenderBlock = undefined;
42390
- storageLink;
42391
- imageDimension;
42392
- board;
42393
- constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
42242
+ constructor(board, points, events, id = "") {
42394
42243
  super(board, id);
42244
+ this.points = points;
42395
42245
  this.events = events;
42396
- this.linkTo = new LinkTo(this.id, events);
42397
- this.board = board;
42398
- this.setStorageLink(storageLink);
42399
- this.imageDimension = imageDimension;
42400
42246
  this.transformation = new Transformation(id, events);
42401
- this.image = new Image;
42402
- this.image.crossOrigin = "anonymous";
42403
- this.image.onload = this.onLoad;
42404
- this.image.onerror = this.onError;
42405
- if (typeof base64 === "string") {
42406
- this.image.src = base64;
42407
- }
42247
+ this.linkTo = new LinkTo(this.id, this.events);
42248
+ this.transformation.subject.subscribe(() => {
42249
+ this.updateMbr();
42250
+ this.updateLines();
42251
+ this.subject.publish(this);
42252
+ });
42408
42253
  this.linkTo.subject.subscribe(() => {
42409
42254
  this.updateMbr();
42255
+ this.updateLines();
42410
42256
  this.subject.publish(this);
42411
42257
  });
42412
- this.transformation.subject.subscribe(this.onTransform);
42413
- }
42414
- setStorageLink(link2) {
42415
- try {
42416
- const url = new URL(link2);
42417
- this.storageLink = `${window?.location.origin}${url.pathname}`;
42418
- } catch (_) {}
42419
- }
42420
- getStorageId() {
42421
- return this.storageLink.split("/").pop();
42422
- }
42423
- handleError = () => {
42424
- console.error("Invalid dataUrl or image failed to load.");
42425
- this.image = getPlaceholderImage(this.board);
42426
- this.updateMbr();
42427
- this.subject.publish(this);
42428
- this.shootLoadCallbacks();
42429
- };
42430
- onLoad = async () => {
42431
- this.shootBeforeLoadCallbacks();
42432
- this.updateMbr();
42433
- this.subject.publish(this);
42434
- this.shootLoadCallbacks();
42435
- };
42436
- onError = (_error) => {
42437
- this.image = getPlaceholderImage(this.board);
42438
- this.updateMbr();
42439
- this.subject.publish(this);
42440
- this.shootLoadCallbacks();
42441
- };
42442
- onTransform = () => {
42443
- this.updateMbr();
42444
- this.subject.publish(this);
42445
- };
42446
- updateMbr() {
42447
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42448
- this.left = translateX;
42449
- this.top = translateY;
42450
- this.right = this.left + this.image.width * scaleX;
42451
- this.bottom = this.top + this.image.height * scaleY;
42452
- }
42453
- doOnceBeforeOnLoad = (callback) => {
42454
- this.loadCallbacks.push(callback);
42455
- };
42456
- doOnceOnLoad = (callback) => {
42457
- this.loadCallbacks.push(callback);
42458
- };
42459
- setId(id) {
42460
- this.id = id;
42461
- this.transformation.setId(id);
42462
- this.linkTo.setId(id);
42463
- return this;
42464
- }
42465
- getId() {
42466
- return this.id;
42258
+ this.updateLines();
42467
42259
  }
42468
42260
  serialize() {
42261
+ this.optimizePoints();
42262
+ const points = [];
42263
+ for (const point5 of this.points) {
42264
+ points.push({ x: point5.x, y: point5.y });
42265
+ }
42469
42266
  return {
42470
- itemType: "Image",
42471
- storageLink: this.storageLink,
42472
- imageDimension: this.imageDimension,
42267
+ itemType: "Drawing",
42268
+ points,
42473
42269
  transformation: this.transformation.serialize(),
42270
+ strokeStyle: this.borderColor,
42271
+ strokeWidth: this.strokeWidth,
42474
42272
  linkTo: this.linkTo.serialize()
42475
42273
  };
42476
42274
  }
42477
- setCoordinates() {
42478
- this.left = this.transformation.matrix.translateX;
42479
- this.top = this.transformation.matrix.translateY;
42480
- this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
42481
- this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
42482
- this.subject.publish(this);
42483
- }
42484
- shootBeforeLoadCallbacks() {
42485
- while (this.beforeLoadCallbacks.length > 0) {
42486
- this.beforeLoadCallbacks.shift()(this);
42275
+ deserialize(data) {
42276
+ this.points = [];
42277
+ for (const point5 of data.points) {
42278
+ this.points.push(new Point(point5.x, point5.y));
42487
42279
  }
42280
+ this.linkTo.deserialize(data.linkTo);
42281
+ this.optimizePoints();
42282
+ this.transformation.deserialize(data.transformation);
42283
+ this.borderColor = data.strokeStyle;
42284
+ this.strokeWidth = data.strokeWidth;
42285
+ this.updateGeometry();
42286
+ return this;
42488
42287
  }
42489
- shootLoadCallbacks() {
42490
- while (this.loadCallbacks.length > 0) {
42491
- this.loadCallbacks.shift()(this);
42492
- }
42288
+ updateGeometry() {
42289
+ this.updatePath2d();
42290
+ this.updateLines();
42291
+ this.updateMbr();
42493
42292
  }
42494
- deserialize(data) {
42495
- if (data.transformation) {
42496
- this.transformation.deserialize(data.transformation);
42293
+ updateMbr() {
42294
+ const offset = this.getStrokeWidth() / 2;
42295
+ const untransformedMbr = this.untransformedMbr.copy();
42296
+ untransformedMbr.left -= offset;
42297
+ untransformedMbr.top -= offset;
42298
+ untransformedMbr.right += offset;
42299
+ untransformedMbr.bottom += offset;
42300
+ const mbr = untransformedMbr.getTransformed(this.transformation.matrix);
42301
+ this.left = mbr.left;
42302
+ this.top = mbr.top;
42303
+ this.right = mbr.right;
42304
+ this.bottom = mbr.bottom;
42305
+ }
42306
+ updatePath2d() {
42307
+ this.path2d = new conf.path2DFactory;
42308
+ const context = this.path2d;
42309
+ const points = this.points;
42310
+ if (points.length < 3) {
42311
+ context.arc(points[0].x, points[0].y, 0.5, 0, Math.PI * 2, true);
42312
+ context.closePath();
42313
+ } else {
42314
+ context.moveTo(points[0].x, points[0].y);
42315
+ let j = 1;
42316
+ for (;j < points.length - 2; j++) {
42317
+ const cx = (points[j].x + points[j + 1].x) / 2;
42318
+ const cy = (points[j].y + points[j + 1].y) / 2;
42319
+ context.quadraticCurveTo(points[j].x, points[j].y, cx, cy);
42320
+ }
42321
+ const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
42322
+ const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
42323
+ context.quadraticCurveTo(points[j].x, points[j].y, x, y);
42497
42324
  }
42498
- this.linkTo.deserialize(data.linkTo);
42499
- this.image.onload = () => {
42500
- this.setCoordinates();
42501
- this.shootLoadCallbacks();
42502
- };
42503
- if (data.storageLink) {
42504
- this.setStorageLink(data.storageLink);
42325
+ let left = Number.MAX_SAFE_INTEGER;
42326
+ let right = Number.MIN_SAFE_INTEGER;
42327
+ let top = Number.MAX_SAFE_INTEGER;
42328
+ let bottom = Number.MIN_SAFE_INTEGER;
42329
+ for (const { x, y } of this.points) {
42330
+ if (x < left) {
42331
+ left = x;
42332
+ }
42333
+ if (x > right) {
42334
+ right = x;
42335
+ }
42336
+ if (y < top) {
42337
+ top = y;
42338
+ }
42339
+ if (y > bottom) {
42340
+ bottom = y;
42341
+ }
42505
42342
  }
42506
- if (this.image.src) {
42507
- return this;
42343
+ this.untransformedMbr = new Mbr(left, top, right, bottom);
42344
+ }
42345
+ updateLines() {
42346
+ this.lines = [];
42347
+ const matrix = this.transformation.matrix;
42348
+ if (this.points.length < 2) {
42349
+ return;
42350
+ }
42351
+ for (let i = 0;i < this.points.length - 2; i++) {
42352
+ const p1 = this.points[i];
42353
+ const p22 = this.points[i + 1];
42354
+ const line = new Line(p1.copy(), p22.copy());
42355
+ line.transform(matrix);
42356
+ this.lines.push(line);
42508
42357
  }
42509
- this.image = getPlaceholderImage(this.board, data.imageDimension);
42510
- const storageImage = new Image;
42511
- storageImage.onload = () => {
42512
- this.image = storageImage;
42513
- this.onLoad();
42514
- };
42515
- storageImage.onerror = this.onError;
42516
- storageImage.src = this.storageLink;
42517
- return this;
42518
42358
  }
42519
- emit(operation) {
42520
- if (this.events) {
42521
- const command = new ImageCommand([this], operation);
42522
- command.apply();
42523
- this.events.emit(operation, command);
42359
+ optimizePoints() {
42360
+ const dp = douglasPeucker(this.points, 1);
42361
+ dp.push(this.points[this.points.length - 1]);
42362
+ this.points = dp;
42363
+ }
42364
+ addPoint(point5) {
42365
+ const previous2 = this.points[this.points.length - 1];
42366
+ if (previous2) {
42367
+ const distance = point5.getDistance(previous2);
42368
+ if (distance >= 2) {
42369
+ this.points.push(point5);
42370
+ }
42524
42371
  } else {
42525
- this.apply(operation);
42372
+ this.points.push(point5);
42526
42373
  }
42374
+ this.updateGeometry();
42527
42375
  }
42528
- setDimensions(dim) {
42529
- this.imageDimension = dim;
42376
+ setId(id) {
42377
+ this.id = id;
42378
+ this.transformation.setId(id);
42379
+ this.linkTo.setId(id);
42380
+ return this;
42530
42381
  }
42531
- apply(op) {
42532
- switch (op.class) {
42533
- case "Transformation":
42534
- this.transformation.apply(op);
42535
- break;
42536
- case "LinkTo":
42537
- this.linkTo.apply(op);
42538
- break;
42539
- case "Image":
42540
- if (op.data.base64) {
42541
- this.image.src = op.data.base64;
42542
- }
42543
- this.setStorageLink(op.data.storageLink);
42544
- this.setDimensions(op.data.imageDimension);
42545
- this.subject.publish(this);
42546
- break;
42547
- }
42382
+ getId() {
42383
+ return this.id;
42548
42384
  }
42549
42385
  render(context) {
42550
42386
  if (this.transformationRenderBlock) {
@@ -42552,8 +42388,12 @@ class ImageItem extends BaseItem {
42552
42388
  }
42553
42389
  const ctx = context.ctx;
42554
42390
  ctx.save();
42391
+ ctx.strokeStyle = this.borderColor;
42392
+ ctx.lineWidth = this.strokeWidth;
42393
+ ctx.lineCap = "round";
42394
+ ctx.setLineDash(this.linePattern);
42555
42395
  this.transformation.matrix.applyToContext(ctx);
42556
- ctx.drawImage(this.image, 0, 0);
42396
+ ctx.stroke(this.path2d.nativePath);
42557
42397
  ctx.restore();
42558
42398
  if (this.getLinkTo()) {
42559
42399
  const { top, right } = this.getMbr();
@@ -42561,26 +42401,61 @@ class ImageItem extends BaseItem {
42561
42401
  }
42562
42402
  }
42563
42403
  renderHTML(documentFactory) {
42564
- const div = documentFactory.createElement("image-item");
42404
+ const div = documentFactory.createElement("drawing-item");
42565
42405
  const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42566
- const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
42567
- div.style.backgroundImage = `url(${this.storageLink})`;
42406
+ const mbr = this.getMbr();
42407
+ const width2 = mbr.getWidth();
42408
+ const height2 = mbr.getHeight();
42409
+ const unscaledWidth = width2 / scaleX;
42410
+ const unscaledHeight = height2 / scaleY;
42411
+ const svg3 = documentFactory.createElementNS("http://www.w3.org/2000/svg", "svg");
42412
+ svg3.setAttribute("width", `${unscaledWidth}px`);
42413
+ svg3.setAttribute("height", `${unscaledHeight}px`);
42414
+ svg3.setAttribute("viewBox", `0 0 ${unscaledWidth} ${unscaledHeight}`);
42415
+ svg3.setAttribute("style", "position: absolute; overflow: visible;");
42416
+ const pathElement = documentFactory.createElementNS("http://www.w3.org/2000/svg", "path");
42417
+ pathElement.setAttribute("d", this.getPathData());
42418
+ pathElement.setAttribute("stroke", this.borderColor);
42419
+ pathElement.setAttribute("stroke-width", `${this.strokeWidth}`);
42420
+ pathElement.setAttribute("fill", "none");
42421
+ svg3.appendChild(pathElement);
42422
+ div.appendChild(svg3);
42568
42423
  div.id = this.getId();
42569
- div.style.width = `${this.imageDimension.width}px`;
42570
- div.style.height = `${this.imageDimension.height}px`;
42571
- div.style.transformOrigin = "top left";
42572
- div.style.transform = transform;
42424
+ div.style.width = unscaledWidth + "px";
42425
+ div.style.height = unscaledHeight + "px";
42426
+ div.style.transformOrigin = "left top";
42427
+ div.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
42573
42428
  div.style.position = "absolute";
42574
- div.style.backgroundSize = "cover";
42575
42429
  div.setAttribute("data-link-to", this.linkTo.serialize() || "");
42576
42430
  if (this.getLinkTo()) {
42577
42431
  const linkElement = this.linkTo.renderHTML(documentFactory);
42578
42432
  scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
42579
- translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
42433
+ translateElementBy(linkElement, (width2 - parseInt(linkElement.style.width)) / scaleX, 0);
42580
42434
  div.appendChild(linkElement);
42581
42435
  }
42582
42436
  return div;
42583
42437
  }
42438
+ getPathData() {
42439
+ const points = this.points;
42440
+ if (points.length < 2) {
42441
+ return "";
42442
+ }
42443
+ let pathData = `M ${points[0].x} ${points[0].y}`;
42444
+ if (points.length < 3) {
42445
+ pathData += ` L ${points[0].x + 0.5} ${points[0].y}`;
42446
+ } else {
42447
+ let j = 1;
42448
+ for (;j < points.length - 2; j++) {
42449
+ const cx = (points[j].x + points[j + 1].x) / 2;
42450
+ const cy = (points[j].y + points[j + 1].y) / 2;
42451
+ pathData += ` Q ${points[j].x} ${points[j].y} ${cx} ${cy}`;
42452
+ }
42453
+ const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
42454
+ const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
42455
+ pathData += ` Q ${points[j].x} ${points[j].y} ${x} ${y}`;
42456
+ }
42457
+ return pathData;
42458
+ }
42584
42459
  getPath() {
42585
42460
  const { left, top, right, bottom } = this.getMbr();
42586
42461
  const leftTop = new Point(left, top);
@@ -42605,27 +42480,162 @@ class ImageItem extends BaseItem {
42605
42480
  new Point(mbr.right, mbr.top + height2 / 2)
42606
42481
  ];
42607
42482
  }
42483
+ getLines() {
42484
+ return this.lines;
42485
+ }
42608
42486
  isClosed() {
42609
42487
  return true;
42610
42488
  }
42611
- getRichText() {
42612
- return null;
42489
+ isEnclosedOrCrossedBy(rect) {
42490
+ for (const line of this.lines) {
42491
+ if (line.isEnclosedOrCrossedBy(rect)) {
42492
+ return true;
42493
+ }
42494
+ }
42495
+ return false;
42496
+ }
42497
+ emit(operation) {
42498
+ if (this.events) {
42499
+ const command = new DrawingCommand([this], operation);
42500
+ command.apply();
42501
+ this.events.emit(operation, command);
42502
+ } else {
42503
+ this.apply(operation);
42504
+ }
42505
+ }
42506
+ apply(op) {
42507
+ switch (op.class) {
42508
+ case "Drawing":
42509
+ switch (op.method) {
42510
+ case "setStrokeColor":
42511
+ this.borderColor = op.color;
42512
+ break;
42513
+ case "setStrokeWidth":
42514
+ this.strokeWidth = op.width;
42515
+ this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
42516
+ break;
42517
+ case "setStrokeOpacity":
42518
+ this.borderOpacity = op.opacity;
42519
+ break;
42520
+ case "setStrokeStyle":
42521
+ this.borderStyle = op.style;
42522
+ this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
42523
+ break;
42524
+ }
42525
+ this.updateMbr();
42526
+ break;
42527
+ case "Transformation":
42528
+ this.transformation.apply(op);
42529
+ break;
42530
+ case "LinkTo":
42531
+ this.linkTo.apply(op);
42532
+ break;
42533
+ default:
42534
+ return;
42535
+ }
42536
+ this.subject.publish(this);
42537
+ }
42538
+ setStrokeOpacity(opacity) {
42539
+ this.emit({
42540
+ class: "Drawing",
42541
+ method: "setStrokeOpacity",
42542
+ item: [this.id],
42543
+ opacity
42544
+ });
42545
+ return this;
42546
+ }
42547
+ getStrokeOpacity() {
42548
+ return this.borderOpacity;
42549
+ }
42550
+ setBorderStyle(style2) {
42551
+ this.emit({
42552
+ class: "Drawing",
42553
+ method: "setStrokeStyle",
42554
+ item: [this.id],
42555
+ style: style2
42556
+ });
42557
+ return this;
42558
+ }
42559
+ getBorderStyle() {
42560
+ return this.borderStyle;
42561
+ }
42562
+ setStrokeColor(color2) {
42563
+ this.emit({
42564
+ class: "Drawing",
42565
+ method: "setStrokeColor",
42566
+ item: [this.id],
42567
+ color: color2
42568
+ });
42569
+ return this;
42570
+ }
42571
+ getStrokeColor() {
42572
+ return this.borderColor;
42573
+ }
42574
+ setStrokeWidth(width2) {
42575
+ this.emit({
42576
+ class: "Drawing",
42577
+ method: "setStrokeWidth",
42578
+ item: [this.id],
42579
+ width: width2,
42580
+ prevWidth: this.strokeWidth
42581
+ });
42582
+ return this;
42613
42583
  }
42614
42584
  getLinkTo() {
42615
42585
  return this.linkTo.link;
42616
42586
  }
42617
- download() {
42618
- const linkElem = document.createElement("a");
42619
- linkElem.href = this.storageLink;
42620
- linkElem.setAttribute("download", "");
42621
- linkElem.click();
42587
+ getStrokeWidth() {
42588
+ return this.strokeWidth;
42622
42589
  }
42623
- onRemove() {
42624
- const storageId = this.getStorageId();
42625
- if (storageId) {
42626
- conf.hooks.beforeMediaRemove([storageId], this.board.getBoardId());
42590
+ getRichText() {
42591
+ return null;
42592
+ }
42593
+ isPointNearLine(point5, threshold = 10) {
42594
+ const transformedMouseX = (point5.x - this.transformation.matrix.translateX) / this.transformation.matrix.scaleX;
42595
+ const transformedMouseY = (point5.y - this.transformation.matrix.translateY) / this.transformation.matrix.scaleY;
42596
+ const transformedMouse = new Point(transformedMouseX, transformedMouseY);
42597
+ for (let i = 0;i < this.points.length - 1; i++) {
42598
+ const p1 = this.points[i];
42599
+ const p22 = this.points[i + 1];
42600
+ const distance = getPerpendicularDistance(transformedMouse, p1, p22);
42601
+ if (distance < threshold) {
42602
+ return true;
42603
+ }
42627
42604
  }
42628
- super.onRemove();
42605
+ return false;
42606
+ }
42607
+ }
42608
+ function getPerpendicularDistance(point5, lineStart, lineEnd) {
42609
+ const { x: px, y: py } = point5;
42610
+ const { x: sx, y: sy } = lineStart;
42611
+ const { x: ex, y: ey } = lineEnd;
42612
+ const numerator = Math.abs((ey - sy) * px - (ex - sx) * py + ex * sy - ey * sx);
42613
+ const denominator = Math.sqrt(Math.pow(ey - sy, 2) + Math.pow(ex - sx, 2));
42614
+ return numerator / denominator;
42615
+ }
42616
+ function douglasPeucker(points, epsilon2) {
42617
+ if (points.length < 3) {
42618
+ return points;
42619
+ }
42620
+ const start = points[0];
42621
+ const end = points[points.length - 1];
42622
+ let maxDistance = 0;
42623
+ let maxIndex = 0;
42624
+ for (let i = 1;i < points.length - 1; i++) {
42625
+ const distance = getPerpendicularDistance(points[i], start, end);
42626
+ if (distance > maxDistance) {
42627
+ maxDistance = distance;
42628
+ maxIndex = i;
42629
+ }
42630
+ }
42631
+ if (maxDistance > epsilon2) {
42632
+ const leftSubPoints = points.slice(0, maxIndex + 1);
42633
+ const rightSubPoints = points.slice(maxIndex);
42634
+ const leftRecursiveResult = douglasPeucker(leftSubPoints, epsilon2);
42635
+ const rightRecursiveResult = douglasPeucker(rightSubPoints, epsilon2);
42636
+ return leftRecursiveResult.slice(0, -1).concat(rightRecursiveResult);
42637
+ } else {
42638
+ return [start, end];
42629
42639
  }
42630
42640
  }
42631
42641
  // src/Items/Group/Group.ts