microboard-temp 0.4.41 → 0.4.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/browser.js +609 -609
- package/dist/cjs/index.js +609 -609
- package/dist/cjs/node.js +609 -609
- package/dist/esm/browser.js +609 -609
- package/dist/esm/index.js +609 -609
- package/dist/esm/node.js +609 -609
- 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";
|
|
@@ -42349,202 +41922,455 @@ class Placeholder extends BaseItem {
|
|
|
42349
41922
|
renderHTML(documentFactory) {
|
|
42350
41923
|
return documentFactory.createElement("div");
|
|
42351
41924
|
}
|
|
42352
|
-
getLinkTo() {
|
|
42353
|
-
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;
|
|
42354
42183
|
}
|
|
42355
42184
|
getRichText() {
|
|
42356
42185
|
return null;
|
|
42357
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
|
+
}
|
|
42358
42203
|
}
|
|
42359
|
-
// src/
|
|
42360
|
-
function
|
|
42361
|
-
|
|
42362
|
-
|
|
42363
|
-
const context = new DrawingContext(board.camera, placeholderContext);
|
|
42364
|
-
const placeholder = new Placeholder(board);
|
|
42365
|
-
if (imageDimension) {
|
|
42366
|
-
placeholderCanvas.width = imageDimension.width;
|
|
42367
|
-
placeholderCanvas.height = imageDimension.height;
|
|
42368
|
-
placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
|
|
42369
|
-
} else {
|
|
42370
|
-
placeholderCanvas.width = 250;
|
|
42371
|
-
placeholderCanvas.height = 50;
|
|
42372
|
-
placeholder.transformation.scaleTo(250 / 100, 50 / 100);
|
|
42204
|
+
// src/isSafari.ts
|
|
42205
|
+
function isSafari() {
|
|
42206
|
+
if (typeof navigator === "undefined") {
|
|
42207
|
+
return false;
|
|
42373
42208
|
}
|
|
42374
|
-
const
|
|
42375
|
-
|
|
42376
|
-
|
|
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;
|
|
42377
42213
|
}
|
|
42378
42214
|
|
|
42379
|
-
|
|
42215
|
+
// src/Items/Drawing/Drawing.ts
|
|
42216
|
+
class Drawing extends BaseItem {
|
|
42217
|
+
points;
|
|
42380
42218
|
events;
|
|
42381
|
-
itemType = "
|
|
42219
|
+
itemType = "Drawing";
|
|
42382
42220
|
parent = "Board";
|
|
42383
|
-
image;
|
|
42384
42221
|
transformation;
|
|
42385
|
-
|
|
42222
|
+
path2d = new conf.path2DFactory;
|
|
42386
42223
|
subject = new Subject;
|
|
42387
|
-
|
|
42388
|
-
|
|
42224
|
+
untransformedMbr = new Mbr;
|
|
42225
|
+
lines = [];
|
|
42226
|
+
linkTo;
|
|
42227
|
+
strokeWidth = 1;
|
|
42228
|
+
borderStyle = "solid";
|
|
42229
|
+
linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
42230
|
+
borderOpacity = 1;
|
|
42389
42231
|
transformationRenderBlock = undefined;
|
|
42390
|
-
|
|
42391
|
-
imageDimension;
|
|
42392
|
-
board;
|
|
42393
|
-
constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
|
|
42232
|
+
constructor(board, points, events, id = "") {
|
|
42394
42233
|
super(board, id);
|
|
42234
|
+
this.points = points;
|
|
42395
42235
|
this.events = events;
|
|
42396
|
-
this.linkTo = new LinkTo(this.id, events);
|
|
42397
|
-
this.board = board;
|
|
42398
|
-
this.setStorageLink(storageLink);
|
|
42399
|
-
this.imageDimension = imageDimension;
|
|
42400
42236
|
this.transformation = new Transformation(id, events);
|
|
42401
|
-
this.
|
|
42402
|
-
this.
|
|
42403
|
-
|
|
42404
|
-
|
|
42405
|
-
|
|
42406
|
-
|
|
42407
|
-
}
|
|
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
|
+
});
|
|
42408
42243
|
this.linkTo.subject.subscribe(() => {
|
|
42409
42244
|
this.updateMbr();
|
|
42245
|
+
this.updateLines();
|
|
42410
42246
|
this.subject.publish(this);
|
|
42411
42247
|
});
|
|
42412
|
-
this.
|
|
42413
|
-
}
|
|
42414
|
-
setStorageLink(link2) {
|
|
42415
|
-
try {
|
|
42416
|
-
const url = new URL(link2);
|
|
42417
|
-
this.storageLink = `${window?.location.origin}${url.pathname}`;
|
|
42418
|
-
} catch (_) {}
|
|
42419
|
-
}
|
|
42420
|
-
getStorageId() {
|
|
42421
|
-
return this.storageLink.split("/").pop();
|
|
42422
|
-
}
|
|
42423
|
-
handleError = () => {
|
|
42424
|
-
console.error("Invalid dataUrl or image failed to load.");
|
|
42425
|
-
this.image = getPlaceholderImage(this.board);
|
|
42426
|
-
this.updateMbr();
|
|
42427
|
-
this.subject.publish(this);
|
|
42428
|
-
this.shootLoadCallbacks();
|
|
42429
|
-
};
|
|
42430
|
-
onLoad = async () => {
|
|
42431
|
-
this.shootBeforeLoadCallbacks();
|
|
42432
|
-
this.updateMbr();
|
|
42433
|
-
this.subject.publish(this);
|
|
42434
|
-
this.shootLoadCallbacks();
|
|
42435
|
-
};
|
|
42436
|
-
onError = (_error) => {
|
|
42437
|
-
this.image = getPlaceholderImage(this.board);
|
|
42438
|
-
this.updateMbr();
|
|
42439
|
-
this.subject.publish(this);
|
|
42440
|
-
this.shootLoadCallbacks();
|
|
42441
|
-
};
|
|
42442
|
-
onTransform = () => {
|
|
42443
|
-
this.updateMbr();
|
|
42444
|
-
this.subject.publish(this);
|
|
42445
|
-
};
|
|
42446
|
-
updateMbr() {
|
|
42447
|
-
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
42448
|
-
this.left = translateX;
|
|
42449
|
-
this.top = translateY;
|
|
42450
|
-
this.right = this.left + this.image.width * scaleX;
|
|
42451
|
-
this.bottom = this.top + this.image.height * scaleY;
|
|
42452
|
-
}
|
|
42453
|
-
doOnceBeforeOnLoad = (callback) => {
|
|
42454
|
-
this.loadCallbacks.push(callback);
|
|
42455
|
-
};
|
|
42456
|
-
doOnceOnLoad = (callback) => {
|
|
42457
|
-
this.loadCallbacks.push(callback);
|
|
42458
|
-
};
|
|
42459
|
-
setId(id) {
|
|
42460
|
-
this.id = id;
|
|
42461
|
-
this.transformation.setId(id);
|
|
42462
|
-
this.linkTo.setId(id);
|
|
42463
|
-
return this;
|
|
42464
|
-
}
|
|
42465
|
-
getId() {
|
|
42466
|
-
return this.id;
|
|
42248
|
+
this.updateLines();
|
|
42467
42249
|
}
|
|
42468
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
|
+
}
|
|
42469
42256
|
return {
|
|
42470
|
-
itemType: "
|
|
42471
|
-
|
|
42472
|
-
imageDimension: this.imageDimension,
|
|
42257
|
+
itemType: "Drawing",
|
|
42258
|
+
points,
|
|
42473
42259
|
transformation: this.transformation.serialize(),
|
|
42260
|
+
strokeStyle: this.borderColor,
|
|
42261
|
+
strokeWidth: this.strokeWidth,
|
|
42474
42262
|
linkTo: this.linkTo.serialize()
|
|
42475
42263
|
};
|
|
42476
42264
|
}
|
|
42477
|
-
|
|
42478
|
-
this.
|
|
42479
|
-
|
|
42480
|
-
|
|
42481
|
-
this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
|
|
42482
|
-
this.subject.publish(this);
|
|
42483
|
-
}
|
|
42484
|
-
shootBeforeLoadCallbacks() {
|
|
42485
|
-
while (this.beforeLoadCallbacks.length > 0) {
|
|
42486
|
-
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));
|
|
42487
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;
|
|
42488
42277
|
}
|
|
42489
|
-
|
|
42490
|
-
|
|
42491
|
-
|
|
42492
|
-
|
|
42278
|
+
updateGeometry() {
|
|
42279
|
+
this.updatePath2d();
|
|
42280
|
+
this.updateLines();
|
|
42281
|
+
this.updateMbr();
|
|
42493
42282
|
}
|
|
42494
|
-
|
|
42495
|
-
|
|
42496
|
-
|
|
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);
|
|
42497
42314
|
}
|
|
42498
|
-
|
|
42499
|
-
|
|
42500
|
-
|
|
42501
|
-
|
|
42502
|
-
}
|
|
42503
|
-
|
|
42504
|
-
|
|
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
|
+
}
|
|
42505
42332
|
}
|
|
42506
|
-
|
|
42507
|
-
|
|
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);
|
|
42508
42347
|
}
|
|
42509
|
-
this.image = getPlaceholderImage(this.board, data.imageDimension);
|
|
42510
|
-
const storageImage = new Image;
|
|
42511
|
-
storageImage.onload = () => {
|
|
42512
|
-
this.image = storageImage;
|
|
42513
|
-
this.onLoad();
|
|
42514
|
-
};
|
|
42515
|
-
storageImage.onerror = this.onError;
|
|
42516
|
-
storageImage.src = this.storageLink;
|
|
42517
|
-
return this;
|
|
42518
42348
|
}
|
|
42519
|
-
|
|
42520
|
-
|
|
42521
|
-
|
|
42522
|
-
|
|
42523
|
-
|
|
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
|
+
}
|
|
42524
42361
|
} else {
|
|
42525
|
-
this.
|
|
42362
|
+
this.points.push(point5);
|
|
42526
42363
|
}
|
|
42364
|
+
this.updateGeometry();
|
|
42527
42365
|
}
|
|
42528
|
-
|
|
42529
|
-
this.
|
|
42366
|
+
setId(id) {
|
|
42367
|
+
this.id = id;
|
|
42368
|
+
this.transformation.setId(id);
|
|
42369
|
+
this.linkTo.setId(id);
|
|
42370
|
+
return this;
|
|
42530
42371
|
}
|
|
42531
|
-
|
|
42532
|
-
|
|
42533
|
-
case "Transformation":
|
|
42534
|
-
this.transformation.apply(op);
|
|
42535
|
-
break;
|
|
42536
|
-
case "LinkTo":
|
|
42537
|
-
this.linkTo.apply(op);
|
|
42538
|
-
break;
|
|
42539
|
-
case "Image":
|
|
42540
|
-
if (op.data.base64) {
|
|
42541
|
-
this.image.src = op.data.base64;
|
|
42542
|
-
}
|
|
42543
|
-
this.setStorageLink(op.data.storageLink);
|
|
42544
|
-
this.setDimensions(op.data.imageDimension);
|
|
42545
|
-
this.subject.publish(this);
|
|
42546
|
-
break;
|
|
42547
|
-
}
|
|
42372
|
+
getId() {
|
|
42373
|
+
return this.id;
|
|
42548
42374
|
}
|
|
42549
42375
|
render(context) {
|
|
42550
42376
|
if (this.transformationRenderBlock) {
|
|
@@ -42552,8 +42378,12 @@ class ImageItem extends BaseItem {
|
|
|
42552
42378
|
}
|
|
42553
42379
|
const ctx = context.ctx;
|
|
42554
42380
|
ctx.save();
|
|
42381
|
+
ctx.strokeStyle = this.borderColor;
|
|
42382
|
+
ctx.lineWidth = this.strokeWidth;
|
|
42383
|
+
ctx.lineCap = "round";
|
|
42384
|
+
ctx.setLineDash(this.linePattern);
|
|
42555
42385
|
this.transformation.matrix.applyToContext(ctx);
|
|
42556
|
-
ctx.
|
|
42386
|
+
ctx.stroke(this.path2d.nativePath);
|
|
42557
42387
|
ctx.restore();
|
|
42558
42388
|
if (this.getLinkTo()) {
|
|
42559
42389
|
const { top, right } = this.getMbr();
|
|
@@ -42561,26 +42391,61 @@ class ImageItem extends BaseItem {
|
|
|
42561
42391
|
}
|
|
42562
42392
|
}
|
|
42563
42393
|
renderHTML(documentFactory) {
|
|
42564
|
-
const div = documentFactory.createElement("
|
|
42394
|
+
const div = documentFactory.createElement("drawing-item");
|
|
42565
42395
|
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
42566
|
-
const
|
|
42567
|
-
|
|
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);
|
|
42568
42413
|
div.id = this.getId();
|
|
42569
|
-
div.style.width =
|
|
42570
|
-
div.style.height =
|
|
42571
|
-
div.style.transformOrigin = "top
|
|
42572
|
-
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})`;
|
|
42573
42418
|
div.style.position = "absolute";
|
|
42574
|
-
div.style.backgroundSize = "cover";
|
|
42575
42419
|
div.setAttribute("data-link-to", this.linkTo.serialize() || "");
|
|
42576
42420
|
if (this.getLinkTo()) {
|
|
42577
42421
|
const linkElement = this.linkTo.renderHTML(documentFactory);
|
|
42578
42422
|
scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
|
|
42579
|
-
translateElementBy(linkElement, (
|
|
42423
|
+
translateElementBy(linkElement, (width2 - parseInt(linkElement.style.width)) / scaleX, 0);
|
|
42580
42424
|
div.appendChild(linkElement);
|
|
42581
42425
|
}
|
|
42582
42426
|
return div;
|
|
42583
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
|
+
}
|
|
42584
42449
|
getPath() {
|
|
42585
42450
|
const { left, top, right, bottom } = this.getMbr();
|
|
42586
42451
|
const leftTop = new Point(left, top);
|
|
@@ -42605,27 +42470,162 @@ class ImageItem extends BaseItem {
|
|
|
42605
42470
|
new Point(mbr.right, mbr.top + height2 / 2)
|
|
42606
42471
|
];
|
|
42607
42472
|
}
|
|
42473
|
+
getLines() {
|
|
42474
|
+
return this.lines;
|
|
42475
|
+
}
|
|
42608
42476
|
isClosed() {
|
|
42609
42477
|
return true;
|
|
42610
42478
|
}
|
|
42611
|
-
|
|
42612
|
-
|
|
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;
|
|
42613
42573
|
}
|
|
42614
42574
|
getLinkTo() {
|
|
42615
42575
|
return this.linkTo.link;
|
|
42616
42576
|
}
|
|
42617
|
-
|
|
42618
|
-
|
|
42619
|
-
linkElem.href = this.storageLink;
|
|
42620
|
-
linkElem.setAttribute("download", "");
|
|
42621
|
-
linkElem.click();
|
|
42577
|
+
getStrokeWidth() {
|
|
42578
|
+
return this.strokeWidth;
|
|
42622
42579
|
}
|
|
42623
|
-
|
|
42624
|
-
|
|
42625
|
-
|
|
42626
|
-
|
|
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
|
+
}
|
|
42627
42594
|
}
|
|
42628
|
-
|
|
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];
|
|
42629
42629
|
}
|
|
42630
42630
|
}
|
|
42631
42631
|
// src/Items/Group/Group.ts
|