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.
- package/dist/cjs/browser.js +610 -609
- package/dist/cjs/index.js +610 -609
- package/dist/cjs/node.js +610 -609
- package/dist/esm/browser.js +610 -609
- package/dist/esm/index.js +610 -609
- package/dist/esm/node.js +610 -609
- package/dist/types/Items/BaseItem/BaseItem.d.ts +1 -1
- package/dist/types/SpatialIndex/SimpleSpatialIndex.d.ts +39 -0
- package/dist/types/SpatialIndex/SpacialIndex.d.ts +0 -31
- package/package.json +1 -1
package/dist/esm/browser.js
CHANGED
|
@@ -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
|
|
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
|
|
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";
|
|
@@ -21449,6 +21022,7 @@ class Items {
|
|
|
21449
21022
|
}
|
|
21450
21023
|
}
|
|
21451
21024
|
|
|
21025
|
+
// src/SpatialIndex/SimpleSpatialIndex.ts
|
|
21452
21026
|
class SimpleSpatialIndex {
|
|
21453
21027
|
subject = new Subject;
|
|
21454
21028
|
itemsArray = [];
|
|
@@ -42198,202 +41772,455 @@ class Placeholder extends BaseItem {
|
|
|
42198
41772
|
renderHTML(documentFactory) {
|
|
42199
41773
|
return documentFactory.createElement("div");
|
|
42200
41774
|
}
|
|
42201
|
-
getLinkTo() {
|
|
42202
|
-
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;
|
|
42203
42033
|
}
|
|
42204
42034
|
getRichText() {
|
|
42205
42035
|
return null;
|
|
42206
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
|
+
}
|
|
42207
42053
|
}
|
|
42208
|
-
// src/
|
|
42209
|
-
function
|
|
42210
|
-
|
|
42211
|
-
|
|
42212
|
-
const context = new DrawingContext(board.camera, placeholderContext);
|
|
42213
|
-
const placeholder = new Placeholder(board);
|
|
42214
|
-
if (imageDimension) {
|
|
42215
|
-
placeholderCanvas.width = imageDimension.width;
|
|
42216
|
-
placeholderCanvas.height = imageDimension.height;
|
|
42217
|
-
placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
|
|
42218
|
-
} else {
|
|
42219
|
-
placeholderCanvas.width = 250;
|
|
42220
|
-
placeholderCanvas.height = 50;
|
|
42221
|
-
placeholder.transformation.scaleTo(250 / 100, 50 / 100);
|
|
42054
|
+
// src/isSafari.ts
|
|
42055
|
+
function isSafari() {
|
|
42056
|
+
if (typeof navigator === "undefined") {
|
|
42057
|
+
return false;
|
|
42222
42058
|
}
|
|
42223
|
-
const
|
|
42224
|
-
|
|
42225
|
-
|
|
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;
|
|
42226
42063
|
}
|
|
42227
42064
|
|
|
42228
|
-
|
|
42065
|
+
// src/Items/Drawing/Drawing.ts
|
|
42066
|
+
class Drawing extends BaseItem {
|
|
42067
|
+
points;
|
|
42229
42068
|
events;
|
|
42230
|
-
itemType = "
|
|
42069
|
+
itemType = "Drawing";
|
|
42231
42070
|
parent = "Board";
|
|
42232
|
-
image;
|
|
42233
42071
|
transformation;
|
|
42234
|
-
|
|
42072
|
+
path2d = new conf.path2DFactory;
|
|
42235
42073
|
subject = new Subject;
|
|
42236
|
-
|
|
42237
|
-
|
|
42074
|
+
untransformedMbr = new Mbr;
|
|
42075
|
+
lines = [];
|
|
42076
|
+
linkTo;
|
|
42077
|
+
strokeWidth = 1;
|
|
42078
|
+
borderStyle = "solid";
|
|
42079
|
+
linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
42080
|
+
borderOpacity = 1;
|
|
42238
42081
|
transformationRenderBlock = undefined;
|
|
42239
|
-
|
|
42240
|
-
imageDimension;
|
|
42241
|
-
board;
|
|
42242
|
-
constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
|
|
42082
|
+
constructor(board, points, events, id = "") {
|
|
42243
42083
|
super(board, id);
|
|
42084
|
+
this.points = points;
|
|
42244
42085
|
this.events = events;
|
|
42245
|
-
this.linkTo = new LinkTo(this.id, events);
|
|
42246
|
-
this.board = board;
|
|
42247
|
-
this.setStorageLink(storageLink);
|
|
42248
|
-
this.imageDimension = imageDimension;
|
|
42249
42086
|
this.transformation = new Transformation(id, events);
|
|
42250
|
-
this.
|
|
42251
|
-
this.
|
|
42252
|
-
|
|
42253
|
-
|
|
42254
|
-
|
|
42255
|
-
|
|
42256
|
-
}
|
|
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
|
+
});
|
|
42257
42093
|
this.linkTo.subject.subscribe(() => {
|
|
42258
42094
|
this.updateMbr();
|
|
42095
|
+
this.updateLines();
|
|
42259
42096
|
this.subject.publish(this);
|
|
42260
42097
|
});
|
|
42261
|
-
this.
|
|
42262
|
-
}
|
|
42263
|
-
setStorageLink(link2) {
|
|
42264
|
-
try {
|
|
42265
|
-
const url = new URL(link2);
|
|
42266
|
-
this.storageLink = `${window?.location.origin}${url.pathname}`;
|
|
42267
|
-
} catch (_) {}
|
|
42268
|
-
}
|
|
42269
|
-
getStorageId() {
|
|
42270
|
-
return this.storageLink.split("/").pop();
|
|
42271
|
-
}
|
|
42272
|
-
handleError = () => {
|
|
42273
|
-
console.error("Invalid dataUrl or image failed to load.");
|
|
42274
|
-
this.image = getPlaceholderImage(this.board);
|
|
42275
|
-
this.updateMbr();
|
|
42276
|
-
this.subject.publish(this);
|
|
42277
|
-
this.shootLoadCallbacks();
|
|
42278
|
-
};
|
|
42279
|
-
onLoad = async () => {
|
|
42280
|
-
this.shootBeforeLoadCallbacks();
|
|
42281
|
-
this.updateMbr();
|
|
42282
|
-
this.subject.publish(this);
|
|
42283
|
-
this.shootLoadCallbacks();
|
|
42284
|
-
};
|
|
42285
|
-
onError = (_error) => {
|
|
42286
|
-
this.image = getPlaceholderImage(this.board);
|
|
42287
|
-
this.updateMbr();
|
|
42288
|
-
this.subject.publish(this);
|
|
42289
|
-
this.shootLoadCallbacks();
|
|
42290
|
-
};
|
|
42291
|
-
onTransform = () => {
|
|
42292
|
-
this.updateMbr();
|
|
42293
|
-
this.subject.publish(this);
|
|
42294
|
-
};
|
|
42295
|
-
updateMbr() {
|
|
42296
|
-
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
42297
|
-
this.left = translateX;
|
|
42298
|
-
this.top = translateY;
|
|
42299
|
-
this.right = this.left + this.image.width * scaleX;
|
|
42300
|
-
this.bottom = this.top + this.image.height * scaleY;
|
|
42301
|
-
}
|
|
42302
|
-
doOnceBeforeOnLoad = (callback) => {
|
|
42303
|
-
this.loadCallbacks.push(callback);
|
|
42304
|
-
};
|
|
42305
|
-
doOnceOnLoad = (callback) => {
|
|
42306
|
-
this.loadCallbacks.push(callback);
|
|
42307
|
-
};
|
|
42308
|
-
setId(id) {
|
|
42309
|
-
this.id = id;
|
|
42310
|
-
this.transformation.setId(id);
|
|
42311
|
-
this.linkTo.setId(id);
|
|
42312
|
-
return this;
|
|
42313
|
-
}
|
|
42314
|
-
getId() {
|
|
42315
|
-
return this.id;
|
|
42098
|
+
this.updateLines();
|
|
42316
42099
|
}
|
|
42317
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
|
+
}
|
|
42318
42106
|
return {
|
|
42319
|
-
itemType: "
|
|
42320
|
-
|
|
42321
|
-
imageDimension: this.imageDimension,
|
|
42107
|
+
itemType: "Drawing",
|
|
42108
|
+
points,
|
|
42322
42109
|
transformation: this.transformation.serialize(),
|
|
42110
|
+
strokeStyle: this.borderColor,
|
|
42111
|
+
strokeWidth: this.strokeWidth,
|
|
42323
42112
|
linkTo: this.linkTo.serialize()
|
|
42324
42113
|
};
|
|
42325
42114
|
}
|
|
42326
|
-
|
|
42327
|
-
this.
|
|
42328
|
-
|
|
42329
|
-
|
|
42330
|
-
this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
|
|
42331
|
-
this.subject.publish(this);
|
|
42332
|
-
}
|
|
42333
|
-
shootBeforeLoadCallbacks() {
|
|
42334
|
-
while (this.beforeLoadCallbacks.length > 0) {
|
|
42335
|
-
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));
|
|
42336
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;
|
|
42337
42127
|
}
|
|
42338
|
-
|
|
42339
|
-
|
|
42340
|
-
|
|
42341
|
-
|
|
42128
|
+
updateGeometry() {
|
|
42129
|
+
this.updatePath2d();
|
|
42130
|
+
this.updateLines();
|
|
42131
|
+
this.updateMbr();
|
|
42342
42132
|
}
|
|
42343
|
-
|
|
42344
|
-
|
|
42345
|
-
|
|
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);
|
|
42346
42164
|
}
|
|
42347
|
-
|
|
42348
|
-
|
|
42349
|
-
|
|
42350
|
-
|
|
42351
|
-
}
|
|
42352
|
-
|
|
42353
|
-
|
|
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
|
+
}
|
|
42354
42182
|
}
|
|
42355
|
-
|
|
42356
|
-
|
|
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);
|
|
42357
42197
|
}
|
|
42358
|
-
this.image = getPlaceholderImage(this.board, data.imageDimension);
|
|
42359
|
-
const storageImage = new Image;
|
|
42360
|
-
storageImage.onload = () => {
|
|
42361
|
-
this.image = storageImage;
|
|
42362
|
-
this.onLoad();
|
|
42363
|
-
};
|
|
42364
|
-
storageImage.onerror = this.onError;
|
|
42365
|
-
storageImage.src = this.storageLink;
|
|
42366
|
-
return this;
|
|
42367
42198
|
}
|
|
42368
|
-
|
|
42369
|
-
|
|
42370
|
-
|
|
42371
|
-
|
|
42372
|
-
|
|
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
|
+
}
|
|
42373
42211
|
} else {
|
|
42374
|
-
this.
|
|
42212
|
+
this.points.push(point5);
|
|
42375
42213
|
}
|
|
42214
|
+
this.updateGeometry();
|
|
42376
42215
|
}
|
|
42377
|
-
|
|
42378
|
-
this.
|
|
42216
|
+
setId(id) {
|
|
42217
|
+
this.id = id;
|
|
42218
|
+
this.transformation.setId(id);
|
|
42219
|
+
this.linkTo.setId(id);
|
|
42220
|
+
return this;
|
|
42379
42221
|
}
|
|
42380
|
-
|
|
42381
|
-
|
|
42382
|
-
case "Transformation":
|
|
42383
|
-
this.transformation.apply(op);
|
|
42384
|
-
break;
|
|
42385
|
-
case "LinkTo":
|
|
42386
|
-
this.linkTo.apply(op);
|
|
42387
|
-
break;
|
|
42388
|
-
case "Image":
|
|
42389
|
-
if (op.data.base64) {
|
|
42390
|
-
this.image.src = op.data.base64;
|
|
42391
|
-
}
|
|
42392
|
-
this.setStorageLink(op.data.storageLink);
|
|
42393
|
-
this.setDimensions(op.data.imageDimension);
|
|
42394
|
-
this.subject.publish(this);
|
|
42395
|
-
break;
|
|
42396
|
-
}
|
|
42222
|
+
getId() {
|
|
42223
|
+
return this.id;
|
|
42397
42224
|
}
|
|
42398
42225
|
render(context) {
|
|
42399
42226
|
if (this.transformationRenderBlock) {
|
|
@@ -42401,8 +42228,12 @@ class ImageItem extends BaseItem {
|
|
|
42401
42228
|
}
|
|
42402
42229
|
const ctx = context.ctx;
|
|
42403
42230
|
ctx.save();
|
|
42231
|
+
ctx.strokeStyle = this.borderColor;
|
|
42232
|
+
ctx.lineWidth = this.strokeWidth;
|
|
42233
|
+
ctx.lineCap = "round";
|
|
42234
|
+
ctx.setLineDash(this.linePattern);
|
|
42404
42235
|
this.transformation.matrix.applyToContext(ctx);
|
|
42405
|
-
ctx.
|
|
42236
|
+
ctx.stroke(this.path2d.nativePath);
|
|
42406
42237
|
ctx.restore();
|
|
42407
42238
|
if (this.getLinkTo()) {
|
|
42408
42239
|
const { top, right } = this.getMbr();
|
|
@@ -42410,26 +42241,61 @@ class ImageItem extends BaseItem {
|
|
|
42410
42241
|
}
|
|
42411
42242
|
}
|
|
42412
42243
|
renderHTML(documentFactory) {
|
|
42413
|
-
const div = documentFactory.createElement("
|
|
42244
|
+
const div = documentFactory.createElement("drawing-item");
|
|
42414
42245
|
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
42415
|
-
const
|
|
42416
|
-
|
|
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);
|
|
42417
42263
|
div.id = this.getId();
|
|
42418
|
-
div.style.width =
|
|
42419
|
-
div.style.height =
|
|
42420
|
-
div.style.transformOrigin = "top
|
|
42421
|
-
div.style.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})`;
|
|
42422
42268
|
div.style.position = "absolute";
|
|
42423
|
-
div.style.backgroundSize = "cover";
|
|
42424
42269
|
div.setAttribute("data-link-to", this.linkTo.serialize() || "");
|
|
42425
42270
|
if (this.getLinkTo()) {
|
|
42426
42271
|
const linkElement = this.linkTo.renderHTML(documentFactory);
|
|
42427
42272
|
scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
|
|
42428
|
-
translateElementBy(linkElement, (
|
|
42273
|
+
translateElementBy(linkElement, (width2 - parseInt(linkElement.style.width)) / scaleX, 0);
|
|
42429
42274
|
div.appendChild(linkElement);
|
|
42430
42275
|
}
|
|
42431
42276
|
return div;
|
|
42432
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
|
+
}
|
|
42433
42299
|
getPath() {
|
|
42434
42300
|
const { left, top, right, bottom } = this.getMbr();
|
|
42435
42301
|
const leftTop = new Point(left, top);
|
|
@@ -42454,27 +42320,162 @@ class ImageItem extends BaseItem {
|
|
|
42454
42320
|
new Point(mbr.right, mbr.top + height2 / 2)
|
|
42455
42321
|
];
|
|
42456
42322
|
}
|
|
42323
|
+
getLines() {
|
|
42324
|
+
return this.lines;
|
|
42325
|
+
}
|
|
42457
42326
|
isClosed() {
|
|
42458
42327
|
return true;
|
|
42459
42328
|
}
|
|
42460
|
-
|
|
42461
|
-
|
|
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;
|
|
42462
42423
|
}
|
|
42463
42424
|
getLinkTo() {
|
|
42464
42425
|
return this.linkTo.link;
|
|
42465
42426
|
}
|
|
42466
|
-
|
|
42467
|
-
|
|
42468
|
-
linkElem.href = this.storageLink;
|
|
42469
|
-
linkElem.setAttribute("download", "");
|
|
42470
|
-
linkElem.click();
|
|
42427
|
+
getStrokeWidth() {
|
|
42428
|
+
return this.strokeWidth;
|
|
42471
42429
|
}
|
|
42472
|
-
|
|
42473
|
-
|
|
42474
|
-
|
|
42475
|
-
|
|
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
|
+
}
|
|
42476
42444
|
}
|
|
42477
|
-
|
|
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];
|
|
42478
42479
|
}
|
|
42479
42480
|
}
|
|
42480
42481
|
// src/Items/Group/Group.ts
|