UNPKG

@inweb/markup

Version:
1,425 lines (1,413 loc) 89.4 kB
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