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