microboard-temp 0.4.40 → 0.4.42

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;
@@ -21459,12 +21032,12 @@ class Items {
21459
21032
  if (enclosed.length === 0) {
21460
21033
  enclosed = underPointer;
21461
21034
  }
21462
- if (underPointer.some((item) => item instanceof Drawing)) {
21035
+ if (underPointer.some((item) => item.itemType === "Drawing")) {
21463
21036
  enclosed = [...underPointer, ...enclosed];
21464
21037
  }
21465
21038
  const { nearest } = enclosed.reduce((acc, item) => {
21466
21039
  const area = item.getMbr().getHeight() * item.getMbr().getWidth();
21467
- if (item instanceof Drawing && !item.isPointNearLine(this.pointer.point)) {
21040
+ if (item.itemType === "Drawing" && !item.isPointNearLine(this.pointer.point)) {
21468
21041
  return acc;
21469
21042
  }
21470
21043
  const isItemTransparent = item instanceof Shape && item?.getBackgroundColor() === "none";
@@ -21599,6 +21172,7 @@ class Items {
21599
21172
  }
21600
21173
  }
21601
21174
 
21175
+ // src/SpatialIndex/SimpleSpatialIndex.ts
21602
21176
  class SimpleSpatialIndex {
21603
21177
  subject = new Subject;
21604
21178
  itemsArray = [];
@@ -42348,202 +41922,455 @@ class Placeholder extends BaseItem {
42348
41922
  renderHTML(documentFactory) {
42349
41923
  return documentFactory.createElement("div");
42350
41924
  }
42351
- getLinkTo() {
42352
- return;
41925
+ getLinkTo() {
41926
+ return;
41927
+ }
41928
+ getRichText() {
41929
+ return null;
41930
+ }
41931
+ }
41932
+ // src/Items/Image/Image.ts
41933
+ function getPlaceholderImage(board, imageDimension) {
41934
+ const placeholderCanvas = conf.documentFactory.createElement("canvas");
41935
+ const placeholderContext = placeholderCanvas.getContext("2d");
41936
+ const context = new DrawingContext(board.camera, placeholderContext);
41937
+ const placeholder = new Placeholder(board);
41938
+ if (imageDimension) {
41939
+ placeholderCanvas.width = imageDimension.width;
41940
+ placeholderCanvas.height = imageDimension.height;
41941
+ placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
41942
+ } else {
41943
+ placeholderCanvas.width = 250;
41944
+ placeholderCanvas.height = 50;
41945
+ placeholder.transformation.scaleTo(250 / 100, 50 / 100);
41946
+ }
41947
+ const placeholderImage = new Image;
41948
+ placeholderImage.src = placeholderCanvas.toDataURL();
41949
+ return placeholderImage;
41950
+ }
41951
+
41952
+ class ImageItem extends BaseItem {
41953
+ events;
41954
+ itemType = "Image";
41955
+ parent = "Board";
41956
+ image;
41957
+ transformation;
41958
+ linkTo;
41959
+ subject = new Subject;
41960
+ loadCallbacks = [];
41961
+ beforeLoadCallbacks = [];
41962
+ transformationRenderBlock = undefined;
41963
+ storageLink;
41964
+ imageDimension;
41965
+ board;
41966
+ constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
41967
+ super(board, id);
41968
+ this.events = events;
41969
+ this.linkTo = new LinkTo(this.id, events);
41970
+ this.board = board;
41971
+ this.setStorageLink(storageLink);
41972
+ this.imageDimension = imageDimension;
41973
+ this.transformation = new Transformation(id, events);
41974
+ this.image = new Image;
41975
+ this.image.crossOrigin = "anonymous";
41976
+ this.image.onload = this.onLoad;
41977
+ this.image.onerror = this.onError;
41978
+ if (typeof base64 === "string") {
41979
+ this.image.src = base64;
41980
+ }
41981
+ this.linkTo.subject.subscribe(() => {
41982
+ this.updateMbr();
41983
+ this.subject.publish(this);
41984
+ });
41985
+ this.transformation.subject.subscribe(this.onTransform);
41986
+ }
41987
+ setStorageLink(link2) {
41988
+ try {
41989
+ const url = new URL(link2);
41990
+ this.storageLink = `${window?.location.origin}${url.pathname}`;
41991
+ } catch (_) {}
41992
+ }
41993
+ getStorageId() {
41994
+ return this.storageLink.split("/").pop();
41995
+ }
41996
+ handleError = () => {
41997
+ console.error("Invalid dataUrl or image failed to load.");
41998
+ this.image = getPlaceholderImage(this.board);
41999
+ this.updateMbr();
42000
+ this.subject.publish(this);
42001
+ this.shootLoadCallbacks();
42002
+ };
42003
+ onLoad = async () => {
42004
+ this.shootBeforeLoadCallbacks();
42005
+ this.updateMbr();
42006
+ this.subject.publish(this);
42007
+ this.shootLoadCallbacks();
42008
+ };
42009
+ onError = (_error) => {
42010
+ this.image = getPlaceholderImage(this.board);
42011
+ this.updateMbr();
42012
+ this.subject.publish(this);
42013
+ this.shootLoadCallbacks();
42014
+ };
42015
+ onTransform = () => {
42016
+ this.updateMbr();
42017
+ this.subject.publish(this);
42018
+ };
42019
+ updateMbr() {
42020
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42021
+ this.left = translateX;
42022
+ this.top = translateY;
42023
+ this.right = this.left + this.image.width * scaleX;
42024
+ this.bottom = this.top + this.image.height * scaleY;
42025
+ }
42026
+ doOnceBeforeOnLoad = (callback) => {
42027
+ this.loadCallbacks.push(callback);
42028
+ };
42029
+ doOnceOnLoad = (callback) => {
42030
+ this.loadCallbacks.push(callback);
42031
+ };
42032
+ setId(id) {
42033
+ this.id = id;
42034
+ this.transformation.setId(id);
42035
+ this.linkTo.setId(id);
42036
+ return this;
42037
+ }
42038
+ getId() {
42039
+ return this.id;
42040
+ }
42041
+ serialize() {
42042
+ return {
42043
+ itemType: "Image",
42044
+ storageLink: this.storageLink,
42045
+ imageDimension: this.imageDimension,
42046
+ transformation: this.transformation.serialize(),
42047
+ linkTo: this.linkTo.serialize()
42048
+ };
42049
+ }
42050
+ setCoordinates() {
42051
+ this.left = this.transformation.matrix.translateX;
42052
+ this.top = this.transformation.matrix.translateY;
42053
+ this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
42054
+ this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
42055
+ this.subject.publish(this);
42056
+ }
42057
+ shootBeforeLoadCallbacks() {
42058
+ while (this.beforeLoadCallbacks.length > 0) {
42059
+ this.beforeLoadCallbacks.shift()(this);
42060
+ }
42061
+ }
42062
+ shootLoadCallbacks() {
42063
+ while (this.loadCallbacks.length > 0) {
42064
+ this.loadCallbacks.shift()(this);
42065
+ }
42066
+ }
42067
+ deserialize(data) {
42068
+ if (data.transformation) {
42069
+ this.transformation.deserialize(data.transformation);
42070
+ }
42071
+ this.linkTo.deserialize(data.linkTo);
42072
+ this.image.onload = () => {
42073
+ this.setCoordinates();
42074
+ this.shootLoadCallbacks();
42075
+ };
42076
+ if (data.storageLink) {
42077
+ this.setStorageLink(data.storageLink);
42078
+ }
42079
+ if (this.image.src) {
42080
+ return this;
42081
+ }
42082
+ this.image = getPlaceholderImage(this.board, data.imageDimension);
42083
+ const storageImage = new Image;
42084
+ storageImage.onload = () => {
42085
+ this.image = storageImage;
42086
+ this.onLoad();
42087
+ };
42088
+ storageImage.onerror = this.onError;
42089
+ storageImage.src = this.storageLink;
42090
+ return this;
42091
+ }
42092
+ emit(operation) {
42093
+ if (this.events) {
42094
+ const command = new ImageCommand([this], operation);
42095
+ command.apply();
42096
+ this.events.emit(operation, command);
42097
+ } else {
42098
+ this.apply(operation);
42099
+ }
42100
+ }
42101
+ setDimensions(dim) {
42102
+ this.imageDimension = dim;
42103
+ }
42104
+ apply(op) {
42105
+ switch (op.class) {
42106
+ case "Transformation":
42107
+ this.transformation.apply(op);
42108
+ break;
42109
+ case "LinkTo":
42110
+ this.linkTo.apply(op);
42111
+ break;
42112
+ case "Image":
42113
+ if (op.data.base64) {
42114
+ this.image.src = op.data.base64;
42115
+ }
42116
+ this.setStorageLink(op.data.storageLink);
42117
+ this.setDimensions(op.data.imageDimension);
42118
+ this.subject.publish(this);
42119
+ break;
42120
+ }
42121
+ }
42122
+ render(context) {
42123
+ if (this.transformationRenderBlock) {
42124
+ return;
42125
+ }
42126
+ const ctx = context.ctx;
42127
+ ctx.save();
42128
+ this.transformation.matrix.applyToContext(ctx);
42129
+ ctx.drawImage(this.image, 0, 0);
42130
+ ctx.restore();
42131
+ if (this.getLinkTo()) {
42132
+ const { top, right } = this.getMbr();
42133
+ this.linkTo.render(context, top, right, this.board.camera.getScale());
42134
+ }
42135
+ }
42136
+ renderHTML(documentFactory) {
42137
+ const div = documentFactory.createElement("image-item");
42138
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42139
+ const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
42140
+ div.style.backgroundImage = `url(${this.storageLink})`;
42141
+ div.id = this.getId();
42142
+ div.style.width = `${this.imageDimension.width}px`;
42143
+ div.style.height = `${this.imageDimension.height}px`;
42144
+ div.style.transformOrigin = "top left";
42145
+ div.style.transform = transform;
42146
+ div.style.position = "absolute";
42147
+ div.style.backgroundSize = "cover";
42148
+ div.setAttribute("data-link-to", this.linkTo.serialize() || "");
42149
+ if (this.getLinkTo()) {
42150
+ const linkElement = this.linkTo.renderHTML(documentFactory);
42151
+ scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
42152
+ translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
42153
+ div.appendChild(linkElement);
42154
+ }
42155
+ return div;
42156
+ }
42157
+ getPath() {
42158
+ const { left, top, right, bottom } = this.getMbr();
42159
+ const leftTop = new Point(left, top);
42160
+ const rightTop = new Point(right, top);
42161
+ const rightBottom = new Point(right, bottom);
42162
+ const leftBottom = new Point(left, bottom);
42163
+ return new Path([
42164
+ new Line(leftTop, rightTop),
42165
+ new Line(rightTop, rightBottom),
42166
+ new Line(rightBottom, leftBottom),
42167
+ new Line(leftBottom, leftTop)
42168
+ ], true);
42169
+ }
42170
+ getSnapAnchorPoints() {
42171
+ const mbr = this.getMbr();
42172
+ const width2 = mbr.getWidth();
42173
+ const height2 = mbr.getHeight();
42174
+ return [
42175
+ new Point(mbr.left + width2 / 2, mbr.top),
42176
+ new Point(mbr.left + width2 / 2, mbr.bottom),
42177
+ new Point(mbr.left, mbr.top + height2 / 2),
42178
+ new Point(mbr.right, mbr.top + height2 / 2)
42179
+ ];
42180
+ }
42181
+ isClosed() {
42182
+ return true;
42353
42183
  }
42354
42184
  getRichText() {
42355
42185
  return null;
42356
42186
  }
42187
+ getLinkTo() {
42188
+ return this.linkTo.link;
42189
+ }
42190
+ download() {
42191
+ const linkElem = document.createElement("a");
42192
+ linkElem.href = this.storageLink;
42193
+ linkElem.setAttribute("download", "");
42194
+ linkElem.click();
42195
+ }
42196
+ onRemove() {
42197
+ const storageId = this.getStorageId();
42198
+ if (storageId) {
42199
+ conf.hooks.beforeMediaRemove([storageId], this.board.getBoardId());
42200
+ }
42201
+ super.onRemove();
42202
+ }
42357
42203
  }
42358
- // src/Items/Image/Image.ts
42359
- function getPlaceholderImage(board, imageDimension) {
42360
- const placeholderCanvas = conf.documentFactory.createElement("canvas");
42361
- const placeholderContext = placeholderCanvas.getContext("2d");
42362
- const context = new DrawingContext(board.camera, placeholderContext);
42363
- const placeholder = new Placeholder(board);
42364
- if (imageDimension) {
42365
- placeholderCanvas.width = imageDimension.width;
42366
- placeholderCanvas.height = imageDimension.height;
42367
- placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
42368
- } else {
42369
- placeholderCanvas.width = 250;
42370
- placeholderCanvas.height = 50;
42371
- placeholder.transformation.scaleTo(250 / 100, 50 / 100);
42204
+ // src/isSafari.ts
42205
+ function isSafari() {
42206
+ if (typeof navigator === "undefined") {
42207
+ return false;
42372
42208
  }
42373
- const placeholderImage = new Image;
42374
- placeholderImage.src = placeholderCanvas.toDataURL();
42375
- return placeholderImage;
42209
+ const agent = navigator.userAgent;
42210
+ const vendor = navigator.vendor;
42211
+ const is2 = vendor !== undefined && vendor.includes("Apple") && agent !== undefined && !agent.includes("CriOS") && !agent.includes("FxiOS");
42212
+ return is2;
42376
42213
  }
42377
42214
 
42378
- class ImageItem extends BaseItem {
42215
+ // src/Items/Drawing/Drawing.ts
42216
+ class Drawing extends BaseItem {
42217
+ points;
42379
42218
  events;
42380
- itemType = "Image";
42219
+ itemType = "Drawing";
42381
42220
  parent = "Board";
42382
- image;
42383
42221
  transformation;
42384
- linkTo;
42222
+ path2d = new conf.path2DFactory;
42385
42223
  subject = new Subject;
42386
- loadCallbacks = [];
42387
- beforeLoadCallbacks = [];
42224
+ untransformedMbr = new Mbr;
42225
+ lines = [];
42226
+ linkTo;
42227
+ strokeWidth = 1;
42228
+ borderStyle = "solid";
42229
+ linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
42230
+ borderOpacity = 1;
42388
42231
  transformationRenderBlock = undefined;
42389
- storageLink;
42390
- imageDimension;
42391
- board;
42392
- constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
42232
+ constructor(board, points, events, id = "") {
42393
42233
  super(board, id);
42234
+ this.points = points;
42394
42235
  this.events = events;
42395
- this.linkTo = new LinkTo(this.id, events);
42396
- this.board = board;
42397
- this.setStorageLink(storageLink);
42398
- this.imageDimension = imageDimension;
42399
42236
  this.transformation = new Transformation(id, events);
42400
- this.image = new Image;
42401
- this.image.crossOrigin = "anonymous";
42402
- this.image.onload = this.onLoad;
42403
- this.image.onerror = this.onError;
42404
- if (typeof base64 === "string") {
42405
- this.image.src = base64;
42406
- }
42237
+ this.linkTo = new LinkTo(this.id, this.events);
42238
+ this.transformation.subject.subscribe(() => {
42239
+ this.updateMbr();
42240
+ this.updateLines();
42241
+ this.subject.publish(this);
42242
+ });
42407
42243
  this.linkTo.subject.subscribe(() => {
42408
42244
  this.updateMbr();
42245
+ this.updateLines();
42409
42246
  this.subject.publish(this);
42410
42247
  });
42411
- this.transformation.subject.subscribe(this.onTransform);
42412
- }
42413
- setStorageLink(link2) {
42414
- try {
42415
- const url = new URL(link2);
42416
- this.storageLink = `${window?.location.origin}${url.pathname}`;
42417
- } catch (_) {}
42418
- }
42419
- getStorageId() {
42420
- return this.storageLink.split("/").pop();
42421
- }
42422
- handleError = () => {
42423
- console.error("Invalid dataUrl or image failed to load.");
42424
- this.image = getPlaceholderImage(this.board);
42425
- this.updateMbr();
42426
- this.subject.publish(this);
42427
- this.shootLoadCallbacks();
42428
- };
42429
- onLoad = async () => {
42430
- this.shootBeforeLoadCallbacks();
42431
- this.updateMbr();
42432
- this.subject.publish(this);
42433
- this.shootLoadCallbacks();
42434
- };
42435
- onError = (_error) => {
42436
- this.image = getPlaceholderImage(this.board);
42437
- this.updateMbr();
42438
- this.subject.publish(this);
42439
- this.shootLoadCallbacks();
42440
- };
42441
- onTransform = () => {
42442
- this.updateMbr();
42443
- this.subject.publish(this);
42444
- };
42445
- updateMbr() {
42446
- const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42447
- this.left = translateX;
42448
- this.top = translateY;
42449
- this.right = this.left + this.image.width * scaleX;
42450
- this.bottom = this.top + this.image.height * scaleY;
42451
- }
42452
- doOnceBeforeOnLoad = (callback) => {
42453
- this.loadCallbacks.push(callback);
42454
- };
42455
- doOnceOnLoad = (callback) => {
42456
- this.loadCallbacks.push(callback);
42457
- };
42458
- setId(id) {
42459
- this.id = id;
42460
- this.transformation.setId(id);
42461
- this.linkTo.setId(id);
42462
- return this;
42463
- }
42464
- getId() {
42465
- return this.id;
42248
+ this.updateLines();
42466
42249
  }
42467
42250
  serialize() {
42251
+ this.optimizePoints();
42252
+ const points = [];
42253
+ for (const point5 of this.points) {
42254
+ points.push({ x: point5.x, y: point5.y });
42255
+ }
42468
42256
  return {
42469
- itemType: "Image",
42470
- storageLink: this.storageLink,
42471
- imageDimension: this.imageDimension,
42257
+ itemType: "Drawing",
42258
+ points,
42472
42259
  transformation: this.transformation.serialize(),
42260
+ strokeStyle: this.borderColor,
42261
+ strokeWidth: this.strokeWidth,
42473
42262
  linkTo: this.linkTo.serialize()
42474
42263
  };
42475
42264
  }
42476
- setCoordinates() {
42477
- this.left = this.transformation.matrix.translateX;
42478
- this.top = this.transformation.matrix.translateY;
42479
- this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
42480
- this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
42481
- this.subject.publish(this);
42482
- }
42483
- shootBeforeLoadCallbacks() {
42484
- while (this.beforeLoadCallbacks.length > 0) {
42485
- this.beforeLoadCallbacks.shift()(this);
42265
+ deserialize(data) {
42266
+ this.points = [];
42267
+ for (const point5 of data.points) {
42268
+ this.points.push(new Point(point5.x, point5.y));
42486
42269
  }
42270
+ this.linkTo.deserialize(data.linkTo);
42271
+ this.optimizePoints();
42272
+ this.transformation.deserialize(data.transformation);
42273
+ this.borderColor = data.strokeStyle;
42274
+ this.strokeWidth = data.strokeWidth;
42275
+ this.updateGeometry();
42276
+ return this;
42487
42277
  }
42488
- shootLoadCallbacks() {
42489
- while (this.loadCallbacks.length > 0) {
42490
- this.loadCallbacks.shift()(this);
42491
- }
42278
+ updateGeometry() {
42279
+ this.updatePath2d();
42280
+ this.updateLines();
42281
+ this.updateMbr();
42492
42282
  }
42493
- deserialize(data) {
42494
- if (data.transformation) {
42495
- this.transformation.deserialize(data.transformation);
42283
+ updateMbr() {
42284
+ const offset = this.getStrokeWidth() / 2;
42285
+ const untransformedMbr = this.untransformedMbr.copy();
42286
+ untransformedMbr.left -= offset;
42287
+ untransformedMbr.top -= offset;
42288
+ untransformedMbr.right += offset;
42289
+ untransformedMbr.bottom += offset;
42290
+ const mbr = untransformedMbr.getTransformed(this.transformation.matrix);
42291
+ this.left = mbr.left;
42292
+ this.top = mbr.top;
42293
+ this.right = mbr.right;
42294
+ this.bottom = mbr.bottom;
42295
+ }
42296
+ updatePath2d() {
42297
+ this.path2d = new conf.path2DFactory;
42298
+ const context = this.path2d;
42299
+ const points = this.points;
42300
+ if (points.length < 3) {
42301
+ context.arc(points[0].x, points[0].y, 0.5, 0, Math.PI * 2, true);
42302
+ context.closePath();
42303
+ } else {
42304
+ context.moveTo(points[0].x, points[0].y);
42305
+ let j = 1;
42306
+ for (;j < points.length - 2; j++) {
42307
+ const cx = (points[j].x + points[j + 1].x) / 2;
42308
+ const cy = (points[j].y + points[j + 1].y) / 2;
42309
+ context.quadraticCurveTo(points[j].x, points[j].y, cx, cy);
42310
+ }
42311
+ const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
42312
+ const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
42313
+ context.quadraticCurveTo(points[j].x, points[j].y, x, y);
42496
42314
  }
42497
- this.linkTo.deserialize(data.linkTo);
42498
- this.image.onload = () => {
42499
- this.setCoordinates();
42500
- this.shootLoadCallbacks();
42501
- };
42502
- if (data.storageLink) {
42503
- this.setStorageLink(data.storageLink);
42315
+ let left = Number.MAX_SAFE_INTEGER;
42316
+ let right = Number.MIN_SAFE_INTEGER;
42317
+ let top = Number.MAX_SAFE_INTEGER;
42318
+ let bottom = Number.MIN_SAFE_INTEGER;
42319
+ for (const { x, y } of this.points) {
42320
+ if (x < left) {
42321
+ left = x;
42322
+ }
42323
+ if (x > right) {
42324
+ right = x;
42325
+ }
42326
+ if (y < top) {
42327
+ top = y;
42328
+ }
42329
+ if (y > bottom) {
42330
+ bottom = y;
42331
+ }
42504
42332
  }
42505
- if (this.image.src) {
42506
- return this;
42333
+ this.untransformedMbr = new Mbr(left, top, right, bottom);
42334
+ }
42335
+ updateLines() {
42336
+ this.lines = [];
42337
+ const matrix = this.transformation.matrix;
42338
+ if (this.points.length < 2) {
42339
+ return;
42340
+ }
42341
+ for (let i = 0;i < this.points.length - 2; i++) {
42342
+ const p1 = this.points[i];
42343
+ const p22 = this.points[i + 1];
42344
+ const line = new Line(p1.copy(), p22.copy());
42345
+ line.transform(matrix);
42346
+ this.lines.push(line);
42507
42347
  }
42508
- this.image = getPlaceholderImage(this.board, data.imageDimension);
42509
- const storageImage = new Image;
42510
- storageImage.onload = () => {
42511
- this.image = storageImage;
42512
- this.onLoad();
42513
- };
42514
- storageImage.onerror = this.onError;
42515
- storageImage.src = this.storageLink;
42516
- return this;
42517
42348
  }
42518
- emit(operation) {
42519
- if (this.events) {
42520
- const command = new ImageCommand([this], operation);
42521
- command.apply();
42522
- this.events.emit(operation, command);
42349
+ optimizePoints() {
42350
+ const dp = douglasPeucker(this.points, 1);
42351
+ dp.push(this.points[this.points.length - 1]);
42352
+ this.points = dp;
42353
+ }
42354
+ addPoint(point5) {
42355
+ const previous2 = this.points[this.points.length - 1];
42356
+ if (previous2) {
42357
+ const distance = point5.getDistance(previous2);
42358
+ if (distance >= 2) {
42359
+ this.points.push(point5);
42360
+ }
42523
42361
  } else {
42524
- this.apply(operation);
42362
+ this.points.push(point5);
42525
42363
  }
42364
+ this.updateGeometry();
42526
42365
  }
42527
- setDimensions(dim) {
42528
- this.imageDimension = dim;
42366
+ setId(id) {
42367
+ this.id = id;
42368
+ this.transformation.setId(id);
42369
+ this.linkTo.setId(id);
42370
+ return this;
42529
42371
  }
42530
- apply(op) {
42531
- switch (op.class) {
42532
- case "Transformation":
42533
- this.transformation.apply(op);
42534
- break;
42535
- case "LinkTo":
42536
- this.linkTo.apply(op);
42537
- break;
42538
- case "Image":
42539
- if (op.data.base64) {
42540
- this.image.src = op.data.base64;
42541
- }
42542
- this.setStorageLink(op.data.storageLink);
42543
- this.setDimensions(op.data.imageDimension);
42544
- this.subject.publish(this);
42545
- break;
42546
- }
42372
+ getId() {
42373
+ return this.id;
42547
42374
  }
42548
42375
  render(context) {
42549
42376
  if (this.transformationRenderBlock) {
@@ -42551,8 +42378,12 @@ class ImageItem extends BaseItem {
42551
42378
  }
42552
42379
  const ctx = context.ctx;
42553
42380
  ctx.save();
42381
+ ctx.strokeStyle = this.borderColor;
42382
+ ctx.lineWidth = this.strokeWidth;
42383
+ ctx.lineCap = "round";
42384
+ ctx.setLineDash(this.linePattern);
42554
42385
  this.transformation.matrix.applyToContext(ctx);
42555
- ctx.drawImage(this.image, 0, 0);
42386
+ ctx.stroke(this.path2d.nativePath);
42556
42387
  ctx.restore();
42557
42388
  if (this.getLinkTo()) {
42558
42389
  const { top, right } = this.getMbr();
@@ -42560,26 +42391,61 @@ class ImageItem extends BaseItem {
42560
42391
  }
42561
42392
  }
42562
42393
  renderHTML(documentFactory) {
42563
- const div = documentFactory.createElement("image-item");
42394
+ const div = documentFactory.createElement("drawing-item");
42564
42395
  const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
42565
- const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
42566
- div.style.backgroundImage = `url(${this.storageLink})`;
42396
+ const mbr = this.getMbr();
42397
+ const width2 = mbr.getWidth();
42398
+ const height2 = mbr.getHeight();
42399
+ const unscaledWidth = width2 / scaleX;
42400
+ const unscaledHeight = height2 / scaleY;
42401
+ const svg3 = documentFactory.createElementNS("http://www.w3.org/2000/svg", "svg");
42402
+ svg3.setAttribute("width", `${unscaledWidth}px`);
42403
+ svg3.setAttribute("height", `${unscaledHeight}px`);
42404
+ svg3.setAttribute("viewBox", `0 0 ${unscaledWidth} ${unscaledHeight}`);
42405
+ svg3.setAttribute("style", "position: absolute; overflow: visible;");
42406
+ const pathElement = documentFactory.createElementNS("http://www.w3.org/2000/svg", "path");
42407
+ pathElement.setAttribute("d", this.getPathData());
42408
+ pathElement.setAttribute("stroke", this.borderColor);
42409
+ pathElement.setAttribute("stroke-width", `${this.strokeWidth}`);
42410
+ pathElement.setAttribute("fill", "none");
42411
+ svg3.appendChild(pathElement);
42412
+ div.appendChild(svg3);
42567
42413
  div.id = this.getId();
42568
- div.style.width = `${this.imageDimension.width}px`;
42569
- div.style.height = `${this.imageDimension.height}px`;
42570
- div.style.transformOrigin = "top left";
42571
- div.style.transform = transform;
42414
+ div.style.width = unscaledWidth + "px";
42415
+ div.style.height = unscaledHeight + "px";
42416
+ div.style.transformOrigin = "left top";
42417
+ div.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
42572
42418
  div.style.position = "absolute";
42573
- div.style.backgroundSize = "cover";
42574
42419
  div.setAttribute("data-link-to", this.linkTo.serialize() || "");
42575
42420
  if (this.getLinkTo()) {
42576
42421
  const linkElement = this.linkTo.renderHTML(documentFactory);
42577
42422
  scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
42578
- translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
42423
+ translateElementBy(linkElement, (width2 - parseInt(linkElement.style.width)) / scaleX, 0);
42579
42424
  div.appendChild(linkElement);
42580
42425
  }
42581
42426
  return div;
42582
42427
  }
42428
+ getPathData() {
42429
+ const points = this.points;
42430
+ if (points.length < 2) {
42431
+ return "";
42432
+ }
42433
+ let pathData = `M ${points[0].x} ${points[0].y}`;
42434
+ if (points.length < 3) {
42435
+ pathData += ` L ${points[0].x + 0.5} ${points[0].y}`;
42436
+ } else {
42437
+ let j = 1;
42438
+ for (;j < points.length - 2; j++) {
42439
+ const cx = (points[j].x + points[j + 1].x) / 2;
42440
+ const cy = (points[j].y + points[j + 1].y) / 2;
42441
+ pathData += ` Q ${points[j].x} ${points[j].y} ${cx} ${cy}`;
42442
+ }
42443
+ const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
42444
+ const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
42445
+ pathData += ` Q ${points[j].x} ${points[j].y} ${x} ${y}`;
42446
+ }
42447
+ return pathData;
42448
+ }
42583
42449
  getPath() {
42584
42450
  const { left, top, right, bottom } = this.getMbr();
42585
42451
  const leftTop = new Point(left, top);
@@ -42604,27 +42470,162 @@ class ImageItem extends BaseItem {
42604
42470
  new Point(mbr.right, mbr.top + height2 / 2)
42605
42471
  ];
42606
42472
  }
42473
+ getLines() {
42474
+ return this.lines;
42475
+ }
42607
42476
  isClosed() {
42608
42477
  return true;
42609
42478
  }
42610
- getRichText() {
42611
- return null;
42479
+ isEnclosedOrCrossedBy(rect) {
42480
+ for (const line of this.lines) {
42481
+ if (line.isEnclosedOrCrossedBy(rect)) {
42482
+ return true;
42483
+ }
42484
+ }
42485
+ return false;
42486
+ }
42487
+ emit(operation) {
42488
+ if (this.events) {
42489
+ const command = new DrawingCommand([this], operation);
42490
+ command.apply();
42491
+ this.events.emit(operation, command);
42492
+ } else {
42493
+ this.apply(operation);
42494
+ }
42495
+ }
42496
+ apply(op) {
42497
+ switch (op.class) {
42498
+ case "Drawing":
42499
+ switch (op.method) {
42500
+ case "setStrokeColor":
42501
+ this.borderColor = op.color;
42502
+ break;
42503
+ case "setStrokeWidth":
42504
+ this.strokeWidth = op.width;
42505
+ this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
42506
+ break;
42507
+ case "setStrokeOpacity":
42508
+ this.borderOpacity = op.opacity;
42509
+ break;
42510
+ case "setStrokeStyle":
42511
+ this.borderStyle = op.style;
42512
+ this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
42513
+ break;
42514
+ }
42515
+ this.updateMbr();
42516
+ break;
42517
+ case "Transformation":
42518
+ this.transformation.apply(op);
42519
+ break;
42520
+ case "LinkTo":
42521
+ this.linkTo.apply(op);
42522
+ break;
42523
+ default:
42524
+ return;
42525
+ }
42526
+ this.subject.publish(this);
42527
+ }
42528
+ setStrokeOpacity(opacity) {
42529
+ this.emit({
42530
+ class: "Drawing",
42531
+ method: "setStrokeOpacity",
42532
+ item: [this.id],
42533
+ opacity
42534
+ });
42535
+ return this;
42536
+ }
42537
+ getStrokeOpacity() {
42538
+ return this.borderOpacity;
42539
+ }
42540
+ setBorderStyle(style2) {
42541
+ this.emit({
42542
+ class: "Drawing",
42543
+ method: "setStrokeStyle",
42544
+ item: [this.id],
42545
+ style: style2
42546
+ });
42547
+ return this;
42548
+ }
42549
+ getBorderStyle() {
42550
+ return this.borderStyle;
42551
+ }
42552
+ setStrokeColor(color2) {
42553
+ this.emit({
42554
+ class: "Drawing",
42555
+ method: "setStrokeColor",
42556
+ item: [this.id],
42557
+ color: color2
42558
+ });
42559
+ return this;
42560
+ }
42561
+ getStrokeColor() {
42562
+ return this.borderColor;
42563
+ }
42564
+ setStrokeWidth(width2) {
42565
+ this.emit({
42566
+ class: "Drawing",
42567
+ method: "setStrokeWidth",
42568
+ item: [this.id],
42569
+ width: width2,
42570
+ prevWidth: this.strokeWidth
42571
+ });
42572
+ return this;
42612
42573
  }
42613
42574
  getLinkTo() {
42614
42575
  return this.linkTo.link;
42615
42576
  }
42616
- download() {
42617
- const linkElem = document.createElement("a");
42618
- linkElem.href = this.storageLink;
42619
- linkElem.setAttribute("download", "");
42620
- linkElem.click();
42577
+ getStrokeWidth() {
42578
+ return this.strokeWidth;
42621
42579
  }
42622
- onRemove() {
42623
- const storageId = this.getStorageId();
42624
- if (storageId) {
42625
- conf.hooks.beforeMediaRemove([storageId], this.board.getBoardId());
42580
+ getRichText() {
42581
+ return null;
42582
+ }
42583
+ isPointNearLine(point5, threshold = 10) {
42584
+ const transformedMouseX = (point5.x - this.transformation.matrix.translateX) / this.transformation.matrix.scaleX;
42585
+ const transformedMouseY = (point5.y - this.transformation.matrix.translateY) / this.transformation.matrix.scaleY;
42586
+ const transformedMouse = new Point(transformedMouseX, transformedMouseY);
42587
+ for (let i = 0;i < this.points.length - 1; i++) {
42588
+ const p1 = this.points[i];
42589
+ const p22 = this.points[i + 1];
42590
+ const distance = getPerpendicularDistance(transformedMouse, p1, p22);
42591
+ if (distance < threshold) {
42592
+ return true;
42593
+ }
42626
42594
  }
42627
- super.onRemove();
42595
+ return false;
42596
+ }
42597
+ }
42598
+ function getPerpendicularDistance(point5, lineStart, lineEnd) {
42599
+ const { x: px, y: py } = point5;
42600
+ const { x: sx, y: sy } = lineStart;
42601
+ const { x: ex, y: ey } = lineEnd;
42602
+ const numerator = Math.abs((ey - sy) * px - (ex - sx) * py + ex * sy - ey * sx);
42603
+ const denominator = Math.sqrt(Math.pow(ey - sy, 2) + Math.pow(ex - sx, 2));
42604
+ return numerator / denominator;
42605
+ }
42606
+ function douglasPeucker(points, epsilon2) {
42607
+ if (points.length < 3) {
42608
+ return points;
42609
+ }
42610
+ const start = points[0];
42611
+ const end = points[points.length - 1];
42612
+ let maxDistance = 0;
42613
+ let maxIndex = 0;
42614
+ for (let i = 1;i < points.length - 1; i++) {
42615
+ const distance = getPerpendicularDistance(points[i], start, end);
42616
+ if (distance > maxDistance) {
42617
+ maxDistance = distance;
42618
+ maxIndex = i;
42619
+ }
42620
+ }
42621
+ if (maxDistance > epsilon2) {
42622
+ const leftSubPoints = points.slice(0, maxIndex + 1);
42623
+ const rightSubPoints = points.slice(maxIndex);
42624
+ const leftRecursiveResult = douglasPeucker(leftSubPoints, epsilon2);
42625
+ const rightRecursiveResult = douglasPeucker(rightSubPoints, epsilon2);
42626
+ return leftRecursiveResult.slice(0, -1).concat(rightRecursiveResult);
42627
+ } else {
42628
+ return [start, end];
42628
42629
  }
42629
42630
  }
42630
42631
  // src/Items/Group/Group.ts