microboard-temp 0.4.41 → 0.4.43

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/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;
@@ -23776,6 +23349,7 @@ class SpatialIndex {
23776
23349
  }
23777
23350
  });
23778
23351
  });
23352
+ console.log([...items, ...children]);
23779
23353
  return [...items, ...children];
23780
23354
  }
23781
23355
  getEnclosedOrCrossed(left, top, right, bottom) {
@@ -23790,6 +23364,7 @@ class SpatialIndex {
23790
23364
  }
23791
23365
  });
23792
23366
  });
23367
+ console.log([...items, ...children]);
23793
23368
  return [...items, ...children];
23794
23369
  }
23795
23370
  getUnderPoint(point3, tolerance = 5) {
@@ -23803,6 +23378,7 @@ class SpatialIndex {
23803
23378
  }
23804
23379
  });
23805
23380
  });
23381
+ console.log([...items, ...children]);
23806
23382
  return [...items, ...children];
23807
23383
  }
23808
23384
  getRectsEnclosedOrCrossed(left, top, right, bottom) {
@@ -23817,6 +23393,7 @@ class SpatialIndex {
23817
23393
  }
23818
23394
  });
23819
23395
  });
23396
+ console.log([...items, ...children]);
23820
23397
  return [...items, ...children];
23821
23398
  }
23822
23399
  getItemsEnclosedOrCrossed(left, top, right, bottom) {
@@ -23836,9 +23413,11 @@ class SpatialIndex {
23836
23413
  distance: point3.getDistance(item.getMbr().getCenter())
23837
23414
  })).filter(({ distance }) => distance <= maxDistance);
23838
23415
  withDistance.sort((a, b) => a.distance - b.distance);
23416
+ console.log(withDistance.slice(0, maxItems).map(({ item }) => item));
23839
23417
  return withDistance.slice(0, maxItems).map(({ item }) => item);
23840
23418
  }
23841
23419
  list() {
23420
+ console.log("list", this.getItemsWithIncludedChildren(this.itemsArray).concat());
23842
23421
  return this.getItemsWithIncludedChildren(this.itemsArray).concat();
23843
23422
  }
23844
23423
  getZIndex(item) {
@@ -23931,12 +23510,12 @@ class Items {
23931
23510
  if (enclosed.length === 0) {
23932
23511
  enclosed = underPointer;
23933
23512
  }
23934
- if (underPointer.some((item) => item instanceof Drawing)) {
23513
+ if (underPointer.some((item) => item.itemType === "Drawing")) {
23935
23514
  enclosed = [...underPointer, ...enclosed];
23936
23515
  }
23937
23516
  const { nearest } = enclosed.reduce((acc, item) => {
23938
23517
  const area = item.getMbr().getHeight() * item.getMbr().getWidth();
23939
- if (item instanceof Drawing && !item.isPointNearLine(this.pointer.point)) {
23518
+ if (item.itemType === "Drawing" && !item.isPointNearLine(this.pointer.point)) {
23940
23519
  return acc;
23941
23520
  }
23942
23521
  const isItemTransparent = item instanceof Shape && item?.getBackgroundColor() === "none";
@@ -24209,6 +23788,7 @@ class SimpleSpatialIndex {
24209
23788
  items.push(item);
24210
23789
  }
24211
23790
  });
23791
+ console.log("simple", items);
24212
23792
  return items;
24213
23793
  }
24214
23794
  getEnclosedOrCrossed(left, top, right, bottom) {
@@ -24219,6 +23799,7 @@ class SimpleSpatialIndex {
24219
23799
  items.push(item);
24220
23800
  }
24221
23801
  });
23802
+ console.log("simple", items);
24222
23803
  return items;
24223
23804
  }
24224
23805
  getUnderPoint(point3, tolerace = 5) {
@@ -24228,12 +23809,14 @@ class SimpleSpatialIndex {
24228
23809
  items.push(item);
24229
23810
  }
24230
23811
  });
23812
+ console.log("simple", items);
24231
23813
  return items;
24232
23814
  }
24233
23815
  getMbr() {
24234
23816
  return this.Mbr;
24235
23817
  }
24236
23818
  list() {
23819
+ console.log("simple list", this.itemsArray.concat());
24237
23820
  return this.itemsArray.concat();
24238
23821
  }
