microboard-temp 0.4.41 → 0.4.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/browser.js +609 -609
- package/dist/cjs/index.js +609 -609
- package/dist/cjs/node.js +609 -609
- package/dist/esm/browser.js +609 -609
- package/dist/esm/index.js +609 -609
- package/dist/esm/node.js +609 -609
- package/package.json +1 -1
package/dist/cjs/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";
|
|
@@ -44822,202 +44395,455 @@ class Placeholder extends BaseItem {
|
|
|
44822
44395
|
renderHTML(documentFactory) {
|
|
44823
44396
|
return documentFactory.createElement("div");
|
|
44824
44397
|
}
|
|
44825
|
-
getLinkTo() {
|
|
44826
|
-
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;
|
|
44827
44656
|
}
|
|
44828
44657
|
getRichText() {
|
|
44829
44658
|
return null;
|
|
44830
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
|
+
}
|
|
44831
44676
|
}
|
|
44832
|
-
// src/
|
|
44833
|
-
function
|
|
44834
|
-
|
|
44835
|
-
|
|
44836
|
-
const context = new DrawingContext(board.camera, placeholderContext);
|
|
44837
|
-
const placeholder = new Placeholder(board);
|
|
44838
|
-
if (imageDimension) {
|
|
44839
|
-
placeholderCanvas.width = imageDimension.width;
|
|
44840
|
-
placeholderCanvas.height = imageDimension.height;
|
|
44841
|
-
placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
|
|
44842
|
-
} else {
|
|
44843
|
-
placeholderCanvas.width = 250;
|
|
44844
|
-
placeholderCanvas.height = 50;
|
|
44845
|
-
placeholder.transformation.scaleTo(250 / 100, 50 / 100);
|
|
44677
|
+
// src/isSafari.ts
|
|
44678
|
+
function isSafari() {
|
|
44679
|
+
if (typeof navigator === "undefined") {
|
|
44680
|
+
return false;
|
|
44846
44681
|
}
|
|
44847
|
-
const
|
|
44848
|
-
|
|
44849
|
-
|
|
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;
|
|
44850
44686
|
}
|
|
44851
44687
|
|
|
44852
|
-
|
|
44688
|
+
// src/Items/Drawing/Drawing.ts
|
|
44689
|
+
class Drawing extends BaseItem {
|
|
44690
|
+
points;
|
|
44853
44691
|
events;
|
|
44854
|
-
itemType = "
|
|
44692
|
+
itemType = "Drawing";
|
|
44855
44693
|
parent = "Board";
|
|
44856
|
-
image;
|
|
44857
44694
|
transformation;
|
|
44858
|
-
|
|
44695
|
+
path2d = new conf.path2DFactory;
|
|
44859
44696
|
subject = new Subject;
|
|
44860
|
-
|
|
44861
|
-
|
|
44697
|
+
untransformedMbr = new Mbr;
|
|
44698
|
+
lines = [];
|
|
44699
|
+
linkTo;
|
|
44700
|
+
strokeWidth = 1;
|
|
44701
|
+
borderStyle = "solid";
|
|
44702
|
+
linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
44703
|
+
borderOpacity = 1;
|
|
44862
44704
|
transformationRenderBlock = undefined;
|
|
44863
|
-
|
|
44864
|
-
imageDimension;
|
|
44865
|
-
board;
|
|
44866
|
-
constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
|
|
44705
|
+
constructor(board, points, events, id = "") {
|
|
44867
44706
|
super(board, id);
|
|
44707
|
+
this.points = points;
|
|
44868
44708
|
this.events = events;
|
|
44869
|
-
this.linkTo = new LinkTo(this.id, events);
|
|
44870
|
-
this.board = board;
|
|
44871
|
-
this.setStorageLink(storageLink);
|
|
44872
|
-
this.imageDimension = imageDimension;
|
|
44873
44709
|
this.transformation = new Transformation(id, events);
|
|
44874
|
-
this.
|
|
44875
|
-
this.
|
|
44876
|
-
|
|
44877
|
-
|
|
44878
|
-
|
|
44879
|
-
|
|
44880
|
-
}
|
|
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
|
+
});
|
|
44881
44716
|
this.linkTo.subject.subscribe(() => {
|
|
44882
44717
|
this.updateMbr();
|
|
44718
|
+
this.updateLines();
|
|
44883
44719
|
this.subject.publish(this);
|
|
44884
44720
|
});
|
|
44885
|
-
this.
|
|
44886
|
-
}
|
|
44887
|
-
setStorageLink(link2) {
|
|
44888
|
-
try {
|
|
44889
|
-
const url = new URL(link2);
|
|
44890
|
-
this.storageLink = `${window?.location.origin}${url.pathname}`;
|
|
44891
|
-
} catch (_) {}
|
|
44892
|
-
}
|
|
44893
|
-
getStorageId() {
|
|
44894
|
-
return this.storageLink.split("/").pop();
|
|
44895
|
-
}
|
|
44896
|
-
handleError = () => {
|
|
44897
|
-
console.error("Invalid dataUrl or image failed to load.");
|
|
44898
|
-
this.image = getPlaceholderImage(this.board);
|
|
44899
|
-
this.updateMbr();
|
|
44900
|
-
this.subject.publish(this);
|
|
44901
|
-
this.shootLoadCallbacks();
|
|
44902
|
-
};
|
|
44903
|
-
onLoad = async () => {
|
|
44904
|
-
this.shootBeforeLoadCallbacks();
|
|
44905
|
-
this.updateMbr();
|
|
44906
|
-
this.subject.publish(this);
|
|
44907
|
-
this.shootLoadCallbacks();
|
|
44908
|
-
};
|
|
44909
|
-
onError = (_error) => {
|
|
44910
|
-
this.image = getPlaceholderImage(this.board);
|
|
44911
|
-
this.updateMbr();
|
|
44912
|
-
this.subject.publish(this);
|
|
44913
|
-
this.shootLoadCallbacks();
|
|
44914
|
-
};
|
|
44915
|
-
onTransform = () => {
|
|
44916
|
-
this.updateMbr();
|
|
44917
|
-
this.subject.publish(this);
|
|
44918
|
-
};
|
|
44919
|
-
updateMbr() {
|
|
44920
|
-
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
44921
|
-
this.left = translateX;
|
|
44922
|
-
this.top = translateY;
|
|
44923
|
-
this.right = this.left + this.image.width * scaleX;
|
|
44924
|
-
this.bottom = this.top + this.image.height * scaleY;
|
|
44925
|
-
}
|
|
44926
|
-
doOnceBeforeOnLoad = (callback) => {
|
|
44927
|
-
this.loadCallbacks.push(callback);
|
|
44928
|
-
};
|
|
44929
|
-
doOnceOnLoad = (callback) => {
|
|
44930
|
-
this.loadCallbacks.push(callback);
|
|
44931
|
-
};
|
|
44932
|
-
setId(id) {
|
|
44933
|
-
this.id = id;
|
|
44934
|
-
this.transformation.setId(id);
|
|
44935
|
-
this.linkTo.setId(id);
|
|
44936
|
-
return this;
|
|
44937
|
-
}
|
|
44938
|
-
getId() {
|
|
44939
|
-
return this.id;
|
|
44721
|
+
this.updateLines();
|
|
44940
44722
|
}
|
|
44941
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
|
+
}
|
|
44942
44729
|
return {
|
|
44943
|
-
itemType: "
|
|
44944
|
-
|
|
44945
|
-
imageDimension: this.imageDimension,
|
|
44730
|
+
itemType: "Drawing",
|
|
44731
|
+
points,
|
|
44946
44732
|
transformation: this.transformation.serialize(),
|
|
44733
|
+
strokeStyle: this.borderColor,
|
|
44734
|
+
strokeWidth: this.strokeWidth,
|
|
44947
44735
|
linkTo: this.linkTo.serialize()
|
|
44948
44736
|
};
|
|
44949
44737
|
}
|
|
44950
|
-
|
|
44951
|
-
this.
|
|
44952
|
-
|
|
44953
|
-
|
|
44954
|
-
this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
|
|
44955
|
-
this.subject.publish(this);
|
|
44956
|
-
}
|
|
44957
|
-
shootBeforeLoadCallbacks() {
|
|
44958
|
-
while (this.beforeLoadCallbacks.length > 0) {
|
|
44959
|
-
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));
|
|
44960
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;
|
|
44961
44750
|
}
|
|
44962
|
-
|
|
44963
|
-
|
|
44964
|
-
|
|
44965
|
-
|
|
44751
|
+
updateGeometry() {
|
|
44752
|
+
this.updatePath2d();
|
|
44753
|
+
this.updateLines();
|
|
44754
|
+
this.updateMbr();
|
|
44966
44755
|
}
|
|
44967
|
-
|
|
44968
|
-
|
|
44969
|
-
|
|
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);
|
|
44970
44787
|
}
|
|
44971
|
-
|
|
44972
|
-
|
|
44973
|
-
|
|
44974
|
-
|
|
44975
|
-
}
|
|
44976
|
-
|
|
44977
|
-
|
|
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
|
+
}
|
|
44978
44805
|
}
|
|
44979
|
-
|
|
44980
|
-
|
|
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);
|
|
44981
44820
|
}
|
|
44982
|
-
this.image = getPlaceholderImage(this.board, data.imageDimension);
|
|
44983
|
-
const storageImage = new Image;
|
|
44984
|
-
storageImage.onload = () => {
|
|
44985
|
-
this.image = storageImage;
|
|
44986
|
-
this.onLoad();
|
|
44987
|
-
};
|
|
44988
|
-
storageImage.onerror = this.onError;
|
|
44989
|
-
storageImage.src = this.storageLink;
|
|
44990
|
-
return this;
|
|
44991
44821
|
}
|
|
44992
|
-
|
|
44993
|
-
|
|
44994
|
-
|
|
44995
|
-
|
|
44996
|
-
|
|
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
|
+
}
|
|
44997
44834
|
} else {
|
|
44998
|
-
this.
|
|
44835
|
+
this.points.push(point5);
|
|
44999
44836
|
}
|
|
44837
|
+
this.updateGeometry();
|
|
45000
44838
|
}
|
|
45001
|
-
|
|
45002
|
-
this.
|
|
44839
|
+
setId(id) {
|
|
44840
|
+
this.id = id;
|
|
44841
|
+
this.transformation.setId(id);
|
|
44842
|
+
this.linkTo.setId(id);
|
|
44843
|
+
return this;
|
|
45003
44844
|
}
|
|
45004
|
-
|
|
45005
|
-
|
|
45006
|
-
case "Transformation":
|
|
45007
|
-
this.transformation.apply(op);
|
|
45008
|
-
break;
|
|
45009
|
-
case "LinkTo":
|
|
45010
|
-
this.linkTo.apply(op);
|
|
45011
|
-
break;
|
|
45012
|
-
case "Image":
|
|
45013
|
-
if (op.data.base64) {
|
|
45014
|
-
this.image.src = op.data.base64;
|
|
45015
|
-
}
|
|
45016
|
-
this.setStorageLink(op.data.storageLink);
|
|
45017
|
-
this.setDimensions(op.data.imageDimension);
|
|
45018
|
-
this.subject.publish(this);
|
|
45019
|
-
break;
|
|
45020
|
-
}
|
|
44845
|
+
getId() {
|
|
44846
|
+
return this.id;
|
|
45021
44847
|
}
|
|
45022
44848
|
render(context) {
|
|
45023
44849
|
if (this.transformationRenderBlock) {
|
|
@@ -45025,8 +44851,12 @@ class ImageItem extends BaseItem {
|
|
|
45025
44851
|
}
|
|
45026
44852
|
const ctx = context.ctx;
|
|
45027
44853
|
ctx.save();
|
|
44854
|
+
ctx.strokeStyle = this.borderColor;
|
|
44855
|
+
ctx.lineWidth = this.strokeWidth;
|
|
44856
|
+
ctx.lineCap = "round";
|
|
44857
|
+
ctx.setLineDash(this.linePattern);
|
|
45028
44858
|
this.transformation.matrix.applyToContext(ctx);
|
|
45029
|
-
ctx.
|
|
44859
|
+
ctx.stroke(this.path2d.nativePath);
|
|
45030
44860
|
ctx.restore();
|
|
45031
44861
|
if (this.getLinkTo()) {
|
|
45032
44862
|
const { top, right } = this.getMbr();
|
|
@@ -45034,26 +44864,61 @@ class ImageItem extends BaseItem {
|
|
|
45034
44864
|
}
|
|
45035
44865
|
}
|
|
45036
44866
|
renderHTML(documentFactory) {
|
|
45037
|
-
const div = documentFactory.createElement("
|
|
44867
|
+
const div = documentFactory.createElement("drawing-item");
|
|
45038
44868
|
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
45039
|
-
const
|
|
45040
|
-
|
|
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);
|
|
45041
44886
|
div.id = this.getId();
|
|
45042
|
-
div.style.width =
|
|
45043
|
-
div.style.height =
|
|
45044
|
-
div.style.transformOrigin = "top
|
|
45045
|
-
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})`;
|
|
45046
44891
|
div.style.position = "absolute";
|
|
45047
|
-
div.style.backgroundSize = "cover";
|
|
45048
44892
|
div.setAttribute("data-link-to", this.linkTo.serialize() || "");
|
|
45049
44893
|
if (this.getLinkTo()) {
|
|
45050
44894
|
const linkElement = this.linkTo.renderHTML(documentFactory);
|
|
45051
44895
|
scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
|
|
45052
|
-
translateElementBy(linkElement, (
|
|
44896
|
+
translateElementBy(linkElement, (width2 - parseInt(linkElement.style.width)) / scaleX, 0);
|
|
45053
44897
|
div.appendChild(linkElement);
|
|
45054
44898
|
}
|
|
45055
44899
|
return div;
|
|
45056
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
|
+
}
|
|
45057
44922
|
getPath() {
|
|
45058
44923
|
const { left, top, right, bottom } = this.getMbr();
|
|
45059
44924
|
const leftTop = new Point(left, top);
|
|
@@ -45078,27 +44943,162 @@ class ImageItem extends BaseItem {
|
|
|
45078
44943
|
new Point(mbr.right, mbr.top + height2 / 2)
|
|
45079
44944
|
];
|
|
45080
44945
|
}
|
|
44946
|
+
getLines() {
|
|
44947
|
+
return this.lines;
|
|
44948
|
+
}
|
|
45081
44949
|
isClosed() {
|
|
45082
44950
|
return true;
|
|
45083
44951
|
}
|
|
45084
|
-
|
|
45085
|
-
|
|
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;
|
|
45086
45046
|
}
|
|
45087
45047
|
getLinkTo() {
|
|
45088
45048
|
return this.linkTo.link;
|
|
45089
45049
|
}
|
|
45090
|
-
|
|
45091
|
-
|
|
45092
|
-
linkElem.href = this.storageLink;
|
|
45093
|
-
linkElem.setAttribute("download", "");
|
|
45094
|
-
linkElem.click();
|
|
45050
|
+
getStrokeWidth() {
|
|
45051
|
+
return this.strokeWidth;
|
|
45095
45052
|
}
|
|
45096
|
-
|
|
45097
|
-
|
|
45098
|
-
|
|
45099
|
-
|
|
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
|
+
}
|
|
45100
45067
|
}
|
|
45101
|
-
|
|
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];
|
|
45102
45102
|
}
|
|
45103
45103
|
}
|
|
45104
45104
|
// src/Items/Group/Group.ts
|