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