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