microboard-temp 0.4.40 → 0.4.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/browser.js +610 -609
- package/dist/cjs/index.js +610 -609
- package/dist/cjs/node.js +610 -609
- package/dist/esm/browser.js +610 -609
- package/dist/esm/index.js +610 -609
- package/dist/esm/node.js +610 -609
- package/dist/types/Items/BaseItem/BaseItem.d.ts +1 -1
- package/dist/types/SpatialIndex/SimpleSpatialIndex.d.ts +39 -0
- package/dist/types/SpatialIndex/SpacialIndex.d.ts +0 -31
- package/package.json +1 -1
package/dist/cjs/node.js
CHANGED
|
@@ -22182,433 +22182,6 @@ class NoOpCommand {
|
|
|
22182
22182
|
}
|
|
22183
22183
|
}
|
|
22184
22184
|
|
|
22185
|
-
// src/isSafari.ts
|
|
22186
|
-
function isSafari() {
|
|
22187
|
-
if (typeof navigator === "undefined") {
|
|
22188
|
-
return false;
|
|
22189
|
-
}
|
|
22190
|
-
const agent = navigator.userAgent;
|
|
22191
|
-
const vendor = navigator.vendor;
|
|
22192
|
-
const is = vendor !== undefined && vendor.includes("Apple") && agent !== undefined && !agent.includes("CriOS") && !agent.includes("FxiOS");
|
|
22193
|
-
return is;
|
|
22194
|
-
}
|
|
22195
|
-
|
|
22196
|
-
// src/Items/Drawing/Drawing.ts
|
|
22197
|
-
class Drawing extends BaseItem {
|
|
22198
|
-
points;
|
|
22199
|
-
events;
|
|
22200
|
-
itemType = "Drawing";
|
|
22201
|
-
parent = "Board";
|
|
22202
|
-
transformation;
|
|
22203
|
-
path2d = new conf.path2DFactory;
|
|
22204
|
-
subject = new Subject;
|
|
22205
|
-
untransformedMbr = new Mbr;
|
|
22206
|
-
lines = [];
|
|
22207
|
-
linkTo;
|
|
22208
|
-
strokeWidth = 1;
|
|
22209
|
-
borderStyle = "solid";
|
|
22210
|
-
linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
22211
|
-
borderOpacity = 1;
|
|
22212
|
-
transformationRenderBlock = undefined;
|
|
22213
|
-
constructor(board, points, events, id = "") {
|
|
22214
|
-
super(board, id);
|
|
22215
|
-
this.points = points;
|
|
22216
|
-
this.events = events;
|
|
22217
|
-
this.transformation = new Transformation(id, events);
|
|
22218
|
-
this.linkTo = new LinkTo(this.id, this.events);
|
|
22219
|
-
this.transformation.subject.subscribe(() => {
|
|
22220
|
-
this.updateMbr();
|
|
22221
|
-
this.updateLines();
|
|
22222
|
-
this.subject.publish(this);
|
|
22223
|
-
});
|
|
22224
|
-
this.linkTo.subject.subscribe(() => {
|
|
22225
|
-
this.updateMbr();
|
|
22226
|
-
this.updateLines();
|
|
22227
|
-
this.subject.publish(this);
|
|
22228
|
-
});
|
|
22229
|
-
this.updateLines();
|
|
22230
|
-
}
|
|
22231
|
-
serialize() {
|
|
22232
|
-
this.optimizePoints();
|
|
22233
|
-
const points = [];
|
|
22234
|
-
for (const point3 of this.points) {
|
|
22235
|
-
points.push({ x: point3.x, y: point3.y });
|
|
22236
|
-
}
|
|
22237
|
-
return {
|
|
22238
|
-
itemType: "Drawing",
|
|
22239
|
-
points,
|
|
22240
|
-
transformation: this.transformation.serialize(),
|
|
22241
|
-
strokeStyle: this.borderColor,
|
|
22242
|
-
strokeWidth: this.strokeWidth,
|
|
22243
|
-
linkTo: this.linkTo.serialize()
|
|
22244
|
-
};
|
|
22245
|
-
}
|
|
22246
|
-
deserialize(data) {
|
|
22247
|
-
this.points = [];
|
|
22248
|
-
for (const point3 of data.points) {
|
|
22249
|
-
this.points.push(new Point(point3.x, point3.y));
|
|
22250
|
-
}
|
|
22251
|
-
this.linkTo.deserialize(data.linkTo);
|
|
22252
|
-
this.optimizePoints();
|
|
22253
|
-
this.transformation.deserialize(data.transformation);
|
|
22254
|
-
this.borderColor = data.strokeStyle;
|
|
22255
|
-
this.strokeWidth = data.strokeWidth;
|
|
22256
|
-
this.updateGeometry();
|
|
22257
|
-
return this;
|
|
22258
|
-
}
|
|
22259
|
-
updateGeometry() {
|
|
22260
|
-
this.updatePath2d();
|
|
22261
|
-
this.updateLines();
|
|
22262
|
-
this.updateMbr();
|
|
22263
|
-
}
|
|
22264
|
-
updateMbr() {
|
|
22265
|
-
const offset = this.getStrokeWidth() / 2;
|
|
22266
|
-
const untransformedMbr = this.untransformedMbr.copy();
|
|
22267
|
-
untransformedMbr.left -= offset;
|
|
22268
|
-
untransformedMbr.top -= offset;
|
|
22269
|
-
untransformedMbr.right += offset;
|
|
22270
|
-
untransformedMbr.bottom += offset;
|
|
22271
|
-
const mbr = untransformedMbr.getTransformed(this.transformation.matrix);
|
|
22272
|
-
this.left = mbr.left;
|
|
22273
|
-
this.top = mbr.top;
|
|
22274
|
-
this.right = mbr.right;
|
|
22275
|
-
this.bottom = mbr.bottom;
|
|
22276
|
-
}
|
|
22277
|
-
updatePath2d() {
|
|
22278
|
-
this.path2d = new conf.path2DFactory;
|
|
22279
|
-
const context = this.path2d;
|
|
22280
|
-
const points = this.points;
|
|
22281
|
-
if (points.length < 3) {
|
|
22282
|
-
context.arc(points[0].x, points[0].y, 0.5, 0, Math.PI * 2, true);
|
|
22283
|
-
context.closePath();
|
|
22284
|
-
} else {
|
|
22285
|
-
context.moveTo(points[0].x, points[0].y);
|
|
22286
|
-
let j = 1;
|
|
22287
|
-
for (;j < points.length - 2; j++) {
|
|
22288
|
-
const cx = (points[j].x + points[j + 1].x) / 2;
|
|
22289
|
-
const cy = (points[j].y + points[j + 1].y) / 2;
|
|
22290
|
-
context.quadraticCurveTo(points[j].x, points[j].y, cx, cy);
|
|
22291
|
-
}
|
|
22292
|
-
const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
|
|
22293
|
-
const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
|
|
22294
|
-
context.quadraticCurveTo(points[j].x, points[j].y, x, y);
|
|
22295
|
-
}
|
|
22296
|
-
let left = Number.MAX_SAFE_INTEGER;
|
|
22297
|
-
let right = Number.MIN_SAFE_INTEGER;
|
|
22298
|
-
let top = Number.MAX_SAFE_INTEGER;
|
|
22299
|
-
let bottom = Number.MIN_SAFE_INTEGER;
|
|
22300
|
-
for (const { x, y } of this.points) {
|
|
22301
|
-
if (x < left) {
|
|
22302
|
-
left = x;
|
|
22303
|
-
}
|
|
22304
|
-
if (x > right) {
|
|
22305
|
-
right = x;
|
|
22306
|
-
}
|
|
22307
|
-
if (y < top) {
|
|
22308
|
-
top = y;
|
|
22309
|
-
}
|
|
22310
|
-
if (y > bottom) {
|
|
22311
|
-
bottom = y;
|
|
22312
|
-
}
|
|
22313
|
-
}
|
|
22314
|
-
this.untransformedMbr = new Mbr(left, top, right, bottom);
|
|
22315
|
-
}
|
|
22316
|
-
updateLines() {
|
|
22317
|
-
this.lines = [];
|
|
22318
|
-
const matrix = this.transformation.matrix;
|
|
22319
|
-
if (this.points.length < 2) {
|
|
22320
|
-
return;
|
|
22321
|
-
}
|
|
22322
|
-
for (let i = 0;i < this.points.length - 2; i++) {
|
|
22323
|
-
const p1 = this.points[i];
|
|
22324
|
-
const p2 = this.points[i + 1];
|
|
22325
|
-
const line = new Line(p1.copy(), p2.copy());
|
|
22326
|
-
line.transform(matrix);
|
|
22327
|
-
this.lines.push(line);
|
|
22328
|
-
}
|
|
22329
|
-
}
|
|
22330
|
-
optimizePoints() {
|
|
22331
|
-
const dp = douglasPeucker(this.points, 1);
|
|
22332
|
-
dp.push(this.points[this.points.length - 1]);
|
|
22333
|
-
this.points = dp;
|
|
22334
|
-
}
|
|
22335
|
-
addPoint(point3) {
|
|
22336
|
-
const previous2 = this.points[this.points.length - 1];
|
|
22337
|
-
if (previous2) {
|
|
22338
|
-
const distance = point3.getDistance(previous2);
|
|
22339
|
-
if (distance >= 2) {
|
|
22340
|
-
this.points.push(point3);
|
|
22341
|
-
}
|
|
22342
|
-
} else {
|
|
22343
|
-
this.points.push(point3);
|
|
22344
|
-
}
|
|
22345
|
-
this.updateGeometry();
|
|
22346
|
-
}
|
|
22347
|
-
setId(id) {
|
|
22348
|
-
this.id = id;
|
|
22349
|
-
this.transformation.setId(id);
|
|
22350
|
-
this.linkTo.setId(id);
|
|
22351
|
-
return this;
|
|
22352
|
-
}
|
|
22353
|
-
getId() {
|
|
22354
|
-
return this.id;
|
|
22355
|
-
}
|
|
22356
|
-
render(context) {
|
|
22357
|
-
if (this.transformationRenderBlock) {
|
|
22358
|
-
return;
|
|
22359
|
-
}
|
|
22360
|
-
const ctx = context.ctx;
|
|
22361
|
-
ctx.save();
|
|
22362
|
-
ctx.strokeStyle = this.borderColor;
|
|
22363
|
-
ctx.lineWidth = this.strokeWidth;
|
|
22364
|
-
ctx.lineCap = "round";
|
|
22365
|
-
ctx.setLineDash(this.linePattern);
|
|
22366
|
-
this.transformation.matrix.applyToContext(ctx);
|
|
22367
|
-
ctx.stroke(this.path2d.nativePath);
|
|
22368
|
-
ctx.restore();
|
|
22369
|
-
if (this.getLinkTo()) {
|
|
22370
|
-
const { top, right } = this.getMbr();
|
|
22371
|
-
this.linkTo.render(context, top, right, this.board.camera.getScale());
|
|
22372
|
-
}
|
|
22373
|
-
}
|
|
22374
|
-
renderHTML(documentFactory) {
|
|
22375
|
-
const div = documentFactory.createElement("drawing-item");
|
|
22376
|
-
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
22377
|
-
const mbr = this.getMbr();
|
|
22378
|
-
const width = mbr.getWidth();
|
|
22379
|
-
const height = mbr.getHeight();
|
|
22380
|
-
const unscaledWidth = width / scaleX;
|
|
22381
|
-
const unscaledHeight = height / scaleY;
|
|
22382
|
-
const svg = documentFactory.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
22383
|
-
svg.setAttribute("width", `${unscaledWidth}px`);
|
|
22384
|
-
svg.setAttribute("height", `${unscaledHeight}px`);
|
|
22385
|
-
svg.setAttribute("viewBox", `0 0 ${unscaledWidth} ${unscaledHeight}`);
|
|
22386
|
-
svg.setAttribute("style", "position: absolute; overflow: visible;");
|
|
22387
|
-
const pathElement = documentFactory.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
22388
|
-
pathElement.setAttribute("d", this.getPathData());
|
|
22389
|
-
pathElement.setAttribute("stroke", this.borderColor);
|
|
22390
|
-
pathElement.setAttribute("stroke-width", `${this.strokeWidth}`);
|
|
22391
|
-
pathElement.setAttribute("fill", "none");
|
|
22392
|
-
svg.appendChild(pathElement);
|
|
22393
|
-
div.appendChild(svg);
|
|
22394
|
-
div.id = this.getId();
|
|
22395
|
-
div.style.width = unscaledWidth + "px";
|
|
22396
|
-
div.style.height = unscaledHeight + "px";
|
|
22397
|
-
div.style.transformOrigin = "left top";
|
|
22398
|
-
div.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
|
|
22399
|
-
div.style.position = "absolute";
|
|
22400
|
-
div.setAttribute("data-link-to", this.linkTo.serialize() || "");
|
|
22401
|
-
if (this.getLinkTo()) {
|
|
22402
|
-
const linkElement = this.linkTo.renderHTML(documentFactory);
|
|
22403
|
-
scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
|
|
22404
|
-
translateElementBy(linkElement, (width - parseInt(linkElement.style.width)) / scaleX, 0);
|
|
22405
|
-
div.appendChild(linkElement);
|
|
22406
|
-
}
|
|
22407
|
-
return div;
|
|
22408
|
-
}
|
|
22409
|
-
getPathData() {
|
|
22410
|
-
const points = this.points;
|
|
22411
|
-
if (points.length < 2) {
|
|
22412
|
-
return "";
|
|
22413
|
-
}
|
|
22414
|
-
let pathData = `M ${points[0].x} ${points[0].y}`;
|
|
22415
|
-
if (points.length < 3) {
|
|
22416
|
-
pathData += ` L ${points[0].x + 0.5} ${points[0].y}`;
|
|
22417
|
-
} else {
|
|
22418
|
-
let j = 1;
|
|
22419
|
-
for (;j < points.length - 2; j++) {
|
|
22420
|
-
const cx = (points[j].x + points[j + 1].x) / 2;
|
|
22421
|
-
const cy = (points[j].y + points[j + 1].y) / 2;
|
|
22422
|
-
pathData += ` Q ${points[j].x} ${points[j].y} ${cx} ${cy}`;
|
|
22423
|
-
}
|
|
22424
|
-
const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
|
|
22425
|
-
const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
|
|
22426
|
-
pathData += ` Q ${points[j].x} ${points[j].y} ${x} ${y}`;
|
|
22427
|
-
}
|
|
22428
|
-
return pathData;
|
|
22429
|
-
}
|
|
22430
|
-
getPath() {
|
|
22431
|
-
const { left, top, right, bottom } = this.getMbr();
|
|
22432
|
-
const leftTop = new Point(left, top);
|
|
22433
|
-
const rightTop = new Point(right, top);
|
|
22434
|
-
const rightBottom = new Point(right, bottom);
|
|
22435
|
-
const leftBottom = new Point(left, bottom);
|
|
22436
|
-
return new Path([
|
|
22437
|
-
new Line(leftTop, rightTop),
|
|
22438
|
-
new Line(rightTop, rightBottom),
|
|
22439
|
-
new Line(rightBottom, leftBottom),
|
|
22440
|
-
new Line(leftBottom, leftTop)
|
|
22441
|
-
], true);
|
|
22442
|
-
}
|
|
22443
|
-
getSnapAnchorPoints() {
|
|
22444
|
-
const mbr = this.getMbr();
|
|
22445
|
-
const width = mbr.getWidth();
|
|
22446
|
-
const height = mbr.getHeight();
|
|
22447
|
-
return [
|
|
22448
|
-
new Point(mbr.left + width / 2, mbr.top),
|
|
22449
|
-
new Point(mbr.left + width / 2, mbr.bottom),
|
|
22450
|
-
new Point(mbr.left, mbr.top + height / 2),
|
|
22451
|
-
new Point(mbr.right, mbr.top + height / 2)
|
|
22452
|
-
];
|
|
22453
|
-
}
|
|
22454
|
-
getLines() {
|
|
22455
|
-
return this.lines;
|
|
22456
|
-
}
|
|
22457
|
-
isClosed() {
|
|
22458
|
-
return true;
|
|
22459
|
-
}
|
|
22460
|
-
isEnclosedOrCrossedBy(rect) {
|
|
22461
|
-
for (const line of this.lines) {
|
|
22462
|
-
if (line.isEnclosedOrCrossedBy(rect)) {
|
|
22463
|
-
return true;
|
|
22464
|
-
}
|
|
22465
|
-
}
|
|
22466
|
-
return false;
|
|
22467
|
-
}
|
|
22468
|
-
emit(operation) {
|
|
22469
|
-
if (this.events) {
|
|
22470
|
-
const command = new DrawingCommand([this], operation);
|
|
22471
|
-
command.apply();
|
|
22472
|
-
this.events.emit(operation, command);
|
|
22473
|
-
} else {
|
|
22474
|
-
this.apply(operation);
|
|
22475
|
-
}
|
|
22476
|
-
}
|
|
22477
|
-
apply(op) {
|
|
22478
|
-
switch (op.class) {
|
|
22479
|
-
case "Drawing":
|
|
22480
|
-
switch (op.method) {
|
|
22481
|
-
case "setStrokeColor":
|
|
22482
|
-
this.borderColor = op.color;
|
|
22483
|
-
break;
|
|
22484
|
-
case "setStrokeWidth":
|
|
22485
|
-
this.strokeWidth = op.width;
|
|
22486
|
-
this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
22487
|
-
break;
|
|
22488
|
-
case "setStrokeOpacity":
|
|
22489
|
-
this.borderOpacity = op.opacity;
|
|
22490
|
-
break;
|
|
22491
|
-
case "setStrokeStyle":
|
|
22492
|
-
this.borderStyle = op.style;
|
|
22493
|
-
this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
22494
|
-
break;
|
|
22495
|
-
}
|
|
22496
|
-
this.updateMbr();
|
|
22497
|
-
break;
|
|
22498
|
-
case "Transformation":
|
|
22499
|
-
this.transformation.apply(op);
|
|
22500
|
-
break;
|
|
22501
|
-
case "LinkTo":
|
|
22502
|
-
this.linkTo.apply(op);
|
|
22503
|
-
break;
|
|
22504
|
-
default:
|
|
22505
|
-
return;
|
|
22506
|
-
}
|
|
22507
|
-
this.subject.publish(this);
|
|
22508
|
-
}
|
|
22509
|
-
setStrokeOpacity(opacity) {
|
|
22510
|
-
this.emit({
|
|
22511
|
-
class: "Drawing",
|
|
22512
|
-
method: "setStrokeOpacity",
|
|
22513
|
-
item: [this.id],
|
|
22514
|
-
opacity
|
|
22515
|
-
});
|
|
22516
|
-
return this;
|
|
22517
|
-
}
|
|
22518
|
-
getStrokeOpacity() {
|
|
22519
|
-
return this.borderOpacity;
|
|
22520
|
-
}
|
|
22521
|
-
setBorderStyle(style) {
|
|
22522
|
-
this.emit({
|
|
22523
|
-
class: "Drawing",
|
|
22524
|
-
method: "setStrokeStyle",
|
|
22525
|
-
item: [this.id],
|
|
22526
|
-
style
|
|
22527
|
-
});
|
|
22528
|
-
return this;
|
|
22529
|
-
}
|
|
22530
|
-
getBorderStyle() {
|
|
22531
|
-
return this.borderStyle;
|
|
22532
|
-
}
|
|
22533
|
-
setStrokeColor(color) {
|
|
22534
|
-
this.emit({
|
|
22535
|
-
class: "Drawing",
|
|
22536
|
-
method: "setStrokeColor",
|
|
22537
|
-
item: [this.id],
|
|
22538
|
-
color
|
|
22539
|
-
});
|
|
22540
|
-
return this;
|
|
22541
|
-
}
|
|
22542
|
-
getStrokeColor() {
|
|
22543
|
-
return this.borderColor;
|
|
22544
|
-
}
|
|
22545
|
-
setStrokeWidth(width) {
|
|
22546
|
-
this.emit({
|
|
22547
|
-
class: "Drawing",
|
|
22548
|
-
method: "setStrokeWidth",
|
|
22549
|
-
item: [this.id],
|
|
22550
|
-
width,
|
|
22551
|
-
prevWidth: this.strokeWidth
|
|
22552
|
-
});
|
|
22553
|
-
return this;
|
|
22554
|
-
}
|
|
22555
|
-
getLinkTo() {
|
|
22556
|
-
return this.linkTo.link;
|
|
22557
|
-
}
|
|
22558
|
-
getStrokeWidth() {
|
|
22559
|
-
return this.strokeWidth;
|
|
22560
|
-
}
|
|
22561
|
-
getRichText() {
|
|
22562
|
-
return null;
|
|
22563
|
-
}
|
|
22564
|
-
isPointNearLine(point3, threshold = 10) {
|
|
22565
|
-
const transformedMouseX = (point3.x - this.transformation.matrix.translateX) / this.transformation.matrix.scaleX;
|
|
22566
|
-
const transformedMouseY = (point3.y - this.transformation.matrix.translateY) / this.transformation.matrix.scaleY;
|
|
22567
|
-
const transformedMouse = new Point(transformedMouseX, transformedMouseY);
|
|
22568
|
-
for (let i = 0;i < this.points.length - 1; i++) {
|
|
22569
|
-
const p1 = this.points[i];
|
|
22570
|
-
const p2 = this.points[i + 1];
|
|
22571
|
-
const distance = getPerpendicularDistance(transformedMouse, p1, p2);
|
|
22572
|
-
if (distance < threshold) {
|
|
22573
|
-
return true;
|
|
22574
|
-
}
|
|
22575
|
-
}
|
|
22576
|
-
return false;
|
|
22577
|
-
}
|
|
22578
|
-
}
|
|
22579
|
-
function getPerpendicularDistance(point3, lineStart, lineEnd) {
|
|
22580
|
-
const { x: px, y: py } = point3;
|
|
22581
|
-
const { x: sx, y: sy } = lineStart;
|
|
22582
|
-
const { x: ex, y: ey } = lineEnd;
|
|
22583
|
-
const numerator = Math.abs((ey - sy) * px - (ex - sx) * py + ex * sy - ey * sx);
|
|
22584
|
-
const denominator = Math.sqrt(Math.pow(ey - sy, 2) + Math.pow(ex - sx, 2));
|
|
22585
|
-
return numerator / denominator;
|
|
22586
|
-
}
|
|
22587
|
-
function douglasPeucker(points, epsilon2) {
|
|
22588
|
-
if (points.length < 3) {
|
|
22589
|
-
return points;
|
|
22590
|
-
}
|
|
22591
|
-
const start = points[0];
|
|
22592
|
-
const end = points[points.length - 1];
|
|
22593
|
-
let maxDistance = 0;
|
|
22594
|
-
let maxIndex = 0;
|
|
22595
|
-
for (let i = 1;i < points.length - 1; i++) {
|
|
22596
|
-
const distance = getPerpendicularDistance(points[i], start, end);
|
|
22597
|
-
if (distance > maxDistance) {
|
|
22598
|
-
maxDistance = distance;
|
|
22599
|
-
maxIndex = i;
|
|
22600
|
-
}
|
|
22601
|
-
}
|
|
22602
|
-
if (maxDistance > epsilon2) {
|
|
22603
|
-
const leftSubPoints = points.slice(0, maxIndex + 1);
|
|
22604
|
-
const rightSubPoints = points.slice(maxIndex);
|
|
22605
|
-
const leftRecursiveResult = douglasPeucker(leftSubPoints, epsilon2);
|
|
22606
|
-
const rightRecursiveResult = douglasPeucker(rightSubPoints, epsilon2);
|
|
22607
|
-
return leftRecursiveResult.slice(0, -1).concat(rightRecursiveResult);
|
|
22608
|
-
} else {
|
|
22609
|
-
return [start, end];
|
|
22610
|
-
}
|
|
22611
|
-
}
|
|
22612
22185
|
// src/SpatialIndex/LayeredIndex/Layers.ts
|
|
22613
22186
|
class Layers {
|
|
22614
22187
|
getNewLayer;
|
|
@@ -23931,12 +23504,12 @@ class Items {
|
|
|
23931
23504
|
if (enclosed.length === 0) {
|
|
23932
23505
|
enclosed = underPointer;
|
|
23933
23506
|
}
|
|
23934
|
-
if (underPointer.some((item) => item
|
|
23507
|
+
if (underPointer.some((item) => item.itemType === "Drawing")) {
|
|
23935
23508
|
enclosed = [...underPointer, ...enclosed];
|
|
23936
23509
|
}
|
|
23937
23510
|
const { nearest } = enclosed.reduce((acc, item) => {
|
|
23938
23511
|
const area = item.getMbr().getHeight() * item.getMbr().getWidth();
|
|
23939
|
-
if (item
|
|
23512
|
+
if (item.itemType === "Drawing" && !item.isPointNearLine(this.pointer.point)) {
|
|
23940
23513
|
return acc;
|
|
23941
23514
|
}
|
|
23942
23515
|
const isItemTransparent = item instanceof Shape && item?.getBackgroundColor() === "none";
|
|
@@ -24071,6 +23644,7 @@ class Items {
|
|
|
24071
23644
|
}
|
|
24072
23645
|
}
|
|
24073
23646
|
|
|
23647
|
+
// src/SpatialIndex/SimpleSpatialIndex.ts
|
|
24074
23648
|
class SimpleSpatialIndex {
|
|
24075
23649
|
subject = new Subject;
|
|
24076
23650
|
itemsArray = [];
|
|
@@ -44821,202 +44395,455 @@ class Placeholder extends BaseItem {
|
|
|
44821
44395
|
renderHTML(documentFactory) {
|
|
44822
44396
|
return documentFactory.createElement("div");
|
|
44823
44397
|
}
|
|
44824
|
-
getLinkTo() {
|
|
44825
|
-
return;
|
|
44398
|
+
getLinkTo() {
|
|
44399
|
+
return;
|
|
44400
|
+
}
|
|
44401
|
+
getRichText() {
|
|
44402
|
+
return null;
|
|
44403
|
+
}
|
|
44404
|
+
}
|
|
44405
|
+
// src/Items/Image/Image.ts
|
|
44406
|
+
function getPlaceholderImage(board, imageDimension) {
|
|
44407
|
+
const placeholderCanvas = conf.documentFactory.createElement("canvas");
|
|
44408
|
+
const placeholderContext = placeholderCanvas.getContext("2d");
|
|
44409
|
+
const context = new DrawingContext(board.camera, placeholderContext);
|
|
44410
|
+
const placeholder = new Placeholder(board);
|
|
44411
|
+
if (imageDimension) {
|
|
44412
|
+
placeholderCanvas.width = imageDimension.width;
|
|
44413
|
+
placeholderCanvas.height = imageDimension.height;
|
|
44414
|
+
placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
|
|
44415
|
+
} else {
|
|
44416
|
+
placeholderCanvas.width = 250;
|
|
44417
|
+
placeholderCanvas.height = 50;
|
|
44418
|
+
placeholder.transformation.scaleTo(250 / 100, 50 / 100);
|
|
44419
|
+
}
|
|
44420
|
+
const placeholderImage = new Image;
|
|
44421
|
+
placeholderImage.src = placeholderCanvas.toDataURL();
|
|
44422
|
+
return placeholderImage;
|
|
44423
|
+
}
|
|
44424
|
+
|
|
44425
|
+
class ImageItem extends BaseItem {
|
|
44426
|
+
events;
|
|
44427
|
+
itemType = "Image";
|
|
44428
|
+
parent = "Board";
|
|
44429
|
+
image;
|
|
44430
|
+
transformation;
|
|
44431
|
+
linkTo;
|
|
44432
|
+
subject = new Subject;
|
|
44433
|
+
loadCallbacks = [];
|
|
44434
|
+
beforeLoadCallbacks = [];
|
|
44435
|
+
transformationRenderBlock = undefined;
|
|
44436
|
+
storageLink;
|
|
44437
|
+
imageDimension;
|
|
44438
|
+
board;
|
|
44439
|
+
constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
|
|
44440
|
+
super(board, id);
|
|
44441
|
+
this.events = events;
|
|
44442
|
+
this.linkTo = new LinkTo(this.id, events);
|
|
44443
|
+
this.board = board;
|
|
44444
|
+
this.setStorageLink(storageLink);
|
|
44445
|
+
this.imageDimension = imageDimension;
|
|
44446
|
+
this.transformation = new Transformation(id, events);
|
|
44447
|
+
this.image = new Image;
|
|
44448
|
+
this.image.crossOrigin = "anonymous";
|
|
44449
|
+
this.image.onload = this.onLoad;
|
|
44450
|
+
this.image.onerror = this.onError;
|
|
44451
|
+
if (typeof base64 === "string") {
|
|
44452
|
+
this.image.src = base64;
|
|
44453
|
+
}
|
|
44454
|
+
this.linkTo.subject.subscribe(() => {
|
|
44455
|
+
this.updateMbr();
|
|
44456
|
+
this.subject.publish(this);
|
|
44457
|
+
});
|
|
44458
|
+
this.transformation.subject.subscribe(this.onTransform);
|
|
44459
|
+
}
|
|
44460
|
+
setStorageLink(link2) {
|
|
44461
|
+
try {
|
|
44462
|
+
const url = new URL(link2);
|
|
44463
|
+
this.storageLink = `${window?.location.origin}${url.pathname}`;
|
|
44464
|
+
} catch (_) {}
|
|
44465
|
+
}
|
|
44466
|
+
getStorageId() {
|
|
44467
|
+
return this.storageLink.split("/").pop();
|
|
44468
|
+
}
|
|
44469
|
+
handleError = () => {
|
|
44470
|
+
console.error("Invalid dataUrl or image failed to load.");
|
|
44471
|
+
this.image = getPlaceholderImage(this.board);
|
|
44472
|
+
this.updateMbr();
|
|
44473
|
+
this.subject.publish(this);
|
|
44474
|
+
this.shootLoadCallbacks();
|
|
44475
|
+
};
|
|
44476
|
+
onLoad = async () => {
|
|
44477
|
+
this.shootBeforeLoadCallbacks();
|
|
44478
|
+
this.updateMbr();
|
|
44479
|
+
this.subject.publish(this);
|
|
44480
|
+
this.shootLoadCallbacks();
|
|
44481
|
+
};
|
|
44482
|
+
onError = (_error) => {
|
|
44483
|
+
this.image = getPlaceholderImage(this.board);
|
|
44484
|
+
this.updateMbr();
|
|
44485
|
+
this.subject.publish(this);
|
|
44486
|
+
this.shootLoadCallbacks();
|
|
44487
|
+
};
|
|
44488
|
+
onTransform = () => {
|
|
44489
|
+
this.updateMbr();
|
|
44490
|
+
this.subject.publish(this);
|
|
44491
|
+
};
|
|
44492
|
+
updateMbr() {
|
|
44493
|
+
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
44494
|
+
this.left = translateX;
|
|
44495
|
+
this.top = translateY;
|
|
44496
|
+
this.right = this.left + this.image.width * scaleX;
|
|
44497
|
+
this.bottom = this.top + this.image.height * scaleY;
|
|
44498
|
+
}
|
|
44499
|
+
doOnceBeforeOnLoad = (callback) => {
|
|
44500
|
+
this.loadCallbacks.push(callback);
|
|
44501
|
+
};
|
|
44502
|
+
doOnceOnLoad = (callback) => {
|
|
44503
|
+
this.loadCallbacks.push(callback);
|
|
44504
|
+
};
|
|
44505
|
+
setId(id) {
|
|
44506
|
+
this.id = id;
|
|
44507
|
+
this.transformation.setId(id);
|
|
44508
|
+
this.linkTo.setId(id);
|
|
44509
|
+
return this;
|
|
44510
|
+
}
|
|
44511
|
+
getId() {
|
|
44512
|
+
return this.id;
|
|
44513
|
+
}
|
|
44514
|
+
serialize() {
|
|
44515
|
+
return {
|
|
44516
|
+
itemType: "Image",
|
|
44517
|
+
storageLink: this.storageLink,
|
|
44518
|
+
imageDimension: this.imageDimension,
|
|
44519
|
+
transformation: this.transformation.serialize(),
|
|
44520
|
+
linkTo: this.linkTo.serialize()
|
|
44521
|
+
};
|
|
44522
|
+
}
|
|
44523
|
+
setCoordinates() {
|
|
44524
|
+
this.left = this.transformation.matrix.translateX;
|
|
44525
|
+
this.top = this.transformation.matrix.translateY;
|
|
44526
|
+
this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
|
|
44527
|
+
this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
|
|
44528
|
+
this.subject.publish(this);
|
|
44529
|
+
}
|
|
44530
|
+
shootBeforeLoadCallbacks() {
|
|
44531
|
+
while (this.beforeLoadCallbacks.length > 0) {
|
|
44532
|
+
this.beforeLoadCallbacks.shift()(this);
|
|
44533
|
+
}
|
|
44534
|
+
}
|
|
44535
|
+
shootLoadCallbacks() {
|
|
44536
|
+
while (this.loadCallbacks.length > 0) {
|
|
44537
|
+
this.loadCallbacks.shift()(this);
|
|
44538
|
+
}
|
|
44539
|
+
}
|
|
44540
|
+
deserialize(data) {
|
|
44541
|
+
if (data.transformation) {
|
|
44542
|
+
this.transformation.deserialize(data.transformation);
|
|
44543
|
+
}
|
|
44544
|
+
this.linkTo.deserialize(data.linkTo);
|
|
44545
|
+
this.image.onload = () => {
|
|
44546
|
+
this.setCoordinates();
|
|
44547
|
+
this.shootLoadCallbacks();
|
|
44548
|
+
};
|
|
44549
|
+
if (data.storageLink) {
|
|
44550
|
+
this.setStorageLink(data.storageLink);
|
|
44551
|
+
}
|
|
44552
|
+
if (this.image.src) {
|
|
44553
|
+
return this;
|
|
44554
|
+
}
|
|
44555
|
+
this.image = getPlaceholderImage(this.board, data.imageDimension);
|
|
44556
|
+
const storageImage = new Image;
|
|
44557
|
+
storageImage.onload = () => {
|
|
44558
|
+
this.image = storageImage;
|
|
44559
|
+
this.onLoad();
|
|
44560
|
+
};
|
|
44561
|
+
storageImage.onerror = this.onError;
|
|
44562
|
+
storageImage.src = this.storageLink;
|
|
44563
|
+
return this;
|
|
44564
|
+
}
|
|
44565
|
+
emit(operation) {
|
|
44566
|
+
if (this.events) {
|
|
44567
|
+
const command = new ImageCommand([this], operation);
|
|
44568
|
+
command.apply();
|
|
44569
|
+
this.events.emit(operation, command);
|
|
44570
|
+
} else {
|
|
44571
|
+
this.apply(operation);
|
|
44572
|
+
}
|
|
44573
|
+
}
|
|
44574
|
+
setDimensions(dim) {
|
|
44575
|
+
this.imageDimension = dim;
|
|
44576
|
+
}
|
|
44577
|
+
apply(op) {
|
|
44578
|
+
switch (op.class) {
|
|
44579
|
+
case "Transformation":
|
|
44580
|
+
this.transformation.apply(op);
|
|
44581
|
+
break;
|
|
44582
|
+
case "LinkTo":
|
|
44583
|
+
this.linkTo.apply(op);
|
|
44584
|
+
break;
|
|
44585
|
+
case "Image":
|
|
44586
|
+
if (op.data.base64) {
|
|
44587
|
+
this.image.src = op.data.base64;
|
|
44588
|
+
}
|
|
44589
|
+
this.setStorageLink(op.data.storageLink);
|
|
44590
|
+
this.setDimensions(op.data.imageDimension);
|
|
44591
|
+
this.subject.publish(this);
|
|
44592
|
+
break;
|
|
44593
|
+
}
|
|
44594
|
+
}
|
|
44595
|
+
render(context) {
|
|
44596
|
+
if (this.transformationRenderBlock) {
|
|
44597
|
+
return;
|
|
44598
|
+
}
|
|
44599
|
+
const ctx = context.ctx;
|
|
44600
|
+
ctx.save();
|
|
44601
|
+
this.transformation.matrix.applyToContext(ctx);
|
|
44602
|
+
ctx.drawImage(this.image, 0, 0);
|
|
44603
|
+
ctx.restore();
|
|
44604
|
+
if (this.getLinkTo()) {
|
|
44605
|
+
const { top, right } = this.getMbr();
|
|
44606
|
+
this.linkTo.render(context, top, right, this.board.camera.getScale());
|
|
44607
|
+
}
|
|
44608
|
+
}
|
|
44609
|
+
renderHTML(documentFactory) {
|
|
44610
|
+
const div = documentFactory.createElement("image-item");
|
|
44611
|
+
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
44612
|
+
const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
|
|
44613
|
+
div.style.backgroundImage = `url(${this.storageLink})`;
|
|
44614
|
+
div.id = this.getId();
|
|
44615
|
+
div.style.width = `${this.imageDimension.width}px`;
|
|
44616
|
+
div.style.height = `${this.imageDimension.height}px`;
|
|
44617
|
+
div.style.transformOrigin = "top left";
|
|
44618
|
+
div.style.transform = transform;
|
|
44619
|
+
div.style.position = "absolute";
|
|
44620
|
+
div.style.backgroundSize = "cover";
|
|
44621
|
+
div.setAttribute("data-link-to", this.linkTo.serialize() || "");
|
|
44622
|
+
if (this.getLinkTo()) {
|
|
44623
|
+
const linkElement = this.linkTo.renderHTML(documentFactory);
|
|
44624
|
+
scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
|
|
44625
|
+
translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
|
|
44626
|
+
div.appendChild(linkElement);
|
|
44627
|
+
}
|
|
44628
|
+
return div;
|
|
44629
|
+
}
|
|
44630
|
+
getPath() {
|
|
44631
|
+
const { left, top, right, bottom } = this.getMbr();
|
|
44632
|
+
const leftTop = new Point(left, top);
|
|
44633
|
+
const rightTop = new Point(right, top);
|
|
44634
|
+
const rightBottom = new Point(right, bottom);
|
|
44635
|
+
const leftBottom = new Point(left, bottom);
|
|
44636
|
+
return new Path([
|
|
44637
|
+
new Line(leftTop, rightTop),
|
|
44638
|
+
new Line(rightTop, rightBottom),
|
|
44639
|
+
new Line(rightBottom, leftBottom),
|
|
44640
|
+
new Line(leftBottom, leftTop)
|
|
44641
|
+
], true);
|
|
44642
|
+
}
|
|
44643
|
+
getSnapAnchorPoints() {
|
|
44644
|
+
const mbr = this.getMbr();
|
|
44645
|
+
const width2 = mbr.getWidth();
|
|
44646
|
+
const height2 = mbr.getHeight();
|
|
44647
|
+
return [
|
|
44648
|
+
new Point(mbr.left + width2 / 2, mbr.top),
|
|
44649
|
+
new Point(mbr.left + width2 / 2, mbr.bottom),
|
|
44650
|
+
new Point(mbr.left, mbr.top + height2 / 2),
|
|
44651
|
+
new Point(mbr.right, mbr.top + height2 / 2)
|
|
44652
|
+
];
|
|
44653
|
+
}
|
|
44654
|
+
isClosed() {
|
|
44655
|
+
return true;
|
|
44826
44656
|
}
|
|
44827
44657
|
getRichText() {
|
|
44828
44658
|
return null;
|
|
44829
44659
|
}
|
|
44660
|
+
getLinkTo() {
|
|
44661
|
+
return this.linkTo.link;
|
|
44662
|
+
}
|
|
44663
|
+
download() {
|
|
44664
|
+
const linkElem = document.createElement("a");
|
|
44665
|
+
linkElem.href = this.storageLink;
|
|
44666
|
+
linkElem.setAttribute("download", "");
|
|
44667
|
+
linkElem.click();
|
|
44668
|
+
}
|
|
44669
|
+
onRemove() {
|
|
44670
|
+
const storageId = this.getStorageId();
|
|
44671
|
+
if (storageId) {
|
|
44672
|
+
conf.hooks.beforeMediaRemove([storageId], this.board.getBoardId());
|
|
44673
|
+
}
|
|
44674
|
+
super.onRemove();
|
|
44675
|
+
}
|
|
44830
44676
|
}
|
|
44831
|
-
// src/
|
|
44832
|
-
function
|
|
44833
|
-
|
|
44834
|
-
|
|
44835
|
-
const context = new DrawingContext(board.camera, placeholderContext);
|
|
44836
|
-
const placeholder = new Placeholder(board);
|
|
44837
|
-
if (imageDimension) {
|
|
44838
|
-
placeholderCanvas.width = imageDimension.width;
|
|
44839
|
-
placeholderCanvas.height = imageDimension.height;
|
|
44840
|
-
placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
|
|
44841
|
-
} else {
|
|
44842
|
-
placeholderCanvas.width = 250;
|
|
44843
|
-
placeholderCanvas.height = 50;
|
|
44844
|
-
placeholder.transformation.scaleTo(250 / 100, 50 / 100);
|
|
44677
|
+
// src/isSafari.ts
|
|
44678
|
+
function isSafari() {
|
|
44679
|
+
if (typeof navigator === "undefined") {
|
|
44680
|
+
return false;
|
|
44845
44681
|
}
|
|
44846
|
-
const
|
|
44847
|
-
|
|
44848
|
-
|
|
44682
|
+
const agent = navigator.userAgent;
|
|
44683
|
+
const vendor = navigator.vendor;
|
|
44684
|
+
const is2 = vendor !== undefined && vendor.includes("Apple") && agent !== undefined && !agent.includes("CriOS") && !agent.includes("FxiOS");
|
|
44685
|
+
return is2;
|
|
44849
44686
|
}
|
|
44850
44687
|
|
|
44851
|
-
|
|
44688
|
+
// src/Items/Drawing/Drawing.ts
|
|
44689
|
+
class Drawing extends BaseItem {
|
|
44690
|
+
points;
|
|
44852
44691
|
events;
|
|
44853
|
-
itemType = "
|
|
44692
|
+
itemType = "Drawing";
|
|
44854
44693
|
parent = "Board";
|
|
44855
|
-
image;
|
|
44856
44694
|
transformation;
|
|
44857
|
-
|
|
44695
|
+
path2d = new conf.path2DFactory;
|
|
44858
44696
|
subject = new Subject;
|
|
44859
|
-
|
|
44860
|
-
|
|
44697
|
+
untransformedMbr = new Mbr;
|
|
44698
|
+
lines = [];
|
|
44699
|
+
linkTo;
|
|
44700
|
+
strokeWidth = 1;
|
|
44701
|
+
borderStyle = "solid";
|
|
44702
|
+
linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
44703
|
+
borderOpacity = 1;
|
|
44861
44704
|
transformationRenderBlock = undefined;
|
|
44862
|
-
|
|
44863
|
-
imageDimension;
|
|
44864
|
-
board;
|
|
44865
|
-
constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
|
|
44705
|
+
constructor(board, points, events, id = "") {
|
|
44866
44706
|
super(board, id);
|
|
44707
|
+
this.points = points;
|
|
44867
44708
|
this.events = events;
|
|
44868
|
-
this.linkTo = new LinkTo(this.id, events);
|
|
44869
|
-
this.board = board;
|
|
44870
|
-
this.setStorageLink(storageLink);
|
|
44871
|
-
this.imageDimension = imageDimension;
|
|
44872
44709
|
this.transformation = new Transformation(id, events);
|
|
44873
|
-
this.
|
|
44874
|
-
this.
|
|
44875
|
-
|
|
44876
|
-
|
|
44877
|
-
|
|
44878
|
-
|
|
44879
|
-
}
|
|
44710
|
+
this.linkTo = new LinkTo(this.id, this.events);
|
|
44711
|
+
this.transformation.subject.subscribe(() => {
|
|
44712
|
+
this.updateMbr();
|
|
44713
|
+
this.updateLines();
|
|
44714
|
+
this.subject.publish(this);
|
|
44715
|
+
});
|
|
44880
44716
|
this.linkTo.subject.subscribe(() => {
|
|
44881
44717
|
this.updateMbr();
|
|
44718
|
+
this.updateLines();
|
|
44882
44719
|
this.subject.publish(this);
|
|
44883
44720
|
});
|
|
44884
|
-
this.
|
|
44885
|
-
}
|
|
44886
|
-
setStorageLink(link2) {
|
|
44887
|
-
try {
|
|
44888
|
-
const url = new URL(link2);
|
|
44889
|
-
this.storageLink = `${window?.location.origin}${url.pathname}`;
|
|
44890
|
-
} catch (_) {}
|
|
44891
|
-
}
|
|
44892
|
-
getStorageId() {
|
|
44893
|
-
return this.storageLink.split("/").pop();
|
|
44894
|
-
}
|
|
44895
|
-
handleError = () => {
|
|
44896
|
-
console.error("Invalid dataUrl or image failed to load.");
|
|
44897
|
-
this.image = getPlaceholderImage(this.board);
|
|
44898
|
-
this.updateMbr();
|
|
44899
|
-
this.subject.publish(this);
|
|
44900
|
-
this.shootLoadCallbacks();
|
|
44901
|
-
};
|
|
44902
|
-
onLoad = async () => {
|
|
44903
|
-
this.shootBeforeLoadCallbacks();
|
|
44904
|
-
this.updateMbr();
|
|
44905
|
-
this.subject.publish(this);
|
|
44906
|
-
this.shootLoadCallbacks();
|
|
44907
|
-
};
|
|
44908
|
-
onError = (_error) => {
|
|
44909
|
-
this.image = getPlaceholderImage(this.board);
|
|
44910
|
-
this.updateMbr();
|
|
44911
|
-
this.subject.publish(this);
|
|
44912
|
-
this.shootLoadCallbacks();
|
|
44913
|
-
};
|
|
44914
|
-
onTransform = () => {
|
|
44915
|
-
this.updateMbr();
|
|
44916
|
-
this.subject.publish(this);
|
|
44917
|
-
};
|
|
44918
|
-
updateMbr() {
|
|
44919
|
-
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
44920
|
-
this.left = translateX;
|
|
44921
|
-
this.top = translateY;
|
|
44922
|
-
this.right = this.left + this.image.width * scaleX;
|
|
44923
|
-
this.bottom = this.top + this.image.height * scaleY;
|
|
44924
|
-
}
|
|
44925
|
-
doOnceBeforeOnLoad = (callback) => {
|
|
44926
|
-
this.loadCallbacks.push(callback);
|
|
44927
|
-
};
|
|
44928
|
-
doOnceOnLoad = (callback) => {
|
|
44929
|
-
this.loadCallbacks.push(callback);
|
|
44930
|
-
};
|
|
44931
|
-
setId(id) {
|
|
44932
|
-
this.id = id;
|
|
44933
|
-
this.transformation.setId(id);
|
|
44934
|
-
this.linkTo.setId(id);
|
|
44935
|
-
return this;
|
|
44936
|
-
}
|
|
44937
|
-
getId() {
|
|
44938
|
-
return this.id;
|
|
44721
|
+
this.updateLines();
|
|
44939
44722
|
}
|
|
44940
44723
|
serialize() {
|
|
44724
|
+
this.optimizePoints();
|
|
44725
|
+
const points = [];
|
|
44726
|
+
for (const point5 of this.points) {
|
|
44727
|
+
points.push({ x: point5.x, y: point5.y });
|
|
44728
|
+
}
|
|
44941
44729
|
return {
|
|
44942
|
-
itemType: "
|
|
44943
|
-
|
|
44944
|
-
imageDimension: this.imageDimension,
|
|
44730
|
+
itemType: "Drawing",
|
|
44731
|
+
points,
|
|
44945
44732
|
transformation: this.transformation.serialize(),
|
|
44733
|
+
strokeStyle: this.borderColor,
|
|
44734
|
+
strokeWidth: this.strokeWidth,
|
|
44946
44735
|
linkTo: this.linkTo.serialize()
|
|
44947
44736
|
};
|
|
44948
44737
|
}
|
|
44949
|
-
|
|
44950
|
-
this.
|
|
44951
|
-
|
|
44952
|
-
|
|
44953
|
-
this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
|
|
44954
|
-
this.subject.publish(this);
|
|
44955
|
-
}
|
|
44956
|
-
shootBeforeLoadCallbacks() {
|
|
44957
|
-
while (this.beforeLoadCallbacks.length > 0) {
|
|
44958
|
-
this.beforeLoadCallbacks.shift()(this);
|
|
44738
|
+
deserialize(data) {
|
|
44739
|
+
this.points = [];
|
|
44740
|
+
for (const point5 of data.points) {
|
|
44741
|
+
this.points.push(new Point(point5.x, point5.y));
|
|
44959
44742
|
}
|
|
44743
|
+
this.linkTo.deserialize(data.linkTo);
|
|
44744
|
+
this.optimizePoints();
|
|
44745
|
+
this.transformation.deserialize(data.transformation);
|
|
44746
|
+
this.borderColor = data.strokeStyle;
|
|
44747
|
+
this.strokeWidth = data.strokeWidth;
|
|
44748
|
+
this.updateGeometry();
|
|
44749
|
+
return this;
|
|
44960
44750
|
}
|
|
44961
|
-
|
|
44962
|
-
|
|
44963
|
-
|
|
44964
|
-
|
|
44751
|
+
updateGeometry() {
|
|
44752
|
+
this.updatePath2d();
|
|
44753
|
+
this.updateLines();
|
|
44754
|
+
this.updateMbr();
|
|
44965
44755
|
}
|
|
44966
|
-
|
|
44967
|
-
|
|
44968
|
-
|
|
44756
|
+
updateMbr() {
|
|
44757
|
+
const offset = this.getStrokeWidth() / 2;
|
|
44758
|
+
const untransformedMbr = this.untransformedMbr.copy();
|
|
44759
|
+
untransformedMbr.left -= offset;
|
|
44760
|
+
untransformedMbr.top -= offset;
|
|
44761
|
+
untransformedMbr.right += offset;
|
|
44762
|
+
untransformedMbr.bottom += offset;
|
|
44763
|
+
const mbr = untransformedMbr.getTransformed(this.transformation.matrix);
|
|
44764
|
+
this.left = mbr.left;
|
|
44765
|
+
this.top = mbr.top;
|
|
44766
|
+
this.right = mbr.right;
|
|
44767
|
+
this.bottom = mbr.bottom;
|
|
44768
|
+
}
|
|
44769
|
+
updatePath2d() {
|
|
44770
|
+
this.path2d = new conf.path2DFactory;
|
|
44771
|
+
const context = this.path2d;
|
|
44772
|
+
const points = this.points;
|
|
44773
|
+
if (points.length < 3) {
|
|
44774
|
+
context.arc(points[0].x, points[0].y, 0.5, 0, Math.PI * 2, true);
|
|
44775
|
+
context.closePath();
|
|
44776
|
+
} else {
|
|
44777
|
+
context.moveTo(points[0].x, points[0].y);
|
|
44778
|
+
let j = 1;
|
|
44779
|
+
for (;j < points.length - 2; j++) {
|
|
44780
|
+
const cx = (points[j].x + points[j + 1].x) / 2;
|
|
44781
|
+
const cy = (points[j].y + points[j + 1].y) / 2;
|
|
44782
|
+
context.quadraticCurveTo(points[j].x, points[j].y, cx, cy);
|
|
44783
|
+
}
|
|
44784
|
+
const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
|
|
44785
|
+
const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
|
|
44786
|
+
context.quadraticCurveTo(points[j].x, points[j].y, x, y);
|
|
44969
44787
|
}
|
|
44970
|
-
|
|
44971
|
-
|
|
44972
|
-
|
|
44973
|
-
|
|
44974
|
-
}
|
|
44975
|
-
|
|
44976
|
-
|
|
44788
|
+
let left = Number.MAX_SAFE_INTEGER;
|
|
44789
|
+
let right = Number.MIN_SAFE_INTEGER;
|
|
44790
|
+
let top = Number.MAX_SAFE_INTEGER;
|
|
44791
|
+
let bottom = Number.MIN_SAFE_INTEGER;
|
|
44792
|
+
for (const { x, y } of this.points) {
|
|
44793
|
+
if (x < left) {
|
|
44794
|
+
left = x;
|
|
44795
|
+
}
|
|
44796
|
+
if (x > right) {
|
|
44797
|
+
right = x;
|
|
44798
|
+
}
|
|
44799
|
+
if (y < top) {
|
|
44800
|
+
top = y;
|
|
44801
|
+
}
|
|
44802
|
+
if (y > bottom) {
|
|
44803
|
+
bottom = y;
|
|
44804
|
+
}
|
|
44977
44805
|
}
|
|
44978
|
-
|
|
44979
|
-
|
|
44806
|
+
this.untransformedMbr = new Mbr(left, top, right, bottom);
|
|
44807
|
+
}
|
|
44808
|
+
updateLines() {
|
|
44809
|
+
this.lines = [];
|
|
44810
|
+
const matrix = this.transformation.matrix;
|
|
44811
|
+
if (this.points.length < 2) {
|
|
44812
|
+
return;
|
|
44813
|
+
}
|
|
44814
|
+
for (let i = 0;i < this.points.length - 2; i++) {
|
|
44815
|
+
const p1 = this.points[i];
|
|
44816
|
+
const p22 = this.points[i + 1];
|
|
44817
|
+
const line = new Line(p1.copy(), p22.copy());
|
|
44818
|
+
line.transform(matrix);
|
|
44819
|
+
this.lines.push(line);
|
|
44980
44820
|
}
|
|
44981
|
-
this.image = getPlaceholderImage(this.board, data.imageDimension);
|
|
44982
|
-
const storageImage = new Image;
|
|
44983
|
-
storageImage.onload = () => {
|
|
44984
|
-
this.image = storageImage;
|
|
44985
|
-
this.onLoad();
|
|
44986
|
-
};
|
|
44987
|
-
storageImage.onerror = this.onError;
|
|
44988
|
-
storageImage.src = this.storageLink;
|
|
44989
|
-
return this;
|
|
44990
44821
|
}
|
|
44991
|
-
|
|
44992
|
-
|
|
44993
|
-
|
|
44994
|
-
|
|
44995
|
-
|
|
44822
|
+
optimizePoints() {
|
|
44823
|
+
const dp = douglasPeucker(this.points, 1);
|
|
44824
|
+
dp.push(this.points[this.points.length - 1]);
|
|
44825
|
+
this.points = dp;
|
|
44826
|
+
}
|
|
44827
|
+
addPoint(point5) {
|
|
44828
|
+
const previous2 = this.points[this.points.length - 1];
|
|
44829
|
+
if (previous2) {
|
|
44830
|
+
const distance = point5.getDistance(previous2);
|
|
44831
|
+
if (distance >= 2) {
|
|
44832
|
+
this.points.push(point5);
|
|
44833
|
+
}
|
|
44996
44834
|
} else {
|
|
44997
|
-
this.
|
|
44835
|
+
this.points.push(point5);
|
|
44998
44836
|
}
|
|
44837
|
+
this.updateGeometry();
|
|
44999
44838
|
}
|
|
45000
|
-
|
|
45001
|
-
this.
|
|
44839
|
+
setId(id) {
|
|
44840
|
+
this.id = id;
|
|
44841
|
+
this.transformation.setId(id);
|
|
44842
|
+
this.linkTo.setId(id);
|
|
44843
|
+
return this;
|
|
45002
44844
|
}
|
|
45003
|
-
|
|
45004
|
-
|
|
45005
|
-
case "Transformation":
|
|
45006
|
-
this.transformation.apply(op);
|
|
45007
|
-
break;
|
|
45008
|
-
case "LinkTo":
|
|
45009
|
-
this.linkTo.apply(op);
|
|
45010
|
-
break;
|
|
45011
|
-
case "Image":
|
|
45012
|
-
if (op.data.base64) {
|
|
45013
|
-
this.image.src = op.data.base64;
|
|
45014
|
-
}
|
|
45015
|
-
this.setStorageLink(op.data.storageLink);
|
|
45016
|
-
this.setDimensions(op.data.imageDimension);
|
|
45017
|
-
this.subject.publish(this);
|
|
45018
|
-
break;
|
|
45019
|
-
}
|
|
44845
|
+
getId() {
|
|
44846
|
+
return this.id;
|
|
45020
44847
|
}
|
|
45021
44848
|
render(context) {
|
|
45022
44849
|
if (this.transformationRenderBlock) {
|
|
@@ -45024,8 +44851,12 @@ class ImageItem extends BaseItem {
|
|
|
45024
44851
|
}
|
|
45025
44852
|
const ctx = context.ctx;
|
|
45026
44853
|
ctx.save();
|
|
44854
|
+
ctx.strokeStyle = this.borderColor;
|
|
44855
|
+
ctx.lineWidth = this.strokeWidth;
|
|
44856
|
+
ctx.lineCap = "round";
|
|
44857
|
+
ctx.setLineDash(this.linePattern);
|
|
45027
44858
|
this.transformation.matrix.applyToContext(ctx);
|
|
45028
|
-
ctx.
|
|
44859
|
+
ctx.stroke(this.path2d.nativePath);
|
|
45029
44860
|
ctx.restore();
|
|
45030
44861
|
if (this.getLinkTo()) {
|
|
45031
44862
|
const { top, right } = this.getMbr();
|
|
@@ -45033,26 +44864,61 @@ class ImageItem extends BaseItem {
|
|
|
45033
44864
|
}
|
|
45034
44865
|
}
|
|
45035
44866
|
renderHTML(documentFactory) {
|
|
45036
|
-
const div = documentFactory.createElement("
|
|
44867
|
+
const div = documentFactory.createElement("drawing-item");
|
|
45037
44868
|
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
45038
|
-
const
|
|
45039
|
-
|
|
44869
|
+
const mbr = this.getMbr();
|
|
44870
|
+
const width2 = mbr.getWidth();
|
|
44871
|
+
const height2 = mbr.getHeight();
|
|
44872
|
+
const unscaledWidth = width2 / scaleX;
|
|
44873
|
+
const unscaledHeight = height2 / scaleY;
|
|
44874
|
+
const svg3 = documentFactory.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
44875
|
+
svg3.setAttribute("width", `${unscaledWidth}px`);
|
|
44876
|
+
svg3.setAttribute("height", `${unscaledHeight}px`);
|
|
44877
|
+
svg3.setAttribute("viewBox", `0 0 ${unscaledWidth} ${unscaledHeight}`);
|
|
44878
|
+
svg3.setAttribute("style", "position: absolute; overflow: visible;");
|
|
44879
|
+
const pathElement = documentFactory.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
44880
|
+
pathElement.setAttribute("d", this.getPathData());
|
|
44881
|
+
pathElement.setAttribute("stroke", this.borderColor);
|
|
44882
|
+
pathElement.setAttribute("stroke-width", `${this.strokeWidth}`);
|
|
44883
|
+
pathElement.setAttribute("fill", "none");
|
|
44884
|
+
svg3.appendChild(pathElement);
|
|
44885
|
+
div.appendChild(svg3);
|
|
45040
44886
|
div.id = this.getId();
|
|
45041
|
-
div.style.width =
|
|
45042
|
-
div.style.height =
|
|
45043
|
-
div.style.transformOrigin = "top
|
|
45044
|
-
div.style.transform =
|
|
44887
|
+
div.style.width = unscaledWidth + "px";
|
|
44888
|
+
div.style.height = unscaledHeight + "px";
|
|
44889
|
+
div.style.transformOrigin = "left top";
|
|
44890
|
+
div.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
|
|
45045
44891
|
div.style.position = "absolute";
|
|
45046
|
-
div.style.backgroundSize = "cover";
|
|
45047
44892
|
div.setAttribute("data-link-to", this.linkTo.serialize() || "");
|
|
45048
44893
|
if (this.getLinkTo()) {
|
|
45049
44894
|
const linkElement = this.linkTo.renderHTML(documentFactory);
|
|
45050
44895
|
scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
|
|
45051
|
-
translateElementBy(linkElement, (
|
|
44896
|
+
translateElementBy(linkElement, (width2 - parseInt(linkElement.style.width)) / scaleX, 0);
|
|
45052
44897
|
div.appendChild(linkElement);
|
|
45053
44898
|
}
|
|
45054
44899
|
return div;
|
|
45055
44900
|
}
|
|
44901
|
+
getPathData() {
|
|
44902
|
+
const points = this.points;
|
|
44903
|
+
if (points.length < 2) {
|
|
44904
|
+
return "";
|
|
44905
|
+
}
|
|
44906
|
+
let pathData = `M ${points[0].x} ${points[0].y}`;
|
|
44907
|
+
if (points.length < 3) {
|
|
44908
|
+
pathData += ` L ${points[0].x + 0.5} ${points[0].y}`;
|
|
44909
|
+
} else {
|
|
44910
|
+
let j = 1;
|
|
44911
|
+
for (;j < points.length - 2; j++) {
|
|
44912
|
+
const cx = (points[j].x + points[j + 1].x) / 2;
|
|
44913
|
+
const cy = (points[j].y + points[j + 1].y) / 2;
|
|
44914
|
+
pathData += ` Q ${points[j].x} ${points[j].y} ${cx} ${cy}`;
|
|
44915
|
+
}
|
|
44916
|
+
const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
|
|
44917
|
+
const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
|
|
44918
|
+
pathData += ` Q ${points[j].x} ${points[j].y} ${x} ${y}`;
|
|
44919
|
+
}
|
|
44920
|
+
return pathData;
|
|
44921
|
+
}
|
|
45056
44922
|
getPath() {
|
|
45057
44923
|
const { left, top, right, bottom } = this.getMbr();
|
|
45058
44924
|
const leftTop = new Point(left, top);
|
|
@@ -45077,27 +44943,162 @@ class ImageItem extends BaseItem {
|
|
|
45077
44943
|
new Point(mbr.right, mbr.top + height2 / 2)
|
|
45078
44944
|
];
|
|
45079
44945
|
}
|
|
44946
|
+
getLines() {
|
|
44947
|
+
return this.lines;
|
|
44948
|
+
}
|
|
45080
44949
|
isClosed() {
|
|
45081
44950
|
return true;
|
|
45082
44951
|
}
|
|
45083
|
-
|
|
45084
|
-
|
|
44952
|
+
isEnclosedOrCrossedBy(rect) {
|
|
44953
|
+
for (const line of this.lines) {
|
|
44954
|
+
if (line.isEnclosedOrCrossedBy(rect)) {
|
|
44955
|
+
return true;
|
|
44956
|
+
}
|
|
44957
|
+
}
|
|
44958
|
+
return false;
|
|
44959
|
+
}
|
|
44960
|
+
emit(operation) {
|
|
44961
|
+
if (this.events) {
|
|
44962
|
+
const command = new DrawingCommand([this], operation);
|
|
44963
|
+
command.apply();
|
|
44964
|
+
this.events.emit(operation, command);
|
|
44965
|
+
} else {
|
|
44966
|
+
this.apply(operation);
|
|
44967
|
+
}
|
|
44968
|
+
}
|
|
44969
|
+
apply(op) {
|
|
44970
|
+
switch (op.class) {
|
|
44971
|
+
case "Drawing":
|
|
44972
|
+
switch (op.method) {
|
|
44973
|
+
case "setStrokeColor":
|
|
44974
|
+
this.borderColor = op.color;
|
|
44975
|
+
break;
|
|
44976
|
+
case "setStrokeWidth":
|
|
44977
|
+
this.strokeWidth = op.width;
|
|
44978
|
+
this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
44979
|
+
break;
|
|
44980
|
+
case "setStrokeOpacity":
|
|
44981
|
+
this.borderOpacity = op.opacity;
|
|
44982
|
+
break;
|
|
44983
|
+
case "setStrokeStyle":
|
|
44984
|
+
this.borderStyle = op.style;
|
|
44985
|
+
this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
44986
|
+
break;
|
|
44987
|
+
}
|
|
44988
|
+
this.updateMbr();
|
|
44989
|
+
break;
|
|
44990
|
+
case "Transformation":
|
|
44991
|
+
this.transformation.apply(op);
|
|
44992
|
+
break;
|
|
44993
|
+
case "LinkTo":
|
|
44994
|
+
this.linkTo.apply(op);
|
|
44995
|
+
break;
|
|
44996
|
+
default:
|
|
44997
|
+
return;
|
|
44998
|
+
}
|
|
44999
|
+
this.subject.publish(this);
|
|
45000
|
+
}
|
|
45001
|
+
setStrokeOpacity(opacity) {
|
|
45002
|
+
this.emit({
|
|
45003
|
+
class: "Drawing",
|
|
45004
|
+
method: "setStrokeOpacity",
|
|
45005
|
+
item: [this.id],
|
|
45006
|
+
opacity
|
|
45007
|
+
});
|
|
45008
|
+
return this;
|
|
45009
|
+
}
|
|
45010
|
+
getStrokeOpacity() {
|
|
45011
|
+
return this.borderOpacity;
|
|
45012
|
+
}
|
|
45013
|
+
setBorderStyle(style2) {
|
|
45014
|
+
this.emit({
|
|
45015
|
+
class: "Drawing",
|
|
45016
|
+
method: "setStrokeStyle",
|
|
45017
|
+
item: [this.id],
|
|
45018
|
+
style: style2
|
|
45019
|
+
});
|
|
45020
|
+
return this;
|
|
45021
|
+
}
|
|
45022
|
+
getBorderStyle() {
|
|
45023
|
+
return this.borderStyle;
|
|
45024
|
+
}
|
|
45025
|
+
setStrokeColor(color2) {
|
|
45026
|
+
this.emit({
|
|
45027
|
+
class: "Drawing",
|
|
45028
|
+
method: "setStrokeColor",
|
|
45029
|
+
item: [this.id],
|
|
45030
|
+
color: color2
|
|
45031
|
+
});
|
|
45032
|
+
return this;
|
|
45033
|
+
}
|
|
45034
|
+
getStrokeColor() {
|
|
45035
|
+
return this.borderColor;
|
|
45036
|
+
}
|
|
45037
|
+
setStrokeWidth(width2) {
|
|
45038
|
+
this.emit({
|
|
45039
|
+
class: "Drawing",
|
|
45040
|
+
method: "setStrokeWidth",
|
|
45041
|
+
item: [this.id],
|
|
45042
|
+
width: width2,
|
|
45043
|
+
prevWidth: this.strokeWidth
|
|
45044
|
+
});
|
|
45045
|
+
return this;
|
|
45085
45046
|
}
|
|
45086
45047
|
getLinkTo() {
|
|
45087
45048
|
return this.linkTo.link;
|
|
45088
45049
|
}
|
|
45089
|
-
|
|
45090
|
-
|
|
45091
|
-
linkElem.href = this.storageLink;
|
|
45092
|
-
linkElem.setAttribute("download", "");
|
|
45093
|
-
linkElem.click();
|
|
45050
|
+
getStrokeWidth() {
|
|
45051
|
+
return this.strokeWidth;
|
|
45094
45052
|
}
|
|
45095
|
-
|
|
45096
|
-
|
|
45097
|
-
|
|
45098
|
-
|
|
45053
|
+
getRichText() {
|
|
45054
|
+
return null;
|
|
45055
|
+
}
|
|
45056
|
+
isPointNearLine(point5, threshold = 10) {
|
|
45057
|
+
const transformedMouseX = (point5.x - this.transformation.matrix.translateX) / this.transformation.matrix.scaleX;
|
|
45058
|
+
const transformedMouseY = (point5.y - this.transformation.matrix.translateY) / this.transformation.matrix.scaleY;
|
|
45059
|
+
const transformedMouse = new Point(transformedMouseX, transformedMouseY);
|
|
45060
|
+
for (let i = 0;i < this.points.length - 1; i++) {
|
|
45061
|
+
const p1 = this.points[i];
|
|
45062
|
+
const p22 = this.points[i + 1];
|
|
45063
|
+
const distance = getPerpendicularDistance(transformedMouse, p1, p22);
|
|
45064
|
+
if (distance < threshold) {
|
|
45065
|
+
return true;
|
|
45066
|
+
}
|
|
45099
45067
|
}
|
|
45100
|
-
|
|
45068
|
+
return false;
|
|
45069
|
+
}
|
|
45070
|
+
}
|
|
45071
|
+
function getPerpendicularDistance(point5, lineStart, lineEnd) {
|
|
45072
|
+
const { x: px, y: py } = point5;
|
|
45073
|
+
const { x: sx, y: sy } = lineStart;
|
|
45074
|
+
const { x: ex, y: ey } = lineEnd;
|
|
45075
|
+
const numerator = Math.abs((ey - sy) * px - (ex - sx) * py + ex * sy - ey * sx);
|
|
45076
|
+
const denominator = Math.sqrt(Math.pow(ey - sy, 2) + Math.pow(ex - sx, 2));
|
|
45077
|
+
return numerator / denominator;
|
|
45078
|
+
}
|
|
45079
|
+
function douglasPeucker(points, epsilon2) {
|
|
45080
|
+
if (points.length < 3) {
|
|
45081
|
+
return points;
|
|
45082
|
+
}
|
|
45083
|
+
const start = points[0];
|
|
45084
|
+
const end = points[points.length - 1];
|
|
45085
|
+
let maxDistance = 0;
|
|
45086
|
+
let maxIndex = 0;
|
|
45087
|
+
for (let i = 1;i < points.length - 1; i++) {
|
|
45088
|
+
const distance = getPerpendicularDistance(points[i], start, end);
|
|
45089
|
+
if (distance > maxDistance) {
|
|
45090
|
+
maxDistance = distance;
|
|
45091
|
+
maxIndex = i;
|
|
45092
|
+
}
|
|
45093
|
+
}
|
|
45094
|
+
if (maxDistance > epsilon2) {
|
|
45095
|
+
const leftSubPoints = points.slice(0, maxIndex + 1);
|
|
45096
|
+
const rightSubPoints = points.slice(maxIndex);
|
|
45097
|
+
const leftRecursiveResult = douglasPeucker(leftSubPoints, epsilon2);
|
|
45098
|
+
const rightRecursiveResult = douglasPeucker(rightSubPoints, epsilon2);
|
|
45099
|
+
return leftRecursiveResult.slice(0, -1).concat(rightRecursiveResult);
|
|
45100
|
+
} else {
|
|
45101
|
+
return [start, end];
|
|
45101
45102
|
}
|
|
45102
45103
|
}
|
|
45103
45104
|
// src/Items/Group/Group.ts
|