microboard-temp 0.4.40 → 0.4.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/browser.js +610 -609
- package/dist/cjs/index.js +610 -609
- package/dist/cjs/node.js +610 -609
- package/dist/esm/browser.js +610 -609
- package/dist/esm/index.js +610 -609
- package/dist/esm/node.js +610 -609
- package/dist/types/Items/BaseItem/BaseItem.d.ts +1 -1
- package/dist/types/SpatialIndex/SimpleSpatialIndex.d.ts +39 -0
- package/dist/types/SpatialIndex/SpacialIndex.d.ts +0 -31
- package/package.json +1 -1
package/dist/esm/node.js
CHANGED
|
@@ -22020,433 +22020,6 @@ class NoOpCommand {
|
|
|
22020
22020
|
}
|
|
22021
22021
|
}
|
|
22022
22022
|
|
|
22023
|
-
// src/isSafari.ts
|
|
22024
|
-
function isSafari() {
|
|
22025
|
-
if (typeof navigator === "undefined") {
|
|
22026
|
-
return false;
|
|
22027
|
-
}
|
|
22028
|
-
const agent = navigator.userAgent;
|
|
22029
|
-
const vendor = navigator.vendor;
|
|
22030
|
-
const is = vendor !== undefined && vendor.includes("Apple") && agent !== undefined && !agent.includes("CriOS") && !agent.includes("FxiOS");
|
|
22031
|
-
return is;
|
|
22032
|
-
}
|
|
22033
|
-
|
|
22034
|
-
// src/Items/Drawing/Drawing.ts
|
|
22035
|
-
class Drawing extends BaseItem {
|
|
22036
|
-
points;
|
|
22037
|
-
events;
|
|
22038
|
-
itemType = "Drawing";
|
|
22039
|
-
parent = "Board";
|
|
22040
|
-
transformation;
|
|
22041
|
-
path2d = new conf.path2DFactory;
|
|
22042
|
-
subject = new Subject;
|
|
22043
|
-
untransformedMbr = new Mbr;
|
|
22044
|
-
lines = [];
|
|
22045
|
-
linkTo;
|
|
22046
|
-
strokeWidth = 1;
|
|
22047
|
-
borderStyle = "solid";
|
|
22048
|
-
linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
22049
|
-
borderOpacity = 1;
|
|
22050
|
-
transformationRenderBlock = undefined;
|
|
22051
|
-
constructor(board, points, events, id = "") {
|
|
22052
|
-
super(board, id);
|
|
22053
|
-
this.points = points;
|
|
22054
|
-
this.events = events;
|
|
22055
|
-
this.transformation = new Transformation(id, events);
|
|
22056
|
-
this.linkTo = new LinkTo(this.id, this.events);
|
|
22057
|
-
this.transformation.subject.subscribe(() => {
|
|
22058
|
-
this.updateMbr();
|
|
22059
|
-
this.updateLines();
|
|
22060
|
-
this.subject.publish(this);
|
|
22061
|
-
});
|
|
22062
|
-
this.linkTo.subject.subscribe(() => {
|
|
22063
|
-
this.updateMbr();
|
|
22064
|
-
this.updateLines();
|
|
22065
|
-
this.subject.publish(this);
|
|
22066
|
-
});
|
|
22067
|
-
this.updateLines();
|
|
22068
|
-
}
|
|
22069
|
-
serialize() {
|
|
22070
|
-
this.optimizePoints();
|
|
22071
|
-
const points = [];
|
|
22072
|
-
for (const point3 of this.points) {
|
|
22073
|
-
points.push({ x: point3.x, y: point3.y });
|
|
22074
|
-
}
|
|
22075
|
-
return {
|
|
22076
|
-
itemType: "Drawing",
|
|
22077
|
-
points,
|
|
22078
|
-
transformation: this.transformation.serialize(),
|
|
22079
|
-
strokeStyle: this.borderColor,
|
|
22080
|
-
strokeWidth: this.strokeWidth,
|
|
22081
|
-
linkTo: this.linkTo.serialize()
|
|
22082
|
-
};
|
|
22083
|
-
}
|
|
22084
|
-
deserialize(data) {
|
|
22085
|
-
this.points = [];
|
|
22086
|
-
for (const point3 of data.points) {
|
|
22087
|
-
this.points.push(new Point(point3.x, point3.y));
|
|
22088
|
-
}
|
|
22089
|
-
this.linkTo.deserialize(data.linkTo);
|
|
22090
|
-
this.optimizePoints();
|
|
22091
|
-
this.transformation.deserialize(data.transformation);
|
|
22092
|
-
this.borderColor = data.strokeStyle;
|
|
22093
|
-
this.strokeWidth = data.strokeWidth;
|
|
22094
|
-
this.updateGeometry();
|
|
22095
|
-
return this;
|
|
22096
|
-
}
|
|
22097
|
-
updateGeometry() {
|
|
22098
|
-
this.updatePath2d();
|
|
22099
|
-
this.updateLines();
|
|
22100
|
-
this.updateMbr();
|
|
22101
|
-
}
|
|
22102
|
-
updateMbr() {
|
|
22103
|
-
const offset = this.getStrokeWidth() / 2;
|
|
22104
|
-
const untransformedMbr = this.untransformedMbr.copy();
|
|
22105
|
-
untransformedMbr.left -= offset;
|
|
22106
|
-
untransformedMbr.top -= offset;
|
|
22107
|
-
untransformedMbr.right += offset;
|
|
22108
|
-
untransformedMbr.bottom += offset;
|
|
22109
|
-
const mbr = untransformedMbr.getTransformed(this.transformation.matrix);
|
|
22110
|
-
this.left = mbr.left;
|
|
22111
|
-
this.top = mbr.top;
|
|
22112
|
-
this.right = mbr.right;
|
|
22113
|
-
this.bottom = mbr.bottom;
|
|
22114
|
-
}
|
|
22115
|
-
updatePath2d() {
|
|
22116
|
-
this.path2d = new conf.path2DFactory;
|
|
22117
|
-
const context = this.path2d;
|
|
22118
|
-
const points = this.points;
|
|
22119
|
-
if (points.length < 3) {
|
|
22120
|
-
context.arc(points[0].x, points[0].y, 0.5, 0, Math.PI * 2, true);
|
|
22121
|
-
context.closePath();
|
|
22122
|
-
} else {
|
|
22123
|
-
context.moveTo(points[0].x, points[0].y);
|
|
22124
|
-
let j = 1;
|
|
22125
|
-
for (;j < points.length - 2; j++) {
|
|
22126
|
-
const cx = (points[j].x + points[j + 1].x) / 2;
|
|
22127
|
-
const cy = (points[j].y + points[j + 1].y) / 2;
|
|
22128
|
-
context.quadraticCurveTo(points[j].x, points[j].y, cx, cy);
|
|
22129
|
-
}
|
|
22130
|
-
const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
|
|
22131
|
-
const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
|
|
22132
|
-
context.quadraticCurveTo(points[j].x, points[j].y, x, y);
|
|
22133
|
-
}
|
|
22134
|
-
let left = Number.MAX_SAFE_INTEGER;
|
|
22135
|
-
let right = Number.MIN_SAFE_INTEGER;
|
|
22136
|
-
let top = Number.MAX_SAFE_INTEGER;
|
|
22137
|
-
let bottom = Number.MIN_SAFE_INTEGER;
|
|
22138
|
-
for (const { x, y } of this.points) {
|
|
22139
|
-
if (x < left) {
|
|
22140
|
-
left = x;
|
|
22141
|
-
}
|
|
22142
|
-
if (x > right) {
|
|
22143
|
-
right = x;
|
|
22144
|
-
}
|
|
22145
|
-
if (y < top) {
|
|
22146
|
-
top = y;
|
|
22147
|
-
}
|
|
22148
|
-
if (y > bottom) {
|
|
22149
|
-
bottom = y;
|
|
22150
|
-
}
|
|
22151
|
-
}
|
|
22152
|
-
this.untransformedMbr = new Mbr(left, top, right, bottom);
|
|
22153
|
-
}
|
|
22154
|
-
updateLines() {
|
|
22155
|
-
this.lines = [];
|
|
22156
|
-
const matrix = this.transformation.matrix;
|
|
22157
|
-
if (this.points.length < 2) {
|
|
22158
|
-
return;
|
|
22159
|
-
}
|
|
22160
|
-
for (let i = 0;i < this.points.length - 2; i++) {
|
|
22161
|
-
const p1 = this.points[i];
|
|
22162
|
-
const p2 = this.points[i + 1];
|
|
22163
|
-
const line = new Line(p1.copy(), p2.copy());
|
|
22164
|
-
line.transform(matrix);
|
|
22165
|
-
this.lines.push(line);
|
|
22166
|
-
}
|
|
22167
|
-
}
|
|
22168
|
-
optimizePoints() {
|
|
22169
|
-
const dp = douglasPeucker(this.points, 1);
|
|
22170
|
-
dp.push(this.points[this.points.length - 1]);
|
|
22171
|
-
this.points = dp;
|
|
22172
|
-
}
|
|
22173
|
-
addPoint(point3) {
|
|
22174
|
-
const previous2 = this.points[this.points.length - 1];
|
|
22175
|
-
if (previous2) {
|
|
22176
|
-
const distance = point3.getDistance(previous2);
|
|
22177
|
-
if (distance >= 2) {
|
|
22178
|
-
this.points.push(point3);
|
|
22179
|
-
}
|
|
22180
|
-
} else {
|
|
22181
|
-
this.points.push(point3);
|
|
22182
|
-
}
|
|
22183
|
-
this.updateGeometry();
|
|
22184
|
-
}
|
|
22185
|
-
setId(id) {
|
|
22186
|
-
this.id = id;
|
|
22187
|
-
this.transformation.setId(id);
|
|
22188
|
-
this.linkTo.setId(id);
|
|
22189
|
-
return this;
|
|
22190
|
-
}
|
|
22191
|
-
getId() {
|
|
22192
|
-
return this.id;
|
|
22193
|
-
}
|
|
22194
|
-
render(context) {
|
|
22195
|
-
if (this.transformationRenderBlock) {
|
|
22196
|
-
return;
|
|
22197
|
-
}
|
|
22198
|
-
const ctx = context.ctx;
|
|
22199
|
-
ctx.save();
|
|
22200
|
-
ctx.strokeStyle = this.borderColor;
|
|
22201
|
-
ctx.lineWidth = this.strokeWidth;
|
|
22202
|
-
ctx.lineCap = "round";
|
|
22203
|
-
ctx.setLineDash(this.linePattern);
|
|
22204
|
-
this.transformation.matrix.applyToContext(ctx);
|
|
22205
|
-
ctx.stroke(this.path2d.nativePath);
|
|
22206
|
-
ctx.restore();
|
|
22207
|
-
if (this.getLinkTo()) {
|
|
22208
|
-
const { top, right } = this.getMbr();
|
|
22209
|
-
this.linkTo.render(context, top, right, this.board.camera.getScale());
|
|
22210
|
-
}
|
|
22211
|
-
}
|
|
22212
|
-
renderHTML(documentFactory) {
|
|
22213
|
-
const div = documentFactory.createElement("drawing-item");
|
|
22214
|
-
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
22215
|
-
const mbr = this.getMbr();
|
|
22216
|
-
const width = mbr.getWidth();
|
|
22217
|
-
const height = mbr.getHeight();
|
|
22218
|
-
const unscaledWidth = width / scaleX;
|
|
22219
|
-
const unscaledHeight = height / scaleY;
|
|
22220
|
-
const svg = documentFactory.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
22221
|
-
svg.setAttribute("width", `${unscaledWidth}px`);
|
|
22222
|
-
svg.setAttribute("height", `${unscaledHeight}px`);
|
|
22223
|
-
svg.setAttribute("viewBox", `0 0 ${unscaledWidth} ${unscaledHeight}`);
|
|
22224
|
-
svg.setAttribute("style", "position: absolute; overflow: visible;");
|
|
22225
|
-
const pathElement = documentFactory.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
22226
|
-
pathElement.setAttribute("d", this.getPathData());
|
|
22227
|
-
pathElement.setAttribute("stroke", this.borderColor);
|
|
22228
|
-
pathElement.setAttribute("stroke-width", `${this.strokeWidth}`);
|
|
22229
|
-
pathElement.setAttribute("fill", "none");
|
|
22230
|
-
svg.appendChild(pathElement);
|
|
22231
|
-
div.appendChild(svg);
|
|
22232
|
-
div.id = this.getId();
|
|
22233
|
-
div.style.width = unscaledWidth + "px";
|
|
22234
|
-
div.style.height = unscaledHeight + "px";
|
|
22235
|
-
div.style.transformOrigin = "left top";
|
|
22236
|
-
div.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
|
|
22237
|
-
div.style.position = "absolute";
|
|
22238
|
-
div.setAttribute("data-link-to", this.linkTo.serialize() || "");
|
|
22239
|
-
if (this.getLinkTo()) {
|
|
22240
|
-
const linkElement = this.linkTo.renderHTML(documentFactory);
|
|
22241
|
-
scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
|
|
22242
|
-
translateElementBy(linkElement, (width - parseInt(linkElement.style.width)) / scaleX, 0);
|
|
22243
|
-
div.appendChild(linkElement);
|
|
22244
|
-
}
|
|
22245
|
-
return div;
|
|
22246
|
-
}
|
|
22247
|
-
getPathData() {
|
|
22248
|
-
const points = this.points;
|
|
22249
|
-
if (points.length < 2) {
|
|
22250
|
-
return "";
|
|
22251
|
-
}
|
|
22252
|
-
let pathData = `M ${points[0].x} ${points[0].y}`;
|
|
22253
|
-
if (points.length < 3) {
|
|
22254
|
-
pathData += ` L ${points[0].x + 0.5} ${points[0].y}`;
|
|
22255
|
-
} else {
|
|
22256
|
-
let j = 1;
|
|
22257
|
-
for (;j < points.length - 2; j++) {
|
|
22258
|
-
const cx = (points[j].x + points[j + 1].x) / 2;
|
|
22259
|
-
const cy = (points[j].y + points[j + 1].y) / 2;
|
|
22260
|
-
pathData += ` Q ${points[j].x} ${points[j].y} ${cx} ${cy}`;
|
|
22261
|
-
}
|
|
22262
|
-
const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
|
|
22263
|
-
const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
|
|
22264
|
-
pathData += ` Q ${points[j].x} ${points[j].y} ${x} ${y}`;
|
|
22265
|
-
}
|
|
22266
|
-
return pathData;
|
|
22267
|
-
}
|
|
22268
|
-
getPath() {
|
|
22269
|
-
const { left, top, right, bottom } = this.getMbr();
|
|
22270
|
-
const leftTop = new Point(left, top);
|
|
22271
|
-
const rightTop = new Point(right, top);
|
|
22272
|
-
const rightBottom = new Point(right, bottom);
|
|
22273
|
-
const leftBottom = new Point(left, bottom);
|
|
22274
|
-
return new Path([
|
|
22275
|
-
new Line(leftTop, rightTop),
|
|
22276
|
-
new Line(rightTop, rightBottom),
|
|
22277
|
-
new Line(rightBottom, leftBottom),
|
|
22278
|
-
new Line(leftBottom, leftTop)
|
|
22279
|
-
], true);
|
|
22280
|
-
}
|
|
22281
|
-
getSnapAnchorPoints() {
|
|
22282
|
-
const mbr = this.getMbr();
|
|
22283
|
-
const width = mbr.getWidth();
|
|
22284
|
-
const height = mbr.getHeight();
|
|
22285
|
-
return [
|
|
22286
|
-
new Point(mbr.left + width / 2, mbr.top),
|
|
22287
|
-
new Point(mbr.left + width / 2, mbr.bottom),
|
|
22288
|
-
new Point(mbr.left, mbr.top + height / 2),
|
|
22289
|
-
new Point(mbr.right, mbr.top + height / 2)
|
|
22290
|
-
];
|
|
22291
|
-
}
|
|
22292
|
-
getLines() {
|
|
22293
|
-
return this.lines;
|
|
22294
|
-
}
|
|
22295
|
-
isClosed() {
|
|
22296
|
-
return true;
|
|
22297
|
-
}
|
|
22298
|
-
isEnclosedOrCrossedBy(rect) {
|
|
22299
|
-
for (const line of this.lines) {
|
|
22300
|
-
if (line.isEnclosedOrCrossedBy(rect)) {
|
|
22301
|
-
return true;
|
|
22302
|
-
}
|
|
22303
|
-
}
|
|
22304
|
-
return false;
|
|
22305
|
-
}
|
|
22306
|
-
emit(operation) {
|
|
22307
|
-
if (this.events) {
|
|
22308
|
-
const command = new DrawingCommand([this], operation);
|
|
22309
|
-
command.apply();
|
|
22310
|
-
this.events.emit(operation, command);
|
|
22311
|
-
} else {
|
|
22312
|
-
this.apply(operation);
|
|
22313
|
-
}
|
|
22314
|
-
}
|
|
22315
|
-
apply(op) {
|
|
22316
|
-
switch (op.class) {
|
|
22317
|
-
case "Drawing":
|
|
22318
|
-
switch (op.method) {
|
|
22319
|
-
case "setStrokeColor":
|
|
22320
|
-
this.borderColor = op.color;
|
|
22321
|
-
break;
|
|
22322
|
-
case "setStrokeWidth":
|
|
22323
|
-
this.strokeWidth = op.width;
|
|
22324
|
-
this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
22325
|
-
break;
|
|
22326
|
-
case "setStrokeOpacity":
|
|
22327
|
-
this.borderOpacity = op.opacity;
|
|
22328
|
-
break;
|
|
22329
|
-
case "setStrokeStyle":
|
|
22330
|
-
this.borderStyle = op.style;
|
|
22331
|
-
this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
22332
|
-
break;
|
|
22333
|
-
}
|
|
22334
|
-
this.updateMbr();
|
|
22335
|
-
break;
|
|
22336
|
-
case "Transformation":
|
|
22337
|
-
this.transformation.apply(op);
|
|
22338
|
-
break;
|
|
22339
|
-
case "LinkTo":
|
|
22340
|
-
this.linkTo.apply(op);
|
|
22341
|
-
break;
|
|
22342
|
-
default:
|
|
22343
|
-
return;
|
|
22344
|
-
}
|
|
22345
|
-
this.subject.publish(this);
|
|
22346
|
-
}
|
|
22347
|
-
setStrokeOpacity(opacity) {
|
|
22348
|
-
this.emit({
|
|
22349
|
-
class: "Drawing",
|
|
22350
|
-
method: "setStrokeOpacity",
|
|
22351
|
-
item: [this.id],
|
|
22352
|
-
opacity
|
|
22353
|
-
});
|
|
22354
|
-
return this;
|
|
22355
|
-
}
|
|
22356
|
-
getStrokeOpacity() {
|
|
22357
|
-
return this.borderOpacity;
|
|
22358
|
-
}
|
|
22359
|
-
setBorderStyle(style) {
|
|
22360
|
-
this.emit({
|
|
22361
|
-
class: "Drawing",
|
|
22362
|
-
method: "setStrokeStyle",
|
|
22363
|
-
item: [this.id],
|
|
22364
|
-
style
|
|
22365
|
-
});
|
|
22366
|
-
return this;
|
|
22367
|
-
}
|
|
22368
|
-
getBorderStyle() {
|
|
22369
|
-
return this.borderStyle;
|
|
22370
|
-
}
|
|
22371
|
-
setStrokeColor(color) {
|
|
22372
|
-
this.emit({
|
|
22373
|
-
class: "Drawing",
|
|
22374
|
-
method: "setStrokeColor",
|
|
22375
|
-
item: [this.id],
|
|
22376
|
-
color
|
|
22377
|
-
});
|
|
22378
|
-
return this;
|
|
22379
|
-
}
|
|
22380
|
-
getStrokeColor() {
|
|
22381
|
-
return this.borderColor;
|
|
22382
|
-
}
|
|
22383
|
-
setStrokeWidth(width) {
|
|
22384
|
-
this.emit({
|
|
22385
|
-
class: "Drawing",
|
|
22386
|
-
method: "setStrokeWidth",
|
|
22387
|
-
item: [this.id],
|
|
22388
|
-
width,
|
|
22389
|
-
prevWidth: this.strokeWidth
|
|
22390
|
-
});
|
|
22391
|
-
return this;
|
|
22392
|
-
}
|
|
22393
|
-
getLinkTo() {
|
|
22394
|
-
return this.linkTo.link;
|
|
22395
|
-
}
|
|
22396
|
-
getStrokeWidth() {
|
|
22397
|
-
return this.strokeWidth;
|
|
22398
|
-
}
|
|
22399
|
-
getRichText() {
|
|
22400
|
-
return null;
|
|
22401
|
-
}
|
|
22402
|
-
isPointNearLine(point3, threshold = 10) {
|
|
22403
|
-
const transformedMouseX = (point3.x - this.transformation.matrix.translateX) / this.transformation.matrix.scaleX;
|
|
22404
|
-
const transformedMouseY = (point3.y - this.transformation.matrix.translateY) / this.transformation.matrix.scaleY;
|
|
22405
|
-
const transformedMouse = new Point(transformedMouseX, transformedMouseY);
|
|
22406
|
-
for (let i = 0;i < this.points.length - 1; i++) {
|
|
22407
|
-
const p1 = this.points[i];
|
|
22408
|
-
const p2 = this.points[i + 1];
|
|
22409
|
-
const distance = getPerpendicularDistance(transformedMouse, p1, p2);
|
|
22410
|
-
if (distance < threshold) {
|
|
22411
|
-
return true;
|
|
22412
|
-
}
|
|
22413
|
-
}
|
|
22414
|
-
return false;
|
|
22415
|
-
}
|
|
22416
|
-
}
|
|
22417
|
-
function getPerpendicularDistance(point3, lineStart, lineEnd) {
|
|
22418
|
-
const { x: px, y: py } = point3;
|
|
22419
|
-
const { x: sx, y: sy } = lineStart;
|
|
22420
|
-
const { x: ex, y: ey } = lineEnd;
|
|
22421
|
-
const numerator = Math.abs((ey - sy) * px - (ex - sx) * py + ex * sy - ey * sx);
|
|
22422
|
-
const denominator = Math.sqrt(Math.pow(ey - sy, 2) + Math.pow(ex - sx, 2));
|
|
22423
|
-
return numerator / denominator;
|
|
22424
|
-
}
|
|
22425
|
-
function douglasPeucker(points, epsilon2) {
|
|
22426
|
-
if (points.length < 3) {
|
|
22427
|
-
return points;
|
|
22428
|
-
}
|
|
22429
|
-
const start = points[0];
|
|
22430
|
-
const end = points[points.length - 1];
|
|
22431
|
-
let maxDistance = 0;
|
|
22432
|
-
let maxIndex = 0;
|
|
22433
|
-
for (let i = 1;i < points.length - 1; i++) {
|
|
22434
|
-
const distance = getPerpendicularDistance(points[i], start, end);
|
|
22435
|
-
if (distance > maxDistance) {
|
|
22436
|
-
maxDistance = distance;
|
|
22437
|
-
maxIndex = i;
|
|
22438
|
-
}
|
|
22439
|
-
}
|
|
22440
|
-
if (maxDistance > epsilon2) {
|
|
22441
|
-
const leftSubPoints = points.slice(0, maxIndex + 1);
|
|
22442
|
-
const rightSubPoints = points.slice(maxIndex);
|
|
22443
|
-
const leftRecursiveResult = douglasPeucker(leftSubPoints, epsilon2);
|
|
22444
|
-
const rightRecursiveResult = douglasPeucker(rightSubPoints, epsilon2);
|
|
22445
|
-
return leftRecursiveResult.slice(0, -1).concat(rightRecursiveResult);
|
|
22446
|
-
} else {
|
|
22447
|
-
return [start, end];
|
|
22448
|
-
}
|
|
22449
|
-
}
|
|
22450
22023
|
// src/SpatialIndex/LayeredIndex/Layers.ts
|
|
22451
22024
|
class Layers {
|
|
22452
22025
|
getNewLayer;
|
|
@@ -23769,12 +23342,12 @@ class Items {
|
|
|
23769
23342
|
if (enclosed.length === 0) {
|
|
23770
23343
|
enclosed = underPointer;
|
|
23771
23344
|
}
|
|
23772
|
-
if (underPointer.some((item) => item
|
|
23345
|
+
if (underPointer.some((item) => item.itemType === "Drawing")) {
|
|
23773
23346
|
enclosed = [...underPointer, ...enclosed];
|
|
23774
23347
|
}
|
|
23775
23348
|
const { nearest } = enclosed.reduce((acc, item) => {
|
|
23776
23349
|
const area = item.getMbr().getHeight() * item.getMbr().getWidth();
|
|
23777
|
-
if (item
|
|
23350
|
+
if (item.itemType === "Drawing" && !item.isPointNearLine(this.pointer.point)) {
|
|
23778
23351
|
return acc;
|
|
23779
23352
|
}
|
|
23780
23353
|
const isItemTransparent = item instanceof Shape && item?.getBackgroundColor() === "none";
|
|
@@ -23909,6 +23482,7 @@ class Items {
|
|
|
23909
23482
|
}
|
|
23910
23483
|
}
|
|
23911
23484
|
|
|
23485
|
+
// src/SpatialIndex/SimpleSpatialIndex.ts
|
|
23912
23486
|
class SimpleSpatialIndex {
|
|
23913
23487
|
subject = new Subject;
|
|
23914
23488
|
itemsArray = [];
|
|
@@ -44659,202 +44233,455 @@ class Placeholder extends BaseItem {
|
|
|
44659
44233
|
renderHTML(documentFactory) {
|
|
44660
44234
|
return documentFactory.createElement("div");
|
|
44661
44235
|
}
|
|
44662
|
-
getLinkTo() {
|
|
44663
|
-
return;
|
|
44236
|
+
getLinkTo() {
|
|
44237
|
+
return;
|
|
44238
|
+
}
|
|
44239
|
+
getRichText() {
|
|
44240
|
+
return null;
|
|
44241
|
+
}
|
|
44242
|
+
}
|
|
44243
|
+
// src/Items/Image/Image.ts
|
|
44244
|
+
function getPlaceholderImage(board, imageDimension) {
|
|
44245
|
+
const placeholderCanvas = conf.documentFactory.createElement("canvas");
|
|
44246
|
+
const placeholderContext = placeholderCanvas.getContext("2d");
|
|
44247
|
+
const context = new DrawingContext(board.camera, placeholderContext);
|
|
44248
|
+
const placeholder = new Placeholder(board);
|
|
44249
|
+
if (imageDimension) {
|
|
44250
|
+
placeholderCanvas.width = imageDimension.width;
|
|
44251
|
+
placeholderCanvas.height = imageDimension.height;
|
|
44252
|
+
placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
|
|
44253
|
+
} else {
|
|
44254
|
+
placeholderCanvas.width = 250;
|
|
44255
|
+
placeholderCanvas.height = 50;
|
|
44256
|
+
placeholder.transformation.scaleTo(250 / 100, 50 / 100);
|
|
44257
|
+
}
|
|
44258
|
+
const placeholderImage = new Image;
|
|
44259
|
+
placeholderImage.src = placeholderCanvas.toDataURL();
|
|
44260
|
+
return placeholderImage;
|
|
44261
|
+
}
|
|
44262
|
+
|
|
44263
|
+
class ImageItem extends BaseItem {
|
|
44264
|
+
events;
|
|
44265
|
+
itemType = "Image";
|
|
44266
|
+
parent = "Board";
|
|
44267
|
+
image;
|
|
44268
|
+
transformation;
|
|
44269
|
+
linkTo;
|
|
44270
|
+
subject = new Subject;
|
|
44271
|
+
loadCallbacks = [];
|
|
44272
|
+
beforeLoadCallbacks = [];
|
|
44273
|
+
transformationRenderBlock = undefined;
|
|
44274
|
+
storageLink;
|
|
44275
|
+
imageDimension;
|
|
44276
|
+
board;
|
|
44277
|
+
constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
|
|
44278
|
+
super(board, id);
|
|
44279
|
+
this.events = events;
|
|
44280
|
+
this.linkTo = new LinkTo(this.id, events);
|
|
44281
|
+
this.board = board;
|
|
44282
|
+
this.setStorageLink(storageLink);
|
|
44283
|
+
this.imageDimension = imageDimension;
|
|
44284
|
+
this.transformation = new Transformation(id, events);
|
|
44285
|
+
this.image = new Image;
|
|
44286
|
+
this.image.crossOrigin = "anonymous";
|
|
44287
|
+
this.image.onload = this.onLoad;
|
|
44288
|
+
this.image.onerror = this.onError;
|
|
44289
|
+
if (typeof base64 === "string") {
|
|
44290
|
+
this.image.src = base64;
|
|
44291
|
+
}
|
|
44292
|
+
this.linkTo.subject.subscribe(() => {
|
|
44293
|
+
this.updateMbr();
|
|
44294
|
+
this.subject.publish(this);
|
|
44295
|
+
});
|
|
44296
|
+
this.transformation.subject.subscribe(this.onTransform);
|
|
44297
|
+
}
|
|
44298
|
+
setStorageLink(link2) {
|
|
44299
|
+
try {
|
|
44300
|
+
const url = new URL(link2);
|
|
44301
|
+
this.storageLink = `${window?.location.origin}${url.pathname}`;
|
|
44302
|
+
} catch (_) {}
|
|
44303
|
+
}
|
|
44304
|
+
getStorageId() {
|
|
44305
|
+
return this.storageLink.split("/").pop();
|
|
44306
|
+
}
|
|
44307
|
+
handleError = () => {
|
|
44308
|
+
console.error("Invalid dataUrl or image failed to load.");
|
|
44309
|
+
this.image = getPlaceholderImage(this.board);
|
|
44310
|
+
this.updateMbr();
|
|
44311
|
+
this.subject.publish(this);
|
|
44312
|
+
this.shootLoadCallbacks();
|
|
44313
|
+
};
|
|
44314
|
+
onLoad = async () => {
|
|
44315
|
+
this.shootBeforeLoadCallbacks();
|
|
44316
|
+
this.updateMbr();
|
|
44317
|
+
this.subject.publish(this);
|
|
44318
|
+
this.shootLoadCallbacks();
|
|
44319
|
+
};
|
|
44320
|
+
onError = (_error) => {
|
|
44321
|
+
this.image = getPlaceholderImage(this.board);
|
|
44322
|
+
this.updateMbr();
|
|
44323
|
+
this.subject.publish(this);
|
|
44324
|
+
this.shootLoadCallbacks();
|
|
44325
|
+
};
|
|
44326
|
+
onTransform = () => {
|
|
44327
|
+
this.updateMbr();
|
|
44328
|
+
this.subject.publish(this);
|
|
44329
|
+
};
|
|
44330
|
+
updateMbr() {
|
|
44331
|
+
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
44332
|
+
this.left = translateX;
|
|
44333
|
+
this.top = translateY;
|
|
44334
|
+
this.right = this.left + this.image.width * scaleX;
|
|
44335
|
+
this.bottom = this.top + this.image.height * scaleY;
|
|
44336
|
+
}
|
|
44337
|
+
doOnceBeforeOnLoad = (callback) => {
|
|
44338
|
+
this.loadCallbacks.push(callback);
|
|
44339
|
+
};
|
|
44340
|
+
doOnceOnLoad = (callback) => {
|
|
44341
|
+
this.loadCallbacks.push(callback);
|
|
44342
|
+
};
|
|
44343
|
+
setId(id) {
|
|
44344
|
+
this.id = id;
|
|
44345
|
+
this.transformation.setId(id);
|
|
44346
|
+
this.linkTo.setId(id);
|
|
44347
|
+
return this;
|
|
44348
|
+
}
|
|
44349
|
+
getId() {
|
|
44350
|
+
return this.id;
|
|
44351
|
+
}
|
|
44352
|
+
serialize() {
|
|
44353
|
+
return {
|
|
44354
|
+
itemType: "Image",
|
|
44355
|
+
storageLink: this.storageLink,
|
|
44356
|
+
imageDimension: this.imageDimension,
|
|
44357
|
+
transformation: this.transformation.serialize(),
|
|
44358
|
+
linkTo: this.linkTo.serialize()
|
|
44359
|
+
};
|
|
44360
|
+
}
|
|
44361
|
+
setCoordinates() {
|
|
44362
|
+
this.left = this.transformation.matrix.translateX;
|
|
44363
|
+
this.top = this.transformation.matrix.translateY;
|
|
44364
|
+
this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
|
|
44365
|
+
this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
|
|
44366
|
+
this.subject.publish(this);
|
|
44367
|
+
}
|
|
44368
|
+
shootBeforeLoadCallbacks() {
|
|
44369
|
+
while (this.beforeLoadCallbacks.length > 0) {
|
|
44370
|
+
this.beforeLoadCallbacks.shift()(this);
|
|
44371
|
+
}
|
|
44372
|
+
}
|
|
44373
|
+
shootLoadCallbacks() {
|
|
44374
|
+
while (this.loadCallbacks.length > 0) {
|
|
44375
|
+
this.loadCallbacks.shift()(this);
|
|
44376
|
+
}
|
|
44377
|
+
}
|
|
44378
|
+
deserialize(data) {
|
|
44379
|
+
if (data.transformation) {
|
|
44380
|
+
this.transformation.deserialize(data.transformation);
|
|
44381
|
+
}
|
|
44382
|
+
this.linkTo.deserialize(data.linkTo);
|
|
44383
|
+
this.image.onload = () => {
|
|
44384
|
+
this.setCoordinates();
|
|
44385
|
+
this.shootLoadCallbacks();
|
|
44386
|
+
};
|
|
44387
|
+
if (data.storageLink) {
|
|
44388
|
+
this.setStorageLink(data.storageLink);
|
|
44389
|
+
}
|
|
44390
|
+
if (this.image.src) {
|
|
44391
|
+
return this;
|
|
44392
|
+
}
|
|
44393
|
+
this.image = getPlaceholderImage(this.board, data.imageDimension);
|
|
44394
|
+
const storageImage = new Image;
|
|
44395
|
+
storageImage.onload = () => {
|
|
44396
|
+
this.image = storageImage;
|
|
44397
|
+
this.onLoad();
|
|
44398
|
+
};
|
|
44399
|
+
storageImage.onerror = this.onError;
|
|
44400
|
+
storageImage.src = this.storageLink;
|
|
44401
|
+
return this;
|
|
44402
|
+
}
|
|
44403
|
+
emit(operation) {
|
|
44404
|
+
if (this.events) {
|
|
44405
|
+
const command = new ImageCommand([this], operation);
|
|
44406
|
+
command.apply();
|
|
44407
|
+
this.events.emit(operation, command);
|
|
44408
|
+
} else {
|
|
44409
|
+
this.apply(operation);
|
|
44410
|
+
}
|
|
44411
|
+
}
|
|
44412
|
+
setDimensions(dim) {
|
|
44413
|
+
this.imageDimension = dim;
|
|
44414
|
+
}
|
|
44415
|
+
apply(op) {
|
|
44416
|
+
switch (op.class) {
|
|
44417
|
+
case "Transformation":
|
|
44418
|
+
this.transformation.apply(op);
|
|
44419
|
+
break;
|
|
44420
|
+
case "LinkTo":
|
|
44421
|
+
this.linkTo.apply(op);
|
|
44422
|
+
break;
|
|
44423
|
+
case "Image":
|
|
44424
|
+
if (op.data.base64) {
|
|
44425
|
+
this.image.src = op.data.base64;
|
|
44426
|
+
}
|
|
44427
|
+
this.setStorageLink(op.data.storageLink);
|
|
44428
|
+
this.setDimensions(op.data.imageDimension);
|
|
44429
|
+
this.subject.publish(this);
|
|
44430
|
+
break;
|
|
44431
|
+
}
|
|
44432
|
+
}
|
|
44433
|
+
render(context) {
|
|
44434
|
+
if (this.transformationRenderBlock) {
|
|
44435
|
+
return;
|
|
44436
|
+
}
|
|
44437
|
+
const ctx = context.ctx;
|
|
44438
|
+
ctx.save();
|
|
44439
|
+
this.transformation.matrix.applyToContext(ctx);
|
|
44440
|
+
ctx.drawImage(this.image, 0, 0);
|
|
44441
|
+
ctx.restore();
|
|
44442
|
+
if (this.getLinkTo()) {
|
|
44443
|
+
const { top, right } = this.getMbr();
|
|
44444
|
+
this.linkTo.render(context, top, right, this.board.camera.getScale());
|
|
44445
|
+
}
|
|
44446
|
+
}
|
|
44447
|
+
renderHTML(documentFactory) {
|
|
44448
|
+
const div = documentFactory.createElement("image-item");
|
|
44449
|
+
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
44450
|
+
const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
|
|
44451
|
+
div.style.backgroundImage = `url(${this.storageLink})`;
|
|
44452
|
+
div.id = this.getId();
|
|
44453
|
+
div.style.width = `${this.imageDimension.width}px`;
|
|
44454
|
+
div.style.height = `${this.imageDimension.height}px`;
|
|
44455
|
+
div.style.transformOrigin = "top left";
|
|
44456
|
+
div.style.transform = transform;
|
|
44457
|
+
div.style.position = "absolute";
|
|
44458
|
+
div.style.backgroundSize = "cover";
|
|
44459
|
+
div.setAttribute("data-link-to", this.linkTo.serialize() || "");
|
|
44460
|
+
if (this.getLinkTo()) {
|
|
44461
|
+
const linkElement = this.linkTo.renderHTML(documentFactory);
|
|
44462
|
+
scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
|
|
44463
|
+
translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
|
|
44464
|
+
div.appendChild(linkElement);
|
|
44465
|
+
}
|
|
44466
|
+
return div;
|
|
44467
|
+
}
|
|
44468
|
+
getPath() {
|
|
44469
|
+
const { left, top, right, bottom } = this.getMbr();
|
|
44470
|
+
const leftTop = new Point(left, top);
|
|
44471
|
+
const rightTop = new Point(right, top);
|
|
44472
|
+
const rightBottom = new Point(right, bottom);
|
|
44473
|
+
const leftBottom = new Point(left, bottom);
|
|
44474
|
+
return new Path([
|
|
44475
|
+
new Line(leftTop, rightTop),
|
|
44476
|
+
new Line(rightTop, rightBottom),
|
|
44477
|
+
new Line(rightBottom, leftBottom),
|
|
44478
|
+
new Line(leftBottom, leftTop)
|
|
44479
|
+
], true);
|
|
44480
|
+
}
|
|
44481
|
+
getSnapAnchorPoints() {
|
|
44482
|
+
const mbr = this.getMbr();
|
|
44483
|
+
const width2 = mbr.getWidth();
|
|
44484
|
+
const height2 = mbr.getHeight();
|
|
44485
|
+
return [
|
|
44486
|
+
new Point(mbr.left + width2 / 2, mbr.top),
|
|
44487
|
+
new Point(mbr.left + width2 / 2, mbr.bottom),
|
|
44488
|
+
new Point(mbr.left, mbr.top + height2 / 2),
|
|
44489
|
+
new Point(mbr.right, mbr.top + height2 / 2)
|
|
44490
|
+
];
|
|
44491
|
+
}
|
|
44492
|
+
isClosed() {
|
|
44493
|
+
return true;
|
|
44664
44494
|
}
|
|
44665
44495
|
getRichText() {
|
|
44666
44496
|
return null;
|
|
44667
44497
|
}
|
|
44498
|
+
getLinkTo() {
|
|
44499
|
+
return this.linkTo.link;
|
|
44500
|
+
}
|
|
44501
|
+
download() {
|
|
44502
|
+
const linkElem = document.createElement("a");
|
|
44503
|
+
linkElem.href = this.storageLink;
|
|
44504
|
+
linkElem.setAttribute("download", "");
|
|
44505
|
+
linkElem.click();
|
|
44506
|
+
}
|
|
44507
|
+
onRemove() {
|
|
44508
|
+
const storageId = this.getStorageId();
|
|
44509
|
+
if (storageId) {
|
|
44510
|
+
conf.hooks.beforeMediaRemove([storageId], this.board.getBoardId());
|
|
44511
|
+
}
|
|
44512
|
+
super.onRemove();
|
|
44513
|
+
}
|
|
44668
44514
|
}
|
|
44669
|
-
// src/
|
|
44670
|
-
function
|
|
44671
|
-
|
|
44672
|
-
|
|
44673
|
-
const context = new DrawingContext(board.camera, placeholderContext);
|
|
44674
|
-
const placeholder = new Placeholder(board);
|
|
44675
|
-
if (imageDimension) {
|
|
44676
|
-
placeholderCanvas.width = imageDimension.width;
|
|
44677
|
-
placeholderCanvas.height = imageDimension.height;
|
|
44678
|
-
placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
|
|
44679
|
-
} else {
|
|
44680
|
-
placeholderCanvas.width = 250;
|
|
44681
|
-
placeholderCanvas.height = 50;
|
|
44682
|
-
placeholder.transformation.scaleTo(250 / 100, 50 / 100);
|
|
44515
|
+
// src/isSafari.ts
|
|
44516
|
+
function isSafari() {
|
|
44517
|
+
if (typeof navigator === "undefined") {
|
|
44518
|
+
return false;
|
|
44683
44519
|
}
|
|
44684
|
-
const
|
|
44685
|
-
|
|
44686
|
-
|
|
44520
|
+
const agent = navigator.userAgent;
|
|
44521
|
+
const vendor = navigator.vendor;
|
|
44522
|
+
const is2 = vendor !== undefined && vendor.includes("Apple") && agent !== undefined && !agent.includes("CriOS") && !agent.includes("FxiOS");
|
|
44523
|
+
return is2;
|
|
44687
44524
|
}
|
|
44688
44525
|
|
|
44689
|
-
|
|
44526
|
+
// src/Items/Drawing/Drawing.ts
|
|
44527
|
+
class Drawing extends BaseItem {
|
|
44528
|
+
points;
|
|
44690
44529
|
events;
|
|
44691
|
-
itemType = "
|
|
44530
|
+
itemType = "Drawing";
|
|
44692
44531
|
parent = "Board";
|
|
44693
|
-
image;
|
|
44694
44532
|
transformation;
|
|
44695
|
-
|
|
44533
|
+
path2d = new conf.path2DFactory;
|
|
44696
44534
|
subject = new Subject;
|
|
44697
|
-
|
|
44698
|
-
|
|
44535
|
+
untransformedMbr = new Mbr;
|
|
44536
|
+
lines = [];
|
|
44537
|
+
linkTo;
|
|
44538
|
+
strokeWidth = 1;
|
|
44539
|
+
borderStyle = "solid";
|
|
44540
|
+
linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
44541
|
+
borderOpacity = 1;
|
|
44699
44542
|
transformationRenderBlock = undefined;
|
|
44700
|
-
|
|
44701
|
-
imageDimension;
|
|
44702
|
-
board;
|
|
44703
|
-
constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
|
|
44543
|
+
constructor(board, points, events, id = "") {
|
|
44704
44544
|
super(board, id);
|
|
44545
|
+
this.points = points;
|
|
44705
44546
|
this.events = events;
|
|
44706
|
-
this.linkTo = new LinkTo(this.id, events);
|
|
44707
|
-
this.board = board;
|
|
44708
|
-
this.setStorageLink(storageLink);
|
|
44709
|
-
this.imageDimension = imageDimension;
|
|
44710
44547
|
this.transformation = new Transformation(id, events);
|
|
44711
|
-
this.
|
|
44712
|
-
this.
|
|
44713
|
-
|
|
44714
|
-
|
|
44715
|
-
|
|
44716
|
-
|
|
44717
|
-
}
|
|
44548
|
+
this.linkTo = new LinkTo(this.id, this.events);
|
|
44549
|
+
this.transformation.subject.subscribe(() => {
|
|
44550
|
+
this.updateMbr();
|
|
44551
|
+
this.updateLines();
|
|
44552
|
+
this.subject.publish(this);
|
|
44553
|
+
});
|
|
44718
44554
|
this.linkTo.subject.subscribe(() => {
|
|
44719
44555
|
this.updateMbr();
|
|
44556
|
+
this.updateLines();
|
|
44720
44557
|
this.subject.publish(this);
|
|
44721
44558
|
});
|
|
44722
|
-
this.
|
|
44723
|
-
}
|
|
44724
|
-
setStorageLink(link2) {
|
|
44725
|
-
try {
|
|
44726
|
-
const url = new URL(link2);
|
|
44727
|
-
this.storageLink = `${window?.location.origin}${url.pathname}`;
|
|
44728
|
-
} catch (_) {}
|
|
44729
|
-
}
|
|
44730
|
-
getStorageId() {
|
|
44731
|
-
return this.storageLink.split("/").pop();
|
|
44732
|
-
}
|
|
44733
|
-
handleError = () => {
|
|
44734
|
-
console.error("Invalid dataUrl or image failed to load.");
|
|
44735
|
-
this.image = getPlaceholderImage(this.board);
|
|
44736
|
-
this.updateMbr();
|
|
44737
|
-
this.subject.publish(this);
|
|
44738
|
-
this.shootLoadCallbacks();
|
|
44739
|
-
};
|
|
44740
|
-
onLoad = async () => {
|
|
44741
|
-
this.shootBeforeLoadCallbacks();
|
|
44742
|
-
this.updateMbr();
|
|
44743
|
-
this.subject.publish(this);
|
|
44744
|
-
this.shootLoadCallbacks();
|
|
44745
|
-
};
|
|
44746
|
-
onError = (_error) => {
|
|
44747
|
-
this.image = getPlaceholderImage(this.board);
|
|
44748
|
-
this.updateMbr();
|
|
44749
|
-
this.subject.publish(this);
|
|
44750
|
-
this.shootLoadCallbacks();
|
|
44751
|
-
};
|
|
44752
|
-
onTransform = () => {
|
|
44753
|
-
this.updateMbr();
|
|
44754
|
-
this.subject.publish(this);
|
|
44755
|
-
};
|
|
44756
|
-
updateMbr() {
|
|
44757
|
-
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
44758
|
-
this.left = translateX;
|
|
44759
|
-
this.top = translateY;
|
|
44760
|
-
this.right = this.left + this.image.width * scaleX;
|
|
44761
|
-
this.bottom = this.top + this.image.height * scaleY;
|
|
44762
|
-
}
|
|
44763
|
-
doOnceBeforeOnLoad = (callback) => {
|
|
44764
|
-
this.loadCallbacks.push(callback);
|
|
44765
|
-
};
|
|
44766
|
-
doOnceOnLoad = (callback) => {
|
|
44767
|
-
this.loadCallbacks.push(callback);
|
|
44768
|
-
};
|
|
44769
|
-
setId(id) {
|
|
44770
|
-
this.id = id;
|
|
44771
|
-
this.transformation.setId(id);
|
|
44772
|
-
this.linkTo.setId(id);
|
|
44773
|
-
return this;
|
|
44774
|
-
}
|
|
44775
|
-
getId() {
|
|
44776
|
-
return this.id;
|
|
44559
|
+
this.updateLines();
|
|
44777
44560
|
}
|
|
44778
44561
|
serialize() {
|
|
44562
|
+
this.optimizePoints();
|
|
44563
|
+
const points = [];
|
|
44564
|
+
for (const point5 of this.points) {
|
|
44565
|
+
points.push({ x: point5.x, y: point5.y });
|
|
44566
|
+
}
|
|
44779
44567
|
return {
|
|
44780
|
-
itemType: "
|
|
44781
|
-
|
|
44782
|
-
imageDimension: this.imageDimension,
|
|
44568
|
+
itemType: "Drawing",
|
|
44569
|
+
points,
|
|
44783
44570
|
transformation: this.transformation.serialize(),
|
|
44571
|
+
strokeStyle: this.borderColor,
|
|
44572
|
+
strokeWidth: this.strokeWidth,
|
|
44784
44573
|
linkTo: this.linkTo.serialize()
|
|
44785
44574
|
};
|
|
44786
44575
|
}
|
|
44787
|
-
|
|
44788
|
-
this.
|
|
44789
|
-
|
|
44790
|
-
|
|
44791
|
-
this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
|
|
44792
|
-
this.subject.publish(this);
|
|
44793
|
-
}
|
|
44794
|
-
shootBeforeLoadCallbacks() {
|
|
44795
|
-
while (this.beforeLoadCallbacks.length > 0) {
|
|
44796
|
-
this.beforeLoadCallbacks.shift()(this);
|
|
44576
|
+
deserialize(data) {
|
|
44577
|
+
this.points = [];
|
|
44578
|
+
for (const point5 of data.points) {
|
|
44579
|
+
this.points.push(new Point(point5.x, point5.y));
|
|
44797
44580
|
}
|
|
44581
|
+
this.linkTo.deserialize(data.linkTo);
|
|
44582
|
+
this.optimizePoints();
|
|
44583
|
+
this.transformation.deserialize(data.transformation);
|
|
44584
|
+
this.borderColor = data.strokeStyle;
|
|
44585
|
+
this.strokeWidth = data.strokeWidth;
|
|
44586
|
+
this.updateGeometry();
|
|
44587
|
+
return this;
|
|
44798
44588
|
}
|
|
44799
|
-
|
|
44800
|
-
|
|
44801
|
-
|
|
44802
|
-
|
|
44589
|
+
updateGeometry() {
|
|
44590
|
+
this.updatePath2d();
|
|
44591
|
+
this.updateLines();
|
|
44592
|
+
this.updateMbr();
|
|
44803
44593
|
}
|
|
44804
|
-
|
|
44805
|
-
|
|
44806
|
-
|
|
44594
|
+
updateMbr() {
|
|
44595
|
+
const offset = this.getStrokeWidth() / 2;
|
|
44596
|
+
const untransformedMbr = this.untransformedMbr.copy();
|
|
44597
|
+
untransformedMbr.left -= offset;
|
|
44598
|
+
untransformedMbr.top -= offset;
|
|
44599
|
+
untransformedMbr.right += offset;
|
|
44600
|
+
untransformedMbr.bottom += offset;
|
|
44601
|
+
const mbr = untransformedMbr.getTransformed(this.transformation.matrix);
|
|
44602
|
+
this.left = mbr.left;
|
|
44603
|
+
this.top = mbr.top;
|
|
44604
|
+
this.right = mbr.right;
|
|
44605
|
+
this.bottom = mbr.bottom;
|
|
44606
|
+
}
|
|
44607
|
+
updatePath2d() {
|
|
44608
|
+
this.path2d = new conf.path2DFactory;
|
|
44609
|
+
const context = this.path2d;
|
|
44610
|
+
const points = this.points;
|
|
44611
|
+
if (points.length < 3) {
|
|
44612
|
+
context.arc(points[0].x, points[0].y, 0.5, 0, Math.PI * 2, true);
|
|
44613
|
+
context.closePath();
|
|
44614
|
+
} else {
|
|
44615
|
+
context.moveTo(points[0].x, points[0].y);
|
|
44616
|
+
let j = 1;
|
|
44617
|
+
for (;j < points.length - 2; j++) {
|
|
44618
|
+
const cx = (points[j].x + points[j + 1].x) / 2;
|
|
44619
|
+
const cy = (points[j].y + points[j + 1].y) / 2;
|
|
44620
|
+
context.quadraticCurveTo(points[j].x, points[j].y, cx, cy);
|
|
44621
|
+
}
|
|
44622
|
+
const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
|
|
44623
|
+
const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
|
|
44624
|
+
context.quadraticCurveTo(points[j].x, points[j].y, x, y);
|
|
44807
44625
|
}
|
|
44808
|
-
|
|
44809
|
-
|
|
44810
|
-
|
|
44811
|
-
|
|
44812
|
-
}
|
|
44813
|
-
|
|
44814
|
-
|
|
44626
|
+
let left = Number.MAX_SAFE_INTEGER;
|
|
44627
|
+
let right = Number.MIN_SAFE_INTEGER;
|
|
44628
|
+
let top = Number.MAX_SAFE_INTEGER;
|
|
44629
|
+
let bottom = Number.MIN_SAFE_INTEGER;
|
|
44630
|
+
for (const { x, y } of this.points) {
|
|
44631
|
+
if (x < left) {
|
|
44632
|
+
left = x;
|
|
44633
|
+
}
|
|
44634
|
+
if (x > right) {
|
|
44635
|
+
right = x;
|
|
44636
|
+
}
|
|
44637
|
+
if (y < top) {
|
|
44638
|
+
top = y;
|
|
44639
|
+
}
|
|
44640
|
+
if (y > bottom) {
|
|
44641
|
+
bottom = y;
|
|
44642
|
+
}
|
|
44815
44643
|
}
|
|
44816
|
-
|
|
44817
|
-
|
|
44644
|
+
this.untransformedMbr = new Mbr(left, top, right, bottom);
|
|
44645
|
+
}
|
|
44646
|
+
updateLines() {
|
|
44647
|
+
this.lines = [];
|
|
44648
|
+
const matrix = this.transformation.matrix;
|
|
44649
|
+
if (this.points.length < 2) {
|
|
44650
|
+
return;
|
|
44651
|
+
}
|
|
44652
|
+
for (let i = 0;i < this.points.length - 2; i++) {
|
|
44653
|
+
const p1 = this.points[i];
|
|
44654
|
+
const p22 = this.points[i + 1];
|
|
44655
|
+
const line = new Line(p1.copy(), p22.copy());
|
|
44656
|
+
line.transform(matrix);
|
|
44657
|
+
this.lines.push(line);
|
|
44818
44658
|
}
|
|
44819
|
-
this.image = getPlaceholderImage(this.board, data.imageDimension);
|
|
44820
|
-
const storageImage = new Image;
|
|
44821
|
-
storageImage.onload = () => {
|
|
44822
|
-
this.image = storageImage;
|
|
44823
|
-
this.onLoad();
|
|
44824
|
-
};
|
|
44825
|
-
storageImage.onerror = this.onError;
|
|
44826
|
-
storageImage.src = this.storageLink;
|
|
44827
|
-
return this;
|
|
44828
44659
|
}
|
|
44829
|
-
|
|
44830
|
-
|
|
44831
|
-
|
|
44832
|
-
|
|
44833
|
-
|
|
44660
|
+
optimizePoints() {
|
|
44661
|
+
const dp = douglasPeucker(this.points, 1);
|
|
44662
|
+
dp.push(this.points[this.points.length - 1]);
|
|
44663
|
+
this.points = dp;
|
|
44664
|
+
}
|
|
44665
|
+
addPoint(point5) {
|
|
44666
|
+
const previous2 = this.points[this.points.length - 1];
|
|
44667
|
+
if (previous2) {
|
|
44668
|
+
const distance = point5.getDistance(previous2);
|
|
44669
|
+
if (distance >= 2) {
|
|
44670
|
+
this.points.push(point5);
|
|
44671
|
+
}
|
|
44834
44672
|
} else {
|
|
44835
|
-
this.
|
|
44673
|
+
this.points.push(point5);
|
|
44836
44674
|
}
|
|
44675
|
+
this.updateGeometry();
|
|
44837
44676
|
}
|
|
44838
|
-
|
|
44839
|
-
this.
|
|
44677
|
+
setId(id) {
|
|
44678
|
+
this.id = id;
|
|
44679
|
+
this.transformation.setId(id);
|
|
44680
|
+
this.linkTo.setId(id);
|
|
44681
|
+
return this;
|
|
44840
44682
|
}
|
|
44841
|
-
|
|
44842
|
-
|
|
44843
|
-
case "Transformation":
|
|
44844
|
-
this.transformation.apply(op);
|
|
44845
|
-
break;
|
|
44846
|
-
case "LinkTo":
|
|
44847
|
-
this.linkTo.apply(op);
|
|
44848
|
-
break;
|
|
44849
|
-
case "Image":
|
|
44850
|
-
if (op.data.base64) {
|
|
44851
|
-
this.image.src = op.data.base64;
|
|
44852
|
-
}
|
|
44853
|
-
this.setStorageLink(op.data.storageLink);
|
|
44854
|
-
this.setDimensions(op.data.imageDimension);
|
|
44855
|
-
this.subject.publish(this);
|
|
44856
|
-
break;
|
|
44857
|
-
}
|
|
44683
|
+
getId() {
|
|
44684
|
+
return this.id;
|
|
44858
44685
|
}
|
|
44859
44686
|
render(context) {
|
|
44860
44687
|
if (this.transformationRenderBlock) {
|
|
@@ -44862,8 +44689,12 @@ class ImageItem extends BaseItem {
|
|
|
44862
44689
|
}
|
|
44863
44690
|
const ctx = context.ctx;
|
|
44864
44691
|
ctx.save();
|
|
44692
|
+
ctx.strokeStyle = this.borderColor;
|
|
44693
|
+
ctx.lineWidth = this.strokeWidth;
|
|
44694
|
+
ctx.lineCap = "round";
|
|
44695
|
+
ctx.setLineDash(this.linePattern);
|
|
44865
44696
|
this.transformation.matrix.applyToContext(ctx);
|
|
44866
|
-
ctx.
|
|
44697
|
+
ctx.stroke(this.path2d.nativePath);
|
|
44867
44698
|
ctx.restore();
|
|
44868
44699
|
if (this.getLinkTo()) {
|
|
44869
44700
|
const { top, right } = this.getMbr();
|
|
@@ -44871,26 +44702,61 @@ class ImageItem extends BaseItem {
|
|
|
44871
44702
|
}
|
|
44872
44703
|
}
|
|
44873
44704
|
renderHTML(documentFactory) {
|
|
44874
|
-
const div = documentFactory.createElement("
|
|
44705
|
+
const div = documentFactory.createElement("drawing-item");
|
|
44875
44706
|
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
44876
|
-
const
|
|
44877
|
-
|
|
44707
|
+
const mbr = this.getMbr();
|
|
44708
|
+
const width2 = mbr.getWidth();
|
|
44709
|
+
const height2 = mbr.getHeight();
|
|
44710
|
+
const unscaledWidth = width2 / scaleX;
|
|
44711
|
+
const unscaledHeight = height2 / scaleY;
|
|
44712
|
+
const svg3 = documentFactory.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
44713
|
+
svg3.setAttribute("width", `${unscaledWidth}px`);
|
|
44714
|
+
svg3.setAttribute("height", `${unscaledHeight}px`);
|
|
44715
|
+
svg3.setAttribute("viewBox", `0 0 ${unscaledWidth} ${unscaledHeight}`);
|
|
44716
|
+
svg3.setAttribute("style", "position: absolute; overflow: visible;");
|
|
44717
|
+
const pathElement = documentFactory.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
44718
|
+
pathElement.setAttribute("d", this.getPathData());
|
|
44719
|
+
pathElement.setAttribute("stroke", this.borderColor);
|
|
44720
|
+
pathElement.setAttribute("stroke-width", `${this.strokeWidth}`);
|
|
44721
|
+
pathElement.setAttribute("fill", "none");
|
|
44722
|
+
svg3.appendChild(pathElement);
|
|
44723
|
+
div.appendChild(svg3);
|
|
44878
44724
|
div.id = this.getId();
|
|
44879
|
-
div.style.width =
|
|
44880
|
-
div.style.height =
|
|
44881
|
-
div.style.transformOrigin = "top
|
|
44882
|
-
div.style.transform =
|
|
44725
|
+
div.style.width = unscaledWidth + "px";
|
|
44726
|
+
div.style.height = unscaledHeight + "px";
|
|
44727
|
+
div.style.transformOrigin = "left top";
|
|
44728
|
+
div.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
|
|
44883
44729
|
div.style.position = "absolute";
|
|
44884
|
-
div.style.backgroundSize = "cover";
|
|
44885
44730
|
div.setAttribute("data-link-to", this.linkTo.serialize() || "");
|
|
44886
44731
|
if (this.getLinkTo()) {
|
|
44887
44732
|
const linkElement = this.linkTo.renderHTML(documentFactory);
|
|
44888
44733
|
scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
|
|
44889
|
-
translateElementBy(linkElement, (
|
|
44734
|
+
translateElementBy(linkElement, (width2 - parseInt(linkElement.style.width)) / scaleX, 0);
|
|
44890
44735
|
div.appendChild(linkElement);
|
|
44891
44736
|
}
|
|
44892
44737
|
return div;
|
|
44893
44738
|
}
|
|
44739
|
+
getPathData() {
|
|
44740
|
+
const points = this.points;
|
|
44741
|
+
if (points.length < 2) {
|
|
44742
|
+
return "";
|
|
44743
|
+
}
|
|
44744
|
+
let pathData = `M ${points[0].x} ${points[0].y}`;
|
|
44745
|
+
if (points.length < 3) {
|
|
44746
|
+
pathData += ` L ${points[0].x + 0.5} ${points[0].y}`;
|
|
44747
|
+
} else {
|
|
44748
|
+
let j = 1;
|
|
44749
|
+
for (;j < points.length - 2; j++) {
|
|
44750
|
+
const cx = (points[j].x + points[j + 1].x) / 2;
|
|
44751
|
+
const cy = (points[j].y + points[j + 1].y) / 2;
|
|
44752
|
+
pathData += ` Q ${points[j].x} ${points[j].y} ${cx} ${cy}`;
|
|
44753
|
+
}
|
|
44754
|
+
const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
|
|
44755
|
+
const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
|
|
44756
|
+
pathData += ` Q ${points[j].x} ${points[j].y} ${x} ${y}`;
|
|
44757
|
+
}
|
|
44758
|
+
return pathData;
|
|
44759
|
+
}
|
|
44894
44760
|
getPath() {
|
|
44895
44761
|
const { left, top, right, bottom } = this.getMbr();
|
|
44896
44762
|
const leftTop = new Point(left, top);
|
|
@@ -44915,27 +44781,162 @@ class ImageItem extends BaseItem {
|
|
|
44915
44781
|
new Point(mbr.right, mbr.top + height2 / 2)
|
|
44916
44782
|
];
|
|
44917
44783
|
}
|
|
44784
|
+
getLines() {
|
|
44785
|
+
return this.lines;
|
|
44786
|
+
}
|
|
44918
44787
|
isClosed() {
|
|
44919
44788
|
return true;
|
|
44920
44789
|
}
|
|
44921
|
-
|
|
44922
|
-
|
|
44790
|
+
isEnclosedOrCrossedBy(rect) {
|
|
44791
|
+
for (const line of this.lines) {
|
|
44792
|
+
if (line.isEnclosedOrCrossedBy(rect)) {
|
|
44793
|
+
return true;
|
|
44794
|
+
}
|
|
44795
|
+
}
|
|
44796
|
+
return false;
|
|
44797
|
+
}
|
|
44798
|
+
emit(operation) {
|
|
44799
|
+
if (this.events) {
|
|
44800
|
+
const command = new DrawingCommand([this], operation);
|
|
44801
|
+
command.apply();
|
|
44802
|
+
this.events.emit(operation, command);
|
|
44803
|
+
} else {
|
|
44804
|
+
this.apply(operation);
|
|
44805
|
+
}
|
|
44806
|
+
}
|
|
44807
|
+
apply(op) {
|
|
44808
|
+
switch (op.class) {
|
|
44809
|
+
case "Drawing":
|
|
44810
|
+
switch (op.method) {
|
|
44811
|
+
case "setStrokeColor":
|
|
44812
|
+
this.borderColor = op.color;
|
|
44813
|
+
break;
|
|
44814
|
+
case "setStrokeWidth":
|
|
44815
|
+
this.strokeWidth = op.width;
|
|
44816
|
+
this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
44817
|
+
break;
|
|
44818
|
+
case "setStrokeOpacity":
|
|
44819
|
+
this.borderOpacity = op.opacity;
|
|
44820
|
+
break;
|
|
44821
|
+
case "setStrokeStyle":
|
|
44822
|
+
this.borderStyle = op.style;
|
|
44823
|
+
this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
44824
|
+
break;
|
|
44825
|
+
}
|
|
44826
|
+
this.updateMbr();
|
|
44827
|
+
break;
|
|
44828
|
+
case "Transformation":
|
|
44829
|
+
this.transformation.apply(op);
|
|
44830
|
+
break;
|
|
44831
|
+
case "LinkTo":
|
|
44832
|
+
this.linkTo.apply(op);
|
|
44833
|
+
break;
|
|
44834
|
+
default:
|
|
44835
|
+
return;
|
|
44836
|
+
}
|
|
44837
|
+
this.subject.publish(this);
|
|
44838
|
+
}
|
|
44839
|
+
setStrokeOpacity(opacity) {
|
|
44840
|
+
this.emit({
|
|
44841
|
+
class: "Drawing",
|
|
44842
|
+
method: "setStrokeOpacity",
|
|
44843
|
+
item: [this.id],
|
|
44844
|
+
opacity
|
|
44845
|
+
});
|
|
44846
|
+
return this;
|
|
44847
|
+
}
|
|
44848
|
+
getStrokeOpacity() {
|
|
44849
|
+
return this.borderOpacity;
|
|
44850
|
+
}
|
|
44851
|
+
setBorderStyle(style2) {
|
|
44852
|
+
this.emit({
|
|
44853
|
+
class: "Drawing",
|
|
44854
|
+
method: "setStrokeStyle",
|
|
44855
|
+
item: [this.id],
|
|
44856
|
+
style: style2
|
|
44857
|
+
});
|
|
44858
|
+
return this;
|
|
44859
|
+
}
|
|
44860
|
+
getBorderStyle() {
|
|
44861
|
+
return this.borderStyle;
|
|
44862
|
+
}
|
|
44863
|
+
setStrokeColor(color2) {
|
|
44864
|
+
this.emit({
|
|
44865
|
+
class: "Drawing",
|
|
44866
|
+
method: "setStrokeColor",
|
|
44867
|
+
item: [this.id],
|
|
44868
|
+
color: color2
|
|
44869
|
+
});
|
|
44870
|
+
return this;
|
|
44871
|
+
}
|
|
44872
|
+
getStrokeColor() {
|
|
44873
|
+
return this.borderColor;
|
|
44874
|
+
}
|
|
44875
|
+
setStrokeWidth(width2) {
|
|
44876
|
+
this.emit({
|
|
44877
|
+
class: "Drawing",
|
|
44878
|
+
method: "setStrokeWidth",
|
|
44879
|
+
item: [this.id],
|
|
44880
|
+
width: width2,
|
|
44881
|
+
prevWidth: this.strokeWidth
|
|
44882
|
+
});
|
|
44883
|
+
return this;
|
|
44923
44884
|
}
|
|
44924
44885
|
getLinkTo() {
|
|
44925
44886
|
return this.linkTo.link;
|
|
44926
44887
|
}
|
|
44927
|
-
|
|
44928
|
-
|
|
44929
|
-
linkElem.href = this.storageLink;
|
|
44930
|
-
linkElem.setAttribute("download", "");
|
|
44931
|
-
linkElem.click();
|
|
44888
|
+
getStrokeWidth() {
|
|
44889
|
+
return this.strokeWidth;
|
|
44932
44890
|
}
|
|
44933
|
-
|
|
44934
|
-
|
|
44935
|
-
|
|
44936
|
-
|
|
44891
|
+
getRichText() {
|
|
44892
|
+
return null;
|
|
44893
|
+
}
|
|
44894
|
+
isPointNearLine(point5, threshold = 10) {
|
|
44895
|
+
const transformedMouseX = (point5.x - this.transformation.matrix.translateX) / this.transformation.matrix.scaleX;
|
|
44896
|
+
const transformedMouseY = (point5.y - this.transformation.matrix.translateY) / this.transformation.matrix.scaleY;
|
|
44897
|
+
const transformedMouse = new Point(transformedMouseX, transformedMouseY);
|
|
44898
|
+
for (let i = 0;i < this.points.length - 1; i++) {
|
|
44899
|
+
const p1 = this.points[i];
|
|
44900
|
+
const p22 = this.points[i + 1];
|
|
44901
|
+
const distance = getPerpendicularDistance(transformedMouse, p1, p22);
|
|
44902
|
+
if (distance < threshold) {
|
|
44903
|
+
return true;
|
|
44904
|
+
}
|
|
44937
44905
|
}
|
|
44938
|
-
|
|
44906
|
+
return false;
|
|
44907
|
+
}
|
|
44908
|
+
}
|
|
44909
|
+
function getPerpendicularDistance(point5, lineStart, lineEnd) {
|
|
44910
|
+
const { x: px, y: py } = point5;
|
|
44911
|
+
const { x: sx, y: sy } = lineStart;
|
|
44912
|
+
const { x: ex, y: ey } = lineEnd;
|
|
44913
|
+
const numerator = Math.abs((ey - sy) * px - (ex - sx) * py + ex * sy - ey * sx);
|
|
44914
|
+
const denominator = Math.sqrt(Math.pow(ey - sy, 2) + Math.pow(ex - sx, 2));
|
|
44915
|
+
return numerator / denominator;
|
|
44916
|
+
}
|
|
44917
|
+
function douglasPeucker(points, epsilon2) {
|
|
44918
|
+
if (points.length < 3) {
|
|
44919
|
+
return points;
|
|
44920
|
+
}
|
|
44921
|
+
const start = points[0];
|
|
44922
|
+
const end = points[points.length - 1];
|
|
44923
|
+
let maxDistance = 0;
|
|
44924
|
+
let maxIndex = 0;
|
|
44925
|
+
for (let i = 1;i < points.length - 1; i++) {
|
|
44926
|
+
const distance = getPerpendicularDistance(points[i], start, end);
|
|
44927
|
+
if (distance > maxDistance) {
|
|
44928
|
+
maxDistance = distance;
|
|
44929
|
+
maxIndex = i;
|
|
44930
|
+
}
|
|
44931
|
+
}
|
|
44932
|
+
if (maxDistance > epsilon2) {
|
|
44933
|
+
const leftSubPoints = points.slice(0, maxIndex + 1);
|
|
44934
|
+
const rightSubPoints = points.slice(maxIndex);
|
|
44935
|
+
const leftRecursiveResult = douglasPeucker(leftSubPoints, epsilon2);
|
|
44936
|
+
const rightRecursiveResult = douglasPeucker(rightSubPoints, epsilon2);
|
|
44937
|
+
return leftRecursiveResult.slice(0, -1).concat(rightRecursiveResult);
|
|
44938
|
+
} else {
|
|
44939
|
+
return [start, end];
|
|
44939
44940
|
}
|
|
44940
44941
|
}
|
|
44941
44942
|
// src/Items/Group/Group.ts
|