microboard-temp 0.4.40 → 0.4.42

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