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