24239
23822
  getZIndex(item) {
@@ -44822,202 +44405,455 @@ class Placeholder extends BaseItem {
44822
44405
  renderHTML(documentFactory) {
44823
44406
  return documentFactory.createElement("div");
44824
44407
  }
44825
- getLinkTo() {
44826
- return;
44408
+ getLinkTo() {
44409
+ return;
44410
+ }
44411
+ getRichText() {
44412
+ return null;
44413
+ }
44414
+ }
44415
+ // src/Items/Image/Image.ts
44416
+ function getPlaceholderImage(board, imageDimension) {
44417
+ const placeholderCanvas = conf.documentFactory.createElement("canvas");
44418
+ const placeholderContext = placeholderCanvas.getContext("2d");
44419
+ const context = new DrawingContext(board.camera, placeholderContext);
44420
+ const placeholder = new Placeholder(board);
44421
+ if (imageDimension) {
44422
+ placeholderCanvas.width = imageDimension.width;
44423
+ placeholderCanvas.height = imageDimension.height;
44424
+ placeholder.transformation.scaleTo(imageDimension.width / 100, imageDimension.height / 100);
44425
+ } else {
44426
+ placeholderCanvas.width = 250;
44427
+ placeholderCanvas.height = 50;
44428
+ placeholder.transformation.scaleTo(250 / 100, 50 / 100);
44429
+ }
44430
+ const placeholderImage = new Image;
44431
+ placeholderImage.src = placeholderCanvas.toDataURL();
44432
+ return placeholderImage;
44433
+ }
44434
+
44435
+ class ImageItem extends BaseItem {
44436
+ events;
44437
+ itemType = "Image";
44438
+ parent = "Board";
44439
+ image;
44440
+ transformation;
44441
+ linkTo;
44442
+ subject = new Subject;
44443
+ loadCallbacks = [];
44444
+ beforeLoadCallbacks = [];
44445
+ transformationRenderBlock = undefined;
44446
+ storageLink;
44447
+ imageDimension;
44448
+ board;
44449
+ constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
44450
+ super(board, id);
44451
+ this.events = events;
44452
+ this.linkTo = new LinkTo(this.id, events);
44453
+ this.board = board;
44454
+ this.setStorageLink(storageLink);
44455
+ this.imageDimension = imageDimension;
44456
+ this.transformation = new Transformation(id, events);
44457
+ this.image = new Image;
44458
+ this.image.crossOrigin = "anonymous";
44459
+ this.image.onload = this.onLoad;
44460
+ this.image.onerror = this.onError;
44461
+ if (typeof base64 === "string") {
44462
+ this.image.src = base64;
44463
+ }
44464
+ this.linkTo.subject.subscribe(() => {
44465
+ this.updateMbr();
44466
+ this.subject.publish(this);
44467
+ });
44468
+ this.transformation.subject.subscribe(this.onTransform);
44469
+ }
44470
+ setStorageLink(link2) {
44471
+ try {
44472
+ const url = new URL(link2);
44473
+ this.storageLink = `${window?.location.origin}${url.pathname}`;
44474
+ } catch (_) {}
44475
+ }
44476
+ getStorageId() {
44477
+ return this.storageLink.split("/").pop();
44478
+ }
44479
+ handleError = () => {
44480
+ console.error("Invalid dataUrl or image failed to load.");
44481
+ this.image = getPlaceholderImage(this.board);
44482
+ this.updateMbr();
44483
+ this.subject.publish(this);
44484
+ this.shootLoadCallbacks();
44485
+ };
44486
+ onLoad = async () => {
44487
+ this.shootBeforeLoadCallbacks();
44488
+ this.updateMbr();
44489
+ this.subject.publish(this);
44490
+ this.shootLoadCallbacks();
44491
+ };
44492
+ onError = (_error) => {
44493
+ this.image = getPlaceholderImage(this.board);
44494
+ this.updateMbr();
44495
+ this.subject.publish(this);
44496
+ this.shootLoadCallbacks();
44497
+ };
44498
+ onTransform = () => {
44499
+ this.updateMbr();
44500
+ this.subject.publish(this);
44501
+ };
44502
+ updateMbr() {
44503
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
44504
+ this.left = translateX;
44505
+ this.top = translateY;
44506
+ this.right = this.left + this.image.width * scaleX;
44507
+ this.bottom = this.top + this.image.height * scaleY;
44508
+ }
44509
+ doOnceBeforeOnLoad = (callback) => {
44510
+ this.loadCallbacks.push(callback);
44511
+ };
44512
+ doOnceOnLoad = (callback) => {
44513
+ this.loadCallbacks.push(callback);
44514
+ };
44515
+ setId(id) {
44516
+ this.id = id;
44517
+ this.transformation.setId(id);
44518
+ this.linkTo.setId(id);
44519
+ return this;
44520
+ }
44521
+ getId() {
44522
+ return this.id;
44523
+ }
44524
+ serialize() {
44525
+ return {
44526
+ itemType: "Image",
44527
+ storageLink: this.storageLink,
44528
+ imageDimension: this.imageDimension,
44529
+ transformation: this.transformation.serialize(),
44530
+ linkTo: this.linkTo.serialize()
44531
+ };
44532
+ }
44533
+ setCoordinates() {
44534
+ this.left = this.transformation.matrix.translateX;
44535
+ this.top = this.transformation.matrix.translateY;
44536
+ this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
44537
+ this.bottom = this.top + this.image.height * this.transformation.matrix.scaleY;
44538
+ this.subject.publish(this);
44539
+ }
44540
+ shootBeforeLoadCallbacks() {
44541
+ while (this.beforeLoadCallbacks.length > 0) {
44542
+ this.beforeLoadCallbacks.shift()(this);
44543
+ }
44544
+ }
44545
+ shootLoadCallbacks() {
44546
+ while (this.loadCallbacks.length > 0) {
44547
+ this.loadCallbacks.shift()(this);
44548
+ }
44549
+ }
44550
+ deserialize(data) {
44551
+ if (data.transformation) {
44552
+ this.transformation.deserialize(data.transformation);
44553
+ }
44554
+ this.linkTo.deserialize(data.linkTo);
44555
+ this.image.onload = () => {
44556
+ this.setCoordinates();
44557
+ this.shootLoadCallbacks();
44558
+ };
44559
+ if (data.storageLink) {
44560
+ this.setStorageLink(data.storageLink);
44561
+ }
44562
+ if (this.image.src) {
44563
+ return this;
44564
+ }
44565
+ this.image = getPlaceholderImage(this.board, data.imageDimension);
44566
+ const storageImage = new Image;
44567
+ storageImage.onload = () => {
44568
+ this.image = storageImage;
44569
+ this.onLoad();
44570
+ };
44571
+ storageImage.onerror = this.onError;
44572
+ storageImage.src = this.storageLink;
44573
+ return this;
44574
+ }
44575
+ emit(operation) {
44576
+ if (this.events) {
44577
+ const command = new ImageCommand([this], operation);
44578
+ command.apply();
44579
+ this.events.emit(operation, command);
44580
+ } else {
44581
+ this.apply(operation);
44582
+ }
44583
+ }
44584
+ setDimensions(dim) {
44585
+ this.imageDimension = dim;
44586
+ }
44587
+ apply(op) {
44588
+ switch (op.class) {
44589
+ case "Transformation":
44590
+ this.transformation.apply(op);
44591
+ break;
44592
+ case "LinkTo":
44593
+ this.linkTo.apply(op);
44594
+ break;
44595
+ case "Image":
44596
+ if (op.data.base64) {
44597
+ this.image.src = op.data.base64;
44598
+ }
44599
+ this.setStorageLink(op.data.storageLink);
44600
+ this.setDimensions(op.data.imageDimension);
44601
+ this.subject.publish(this);
44602
+ break;
44603
+ }
44604
+ }
44605
+ render(context) {
44606
+ if (this.transformationRenderBlock) {
44607
+ return;
44608
+ }
44609
+ const ctx = context.ctx;
44610
+ ctx.save();
44611
+ this.transformation.matrix.applyToContext(ctx);
44612
+ ctx.drawImage(this.image, 0, 0);
44613
+ ctx.restore();
44614
+ if (this.getLinkTo()) {
44615
+ const { top, right } = this.getMbr();
44616
+ this.linkTo.render(context, top, right, this.board.camera.getScale());
44617
+ }
44618
+ }
44619
+ renderHTML(documentFactory) {
44620
+ const div = documentFactory.createElement("image-item");
44621
+ const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
44622
+ const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
44623
+ div.style.backgroundImage = `url(${this.storageLink})`;
44624
+ div.id = this.getId();
44625
+ div.style.width = `${this.imageDimension.width}px`;
44626
+ div.style.height = `${this.imageDimension.height}px`;
44627
+ div.style.transformOrigin = "top left";
44628
+ div.style.transform = transform;
44629
+ div.style.position = "absolute";
44630
+ div.style.backgroundSize = "cover";
44631
+ div.setAttribute("data-link-to", this.linkTo.serialize() || "");
44632
+ if (this.getLinkTo()) {
44633
+ const linkElement = this.linkTo.renderHTML(documentFactory);
44634
+ scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
44635
+ translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
44636
+ div.appendChild(linkElement);
44637
+ }
44638
+ return div;
44639
+ }
44640
+ getPath() {
44641
+ const { left, top, right, bottom } = this.getMbr();
44642
+ const leftTop = new Point(left, top);
44643
+ const rightTop = new Point(right, top);
44644
+ const rightBottom = new Point(right, bottom);
44645
+ const leftBottom = new Point(left, bottom);
44646
+ return new Path([
44647
+ new Line(leftTop, rightTop),
44648
+ new Line(rightTop, rightBottom),
44649
+ new Line(rightBottom, leftBottom),
44650
+ new Line(leftBottom, leftTop)
44651
+ ], true);
44652
+ }
44653
+ getSnapAnchorPoints() {
44654
+ const mbr = this.getMbr();
44655
+ const width2 = mbr.getWidth();
44656
+ const height2 = mbr.getHeight();
44657
+ return [
44658
+ new Point(mbr.left + width2 / 2, mbr.top),
44659
+ new Point(mbr.left + width2 / 2, mbr.bottom),
44660
+ new Point(mbr.left, mbr.top + height2 / 2),
44661
+ new Point(mbr.right, mbr.top + height2 / 2)
44662
+ ];
44663
+ }
44664
+ isClosed() {
44665
+ return true;
44827
44666
  }
44828
44667
  getRichText() {
44829
44668
  return null;
44830
44669
  }
44670
+ getLinkTo() {
44671
+ return this.linkTo.link;
44672
+ }
44673
+ download() {
44674
+ const linkElem = document.createElement("a");
44675
+ linkElem.href = this.storageLink;
44676
+ linkElem.setAttribute("download", "");
44677
+ linkElem.click();
44678
+ }
44679
+ onRemove() {
44680
+ const storageId = this.getStorageId();
44681
+ if (storageId) {
44682
+ conf.hooks.beforeMediaRemove([storageId], this.board.getBoardId());
44683
+ }
44684
+ super.onRemove();
44685
+ }
44831
44686
  }
44832
- // src/Items/Image/Image.ts
44833
- function getPlaceholderImage(board, imageDimension) {
44834
- const placeholderCanvas = conf.documentFactory.createElement("canvas");
44835
- const placeholderContext = placeholderCanvas.getContext("2d");
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);
44687
+ // src/isSafari.ts
44688
+ function isSafari() {
44689
+ if (typeof navigator === "undefined") {
44690
+ return false;
44846
44691
  }
44847
- const placeholderImage = new Image;
44848
- placeholderImage.src = placeholderCanvas.toDataURL();
44849
- return placeholderImage;
44692
+ const agent = navigator.userAgent;
44693
+ const vendor = navigator.vendor;
44694
+ const is2 = vendor !== undefined && vendor.includes("Apple") && agent !== undefined && !agent.includes("CriOS") && !agent.includes("FxiOS");
44695
+ return is2;
44850
44696
  }
44851
44697
 
44852
- class ImageItem extends BaseItem {
44698
+ // src/Items/Drawing/Drawing.ts
44699
+ class Drawing extends BaseItem {
44700
+ points;
44853
44701
  events;
44854
- itemType = "Image";
44702
+ itemType = "Drawing";
44855
44703
  parent = "Board";
44856
- image;
44857
44704
  transformation;
44858
- linkTo;
44705
+ path2d = new conf.path2DFactory;
44859
44706
  subject = new Subject;
44860
- loadCallbacks = [];
44861
- beforeLoadCallbacks = [];
44707
+ untransformedMbr = new Mbr;
44708
+ lines = [];
44709
+ linkTo;
44710
+ strokeWidth = 1;
44711
+ borderStyle = "solid";
44712
+ linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
44713
+ borderOpacity = 1;
44862
44714
  transformationRenderBlock = undefined;
44863
- storageLink;
44864
- imageDimension;
44865
- board;
44866
- constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
44715
+ constructor(board, points, events, id = "") {
44867
44716
  super(board, id);
44717
+ this.points = points;
44868
44718
  this.events = events;
44869
- this.linkTo = new LinkTo(this.id, events);
44870
- this.board = board;
44871
- this.setStorageLink(storageLink);
44872
- this.imageDimension = imageDimension;
44873
44719
  this.transformation = new Transformation(id, events);
44874
- this.image = new Image;
44875
- this.image.crossOrigin = "anonymous";
44876
- this.image.onload = this.onLoad;
44877
- this.image.onerror = this.onError;
44878
- if (typeof base64 === "string") {
44879
- this.image.src = base64;
44880
- }
44720
+ this.linkTo = new LinkTo(this.id, this.events);
44721
+ this.transformation.subject.subscribe(() => {
44722
+ this.updateMbr();
44723
+ this.updateLines();
44724
+ this.subject.publish(this);
44725
+ });
44881
44726
  this.linkTo.subject.subscribe(() => {
44882
44727
  this.updateMbr();
44728
+ this.updateLines();
44883
44729
  this.subject.publish(this);
44884
44730
  });
44885
- this.transformation.subject.subscribe(this.onTransform);
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;
44731
+ this.updateLines();
44940
44732
  }
44941
44733
  serialize() {
44734
+ this.optimizePoints();
44735
+ const points = [];
44736
+ for (const point5 of this.points) {
44737
+ points.push({ x: point5.x, y: point5.y });
44738
+ }
44942
44739
  return {
44943
- itemType: "Image",
44944
- storageLink: this.storageLink,
44945
- imageDimension: this.imageDimension,
44740
+ itemType: "Drawing",
44741
+ points,
44946
44742
  transformation: this.transformation.serialize(),
44743
+ strokeStyle: this.borderColor,
44744
+ strokeWidth: this.strokeWidth,
44947
44745
  linkTo: this.linkTo.serialize()
44948
44746
  };
44949
44747
  }
44950
- setCoordinates() {
44951
- this.left = this.transformation.matrix.translateX;
44952
- this.top = this.transformation.matrix.translateY;
44953
- this.right = this.left + this.image.width * this.transformation.matrix.scaleX;
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);
44748
+ deserialize(data) {
44749
+ this.points = [];
44750
+ for (const point5 of data.points) {
44751
+ this.points.push(new Point(point5.x, point5.y));
44960
44752
  }
44753
+ this.linkTo.deserialize(data.linkTo);
44754
+ this.optimizePoints();
44755
+ this.transformation.deserialize(data.transformation);
44756
+ this.borderColor = data.strokeStyle;
44757
+ this.strokeWidth = data.strokeWidth;
44758
+ this.updateGeometry();
44759
+ return this;
44961
44760
  }
44962
- shootLoadCallbacks() {
44963
- while (this.loadCallbacks.length > 0) {
44964
- this.loadCallbacks.shift()(this);
44965
- }
44761
+ updateGeometry() {
44762
+ this.updatePath2d();
44763
+ this.updateLines();
44764
+ this.updateMbr();
44966
44765
  }
44967
- deserialize(data) {
44968
- if (data.transformation) {
44969
- this.transformation.deserialize(data.transformation);
44766
+ updateMbr() {
44767
+ const offset = this.getStrokeWidth() / 2;
44768
+ const untransformedMbr = this.untransformedMbr.copy();
44769
+ untransformedMbr.left -= offset;
44770
+ untransformedMbr.top -= offset;
44771
+ untransformedMbr.right += offset;
44772
+ untransformedMbr.bottom += offset;
44773
+ const mbr = untransformedMbr.getTransformed(this.transformation.matrix);
44774
+ this.left = mbr.left;
44775
+ this.top = mbr.top;
44776
+ this.right = mbr.right;
44777
+ this.bottom = mbr.bottom;
44778
+ }
44779
+ updatePath2d() {
44780
+ this.path2d = new conf.path2DFactory;
44781
+ const context = this.path2d;
44782
+ const points = this.points;
44783
+ if (points.length < 3) {
44784
+ context.arc(points[0].x, points[0].y, 0.5, 0, Math.PI * 2, true);
44785
+ context.closePath();
44786
+ } else {
44787
+ context.moveTo(points[0].x, points[0].y);
44788
+ let j = 1;
44789
+ for (;j < points.length - 2; j++) {
44790
+ const cx = (points[j].x + points[j + 1].x) / 2;
44791
+ const cy = (points[j].y + points[j + 1].y) / 2;
44792
+ context.quadraticCurveTo(points[j].x, points[j].y, cx, cy);
44793
+ }
44794
+ const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
44795
+ const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
44796
+ context.quadraticCurveTo(points[j].x, points[j].y, x, y);
44970
44797
  }
44971
- this.linkTo.deserialize(data.linkTo);
44972
- this.image.onload = () => {
44973
- this.setCoordinates();
44974
- this.shootLoadCallbacks();
44975
- };
44976
- if (data.storageLink) {
44977
- this.setStorageLink(data.storageLink);
44798
+ let left = Number.MAX_SAFE_INTEGER;
44799
+ let right = Number.MIN_SAFE_INTEGER;
44800
+ let top = Number.MAX_SAFE_INTEGER;
44801
+ let bottom = Number.MIN_SAFE_INTEGER;
44802
+ for (const { x, y } of this.points) {
44803
+ if (x < left) {
44804
+ left = x;
44805
+ }
44806
+ if (x > right) {
44807
+ right = x;
44808
+ }
44809
+ if (y < top) {
44810
+ top = y;
44811
+ }
44812
+ if (y > bottom) {
44813
+ bottom = y;
44814
+ }
44978
44815
  }
44979
- if (this.image.src) {
44980
- return this;
44816
+ this.untransformedMbr = new Mbr(left, top, right, bottom);
44817
+ }
44818
+ updateLines() {
44819
+ this.lines = [];
44820
+ const matrix = this.transformation.matrix;
44821
+ if (this.points.length < 2) {
44822
+ return;
44823
+ }
44824
+ for (let i = 0;i < this.points.length - 2; i++) {
44825
+ const p1 = this.points[i];
44826
+ const p22 = this.points[i + 1];
44827
+ const line = new Line(p1.copy(), p22.copy());
44828
+ line.transform(matrix);
44829
+ this.lines.push(line);
44981
44830
  }
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
44831
  }
44992
- emit(operation) {
44993
- if (this.events) {
44994
- const command = new ImageCommand([this], operation);
44995
- command.apply();
44996
- this.events.emit(operation, command);
44832
+ optimizePoints() {
44833
+ const dp = douglasPeucker(this.points, 1);
44834
+ dp.push(this.points[this.points.length - 1]);
44835
+ this.points = dp;
44836
+ }
44837
+ addPoint(point5) {
44838
+ const previous2 = this.points[this.points.length - 1];
44839
+ if (previous2) {
44840
+ const distance = point5.getDistance(previous2);
44841
+ if (distance >= 2) {
44842
+ this.points.push(point5);
44843
+ }
44997
44844
  } else {
44998
- this.apply(operation);
44845
+ this.points.push(point5);
44999
44846
  }
44847
+ this.updateGeometry();
45000
44848
  }
45001
- setDimensions(dim) {
45002
- this.imageDimension = dim;
44849
+ setId(id) {
44850
+ this.id = id;
44851
+ this.transformation.setId(id);
44852
+ this.linkTo.setId(id);
44853
+ return this;
45003
44854
  }
45004
- apply(op) {
45005
- switch (op.class) {
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
- }
44855
+ getId() {
44856
+ return this.id;
45021
44857
  }
45022
44858
  render(context) {
45023
44859
  if (this.transformationRenderBlock) {
@@ -45025,8 +44861,12 @@ class ImageItem extends BaseItem {
45025
44861
  }
45026
44862
  const ctx = context.ctx;
45027
44863
  ctx.save();
44864
+ ctx.strokeStyle = this.borderColor;
44865
+ ctx.lineWidth = this.strokeWidth;
44866
+ ctx.lineCap = "round";
44867
+ ctx.setLineDash(this.linePattern);
45028
44868
  this.transformation.matrix.applyToContext(ctx);
45029
- ctx.drawImage(this.image, 0, 0);
44869
+ ctx.stroke(this.path2d.nativePath);
45030
44870
  ctx.restore();
45031
44871
  if (this.getLinkTo()) {
45032
44872
  const { top, right } = this.getMbr();
@@ -45034,26 +44874,61 @@ class ImageItem extends BaseItem {
45034
44874
  }
45035
44875
  }
45036
44876
  renderHTML(documentFactory) {
45037
- const div = documentFactory.createElement("image-item");
44877
+ const div = documentFactory.createElement("drawing-item");
45038
44878
  const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
45039
- const transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
45040
- div.style.backgroundImage = `url(${this.storageLink})`;
44879
+ const mbr = this.getMbr();
44880
+ const width2 = mbr.getWidth();
44881
+ const height2 = mbr.getHeight();
44882
+ const unscaledWidth = width2 / scaleX;
44883
+ const unscaledHeight = height2 / scaleY;
44884
+ const svg3 = documentFactory.createElementNS("http://www.w3.org/2000/svg", "svg");
44885
+ svg3.setAttribute("width", `${unscaledWidth}px`);
44886
+ svg3.setAttribute("height", `${unscaledHeight}px`);
44887
+ svg3.setAttribute("viewBox", `0 0 ${unscaledWidth} ${unscaledHeight}`);
44888
+ svg3.setAttribute("style", "position: absolute; overflow: visible;");
44889
+ const pathElement = documentFactory.createElementNS("http://www.w3.org/2000/svg", "path");
44890
+ pathElement.setAttribute("d", this.getPathData());
44891
+ pathElement.setAttribute("stroke", this.borderColor);
44892
+ pathElement.setAttribute("stroke-width", `${this.strokeWidth}`);
44893
+ pathElement.setAttribute("fill", "none");
44894
+ svg3.appendChild(pathElement);
44895
+ div.appendChild(svg3);
45041
44896
  div.id = this.getId();
45042
- div.style.width = `${this.imageDimension.width}px`;
45043
- div.style.height = `${this.imageDimension.height}px`;
45044
- div.style.transformOrigin = "top left";
45045
- div.style.transform = transform;
44897
+ div.style.width = unscaledWidth + "px";
44898
+ div.style.height = unscaledHeight + "px";
44899
+ div.style.transformOrigin = "left top";
44900
+ div.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`;
45046
44901
  div.style.position = "absolute";
45047
- div.style.backgroundSize = "cover";
45048
44902
  div.setAttribute("data-link-to", this.linkTo.serialize() || "");
45049
44903
  if (this.getLinkTo()) {
45050
44904
  const linkElement = this.linkTo.renderHTML(documentFactory);
45051
44905
  scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
45052
- translateElementBy(linkElement, (this.getMbr().getWidth() - parseInt(linkElement.style.width)) / scaleX, 0);
44906
+ translateElementBy(linkElement, (width2 - parseInt(linkElement.style.width)) / scaleX, 0);
45053
44907
  div.appendChild(linkElement);
45054
44908
  }
45055
44909
  return div;
45056
44910
  }
44911
+ getPathData() {
44912
+ const points = this.points;
44913
+ if (points.length < 2) {
44914
+ return "";
44915
+ }
44916
+ let pathData = `M ${points[0].x} ${points[0].y}`;
44917
+ if (points.length < 3) {
44918
+ pathData += ` L ${points[0].x + 0.5} ${points[0].y}`;
44919
+ } else {
44920
+ let j = 1;
44921
+ for (;j < points.length - 2; j++) {
44922
+ const cx = (points[j].x + points[j + 1].x) / 2;
44923
+ const cy = (points[j].y + points[j + 1].y) / 2;
44924
+ pathData += ` Q ${points[j].x} ${points[j].y} ${cx} ${cy}`;
44925
+ }
44926
+ const x = points[j].x === points[j + 1].x && isSafari() ? points[j + 1].x + 0.01 : points[j + 1].x;
44927
+ const y = points[j].y === points[j + 1].y && isSafari() ? points[j + 1].y + 0.01 : points[j + 1].y;
44928
+ pathData += ` Q ${points[j].x} ${points[j].y} ${x} ${y}`;
44929
+ }
44930
+ return pathData;
44931
+ }
45057
44932
  getPath() {
45058
44933
  const { left, top, right, bottom } = this.getMbr();
45059
44934
  const leftTop = new Point(left, top);
@@ -45078,27 +44953,162 @@ class ImageItem extends BaseItem {
45078
44953
  new Point(mbr.right, mbr.top + height2 / 2)
45079
44954
  ];
45080
44955
  }
44956
+ getLines() {
44957
+ return this.lines;
44958
+ }
45081
44959
  isClosed() {
45082
44960
  return true;
45083
44961
  }
45084
- getRichText() {
45085
- return null;
44962
+ isEnclosedOrCrossedBy(rect) {
44963
+ for (const line of this.lines) {
44964
+ if (line.isEnclosedOrCrossedBy(rect)) {
44965
+ return true;
44966
+ }
44967
+ }
44968
+ return false;
44969
+ }
44970
+ emit(operation) {
44971
+ if (this.events) {
44972
+ const command = new DrawingCommand([this], operation);
44973
+ command.apply();
44974
+ this.events.emit(operation, command);
44975
+ } else {
44976
+ this.apply(operation);
44977
+ }
44978
+ }
44979
+ apply(op) {
44980
+ switch (op.class) {
44981
+ case "Drawing":
44982
+ switch (op.method) {
44983
+ case "setStrokeColor":
44984
+ this.borderColor = op.color;
44985
+ break;
44986
+ case "setStrokeWidth":
44987
+ this.strokeWidth = op.width;
44988
+ this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
44989
+ break;
44990
+ case "setStrokeOpacity":
44991
+ this.borderOpacity = op.opacity;
44992
+ break;
44993
+ case "setStrokeStyle":
44994
+ this.borderStyle = op.style;
44995
+ this.linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
44996
+ break;
44997
+ }
44998
+ this.updateMbr();
44999
+ break;
45000
+ case "Transformation":
45001
+ this.transformation.apply(op);
45002
+ break;
45003
+ case "LinkTo":
45004
+ this.linkTo.apply(op);
45005
+ break;
45006
+ default:
45007
+ return;
45008
+ }
45009
+ this.subject.publish(this);
45010
+ }
45011
+ setStrokeOpacity(opacity) {
45012
+ this.emit({
45013
+ class: "Drawing",
45014
+ method: "setStrokeOpacity",
45015
+ item: [this.id],
45016
+ opacity
45017
+ });
45018
+ return this;
45019
+ }
45020
+ getStrokeOpacity() {
45021
+ return this.borderOpacity;
45022
+ }
45023
+ setBorderStyle(style2) {
45024
+ this.emit({
45025
+ class: "Drawing",
45026
+ method: "setStrokeStyle",
45027
+ item: [this.id],
45028
+ style: style2
45029
+ });
45030
+ return this;
45031
+ }
45032
+ getBorderStyle() {
45033
+ return this.borderStyle;
45034
+ }
45035
+ setStrokeColor(color2) {
45036
+ this.emit({
45037
+ class: "Drawing",
45038
+ method: "setStrokeColor",
45039
+ item: [this.id],
45040
+ color: color2
45041
+ });
45042
+ return this;
45043
+ }
45044
+ getStrokeColor() {
45045
+ return this.borderColor;
45046
+ }
45047
+ setStrokeWidth(width2) {
45048
+ this.emit({
45049
+ class: "Drawing",
45050
+ method: "setStrokeWidth",
45051
+ item: [this.id],
45052
+ width: width2,
45053
+ prevWidth: this.strokeWidth
45054
+ });
45055
+ return this;
45086
45056
  }
45087
45057
  getLinkTo() {
45088
45058
  return this.linkTo.link;
45089
45059
  }
45090
- download() {
45091
- const linkElem = document.createElement("a");
45092
- linkElem.href = this.storageLink;
45093
- linkElem.setAttribute("download", "");
45094
- linkElem.click();
45060
+ getStrokeWidth() {
45061
+ return this.strokeWidth;
45095
45062
  }
45096
- onRemove() {
45097
- const storageId = this.getStorageId();
45098
- if (storageId) {
45099
- conf.hooks.beforeMediaRemove([storageId], this.board.getBoardId());
45063
+ getRichText() {
45064
+ return null;
45065
+ }
45066
+ isPointNearLine(point5, threshold = 10) {
45067
+ const transformedMouseX = (point5.x - this.transformation.matrix.translateX) / this.transformation.matrix.scaleX;
45068
+ const transformedMouseY = (point5.y - this.transformation.matrix.translateY) / this.transformation.matrix.scaleY;
45069
+ const transformedMouse = new Point(transformedMouseX, transformedMouseY);
45070
+ for (let i = 0;i < this.points.length - 1; i++) {
45071
+ const p1 = this.points[i];
45072
+ const p22 = this.points[i + 1];
45073
+ const distance = getPerpendicularDistance(transformedMouse, p1, p22);
45074
+ if (distance < threshold) {
45075
+ return true;
45076
+ }
45100
45077
  }
45101
- super.onRemove();
45078
+ return false;
45079
+ }
45080
+ }
45081
+ function getPerpendicularDistance(point5, lineStart, lineEnd) {
45082
+ const { x: px, y: py } = point5;
45083
+ const { x: sx, y: sy } = lineStart;
45084
+ const { x: ex, y: ey } = lineEnd;
45085
+ const numerator = Math.abs((ey - sy) * px - (ex - sx) * py + ex * sy - ey * sx);
45086
+ const denominator = Math.sqrt(Math.pow(ey - sy, 2) + Math.pow(ex - sx, 2));
45087
+ return numerator / denominator;
45088
+ }
45089
+ function douglasPeucker(points, epsilon2) {
45090
+ if (points.length < 3) {
45091
+ return points;
45092
+ }
45093
+ const start = points[0];
45094
+ const end = points[points.length - 1];
45095
+ let maxDistance = 0;
45096
+ let maxIndex = 0;
45097
+ for (let i = 1;i < points.length - 1; i++) {
45098
+ const distance = getPerpendicularDistance(points[i], start, end);
45099
+ if (distance > maxDistance) {
45100
+ maxDistance = distance;
45101
+ maxIndex = i;
45102
+ }
45103
+ }
45104
+ if (maxDistance > epsilon2) {
45105
+ const leftSubPoints = points.slice(0, maxIndex + 1);
45106
+ const rightSubPoints = points.slice(maxIndex);
45107
+ const leftRecursiveResult = douglasPeucker(leftSubPoints, epsilon2);
45108
+ const rightRecursiveResult = douglasPeucker(rightSubPoints, epsilon2);
45109
+ return leftRecursiveResult.slice(0, -1).concat(rightRecursiveResult);
45110
+ } else {
45111
+ return [start, end];
45102
45112
  }
45103
45113
  }
45104
45114
  // src/Items/Group/Group.ts