@inweb/markup
Version:
JavaScript 2D markups
1,425 lines (1,413 loc) • 89.4 kB
JavaScript
import Konva from "konva";
class WorldTransform {
screenToWorld(position) {
return {
x: position.x,
y: position.y,
z: 0
};
}
worldToScreen(position) {
return {
x: position.x,
y: position.y
};
}
getScale() {
return {
x: 1,
y: 1,
z: 1
};
}
}
class MarkupColor {
constructor(r, g, b) {
this.setColor(r, g, b);
}
asHex() {
return "#" + this.HEX;
}
asRGB() {
return {
r: this.R,
g: this.G,
b: this.B
};
}
setColor(r, g, b) {
this.R = r;
this.G = g;
this.B = b;
this.HEX = this.rgbToHex(r, g, b);
}
rgbToHex(r, g, b) {
const valueToHex = c => {
const hex = c.toString(16);
return hex === "0" ? "00" : hex;
};
return valueToHex(r) + valueToHex(g) + valueToHex(b);
}
}
const LineTypeSpecs = new Map([ [ "solid", [] ], [ "dot", [ 30, 30, .001, 30 ] ], [ "dash", [ 30, 30 ] ] ]);
class KonvaLine {
constructor(params, ref = null, worldTransformer = new WorldTransform) {
var _a, _b;
this._worldTransformer = worldTransformer;
if (ref) {
this._ref = ref;
let wcsPoints = this._ref.getAttr("wcsPoints");
if (!wcsPoints) {
wcsPoints = [];
let points = this._ref.points();
let wcsPoint;
for (let i = 0; i < points.length; i += 2) {
wcsPoint = this._worldTransformer.screenToWorld({
x: points[i],
y: points[i + 1]
});
wcsPoints.push({
x: wcsPoint.x,
y: wcsPoint.y,
z: wcsPoint.z
});
}
this._ref.setAttr("wcsPoints", wcsPoints);
}
return;
}
if (!params) params = {};
if (!params.points) params.points = [ {
x: 0,
y: 0
}, {
x: 100,
y: 100
} ];
const konvaPoints = [];
const wcsPoints = [];
params.points.forEach((point => {
konvaPoints.push(point.x, point.y);
let wcsPoint = this._worldTransformer.screenToWorld({
x: point.x,
y: point.y
});
wcsPoints.push({
x: wcsPoint.x,
y: wcsPoint.y,
z: wcsPoint.z
});
}));
this._ref = new Konva.Line({
stroke: (_a = params.color) !== null && _a !== undefined ? _a : "#ff0000",
strokeWidth: (_b = params.width) !== null && _b !== undefined ? _b : 4,
globalCompositeOperation: "source-over",
lineCap: "round",
lineJoin: "round",
points: konvaPoints,
draggable: true,
strokeScaleEnabled: false,
dash: LineTypeSpecs.get(params.type) || []
});
this._ref.setAttr("wcsPoints", wcsPoints);
this._ref.on("transform", (e => {
const attrs = e.target.attrs;
if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
}));
this._ref.on("transformend", (e => {
const absoluteTransform = this._ref.getAbsoluteTransform();
let wcsPoints = [];
let points = this._ref.points();
let wcsPoint;
for (let i = 0; i < points.length; i += 2) {
const position = absoluteTransform.point({
x: points[i],
y: points[i + 1]
});
wcsPoint = this._worldTransformer.screenToWorld({
x: position.x,
y: position.y
});
wcsPoints.push({
x: wcsPoint.x,
y: wcsPoint.y,
z: wcsPoint.z
});
}
this._ref.setAttr("wcsPoints", wcsPoints);
}));
this._ref.on("dragend", (e => {
const absoluteTransform = this._ref.getAbsoluteTransform();
let wcsPoints = [];
let points = this._ref.points();
let wcsPoint;
for (let i = 0; i < points.length; i += 2) {
const position = absoluteTransform.point({
x: points[i],
y: points[i + 1]
});
wcsPoint = this._worldTransformer.screenToWorld({
x: position.x,
y: position.y
});
wcsPoints.push({
x: wcsPoint.x,
y: wcsPoint.y,
z: wcsPoint.z
});
}
this._ref.setAttr("wcsPoints", wcsPoints);
}));
this._ref.id(this._ref._id.toString());
}
ref() {
return this._ref;
}
id() {
return this._ref.id();
}
enableMouseEditing(value) {
this._ref.draggable(value);
}
type() {
return "Line";
}
getColor() {
return this._ref.stroke();
}
setColor(hex) {
this._ref.stroke(hex);
}
getRotation() {
return this._ref.rotation();
}
setRotation(degrees) {
this._ref.rotation(degrees);
}
getZIndex() {
return this._ref.zIndex();
}
setZIndex(zIndex) {
this._ref.zIndex(zIndex);
}
delete() {
this._ref.destroy();
this._ref = null;
}
getPoints() {
return this._ref.points();
}
setLineWidth(size) {
this._ref.strokeWidth(size);
}
getLineWidth() {
return this._ref.strokeWidth();
}
getLineType() {
const typeSpecs = this._ref.dash() || [];
let type;
switch (typeSpecs) {
case LineTypeSpecs.get("dot"):
type = "dot";
break;
case LineTypeSpecs.get("dash"):
type = "dash";
break;
default:
type = "solid";
break;
}
return type;
}
setLineType(type) {
const specs = LineTypeSpecs.get(type);
if (specs) this._ref.dash(specs);
}
addPoints(points) {
let newPoints = this._ref.points();
let wcsPoints = this._ref.getAttr("wcsPoints");
points.forEach((point => {
newPoints = newPoints.concat([ point.x, point.y ]);
let wcsPoint = this._worldTransformer.screenToWorld(point);
wcsPoints.push(wcsPoint);
}));
this._ref.points(newPoints);
}
updateScreenCoordinates() {
let wcsPoints = this._ref.getAttr("wcsPoints");
let points = [];
let invert = this._ref.getAbsoluteTransform().copy();
invert = invert.invert();
wcsPoints.forEach((point => {
let screenPoint = this._worldTransformer.worldToScreen(point);
screenPoint = invert.point({
x: screenPoint.x,
y: screenPoint.y
});
points.push(screenPoint.x);
points.push(screenPoint.y);
}));
this._ref.points([]);
this._ref.points(points);
this._ref.clearCache();
}
}
class KonvaText {
constructor(params, ref = null, worldTransformer = new WorldTransform) {
var _a, _b, _c;
this.TEXT_FONT_FAMILY = "Calibri";
this._worldTransformer = worldTransformer;
if (ref) {
this._ref = ref;
const wcsStart = this._ref.getAttr("wcsStart");
if (!wcsStart) {
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: ref.x(),
y: ref.y()
}));
}
return;
}
if (!params) params = {};
if (!params.position) params.position = {
x: 0,
y: 0
};
if (!params.text) params.text = "default";
this._ref = new Konva.Text({
x: params.position.x,
y: params.position.y,
text: params.text,
fontSize: (_a = params.fontSize) !== null && _a !== undefined ? _a : 34,
fontFamily: this.TEXT_FONT_FAMILY,
fill: (_b = params.color) !== null && _b !== undefined ? _b : "#ff0000",
align: "left",
draggable: true,
rotation: (_c = params.rotation) !== null && _c !== undefined ? _c : 0
});
this._ref.width(this._ref.getTextWidth());
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: params.position.x,
y: params.position.y
}));
this._ref.on("transform", (e => {
const attrs = e.target.attrs;
if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
const scaleByX = Math.abs(attrs.scaleX - 1) > 1e-5;
const scaleByY = Math.abs(attrs.scaleY - 1) > 1e-5;
let newWidth = this._ref.width();
if (scaleByX) newWidth *= attrs.scaleX;
let newHeight = this._ref.height();
if (scaleByY) newHeight *= attrs.scaleY;
const minWidth = 50;
if (newWidth < minWidth) newWidth = minWidth;
if (newHeight < Math.round(this.getFontSize())) newHeight = Math.round(this.getFontSize());
if (scaleByX) {
this._ref.width(newWidth);
}
if (scaleByY) {
this._ref.height(newHeight);
}
this._ref.scale({
x: 1,
y: 1
});
}));
this._ref.on("transformend", (e => {
const attrs = e.target.attrs;
if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
const absoluteTransform = this._ref.getStage().getAbsoluteTransform();
const position = absoluteTransform.point({
x: this._ref.x(),
y: this._ref.y()
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld(position));
}));
this._ref.on("dragend", (e => {
const absoluteTransform = this._ref.getStage().getAbsoluteTransform();
const position = absoluteTransform.point({
x: this._ref.x(),
y: this._ref.y()
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld(position));
}));
this._ref.id(this._ref._id.toString());
}
ref() {
return this._ref;
}
id() {
return this._ref.id();
}
enableMouseEditing(value) {
this._ref.draggable(value);
}
type() {
return "Text";
}
getColor() {
return this._ref.fill();
}
setColor(hex) {
this._ref.fill(hex);
}
getRotation() {
return this._ref.rotation();
}
setRotation(degrees) {
this._ref.rotation(degrees);
}
getZIndex() {
return this._ref.zIndex();
}
setZIndex(zIndex) {
this._ref.zIndex(zIndex);
}
delete() {
this._ref.destroy();
this._ref = null;
}
getText() {
return this._ref.text();
}
setText(text) {
this._ref.text(text);
}
getPosition() {
return this._ref.getPosition();
}
setPosition(x, y) {
this._ref.setPosition({
x: x,
y: y
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: x,
y: y
}));
}
getFontSize() {
return this._ref.fontSize();
}
setFontSize(size) {
this._ref.fontSize(size);
}
updateScreenCoordinates() {
let screenPositionStart = this._worldTransformer.worldToScreen(this._ref.getAttr("wcsStart"));
let invert = this._ref.getStage().getAbsoluteTransform().copy();
invert = invert.invert();
const positionStart = invert.point(screenPositionStart);
this._ref.position({
x: positionStart.x,
y: positionStart.y
});
}
}
class KonvaRectangle {
constructor(params, ref = null, worldTransformer = new WorldTransform) {
var _a, _b, _c, _d;
this._worldTransformer = worldTransformer;
if (ref) {
this._ref = ref;
const wcsStart = this._ref.getAttr("wcsStart");
const wcsEnd = this._ref.getAttr("wcsEnd");
if (!wcsStart) {
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: ref.x(),
y: ref.y()
}));
}
if (!wcsEnd) {
const rightBottomPoint = {
x: ref.x() + ref.width(),
y: ref.y() + ref.height()
};
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({
x: rightBottomPoint.x,
y: rightBottomPoint.y
}));
}
return;
}
if (!params) params = {};
if (!params.position) params.position = {
x: 0,
y: 0
};
if (params.position2) {
params.width = params.position.x - params.position2.x;
params.height = params.position.y - params.position2.y;
} else {
if (!params.width || !params.height) {
params.position2 = {
x: 200,
y: 200
};
params.width = 200;
params.height = 200;
} else {
params.position2 = {
x: params.position.x + params.width,
y: params.position.y + params.height
};
}
}
this._ref = new Konva.Rect({
stroke: (_a = params.color) !== null && _a !== undefined ? _a : "#ff0000",
strokeWidth: (_b = params.lineWidth) !== null && _b !== undefined ? _b : 4,
globalCompositeOperation: "source-over",
lineCap: "round",
lineJoin: "round",
x: params.position.x,
y: params.position.y,
width: (_c = params.width) !== null && _c !== undefined ? _c : 200,
height: (_d = params.height) !== null && _d !== undefined ? _d : 200,
draggable: true,
strokeScaleEnabled: false
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: params.position.x,
y: params.position.y
}));
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({
x: params.position2.x,
y: params.position2.y
}));
this._ref.on("transform", (e => {
const attrs = e.target.attrs;
const scaleByX = Math.abs(attrs.scaleX - 1) > 1e-5;
const scaleByY = Math.abs(attrs.scaleY - 1) > 1e-5;
let newWidth = this._ref.width();
if (scaleByX) newWidth *= attrs.scaleX;
let newHeight = this._ref.height();
if (scaleByY) newHeight *= attrs.scaleY;
const minWidth = 50;
const minHeight = 50;
if (newWidth < minWidth) newWidth = minWidth;
if (newHeight < minHeight) newHeight = minHeight;
if (scaleByX) {
this._ref.width(newWidth);
}
if (scaleByY) {
this._ref.height(newHeight);
}
this._ref.scale({
x: 1,
y: 1
});
}));
this._ref.on("transformend", (e => {
const attrs = e.target.attrs;
if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
const absoluteTransform = this._ref.getStage().getAbsoluteTransform();
const position = absoluteTransform.point({
x: this._ref.x(),
y: this._ref.y()
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld(position));
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({
x: position.x + this._ref.width(),
y: position.y + this._ref.height()
}));
}));
this._ref.on("dragend", (e => {
const absoluteTransform = this._ref.getStage().getAbsoluteTransform();
const position = absoluteTransform.point({
x: this._ref.x(),
y: this._ref.y()
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld(position));
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({
x: position.x + this._ref.width(),
y: position.y + this._ref.height()
}));
}));
this._ref.id(this._ref._id.toString());
}
getPosition() {
return this._ref.position();
}
getWidth() {
return this._ref.width();
}
getHeigth() {
return this._ref.height();
}
setWidth(w) {
this._ref.width(w);
const rightLowerPoint = {
x: this._ref.x() + w,
y: this._ref.y() + this._ref.height()
};
const wcsRightLowerPoint = this._worldTransformer.screenToWorld(rightLowerPoint);
this._ref.setAttr("wcsEnd", wcsRightLowerPoint);
}
setHeight(h) {
this._ref.height(h);
const rightLowerPoint = {
x: this._ref.x() + this._ref.width(),
y: this._ref.y() + h
};
const wcsRightLowerPoint = this._worldTransformer.screenToWorld(rightLowerPoint);
this._ref.setAttr("wcsEnd", wcsRightLowerPoint);
}
setPosition(x, y) {
this._ref.setPosition({
x: x,
y: y
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: x,
y: y
}));
}
ref() {
return this._ref;
}
id() {
return this._ref.id();
}
enableMouseEditing(value) {
this._ref.draggable(value);
}
type() {
return "Rectangle";
}
getColor() {
return this._ref.stroke();
}
setColor(hex) {
this._ref.stroke(hex);
}
getRotation() {
return this._ref.rotation();
}
setRotation(degrees) {
this._ref.rotation(degrees);
}
getZIndex() {
return this._ref.zIndex();
}
setZIndex(zIndex) {
this._ref.zIndex(zIndex);
}
delete() {
this._ref.destroy();
this._ref = null;
}
setLineWidth(size) {
this._ref.strokeWidth(size);
}
getLineWidth() {
return this._ref.strokeWidth();
}
updateScreenCoordinates() {
let screenPositionStart = this._worldTransformer.worldToScreen(this._ref.getAttr("wcsStart"));
let screenPositionEnd = this._worldTransformer.worldToScreen(this._ref.getAttr("wcsEnd"));
let invert = this._ref.getStage().getAbsoluteTransform().copy();
invert = invert.invert();
const positionStart = invert.point(screenPositionStart);
const positionEnd = invert.point(screenPositionEnd);
this._ref.position({
x: positionStart.x,
y: positionStart.y
});
this._ref.width(Math.abs(positionEnd.x - positionStart.x));
this._ref.height(Math.abs(positionEnd.y - positionStart.y));
}
}
class KonvaEllipse {
constructor(params, ref = null, worldTransformer = new WorldTransform) {
var _a, _b;
this._worldTransformer = worldTransformer;
if (ref) {
this._ref = ref;
const wcsPosition = this._ref.getAttr("wcsPosition");
const radiusX = this._ref.getAttr("wcsRadiusX");
const radiusY = this._ref.getAttr("wcsRadiusY");
if (!wcsPosition) {
this._ref.setAttr("wcsPosition", this._worldTransformer.screenToWorld({
x: ref.x(),
y: ref.y()
}));
}
if (!radiusX) {
this._ref.setAttr("wcsRadiusX", this._worldTransformer.screenToWorld({
x: ref.x() + ref.radiusX(),
y: ref.y()
}));
}
if (!radiusY) {
this._ref.setAttr("wcsRadiusY", this._worldTransformer.screenToWorld({
x: ref.x(),
y: ref.y() + ref.radiusY()
}));
}
return;
}
if (!params) params = {};
if (!params.position) params.position = {
x: 0,
y: 0
};
if (!params.radius) params.radius = {
x: 25,
y: 25
};
this._ref = new Konva.Ellipse({
stroke: (_a = params.color) !== null && _a !== undefined ? _a : "#ff0000",
strokeWidth: (_b = params.lineWidth) !== null && _b !== undefined ? _b : 4,
globalCompositeOperation: "source-over",
lineCap: "round",
lineJoin: "round",
x: params.position.x,
y: params.position.y,
radiusX: params.radius.x,
radiusY: params.radius.y,
draggable: true,
strokeScaleEnabled: false
});
this._ref.setAttr("wcsPosition", this._worldTransformer.screenToWorld({
x: params.position.x,
y: params.position.y
}));
this._ref.setAttr("wcsRadiusX", this._worldTransformer.screenToWorld({
x: this._ref.x() + params.radius.x,
y: this._ref.y()
}));
this._ref.setAttr("wcsRadiusY", this._worldTransformer.screenToWorld({
x: this._ref.x(),
y: this._ref.y() + params.radius.y
}));
this._ref.on("transform", (e => {
const attrs = e.target.attrs;
if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
const scaleByX = Math.abs(attrs.scaleX - 1) > 1e-5;
const scaleByY = Math.abs(attrs.scaleY - 1) > 1e-5;
let newRadiusX = this._ref.radiusX();
if (scaleByX) newRadiusX *= attrs.scaleX;
let newRadiusY = this._ref.radiusY();
if (scaleByY) newRadiusY *= attrs.scaleY;
const minRadiusX = 25;
const minRadiusY = 25;
if (newRadiusX < minRadiusX) newRadiusX = minRadiusX;
if (newRadiusY < minRadiusY) newRadiusY = minRadiusY;
if (e.evt.ctrlKey || e.evt.shiftKey) {
if (scaleByX) {
this._ref.radius({
x: newRadiusX,
y: newRadiusX
});
} else {
this._ref.radius({
x: newRadiusY,
y: newRadiusY
});
}
} else {
this._ref.radius({
x: newRadiusX,
y: newRadiusY
});
}
this._ref.scale({
x: 1,
y: 1
});
}));
this._ref.on("transformend", (e => {
const absoluteTransform = this._ref.getStage().getAbsoluteTransform();
const position = absoluteTransform.point({
x: this._ref.x(),
y: this._ref.y()
});
this._ref.setAttr("wcsPosition", this._worldTransformer.screenToWorld(position));
const radiusX = absoluteTransform.point({
x: this._ref.x() + this._ref.radiusX(),
y: this._ref.y()
});
this._ref.setAttr("wcsRadiusX", this._worldTransformer.screenToWorld(radiusX));
const radiusY = absoluteTransform.point({
x: this._ref.x(),
y: this._ref.y() + this._ref.radiusY()
});
this._ref.setAttr("wcsRadiusY", this._worldTransformer.screenToWorld(radiusY));
}));
this._ref.on("dragend", (e => {
const absoluteTransform = this._ref.getStage().getAbsoluteTransform();
const position = absoluteTransform.point({
x: this._ref.x(),
y: this._ref.y()
});
this._ref.setAttr("wcsPosition", this._worldTransformer.screenToWorld(position));
const radiusX = absoluteTransform.point({
x: this._ref.x() + this._ref.radiusX(),
y: this._ref.y()
});
this._ref.setAttr("wcsRadiusX", this._worldTransformer.screenToWorld(radiusX));
const radiusY = absoluteTransform.point({
x: this._ref.x(),
y: this._ref.y() + this._ref.radiusY()
});
this._ref.setAttr("wcsRadiusY", this._worldTransformer.screenToWorld(radiusY));
}));
this._ref.id(this._ref._id.toString());
}
getPosition() {
return this._ref.position();
}
setPosition(x, y) {
this._ref.setPosition({
x: x,
y: y
});
this._ref.setAttr("wcsPosition", this._worldTransformer.screenToWorld({
x: x,
y: y
}));
}
getRadiusX() {
return this._ref.radiusX();
}
setRadiusX(r) {
this._ref.radiusX(r);
this._ref.setAttr("wcsRadiusX", this._worldTransformer.screenToWorld({
x: this._ref.x() + r,
y: this._ref.y()
}));
}
getRadiusY() {
return this._ref.radiusY();
}
setRadiusY(r) {
this._ref.radiusY(r);
this._ref.setAttr("wcsRadiusY", this._worldTransformer.screenToWorld({
x: this._ref.x(),
y: this._ref.y() + r
}));
}
getLineWidth() {
return this._ref.strokeWidth();
}
setLineWidth(size) {
this._ref.strokeWidth(size);
}
ref() {
return this._ref;
}
id() {
return this._ref.id();
}
enableMouseEditing(value) {
this._ref.draggable(value);
}
type() {
return "Ellipse";
}
getColor() {
return this._ref.stroke();
}
setColor(hex) {
this._ref.stroke(hex);
}
getRotation() {
return this._ref.rotation();
}
setRotation(degrees) {
this._ref.rotation(degrees);
}
getZIndex() {
return this._ref.zIndex();
}
setZIndex(zIndex) {
this._ref.zIndex(zIndex);
}
delete() {
this._ref.destroy();
this._ref = null;
}
updateScreenCoordinates() {
let screenPosition = this._worldTransformer.worldToScreen(this._ref.getAttr("wcsPosition"));
let radiusX = this._worldTransformer.worldToScreen(this._ref.getAttr("wcsRadiusX"));
let radiusY = this._worldTransformer.worldToScreen(this._ref.getAttr("wcsRadiusY"));
let invert = this._ref.getStage().getAbsoluteTransform().copy();
invert = invert.invert();
const position = invert.point({
x: screenPosition.x,
y: screenPosition.y
});
this._ref.position({
x: position.x,
y: position.y
});
this._ref.radius({
x: Math.abs(invert.point(radiusX).x - position.x),
y: Math.abs(invert.point(radiusY).y - position.y)
});
}
}
class KonvaArrow {
constructor(params, ref = null, worldTransformer = new WorldTransform) {
var _a, _b;
this._worldTransformer = worldTransformer;
if (ref) {
this._ref = ref;
const wcsStart = this._ref.getAttr("wcsStart");
const wcsEnd = this._ref.getAttr("wcsEnd");
if (!wcsStart) this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: ref.points()[0],
y: ref.points()[1]
}));
if (!wcsEnd) this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({
x: ref.points()[2],
y: ref.points()[3]
}));
return;
}
if (!params) params = {};
if (!params.start) params.start = {
x: 0,
y: 0
};
if (!params.end) params.end = {
x: 100,
y: 100
};
this._ref = new Konva.Arrow({
stroke: (_a = params.color) !== null && _a !== undefined ? _a : "#ff0000",
fill: (_b = params.color) !== null && _b !== undefined ? _b : "#ff0000",
strokeWidth: 4,
globalCompositeOperation: "source-over",
lineCap: "round",
lineJoin: "round",
points: [ params.start.x, params.start.y, params.end.x, params.end.y ],
draggable: true,
strokeScaleEnabled: false
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: params.start.x,
y: params.start.y
}));
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({
x: params.end.x,
y: params.end.y
}));
this._ref.on("transformend", (e => {
const attrs = e.target.attrs;
if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
const points = this._ref.points();
const absoluteTransform = this._ref.getAbsoluteTransform();
const transformStart = absoluteTransform.point({
x: points[0],
y: points[1]
});
const transformEnd = absoluteTransform.point({
x: points[2],
y: points[3]
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld(transformStart));
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld(transformEnd));
}));
this._ref.on("dragend", (e => {
const points = this._ref.points();
const absoluteTransform = e.target.getAbsoluteTransform();
const transformStart = absoluteTransform.point({
x: points[0],
y: points[1]
});
const transformEnd = absoluteTransform.point({
x: points[2],
y: points[3]
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld(transformStart));
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld(transformEnd));
}));
this._ref.id(this._ref._id.toString());
}
ref() {
return this._ref;
}
id() {
return this._ref.id();
}
enableMouseEditing(value) {
this._ref.draggable(value);
}
type() {
return "Arrow";
}
getColor() {
return this._ref.stroke();
}
setColor(hex) {
this._ref.stroke(hex);
this._ref.fill(hex);
}
getRotation() {
return this._ref.rotation();
}
setRotation(degrees) {
this._ref.rotation(degrees);
}
getZIndex() {
return this._ref.zIndex();
}
setZIndex(zIndex) {
this._ref.zIndex(zIndex);
}
delete() {
this._ref.destroy();
this._ref = null;
}
getPoints() {
const points = this._ref.points();
return [ {
x: points[0],
y: points[1]
}, {
x: points[2],
y: points[3]
} ];
}
setPoints(points) {
if (points.length === 2) {
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: points[0].x,
y: points[0].y
}));
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({
x: points[1].x,
y: points[1].y
}));
this._ref.points([ points[0].x, points[0].y, points[1].x, points[1].y ]);
}
}
getStartPoint() {
const points = this._ref.points();
return {
x: points[0],
y: points[1]
};
}
setStartPoint(x, y) {
const points = this._ref.points();
this._ref.points([ x, y, points[2], points[3] ]);
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: x,
y: y
}));
}
getEndPoint() {
const points = this._ref.points();
return {
x: points[2],
y: points[3]
};
}
setEndPoint(x, y) {
const points = this._ref.points();
this._ref.points([ points[0], points[1], x, y ]);
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({
x: x,
y: y
}));
}
updateScreenCoordinates() {
let screenStartPoint = this._worldTransformer.worldToScreen(this._ref.getAttr("wcsStart"));
let screenEndPoint = this._worldTransformer.worldToScreen(this._ref.getAttr("wcsEnd"));
let invert = this._ref.getAbsoluteTransform().copy();
invert = invert.invert();
const startPoint = invert.point({
x: screenStartPoint.x,
y: screenStartPoint.y
});
const endPoint = invert.point({
x: screenEndPoint.x,
y: screenEndPoint.y
});
this._ref.points([ startPoint.x, startPoint.y, endPoint.x, endPoint.y ]);
}
}
class KonvaImage {
constructor(params, ref = null, worldTransformer = new WorldTransform) {
var _a, _b;
this._ratio = 1;
this.EPSILON = 1e-5;
this.BASE64_HEADER_START = "data:image/";
this.BASE64_NOT_FOUND = "data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAADsAAAA7AF5KHG9AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAmhJREFUWIXtlr9rVEEQxz+H8RQUJIdeIopYm0vkCg0GBBtbG1NF7Kxt7dR/IGIw/uhTaBNLERURg2kCEUyCYCPi70b0InjGS57FzOZN3r19d+9HJIVfWO52dma/s7Mz8xa2KAaBCWAR+AkECWOmSOIdwC1gtQOpHc+NfQ8wClQ8+1d0vcdH/lQ3bSIRGAZ2pTjAqNovANXIWlXlAXA2zvi2Ln4AjqYgtagYEutENSLvjRoOImFv5iB32Ae8UrLXwFBk3h9ndF0VJnKSO9gTu3yKu5Z1LKnS8YIcABgw5Ks692JZFXcXRJ46Aq6kikCnHNi/mQ50WwVtfaIoBzL3gRk2drSscJ2wrc4VvUoe2wn/41/iBfoVLRnBGnDSY3AAKacy8AmYR+o7K1zCl6wgrgpOAc/MuhvfgMuk+1JGHQgSBcAloKXy78AjYBppJk5/noTulseBMZ23iD/piHFkEdgTQzKk+5wHjmHC3cmBg0BD5xcSTrFXyQPgIWFtDwMvab+2N8DpbhyY1v/3E8gdDgNfVX9SCVZ0/gW4B0wB71S2BpxLcuCM/jaQSHSDEeAX4VMuAG4gTzyHbcAVXXO6GxxwIX+vvxe7JHcYQ07nHqklj96UIW/YhSWzMKcep8VVtf8B1Dw6h4DfhB+sdbgn2R+gnoEc5NR3dZ+3QJ9H74HqXLPCGlJyTfI9y3YCs0owq3OLOpKkLeBI1HhSDT/mdKIPiUCARMTlQx34TMLjtww8IczmO8AJ/N/2JNSQXAiQ671JePePge0+wzJSQq4FFzlaenIvucUAkiQLhC/mLGNZ9xgn5s63BP4CCk0QDtm4BhoAAAAASUVORK5CYII=";
this._worldTransformer = worldTransformer;
if (ref) {
if (!ref.src || !ref.src.startsWith(this.BASE64_HEADER_START)) ref.src = this.BASE64_NOT_FOUND;
if (ref.height() <= this.EPSILON) ref.height(32);
if (ref.width() <= this.EPSILON) ref.width(32);
this._ref = ref;
this._canvasImage = ref.image();
this._ratio = this._ref.height() <= this.EPSILON || this._ref.width() <= this.EPSILON ? 1 : this._ref.height() / this._ref.width();
const wcsStart = this._ref.getAttr("wcsStart");
if (!wcsStart) {
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: ref.x(),
y: ref.y()
}));
}
return;
}
if (!params) params = {};
if (!params.position) params.position = {
x: 0,
y: 0
};
if (!params.src || !params.src.startsWith(this.BASE64_HEADER_START)) params.src = this.BASE64_NOT_FOUND;
this._canvasImage = new Image;
this._canvasImage.onload = () => {
this._ref.image(this._canvasImage);
if (this._ref.height() <= this.EPSILON) this._ref.height(this._canvasImage.height);
if (this._ref.width() <= this.EPSILON) this._ref.width(this._canvasImage.width);
this._ratio = this._ref.height() <= this.EPSILON || this._ref.width() <= this.EPSILON ? 1 : this._ref.height() / this._ref.width();
if ((params.width <= this.EPSILON || params.height <= this.EPSILON) && (params.maxWidth >= this.EPSILON || params.maxWidth >= this.EPSILON)) {
const heightOutOfCanvas = params.maxHeight - this._canvasImage.height;
const widthOutOfCanvas = params.maxWidth - this._canvasImage.width;
if (heightOutOfCanvas <= this.EPSILON || widthOutOfCanvas <= this.EPSILON) {
if (widthOutOfCanvas <= this.EPSILON && widthOutOfCanvas < heightOutOfCanvas / this._ratio) {
this._ref.height(params.maxWidth * this._ratio);
this._ref.width(params.maxWidth);
} else {
this._ref.width(params.maxHeight / this._ratio);
this._ref.height(params.maxHeight);
}
}
}
};
this._canvasImage.onerror = () => {
this._canvasImage.onerror = function() {};
this._canvasImage.src = this.BASE64_NOT_FOUND;
};
this._canvasImage.src = params.src;
this._ref = new Konva.Image({
x: params.position.x,
y: params.position.y,
image: this._canvasImage,
width: (_a = params.width) !== null && _a !== undefined ? _a : 0,
height: (_b = params.height) !== null && _b !== undefined ? _b : 0,
draggable: true
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: params.position.x,
y: params.position.y
}));
this._ref.on("transform", (e => {
const attrs = e.target.attrs;
if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
const scaleByX = Math.abs(attrs.scaleX - 1) > 1e-5;
const scaleByY = Math.abs(attrs.scaleY - 1) > 1e-5;
let newWidth = this._ref.width();
if (scaleByX) newWidth *= attrs.scaleX;
let newHeight = this._ref.height();
if (scaleByY) newHeight *= attrs.scaleY;
if (e.evt.ctrlKey || e.evt.shiftKey) {
if (scaleByX) {
this._ref.width(newWidth);
this._ref.height(newWidth * this._ratio);
} else {
this._ref.width(newHeight / this._ratio);
this._ref.height(newHeight);
}
} else {
if (scaleByX) {
this._ref.width(newWidth);
}
if (scaleByY) {
this._ref.height(newHeight);
}
}
this._ref.scale({
x: 1,
y: 1
});
}));
this._ref.on("transformend", (e => {
const absoluteTransform = this._ref.getStage().getAbsoluteTransform();
const position = absoluteTransform.point({
x: this._ref.x(),
y: this._ref.y()
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld(position));
}));
this._ref.on("dragend", (e => {
const absoluteTransform = this._ref.getStage().getAbsoluteTransform();
const position = absoluteTransform.point({
x: this._ref.x(),
y: this._ref.y()
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld(position));
}));
this._ref.id(this._ref._id.toString());
}
getSrc() {
return this._canvasImage.src;
}
setSrc(src) {
this._canvasImage.src = src;
}
getWidth() {
return this._ref.width();
}
setWidth(w) {
this._ref.width(w);
this._ref.height(w * this._ratio);
}
getHeight() {
return this._ref.height();
}
setHeight(h) {
this._ref.height(h);
this._ref.width(h / this._ratio);
}
ref() {
return this._ref;
}
id() {
return this._ref.id();
}
enableMouseEditing(value) {
this._ref.draggable(value);
}
type() {
return "Image";
}
getRotation() {
return this._ref.rotation();
}
setRotation(degrees) {
this._ref.rotation(degrees);
}
getZIndex() {
return this._ref.zIndex();
}
setZIndex(zIndex) {
this._ref.zIndex(zIndex);
}
delete() {
this._ref.destroy();
this._ref = null;
}
getPosition() {
return this._ref.getPosition();
}
setPosition(x, y) {
this._ref.setPosition({
x: x,
y: y
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: x,
y: y
}));
}
updateScreenCoordinates() {
let screenPositionStart = this._worldTransformer.worldToScreen(this._ref.getAttr("wcsStart"));
let invert = this._ref.getStage().getAbsoluteTransform().copy();
invert = invert.invert();
const positionStart = invert.point(screenPositionStart);
this._ref.position({
x: positionStart.x,
y: positionStart.y
});
}
}
class KonvaCloud {
constructor(params, ref = null, worldTransformer = new WorldTransform) {
var _a, _b, _c, _d;
this._worldTransformer = worldTransformer;
if (ref) {
this._ref = ref;
const wcsStart = this._ref.getAttr("wcsStart");
const wcsEnd = this._ref.getAttr("wcsEnd");
if (!wcsStart) {
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: ref.x(),
y: ref.y()
}));
}
if (!wcsEnd) {
const rightBottomPoint = {
x: ref.x() + ref.width(),
y: ref.y() + ref.height()
};
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({
x: rightBottomPoint.x,
y: rightBottomPoint.y
}));
}
return;
}
if (!params) params = {};
if (!params.position) params.position = {
x: 0,
y: 0
};
if (params.position2) {
params.width = params.position.x - params.position2.x;
params.height = params.position.y - params.position2.y;
} else {
if (!params.width || !params.height) {
params.position2 = {
x: 200,
y: 200
};
params.width = 200;
params.height = 200;
} else {
params.position2 = {
x: params.position.x + params.width,
y: params.position.y + params.height
};
}
}
const ARC_RADIUS = 16;
this._ref = new Konva.Shape({
x: params.position.x,
y: params.position.y,
width: (_a = params.width) !== null && _a !== undefined ? _a : 200,
height: (_b = params.height) !== null && _b !== undefined ? _b : 200,
stroke: (_c = params.color) !== null && _c !== undefined ? _c : "#ff0000",
strokeWidth: (_d = params.lineWidth) !== null && _d !== undefined ? _d : 4,
draggable: true,
strokeScaleEnabled: false,
globalCompositeOperation: "source-over",
sceneFunc: (context, shape) => {
function calculateMidpoint(position, width, height) {
const midX = position.x + width / 2;
const midY = position.y + height / 2;
return {
x: midX,
y: midY
};
}
const points = [ {
x: 0,
y: 0
}, {
x: 0 + this._ref.width(),
y: 0
}, {
x: 0 + this._ref.width(),
y: 0 + this._ref.height()
}, {
x: 0,
y: 0 + this._ref.height()
}, {
x: 0,
y: 0
} ];
const midPoint = calculateMidpoint({
x: 0,
y: 0
}, this._ref.width(), this._ref.height());
const baseArcLength = 30;
context.beginPath();
for (let iPoint = 0; iPoint < points.length - 1; iPoint++) {
let approxArcLength = baseArcLength;
const dx = points[iPoint + 1].x - points[iPoint].x;
const dy = points[iPoint + 1].y - points[iPoint].y;
const length = Math.sqrt(dx * dx + dy * dy);
const arcCount = Math.floor(length / approxArcLength);
const lengthMod = length % approxArcLength;
approxArcLength = baseArcLength + arcCount / lengthMod;
let pX = points[iPoint].x + dx / arcCount / 2;
let pY = points[iPoint].y + dy / arcCount / 2;
const pEndX = points[iPoint + 1].x;
const pEndY = points[iPoint + 1].y;
const endAngle = Math.atan((pEndY - pY) / (pEndX - pX));
const startAngle = endAngle + Math.PI;
const counterClockwise = pX > midPoint.x && pY > midPoint.y;
for (let iArc = 0; iArc < arcCount; iArc++) {
if (counterClockwise) {
context.arc(pX, pY, ARC_RADIUS, endAngle, startAngle);
} else {
context.arc(pX, pY, ARC_RADIUS, startAngle, endAngle);
}
pX += dx / arcCount;
pY += dy / arcCount;
}
}
context.closePath();
context.fillStrokeShape(shape);
}
});
this._ref.className = "Cloud";
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld({
x: params.position.x,
y: params.position.y
}));
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({
x: params.position2.x,
y: params.position2.y
}));
this._ref.on("transform", (e => {
const attrs = e.target.attrs;
const scaleByX = Math.abs(attrs.scaleX - 1) > 1e-5;
const scaleByY = Math.abs(attrs.scaleY - 1) > 1e-5;
let newWidth = this._ref.width();
if (scaleByX) newWidth *= attrs.scaleX;
let newHeight = this._ref.height();
if (scaleByY) newHeight *= attrs.scaleY;
const minWidth = 100;
const minHeight = 100;
if (newWidth < minWidth) newWidth = minWidth;
if (newHeight < minHeight) newHeight = minHeight;
if (scaleByX) {
this._ref.width(newWidth);
}
if (scaleByY) {
this._ref.height(newHeight);
}
this._ref.scale({
x: 1,
y: 1
});
}));
this._ref.on("transformend", (e => {
const attrs = e.target.attrs;
if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation);
const absoluteTransform = this._ref.getStage().getAbsoluteTransform();
const position = absoluteTransform.point({
x: this._ref.x(),
y: this._ref.y()
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld(position));
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({
x: position.x + this._ref.width(),
y: position.y + this._ref.height()
}));
}));
this._ref.on("dragend", (e => {
const absoluteTransform = this._ref.getStage().getAbsoluteTransform();
const position = absoluteTransform.point({
x: this._ref.x(),
y: this._ref.y()
});
this._ref.setAttr("wcsStart", this._worldTransformer.screenToWorld(position));
this._ref.setAttr("wcsEnd", this._worldTransformer.screenToWorld({
x: position.x + this._ref.width(),
y: position.y + this._ref.height()
}));
}));
this._ref.getSelfRect = () => ({
x: 0 - ARC_RADIUS,
y: 0 - ARC_RADIUS,
width: this._ref.width() + 2 * ARC_RADIUS,
height: this._ref.height() + 2 * ARC_RADIUS
});
this._ref.id(this._ref._id.toString());
}
ref() {
return this._ref;
}
id() {
return this._ref.id();
}
enableMouseEditing(value) {
this._ref.draggable(value);
}
type