microboard-temp 0.4.41 → 0.4.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/browser.js +609 -609
- package/dist/cjs/index.js +609 -609
- package/dist/cjs/node.js +609 -609
- package/dist/esm/browser.js +609 -609
- package/dist/esm/index.js +609 -609
- package/dist/esm/node.js +609 -609
- package/package.json +1 -1
package/dist/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
|
|
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
|
|
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";
|
|
@@ -44660,202 +44233,455 @@ class Placeholder extends BaseItem {
|
|
|
44660
44233
|
renderHTML(documentFactory) {
|
|
44661
44234
|
return documentFactory.createElement("div");
|
|
44662
44235
|
}
|
|
44663
|
-
getLinkTo() {
|
|
44664
|
-
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;
|
|
44665
44494
|
}
|
|
44666
44495
|
getRichText() {
|
|
44667
44496
|
return null;
|
|
44668
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
|
+
}
|
|
44669
44514
|
}
|
|
44670
|
-
// src/
|
|
44671
|
-
function
|
|
44672
|
-
|
|
44673
|
-
|
|
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);
|
|
44515
|
+
// src/isSafari.ts
|
|
44516
|
+
function isSafari() {
|
|
44517
|
+
if (typeof navigator === "undefined") {
|
|
44518
|
+
return false;
|
|
44684
44519
|
}
|
|
44685
|
-
const
|
|
44686
|
-
|
|
44687
|
-
|
|
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;
|
|
44688
44524
|
}
|
|
44689
44525
|
|
|
44690
|
-
|
|
44526
|
+
// src/Items/Drawing/Drawing.ts
|
|
44527
|
+
class Drawing extends BaseItem {
|
|
44528
|
+
points;
|
|
44691
44529
|
events;
|
|
44692
|
-
itemType = "
|
|
44530
|
+
itemType = "Drawing";
|
|
44693
44531
|
parent = "Board";
|
|
44694
|
-
image;
|
|
44695
44532
|
transformation;
|
|
44696
|
-
|
|
44533
|
+
path2d = new conf.path2DFactory;
|
|
44697
44534
|
subject = new Subject;
|
|
44698
|
-
|
|
44699
|
-
|
|
44535
|
+
untransformedMbr = new Mbr;
|
|
44536
|
+
lines = [];
|
|
44537
|
+
linkTo;
|
|
44538
|
+
strokeWidth = 1;
|
|
44539
|
+
borderStyle = "solid";
|
|
44540
|
+
linePattern = scalePatterns(this.strokeWidth)[this.borderStyle];
|
|
44541
|
+
borderOpacity = 1;
|
|
44700
44542
|
transformationRenderBlock = undefined;
|
|
44701
|
-
|
|
44702
|
-
imageDimension;
|
|
44703
|
-
board;
|
|
44704
|
-
constructor({ base64, storageLink, imageDimension }, board, events, id = "") {
|
|
44543
|
+
constructor(board, points, events, id = "") {
|
|
44705
44544
|
super(board, id);
|
|
44545
|
+
this.points = points;
|
|
44706
44546
|
this.events = events;
|
|
44707
|
-
this.linkTo = new LinkTo(this.id, events);
|
|
44708
|
-
this.board = board;
|
|
44709
|
-
this.setStorageLink(storageLink);
|
|
44710
|
-
this.imageDimension = imageDimension;
|
|
44711
44547
|
this.transformation = new Transformation(id, events);
|
|
44712
|
-
this.
|
|
44713
|
-
this.
|
|
44714
|
-
|
|
44715
|
-
|
|
44716
|
-
|
|
44717
|
-
|
|
44718
|
-
}
|
|
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
|
+
});
|
|
44719
44554
|
this.linkTo.subject.subscribe(() => {
|
|
44720
44555
|
this.updateMbr();
|
|
44556
|
+
this.updateLines();
|
|
44721
44557
|
this.subject.publish(this);
|
|
44722
44558
|
});
|
|
44723
|
-
this.
|
|
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;
|
|
44559
|
+
this.updateLines();
|
|
44778
44560
|
}
|
|
44779
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
|
+
}
|
|
44780
44567
|
return {
|
|
44781
|
-
itemType: "
|
|
44782
|
-
|
|
44783
|
-
imageDimension: this.imageDimension,
|
|
44568
|
+
itemType: "Drawing",
|
|
44569
|
+
points,
|
|
44784
44570
|
transformation: this.transformation.serialize(),
|
|
44571
|
+
strokeStyle: this.borderColor,
|
|
44572
|
+
strokeWidth: this.strokeWidth,
|
|
44785
44573
|
linkTo: this.linkTo.serialize()
|
|
44786
44574
|
};
|
|
44787
44575
|
}
|
|
44788
|
-
|
|
44789
|
-
this.
|
|
44790
|
-
|
|
44791
|
-
|
|
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);
|
|
44576
|
+
deserialize(data) {
|
|
44577
|
+
this.points = [];
|
|
44578
|
+
for (const point5 of data.points) {
|
|
44579
|
+
this.points.push(new Point(point5.x, point5.y));
|
|
44798
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;
|
|
44799
44588
|
}
|
|
44800
|
-
|
|
44801
|
-
|
|
44802
|
-
|
|
44803
|
-
|
|
44589
|
+
updateGeometry() {
|
|
44590
|
+
this.updatePath2d();
|
|
44591
|
+
this.updateLines();
|
|
44592
|
+
this.updateMbr();
|
|
44804
44593
|
}
|
|
44805
|
-
|
|
44806
|
-
|
|
44807
|
-
|
|
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);
|
|
44808
44625
|
}
|
|
44809
|
-
|
|
44810
|
-
|
|
44811
|
-
|
|
44812
|
-
|
|
44813
|
-
}
|
|
44814
|
-
|
|
44815
|
-
|
|
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
|
+
}
|
|
44816
44643
|
}
|
|
44817
|
-
|
|
44818
|
-
|
|
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);
|
|
44819
44658
|
}
|
|
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
44659
|
}
|
|
44830
|
-
|
|
44831
|
-
|
|
44832
|
-
|
|
44833
|
-
|
|
44834
|
-
|
|
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
|
+
}
|
|
44835
44672
|
} else {
|
|
44836
|
-
this.
|
|
44673
|
+
this.points.push(point5);
|
|
44837
44674
|
}
|
|
44675
|
+
this.updateGeometry();
|
|
44838
44676
|
}
|
|
44839
|
-
|
|
44840
|
-
this.
|
|
44677
|
+
setId(id) {
|
|
44678
|
+
this.id = id;
|
|
44679
|
+
this.transformation.setId(id);
|
|
44680
|
+
this.linkTo.setId(id);
|
|
44681
|
+
return this;
|
|
44841
44682
|
}
|
|
44842
|
-
|
|
44843
|
-
|
|
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
|
-
}
|
|
44683
|
+
getId() {
|
|
44684
|
+
return this.id;
|
|
44859
44685
|
}
|
|
44860
44686
|
render(context) {
|
|
44861
44687
|
if (this.transformationRenderBlock) {
|
|
@@ -44863,8 +44689,12 @@ class ImageItem extends BaseItem {
|
|
|
44863
44689
|
}
|
|
44864
44690
|
const ctx = context.ctx;
|
|
44865
44691
|
ctx.save();
|
|
44692
|
+
ctx.strokeStyle = this.borderColor;
|
|
44693
|
+
ctx.lineWidth = this.strokeWidth;
|
|
44694
|
+
ctx.lineCap = "round";
|
|
44695
|
+
ctx.setLineDash(this.linePattern);
|
|
44866
44696
|
this.transformation.matrix.applyToContext(ctx);
|
|
44867
|
-
ctx.
|
|
44697
|
+
ctx.stroke(this.path2d.nativePath);
|
|
44868
44698
|
ctx.restore();
|
|
44869
44699
|
if (this.getLinkTo()) {
|
|
44870
44700
|
const { top, right } = this.getMbr();
|
|
@@ -44872,26 +44702,61 @@ class ImageItem extends BaseItem {
|
|
|
44872
44702
|
}
|
|
44873
44703
|
}
|
|
44874
44704
|
renderHTML(documentFactory) {
|
|
44875
|
-
const div = documentFactory.createElement("
|
|
44705
|
+
const div = documentFactory.createElement("drawing-item");
|
|
44876
44706
|
const { translateX, translateY, scaleX, scaleY } = this.transformation.matrix;
|
|
44877
|
-
const
|
|
44878
|
-
|
|
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);
|
|
44879
44724
|
div.id = this.getId();
|
|
44880
|
-
div.style.width =
|
|
44881
|
-
div.style.height =
|
|
44882
|
-
div.style.transformOrigin = "top
|
|
44883
|
-
div.style.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})`;
|
|
44884
44729
|
div.style.position = "absolute";
|
|
44885
|
-
div.style.backgroundSize = "cover";
|
|
44886
44730
|
div.setAttribute("data-link-to", this.linkTo.serialize() || "");
|
|
44887
44731
|
if (this.getLinkTo()) {
|
|
44888
44732
|
const linkElement = this.linkTo.renderHTML(documentFactory);
|
|
44889
44733
|
scaleElementBy(linkElement, 1 / scaleX, 1 / scaleY);
|
|
44890
|
-
translateElementBy(linkElement, (
|
|
44734
|
+
translateElementBy(linkElement, (width2 - parseInt(linkElement.style.width)) / scaleX, 0);
|
|
44891
44735
|
div.appendChild(linkElement);
|
|
44892
44736
|
}
|
|
44893
44737
|
return div;
|
|
44894
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
|
+
}
|
|
44895
44760
|
getPath() {
|
|
44896
44761
|
const { left, top, right, bottom } = this.getMbr();
|
|
44897
44762
|
const leftTop = new Point(left, top);
|
|
@@ -44916,27 +44781,162 @@ class ImageItem extends BaseItem {
|
|
|
44916
44781
|
new Point(mbr.right, mbr.top + height2 / 2)
|
|
44917
44782
|
];
|
|
44918
44783
|
}
|
|
44784
|
+
getLines() {
|
|
44785
|
+
return this.lines;
|
|
44786
|
+
}
|
|
44919
44787
|
isClosed() {
|
|
44920
44788
|
return true;
|
|
44921
44789
|
}
|
|
44922
|
-
|
|
44923
|
-
|
|
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;
|
|
44924
44884
|
}
|
|
44925
44885
|
getLinkTo() {
|
|
44926
44886
|
return this.linkTo.link;
|
|
44927
44887
|
}
|
|
44928
|
-
|
|
44929
|
-
|
|
44930
|
-
linkElem.href = this.storageLink;
|
|
44931
|
-
linkElem.setAttribute("download", "");
|
|
44932
|
-
linkElem.click();
|
|
44888
|
+
getStrokeWidth() {
|
|
44889
|
+
return this.strokeWidth;
|
|
44933
44890
|
}
|
|
44934
|
-
|
|
44935
|
-
|
|
44936
|
-
|
|
44937
|
-
|
|
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
|
+
}
|
|
44938
44905
|
}
|
|
44939
|
-
|
|
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];
|
|
44940
44940
|
}
|
|
44941
44941
|
}
|
|
44942
44942
|
// src/Items/Group/Group.ts
|