UNPKG

vue-data-ui-hq

Version:

A user-empowering data visualization Vue 3 components library for eloquent data storytelling

1,162 lines (1,159 loc) 106 kB
import k from "./html2canvas.esm-d2sM-0Wm.js"; import { E as p } from "./jspdf.es.min-wYlldo1s.js"; import { z as v, u as A, A as w, B as M } from "./index-WrV3SAID.js"; import { openBlock as d, createElementBlock as n, createElementVNode as r, normalizeStyle as c, toDisplayString as u, normalizeClass as y, createStaticVNode as F, createCommentVNode as a, withDirectives as N, vModelCheckbox as C, vModelText as x, renderSlot as O, Fragment as L, renderList as G } from "vue"; import { _ } from "./_plugin-vue_export-helper-CHgC5LLL.js"; const m = { props: { config: { type: Object, default() { return {}; } }, dataset: { type: Object, default() { return { shapes: [], lastSelectedShape: void 0 }; } } }, data() { return { activeShape: void 0, strokeSize: 1, currentPointer: { start: { x: 0, y: 0 }, end: { x: 0, end: 0 } }, currentTarget: void 0, hoveredShapeId: void 0, isBold: !1, isBulletTextMode: !1, isDash: !1, isDeleteMode: !1, isDrawing: !1, isDrawingNewShape: !0, isDrawMode: !1, isItalic: !1, isMouseDown: !1, isMoveMode: !1, isPrinting: !1, isResizeMode: !1, isSelectMode: !1, isSummaryOpen: !1, isTextMode: !1, isUnderline: !1, isWriting: !1, lastSelectedShape: this.dataset.lastSelectedShape, pointerDownId: -1, pointerPosition: { x: 0, y: 0 }, preventEdit: !0, selectedGroup: [], shapes: this.dataset.shapes ? this.dataset.shapes : [], shapesOrder: [], step: Math.round(Math.random()) * 1e5, svgHeight: 1e3, svgWidth: 1e3, options: { arrow: { color: "grey", filled: !0 }, circle: { color: "grey", filled: !1, radius: 3, strokeWidth: 2 }, rect: { color: "grey", filled: !1, strokeWidth: 2, height: 12, width: 12 } }, selectedColor: "#000000", showCaret: !1, sizeRatio: 1, slottedSvg: void 0, sourceWidth: 1, sourceHeight: 1, textAlign: "start", textFont: 20, transparency: 100, transparencyCodes: v }; }, watch: { shapes: { handler(t) { t.length === 0 && (this.lastSelectedShape = void 0); } } }, computed: { FINAL_CONFIG() { const t = A().vue_ui_annotator; if (!Object.keys(this.config || {}).length) return t; const i = this.treeShake({ defaultConfig: t, userConfig: this.config }); return this.convertConfigColors(i); }, canSelect() { return this.shapes.filter((t) => !["line", "group"].includes(t.type)).length > 1; }, colorTransparency() { return this.transparencyCodes[this.transparency > 98 ? 98 : this.transparency]; }, cursorClass() { switch (!0) { case this.isDeleteMode: return "default"; case this.isMoveMode: return "move"; case this.isTextMode: return "text"; case this.isResizeMode: return "se-resize"; default: return ""; } }, records() { return this.shapes; }, userShapes() { return this.records.map((t) => { switch (!0) { case (t && t.type === "arrow"): const i = t.strokeWidth > 3 ? 5 : 10, o = t.strokeWidth > 3 ? 2.5 : 5; return ` <defs> <marker id="${t.id}" markerWidth="${i}" markerHeight="${i}" refX="0" refY="${o}" orient="auto" > <polygon points="0 0,${i} ${o}, 0 ${i}" fill="${t.color}" /> </marker> </defs> ${this.includeSelectionIndicator(t)} <g id="${t.id}"> <path style="stroke-linecap: round !important; ${t.isDash ? `stroke-dasharray: ${t.strokeWidth * 3}` : ""}" stroke="${t.color}" id="${t.id}" d="M${t.x},${t.y} ${t.endX},${t.endY}" stroke-width="${t.strokeWidth}" marker-end="url(#${t.id})" /> </g> <g id="${t.id}"> <rect id="${t.id}" x="${t.x - 10}" y="${t.y - 10}" height="20" width="20" fill="rgba(0,0,0,0.3)" style="display:${this.isResizeMode || this.isMoveMode ? "initial" : "none"}; rx:1 !important; ry:1 !important;" /> </g> ${this.includeDeleteButton(t)} </g> `; case (t && t.type === "circle"): return ` <g id="${t.id}"> ${this.includeSelectionIndicator(t)} <circle id="${t.id}" cx="${t.x}" cy="${t.y}" r="${t.circleRadius ? t.circleRadius : Number.MIN_VALUE}" fill="${t.isFilled ? t.color + t.alpha : "rgba(255,255,255,0.001)"}" stroke="${t.color + t.alpha}" stroke-width="${t.strokeWidth}" style="${t.isDash ? `stroke-dasharray: ${t.strokeWidth * 3}` : ""}" > </circle> </g> ${this.includeDeleteButton(t)}`; case (t && t.type === "group"): return `<g id="${t.id}"> <rect id="${this.isResizeMode ? "" : t.id}" x="${t.x}" y="${t.y}" fill="transparent" height="${t.rectHeight}" width="${t.rectWidth}" stroke="grey" stroke-width="1" style="rx:1 !important; ry:1 !important; ${t.isDash ? `stroke-dasharray: ${t.strokeWidth * 3}` : ""}; display:${this.isSelectMode || this.isDeleteMode || this.hoveredShapeId && this.hoveredShapeId === t.id ? "initial" : "none"};" /> <g id="${t.id}"> ${t.content ? t.content : ""} </g> ${this.includeDeleteButton(t)} </g> `; case (t && t.type === "rect"): return `<g id="${t.id}"> ${this.includeSelectionIndicator(t)} <rect id="${this.isResizeMode ? "" : t.id}" x="${t.x}" y="${t.y}" fill="${t.isFilled ? t.color + t.alpha : "rgba(255,255,255,0.001)"}" height="${t.rectHeight}" width="${t.rectWidth}" stroke="${t.color + t.alpha}" stroke-width="${t.strokeWidth}" style="rx:1 !important; ry:1 !important; ${t.isDash ? `stroke-dasharray: ${t.strokeWidth * 3}` : ""}" /> <rect id="${t.id}" x="${t.x + t.rectWidth}" y="${t.y + t.rectHeight}" height="20" width="20" fill="rgba(0,0,0,0.3)" style="display:${this.isResizeMode ? "initial" : "none"}; rx:1 !important; ry:1 !important;" /> ${this.includeDeleteButton(t)} </g> `; case (t && t.type === "line"): return ` <g id="${t.id}"> <path id="${t.id}" d="M${t.path ? t.path : ""}" style="stroke:${t.color + t.alpha} !important; fill:none; stroke-width:${t.strokeWidth} !important; stroke-linecap: round !important; stroke-linejoin: round !important;" /> ${this.includeDeleteButton(t)} </g> `; case (t && t.type === "text"): const h = t.textContent.split("‎"), s = []; for (let e = 0; e < h.length; e += 1) s.push(` ${t.isBulletTextMode ? `<tspan x="${t.x - t.fontSize}" y="${t.y + t.fontSize * e}" id="${t.id}" font-size="${t.fontSize / 2}">⬤</tspan>` : ""} <tspan id="${t.id}" x="${t.x}" y="${t.y + t.fontSize * e}"> ${h[e]} </tspan>`); return ` ${this.includeSelectionIndicator(t)} ${this.computeTextElement( t, s, t.isBulletTextMode )} `; } }); } }, mounted() { const t = this.$refs.drawSvgContainer; let i = !1; this.walkTheDOM(t, (s) => { if (!i && ["DIV", "svg", "section", "canvas"].includes(s.tagName)) { this.slottedSvg = s, i = !0; return; } }); const o = this.slottedSvg.getBoundingClientRect(); this.sizeRatio = o.height / o.width, this.svgWidth = 1e3, this.svgHeight = this.sizeRatio * 1e3, this.sourceWidth = o.width, this.sourceHeight = o.height, new ResizeObserver((s) => { s.forEach((e) => { this.sourceWidth = e.contentRect.width, this.sourceHeight = e.contentRect.height, this.sizeRatio = e.contentRect.height / e.contentRect.width, this.svgHeight = this.sizeRatio * 1e3; }); }).observe(this.slottedSvg), window.addEventListener("keydown", (s) => { this.write(s); }); }, destroyed() { window.removeEventListener("keydown", (t) => { this.write(t); }); }, methods: { treeShake: w, convertConfigColors: M, bringShapeTo(t) { const i = this.shapes.find( (o) => o.id === this.lastSelectedShape.id ); switch (!0) { case t === "front": this.shapes = this.shapes.filter((o) => o.id !== i.id), this.shapes.push(i); break; case t === "back": this.shapes = this.shapes.filter((o) => o.id !== i.id), this.shapes = [i, ...this.shapes]; break; default: return; } }, clickSvg(t) { if (this.isDeleteMode) return; this.deleteEmptyTextElement(), this.isTextMode ? (this.isWriting = !0, this.showCaret = !0) : (this.isWriting = !1, this.showCaret = !1, this.isTextMode = !1); let i = `text_${Math.random() * 1e4}_${Math.random() * 99999}`; if (this.isWriting) { this.shapes.push({ id: i, type: "text", lines: 0, x: this.pointerPosition.x, y: this.pointerPosition.y, textContent: "", fontSize: this.copy(this.textFont), textAlign: this.copy(this.textAlign), isBold: this.copy(this.isBold), isItalic: this.copy(this.isItalic), isUnderline: this.copy(this.isUnderline), color: this.copy(this.selectedColor), isBulletTextMode: this.copy(this.isBulletTextMode) }), this.currentTarget = this.shapes.at(-1), this.lastSelectedShape = this.shapes.at(-1); return; } const o = () => { this.isDash = this.shapes.find((s) => s.id === t.target.id).isDash; }, h = () => { this.strokeSize = this.shapes.find( (s) => s.id === t.target.id ).strokeWidth; }; if (this.isSelectMode = !1, t.target.id.includes("arrow")) { this.activeShape = "arrow", o(), h(); return; } if (t.target.id.includes("circle")) { this.activeShape = "circle", this.options.circle.filled = this.shapes.find( (s) => s.id === t.target.id ).isFilled, o(), h(); return; } if (t.target.id.includes("rect")) { this.activeShape = "rect", this.options.rect.filled = this.shapes.find( (s) => s.id === t.target.id ).isFilled, o(), h(); return; } if (t.target.id.includes("line")) { this.activeShape = "line", h(); return; } if (t.target.id.includes("text")) { this.isTextMode = !0, this.isWriting = !0, this.showCaret = !0; const s = this.shapes.find((e) => e.id === t.target.id); s && s.textAlign && (this.textAlign = this.shapes.find( (e) => e.id === t.target.id ).textAlign), s && (this.isBulletTextMode = this.shapes.find( (e) => e.id === t.target.id ).isBulletTextMode); return; } }, copyPaste() { const t = { ...this.lastSelectedShape, id: `${this.lastSelectedShape.id}_copy`, x: this.lastSelectedShape.x - 100 < 0 ? 1 : this.lastSelectedShape.x - 100, y: this.lastSelectedShape.y - 100 < 0 ? 1 : this.lastSelectedShape.y - 100 }; this.shapes.push(t); }, includeDeleteButton(t, i = !1) { switch (!0) { case t.type === "circle": return ` <g id="${t.id}" style="display:${this.isDeleteMode ? "initial" : "none"};"> <circle id="${t.id}" cx="${t.x}" cy="${t.y}" r="12" fill="red"/> <line stroke="white" stroke-width="2" id="${t.id}" x1="${t.x - 4}" y1="${t.y - 4}" x2="${t.x + 4}" y2="${t.y + 4}"/> <line stroke="white" stroke-width="2" id="${t.id}" x1="${t.x + 4}" y1="${t.y - 4}" x2="${t.x - 4}" y2="${t.y + 4}"/> </g> `; case t.type === "text": let o, h = [-8, -12, -4, -12, -4]; switch (!0) { case t.textAlign === "start": i ? o = [-20, -24, -16, -16, -24] : o = [-16, -20, -12, -12, -20]; break; case t.textAlign === "middle": o = [0, -4, 4, 4, -4], h = [-32, -36, -28, -36, -28]; break; case t.textAlign === "end": o = [16, 20, 12, 12, 20]; break; default: o = [0, 0, 0]; break; } return ` <g id="${t.id}" style="display:${this.isDeleteMode ? "initial" : "none"};"> <circle id="${t.id}" cx="${t.x + o[0]}" cy="${t.y + h[0]}" r="12" fill="red"/> <line stroke="white" stroke-width="2" id="${t.id}" x1="${t.x + o[1]}" y1="${t.y + h[1]}" x2="${t.x + o[2]}" y2="${t.y + h[2]}"/> <line stroke="white" stroke-width="2" id="${t.id}" x1="${t.x + o[3]}" y1="${t.y + h[3]}" x2="${t.x + o[4]}" y2="${t.y + h[4]}"/> </g> `; default: return ` <g id="${t.id}" style="display:${this.isDeleteMode ? "initial" : "none"};"> <circle id="${t.id}" cx="${t.x - 4}" cy="${t.y - 4}" r="12" fill="red"/> <line stroke="white" stroke-width="2" id="${t.id}" x1="${t.x - 8}" y1="${t.y - 8}" x2="${t.x}" y2="${t.y}"/> <line stroke="white" stroke-width="2" id="${t.id}" x1="${t.x}" y1="${t.y - 8}" x2="${t.x - 8}" y2="${t.y}"/> </g> `; } }, includeSelectionIndicator(t) { if (t) switch (!0) { case t.type === "rect": return ` <rect id="${t.id}" style="stroke-dasharray: 10; display:${this.hoveredShapeId && this.hoveredShapeId === t.id ? "initial" : "none"}" x="${t.x - 20}" y="${t.y - 20}" height="${t.rectHeight + 40}" width="${t.rectWidth + 40}" fill="transparent" stroke="grey" /> `; case t.type === "circle": return ` <rect id="${t.id}" style="stroke-dasharray: 10; display:${this.hoveredShapeId && this.hoveredShapeId === t.id ? "initial" : "none"}" x="${t.x - t.circleRadius - 20}" y="${t.y - t.circleRadius - 20}" height="${t.circleRadius * 2 + 40}" width="${t.circleRadius * 2 + 40}" fill="transparent" stroke="grey" /> `; case t.type === "arrow": const i = t.endX - t.x > 0, o = t.endY - t.y > 0; return ` <rect id="${t.id}" style="stroke-dasharray: 10; display:${this.hoveredShapeId && this.hoveredShapeId === t.id ? "initial" : "none"}" x="${i ? t.x - 20 : t.endX - 20}" y="${o ? t.y - 20 : t.endY - 20}" height="${o ? t.endY - t.y + 40 : t.y - t.endY + 40}" width="${i ? t.endX - t.x + 40 : t.x - t.endX + 40}" fill="transparent" stroke="grey" /> `; case t.type === "text": const h = Array.from(document.getElementsByTagName("text")).find( (I) => I.id === t.id ); if (!h) return; const { x: s, y: e, width: l, height: b } = h.getBBox(); return ` <rect id="${t.id}" style="stroke-dasharray: 10; display:${this.hoveredShapeId && this.hoveredShapeId === t.id ? "initial" : "none"}" x="${s - 20}" y="${e - 20}" height="${b + 40}" width="${l + 40}" fill="transparent" stroke="grey" /> `; default: return ""; } }, allowEditAndHoverShapes(t) { t.preventDefault(), this.preventEdit = !1, t.target && t.target.id && (this.hoveredShapeId = t.target.id); }, setSelectedTextAlignTo(t) { !this.lastSelectedShape || this.lastSelectedShape.type !== "text" || (this.lastSelectedShape.textAlign = t); }, undoLastShape() { this.lastSelectedShape = void 0, this.shapes = this.shapes.slice(0, -1); }, write(t) { if (this.preventEdit) return; t.preventDefault(); const i = t.keyCode; if (!this.isWriting) return; this.showCaret = !0; let o; if (this.lastSelectedShape.type === "text" ? o = this.shapes.find((s) => s.id === this.lastSelectedShape.id) : o = this.shapes.at(-1), this.currentTarget = o, o.type !== "text") return; this.currentTarget.isBold = this.copy(this.isBold), this.currentTarget.isItalic = this.copy(this.isItalic), this.currentTarget.isUnderline = this.copy(this.isUnderline); const h = [ 16, 17, 18, 20, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 91, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 221, 255, "Unidentified" ]; switch (!0) { case i === 8: o.textContent = o.textContent.slice(0, -1); break; case i === 9: o.textContent += "&nbsp; &nbsp; &nbsp; &nbsp;"; break; case i === 13: o.lines += 1, o.textContent += "‎"; return; case h.includes(i): return; default: o.textContent += t.key; } }, groupShapes() { if (this.selectedGroup = [], this.activeShape !== "group") { this.isSelectMode = !1, this.shapes = this.shapes.filter((i) => i.type !== "group"); return; } const t = this.shapes.at(-1); if (this.shapes.forEach((i) => { if (i.type !== "group") switch (!0) { case i.type === "arrow": const o = i.x <= i.endX && i.y <= i.endY && t.x <= i.x && t.y <= i.y && t.x + t.rectWidth >= i.endX && t.y + t.rectHeight >= i.endY, h = i.endY < i.y && i.x < i.endX && t.x <= i.x && t.y <= i.y && t.x + t.rectWidth >= i.endX && t.y + t.rectHeight >= i.y, s = i.x > i.endX && i.y < i.endY && t.x <= i.endX && t.y <= i.endY && t.x + t.rectWidth >= i.x && t.y + t.rectHeight >= i.endY, e = i.x > i.endX && i.y > i.endY && t.x <= i.endX && t.y <= i.endY && t.x + t.rectWidth >= i.x && t.y + t.rectHeight >= i.y; (o || h || s || e) && this.selectedGroup.push(i); break; case i.type === "circle": t.x <= i.x + i.circleRadius && t.y <= i.y + i.circleRadius && i.x + i.circleRadius <= t.x + t.rectWidth && i.y + i.circleRadius <= t.y + t.rectHeight && this.selectedGroup.push(i); break; case i.type === "rect": t.x <= i.x && t.y <= i.y && i.x <= t.x + t.rectWidth && i.y <= t.y + t.rectHeight && i.x + i.rectWidth <= t.x + t.rectWidth && i.y + i.rectHeight <= t.y + t.rectHeight && i.rectWidth <= t.rectWidth && i.rectHeight <= t.rectHeight && this.selectedGroup.push(i); break; case i.type === "text": t.x <= i.x && t.y <= i.y && this.selectedGroup.push(i); break; } }), this.selectedGroup = this.selectedGroup.map((i) => ({ ...i, id: t.id, oldId: i.id, diffX: i.x - t.x, diffY: i.y - t.y, diffEndX: i.endX ? i.endX - t.x : 0, diffEndY: i.endY ? i.endY - t.y : 0 })), t.source = this.selectedGroup, this.selectedGroup.length > 1) { const i = this.copy(this.selectedGroup).map((o) => o.oldId); this.shapes = this.shapes.filter((o) => !i.includes(o.id)), this.selectedGroup.forEach((o) => { switch (!0) { case o.type === "circle": t.content += ` <circle id="${o.id}" cx="${o.x}" cy="${o.y}" r="${o.circleRadius ? o.circleRadius : Number.MIN_VALUE}" fill="${o.isFilled ? o.color + o.alpha : "rgba(255,255,255,0.001)"}" stroke="${o.color + o.alpha}" stroke-width="${o.strokeWidth}" style="${o.isDash ? `stroke-dasharray: ${o.strokeWidth * 3}` : ""}" /> `; break; case o.type === "rect": t.content += ` <rect id="${this.isResizeMode ? "" : o.id}" x="${o.x}" y="${o.y}" fill="${o.isFilled ? o.color + o.alpha : "rgba(255,255,255,0.001)"}" height="${o.rectHeight}" width="${o.rectWidth}" stroke="${o.color + o.alpha}" stroke-width="${o.strokeWidth}" style="rx:1 !important; ry:1 !important; ${o.isDash ? `stroke-dasharray: ${o.strokeWidth * 3}` : ""}" /> `; break; case o.type === "arrow": const h = o.strokeWidth > 3 ? 5 : 10, s = o.strokeWidth > 3 ? 2.5 : 5, e = Date.now(); t.content += ` <g id="${o.id}"> <defs> <marker id="${e}" markerWidth="${h}" markerHeight="${h}" refX="0" refY="${s}" orient="auto" > <polygon points="0 0,${h} ${s}, 0 ${h}" fill="${o.color}" /> </marker> </defs> <path style="stroke-linecap: round !important; ${o.isDash ? `stroke-dasharray: ${o.strokeWidth * 3}` : ""}" stroke="${o.color}" id="${o.id}" d="M${o.x},${o.y} ${o.endX},${o.endY}" stroke-width="${o.strokeWidth}" marker-end="url(#${e})" /> </g> `; break; case o.type === "text": const l = o.textContent.split("‎"), b = []; for (let I = 0; I < l.length; I += 1) b.push(` ${o.isBulletTextMode ? `<tspan x="${o.x - o.fontSize}" y="${o.y + o.fontSize * I}" id="${o.id}" font-size="${o.fontSize / 2}">⬤</tspan>` : ""} <tspan id="${o.id}" x="${o.x}" y="${o.y + o.fontSize * I}"> ${l[I]} </tspan>`); t.content += ` ${this.computeTextElement(o, b, o.isBulletTextMode)} `; break; } }); } else this.shapes = this.shapes.filter((i) => i.id !== t.id); }, moveGroup(t) { t.content = "", t.x = this.copy(this.pointerPosition.x) - t.rectWidth / 2, t.y = this.copy(this.pointerPosition.y) - t.rectHeight / 2, t.source.forEach((i) => { switch (!0) { case i.type === "circle": t.content += ` <circle id="${i.id}" cx="${this.copy(this.pointerPosition.x) + i.diffX - t.rectWidth / 2}" cy="${this.copy(this.pointerPosition.y) + i.diffY - t.rectHeight / 2}" r="${i.circleRadius ? i.circleRadius : Number.MIN_VALUE}" fill="${i.isFilled ? i.color + i.alpha : "rgba(255,255,255,0.001)"}" stroke="${i.color + i.alpha}" stroke-width="${i.strokeWidth}" style="${i.isDash ? `stroke-dasharray: ${i.strokeWidth * 3}` : ""}" /> `; break; case i.type === "rect": t.content += ` <rect id="${this.isResizeMode ? "" : i.id}" x="${this.copy(this.pointerPosition.x) + i.diffX - t.rectWidth / 2}" y="${this.copy(this.pointerPosition.y) + i.diffY - t.rectHeight / 2}" fill="${i.isFilled ? i.color + i.alpha : "rgba(255,255,255,0.001)"}" height="${i.rectHeight}" width="${i.rectWidth}" stroke="${i.color + i.alpha}" stroke-width="${i.strokeWidth}" style="rx:1 !important; ry:1 !important; ${i.isDash ? `stroke-dasharray: ${i.strokeWidth * 3}` : ""}" /> `; break; case i.type === "arrow": const o = i.strokeWidth > 3 ? 5 : 10, h = i.strokeWidth > 3 ? 2.5 : 5, s = Date.now(); t.content += ` <g id="${i.id}"> <defs> <marker id="${s}" markerWidth="${o}" markerHeight="${o}" refX="0" refY="${h}" orient="auto" > <polygon points="0 0,${o} ${h}, 0 ${o}" fill="${i.color}" /> </marker> </defs> <path style="stroke-linecap: round !important; ${i.isDash ? `stroke-dasharray: ${i.strokeWidth * 3}` : ""}" stroke="${i.color}" id="${i.id}" d="M${this.copy(this.pointerPosition.x) + i.diffX - t.rectWidth / 2},${this.copy(this.pointerPosition.y) + i.diffY - t.rectHeight / 2} ${this.copy(this.pointerPosition.x) + i.diffEndX - t.rectWidth / 2},${this.copy(this.pointerPosition.y) + i.diffEndY - t.rectHeight / 2}" stroke-width="${i.strokeWidth}" marker-end="url(#${s})" /> </g> `; break; case i.type === "text": const e = i.textContent.split("‎"), l = []; for (let b = 0; b < e.length; b += 1) l.push(` ${i.isBulletTextMode ? `<tspan x="${this.copy(this.pointerPosition.x) + i.diffX - i.fontSize - t.rectWidth / 2}" y="${this.copy(this.pointerPosition.y) + i.diffY + i.fontSize * b - t.rectHeight / 2}" id="${i.id}" font-size="${i.fontSize / 2}">⬤</tspan>` : ""} <tspan id="${i.id}" x="${this.copy(this.pointerPosition.x) + i.diffX - t.rectWidth / 2}" y="${this.copy(this.pointerPosition.y) + i.diffY + i.fontSize * b - t.rectHeight / 2}"> ${e[b]} </tspan>`); t.content += ` ${this.computeTextElement(i, l, i.isBulletTextMode)} `; break; } }); }, chooseAction(t) { switch (t.preventDefault(), this.isMouseDown = !0, !0) { case this.isDrawMode: this.drawDown(); break; } }, chooseMove(t) { switch (t.preventDefault(), t.target.localName !== "svg" && (this.currentTarget = t.target), !0) { case (this.isMoveMode && this.isMouseDown): this.moveDown(); break; case (this.isResizeMode && this.isMouseDown): this.resize(); break; } }, computeCaretPosition(t) { switch (!0) { case t.textAlign === "middle": return `<path stroke="black" stroke-width="2" d="M${t.x},${t.y - t.fontSize} ${t.x},${t.y - t.fontSize - 15}" /> <path stroke="black" stroke-width="2" d="M${t.x - 3},${t.y - t.fontSize - 5} ${t.x},${t.y - t.fontSize} ${t.x + 3},${t.y - t.fontSize - 5}"/>`; case t.textAlign === "start": const i = t.isBulletTextMode ? t.fontSize : 0; return `<path d="M${t.x - 20 - i},${t.y - t.fontSize / 6} ${t.x - 5 - i},${t.y - t.fontSize / 6}" stroke="black" stroke-width="2" /> <path d="M${t.x - 10 - i},${t.y - t.fontSize / 3} ${t.x - 5 - i},${t.y - t.fontSize / 6} ${t.x - 10 - i},${t.y}" stroke="black" stroke-width="2">`; case t.textAlign === "end": return `<path d="M${t.x + 20},${t.y - t.fontSize / 6} ${t.x + 5},${t.y - t.fontSize / 6}" stroke="black" stroke-width="2" /> <path d="M${t.x + 10},${t.y - t.fontSize / 3} ${t.x + 5},${t.y - t.fontSize / 6} ${t.x + 10},${t.y}" stroke="black" stroke-width="2">`; default: return ""; } }, computeTextElement(t, i, o = !1) { switch (!0) { case t.textAlign === "start": return ` <g id="${t.id}"> <rect id="${t.id}" style="display:${this.lastSelectedShape && this.lastSelectedShape.id === t.id ? "initial" : "none"};" x="${t.x}" y="${t.y - 50}" height="${t.lines === 0 || t.lines === 1 ? t.fontSize * 4 : t.fontSize * 2 * t.lines}" width="100" fill="rgba(0,0,0,0)" /> <text style="user-select:none; height:100px;" id="${t.id}" x="${t.x}" y="${t.y}" text-anchor="${t.textAlign}" font-size="${t.fontSize}" fill="${t.color}" font-weight="${t.isBold ? "bold" : "normal"}" font-style="${t.isItalic ? "italic" : "normal"}" text-decoration="${t.isUnderline ? "underline" : "none"}" > ${i.join("")} </text> ${this.showCaret && this.lastSelectedShape && this.lastSelectedShape.id === t.id ? this.computeCaretPosition(t) : ""} ${this.includeDeleteButton(t, o)} </g> `; case t.textAlign === "middle": return ` <g id="${t.id}"> <rect id="${t.id}" style="display:${this.lastSelectedShape && this.lastSelectedShape.id === t.id ? "initial" : "none"};" x="${t.x - 50}" y="${t.y - 50}" height="${t.lines === 0 || t.lines === 1 ? t.fontSize * 4 : t.fontSize * 2 * t.lines}" width="100" fill="rgba(0,0,0,0)" /> <text style="user-select:none; height:100px;" id="${t.id}" x="${t.x}" y="${t.y}" text-anchor="${t.textAlign}" font-size="${t.fontSize}" fill="${t.color}" font-weight="${t.isBold ? "bold" : "normal"}" font-style="${t.isItalic ? "italic" : "normal"}" text-decoration="${t.isUnderline ? "underline" : "none"}" > ${i.join("")} </text> ${this.showCaret && this.lastSelectedShape && this.lastSelectedShape.id === t.id ? this.computeCaretPosition(t) : ""} ${this.includeDeleteButton(t)} </g> `; case t.textAlign === "end": return ` <g id="${t.id}"> <rect id="${t.id}" style="display:${this.lastSelectedShape && this.lastSelectedShape.id === t.id ? "initial" : "none"};" x="${t.x - 100}" y="${t.y - 50}" height="${t.lines === 0 || t.lines === 1 ? t.fontSize * 4 : t.fontSize * 2 * t.lines}" width="100" fill="rgba(0,0,0,0)" /> <text style="user-select:none; height:100px;" id="${t.id}" x="${t.x}" y="${t.y}" text-anchor="${t.textAlign}" font-size="${t.fontSize}" fill="${t.color}" font-weight="${t.isBold ? "bold" : "normal"}" font-style="${t.isItalic ? "italic" : "normal"}" text-decoration="${t.isUnderline ? "underline" : "none"}" > ${i.join("")} </text> ${this.showCaret && this.lastSelectedShape && this.lastSelectedShape.id === t.id ? this.computeCaretPosition(t) : ""} ${this.includeDeleteButton(t)} </g> `; default: return ""; } }, copy(t) { return JSON.parse(JSON.stringify(t)); }, clickShape(t) { const i = t.target.id; switch (!0) { case this.isDeleteMode: this.shapes = [...this.shapes].filter((o) => o.id !== i), this.lastSelectedShape = void 0; break; default: this.lastSelectedShape = this.shapes.find((o) => o.id === i); break; } }, deleteEmptyTextElement() { !this.lastSelectedShape || !this.lastSelectedShape.id.includes("text") || this.lastSelectedShape.textContent === "" && (this.shapes = this.shapes.filter( (t) => t.id !== this.lastSelectedShape.id ), this.lastSelectedShape = this.shapes.at(-1)); }, drawUp(t = !1) { if (!this.activeShape || !this.isDrawing) return; this.currentPointer.end = { x: this.pointerPosition.x, y: this.pointerPosition.y }; let i; this.shapes.length > 0 && this.currentTarget && (i = [...this.shapes].find( (b) => b.id === this.currentTarget.id )); let o, h, s; i && (o = i.x - this.currentPointer.end.x, h = i.y - this.currentPointer.end.y, s = Math.sqrt(o * o + h * h)); let e, l; t ? (e = Math.max(this.currentPointer.end.x, i.x), l = Math.min(this.currentPointer.end.x, i.x), Math.max(this.currentPointer.end.y, i.y), Math.min(this.currentPointer.end.y, i.y)) : (e = Math.max(this.currentPointer.end.x, this.currentPointer.start.x), l = Math.min(this.currentPointer.end.x, this.currentPointer.start.x), Math.max(this.currentPointer.end.y, this.currentPointer.start.y), Math.min(this.currentPointer.end.y, this.currentPointer.start.y)), this.$nextTick(() => { switch (!0) { case this.activeShape === "arrow": this.shapes.at(-1).endX = this.currentPointer.end.x, this.shapes.at(-1).endY = this.currentPointer.end.y; break; case this.activeShape === "circle": const b = 20; this.shapes.at(-1).circleRadius = this.isDrawingNewShape ? this.copy(e - l) + b : s + b; break; case this.activeShape === "line": this.shapes.at( -1 ).path += ` ${this.pointerPosition.x} ${this.pointerPosition.y} `; break; case ["rect", "group"].includes(this.activeShape): const I = 20; this.shapes.at(-1).rectWidth = this.copy(this.currentPointer.end.x - this.shapes.at(-1).x) > 0 ? this.copy(this.currentPointer.end.x - this.shapes.at(-1).x) : I, this.shapes.at(-1).rectHeight = this.copy(this.currentPointer.end.y - this.shapes.at(-1).y) > 0 ? this.copy(this.currentPointer.end.y - this.shapes.at(-1).y) : I; } }); }, drawDown() { if (this.isDrawing = !0, !this.activeShape && !this.isSelectMode || !this.isDrawing) return; this.isDrawingNewShape = !0, this.currentPointer.start = { x: this.pointerPosition.x, y: this.pointerPosition.y }; let t = `${this.isSelectMode ? "group" : this.activeShape}_${Math.random() * 1e4}_${Date.now()}`; switch (!0) { case this.activeShape === "arrow": this.shapes.push({ id: t, x: this.pointerPosition.x, y: this.pointerPosition.y, endX: this.pointerPosition.x, endY: this.pointerPosition.y, type: this.activeShape, color: this.copy(this.selectedColor), strokeWidth: this.copy(Math.abs(this.strokeSize)), isDash: this.copy(this.isDash) }), this.lastSelectedShape = this.shapes.at(-1); break; case this.activeShape === "circle": this.shapes.push({ alpha: this.options.circle.filled ? this.colorTransparency : "", id: t, color: this.copy(this.selectedColor), isFilled: this.copy(this.options.circle.filled), circleRadius: this.copy(this.options.circle.radius), circleStrokeWidth: this.copy(this.options.circle.strokeWidth), type: this.activeShape, x: this.pointerPosition.x, y: this.pointerPosition.y, strokeWidth: this.copy(Math.abs(this.strokeSize)), isDash: this.copy(this.isDash) }), this.lastSelectedShape = this.shapes.at(-1); break; case this.activeShape === "line": this.shapes.push({ alpha: this.copy(this.colorTransparency), id: t, x: this.pointerPosition.x, y: this.pointerPosition.y, type: this.activeShape, color: this.copy(this.selectedColor), strokeWidth: this.copy(Math.abs(this.strokeSize)), isDash: this.copy(this.isDash), path: `${this.pointerPosition.x} ${this.pointerPosition.y}` }), this.lastSelectedShape = this.shapes.at(-1); break; case this.activeShape === "rect": this.shapes.push({ alpha: this.options.rect.filled ? this.colorTransparency : "", id: t, color: this.copy(this.selectedColor), isFilled: this.copy(this.options.rect.filled), rectStrokeWidth: this.copy(this.options.rect.strokeWidth), rectHeight: this.copy(this.options.rect.height), rectWidth: this.copy(this.options.rect.width), type: this.activeShape, x: this.pointerPosition.x, y: this.pointerPosition.y, strokeWidth: this.copy(Math.abs(this.strokeSize)), isDash: this.copy(this.isDash) }), this.lastSelectedShape = this.shapes.at(-1); break; case this.activeShape === "group": this.shapes.push({ alpha: 1, id: `group_${Math.random() * 1e4}_${Date.now()}`, x: this.pointerPosition.x, y: this.pointerPosition.y, isFilled: !1, rectHeight: this.copy(this.options.rect.height), rectWidth: this.copy(this.options.rect.width), rectStrokeWidth: 1, type: "group", color: "grey", strokeWidth: 1, isDash: !0, content: "" }); break; } if ((this.pointerDownId !== -1 || !this.isDrawing) && (clearInterval(this.pointerDownId), this.pointerDownId = -1), this.pointerDownId === -1 && this.isDrawing) { this.pointerDownId = setInterval(this.drawUp, 1); return; } }, move(t) { if (!(!t || !t.id || t.type === "line")) switch (this.lastSelectedShape = t, !0) { case t.type === "arrow": t.x = this.copy(this.pointerPosition.x), t.y = this.copy(this.pointerPosition.y); break; case t.type === "circle": t.x = this.copy(this.pointerPosition.x), t.y = this.copy(this.pointerPosition.y); break; case t.type === "group": this.moveGroup(t); break; case t.type === "rect": t.x = this.copy(this.pointerPosition.x - t.rectWidth / 2), t.y = this.copy(this.pointerPosition.y - t.rectHeight / 2); break; case t.type === "text": const i = Array.from(document.getElementsByTagName("text")).find( (l) => l.id === t.id ); if (!i) return; const { x: o, y: h, width: s, height: e } = i.getBBox(); t.textAlign === "start" && (t.x = this.copy(this.pointerPosition.x - s / 2)), t.textAlign === "middle" && (t.x = this.copy(this.pointerPosition.x)), t.textAlign === "end" && (t.x = this.copy(this.pointerPosition.x + s / 2)), t.lines > 1 ? t.y = this.copy(this.pointerPosition.y - e / 3) : t.y = this.copy(this.pointerPosition.y + t.fontSize / 2); break; } }, moveDown() { if (!this.currentTarget || !this.currentTarget.id) return; const t = this.currentTarget.id, i = this.shapes.find((o) => o.id === t); this.shapes = this.shapes.filter((o) => o.id !== t), this.shapes.push(i), this.pointerDownId === -1 && t && this.move(i); }, print() { this.isPrinting = !0, this.isDeleteMode = !1, this.isMoveMode = !1, this.isResizeMode = !1, this.isTextMode = !1, this.isWriting = !1, this.isSelectMode = !1, this.activeShape = void 0, this.showCaret = !1, this.$nextTick(() => { const t = this.$refs.drawSvgContainer, i = { height: 851.89, width: 595.28 }; this.walkTheDOM(t, (o) => { o && o.nodeType === 1 && (o.setAttribute("font-family", "Helvetica"), o.style.fontFamily = "Helvetica", o.replaceWith(o)); }), k(t).then((o) => { const h = o.width, s = o.height, e = h / i.width * i.height; let l = s, b = 0; const I = i.width, g = 582.28 / h * s, S = o.toDataURL("image/png", 1), f = new p("", "pt", "a4"); if (l < e) f.addImage(S, "PNG", 0, 0, I, g, "", "FAST"); else for (; l > 0; ) f.addImage( S, "PNG", 0, b, I, g, "", "FAST" ), l -= e, b -= i.height - 24, l > 0 && f.addPage(); f.save(`${(/* @__PURE__ */ new Date()).toLocaleDateString()}_annotations.pdf`); }).finally(() => { this.isPrinting = !1, this.walkTheDOM(t, (o) => { o && o.nodeType === 1 && (o.setAttribute("font-family", this.FINAL_CONFIG.style.fontFamily), o.style.fontFamily = this.FINAL_CONFIG.style.fontFamily, o.replaceWith(o)); }); }); }); }, resetDraw() { this.isDrawing = !1, this.isMouseDown = !1, this.pointerDownId = -1, this.isSelectMode && this.groupShapes(), clearInterval(this.pointerDownId); }, resize() { this.isDrawingNewShape = !1; const t = this.currentTarget.id; if (!t) return; this.isDrawing = !0; const i = this.shapes.find((o) => o.id === t); this.activeShape = i.type, this.shapes = this.shapes.filter((o) => o.id !== t), this.shapes.push(i), this.drawUp(!0); }, setFillOfSelectedRect() { !this.lastSelectedShape || !this.lastSelectedShape.id.includes("rect") || (this.lastSelectedShape.isFilled = !this.lastSelectedShape.isFilled); }, setFillOfSelectedCircle() { !this.lastSelectedShape || !this.lastSelectedShape.id.includes("circle") || (this.lastSelectedShape.isFilled = !this.lastSelectedShape.isFilled); }, setColorOfSelectedShape() { this.lastSelectedShape && (this.lastSelectedShape.color = this.copy(this.selectedColor), !["arrow", "text"].includes(this.lastSelectedShape.id) && (this.lastSelectedShape.alpha = this.copy(this.colorTransparency))); }, setSelectedShapeToDash() { !this.lastSelectedShape || this.lastSelectedShape.type === "text" || (this.lastSelectedShape.isDash = this.copy(this.isDash)); }, setTransparencyOfSelectedShape() { !this.lastSelectedShape || ["arrow", "text"].includes(this.lastSelectedShape.id) || (this.lastSelectedShape.alpha = this.copy(this.colorTransparency)); }, setStrokeWidthOfSelectedShape() { !this.lastSelectedShape || !["arrow", "circle", "rect", "line"].includes(this.lastSelectedShape.type) || (this.lastSelectedShape.strokeWidth = this.copy(Math.abs(this.strokeSize))); }, setCurrentStyleOfSelectedText() { !this.lastSelectedShape || this.lastSelectedShape.type !== "text" || (this.lastSelectedShape.isBold = this.copy(this.isBold), this.lastSelectedShape.isItalic = this.copy(this.isItalic), this.lastSelectedShape.isUnderline = this.copy(this.isUnderline), this.lastSelectedShape.fontSize = this.copy(this.textFont), this.lastSelectedShape.isBulletTextMode = this.copy(this.isBulletTextMode)); }, setPointer(t) { t.preventDefault(); const o = this.$refs.mainSvg.getBoundingClientRect(); let h, s; t.touches && t.touches.length > 0 ? (h = t.touches[0].clientX, s = t.touches[0].clientY) : (h = t.clientX, s = t.clientY), this.pointerPosition.x = (h - o.left) / o.width * this.svgWidth, this.pointerPosition.y = (s - o.top) / o.height * this.svgHeight; }, setShapeTo(t) { if (this.showCaret = !1, this.deleteEmptyTextElement(), t === this.activeShape) { this.activeShape = void 0, this.isDrawMode = !1; return; } this.isDrawMode = !0, this.isDeleteMode = !1, this.isMoveMode = !1, this.isResizeMode = !1, this.isTextMode = !1, this.activeShape = t; }, toggleSummary() { this.isSummaryOpen = !this.isSummaryOpen, this.isSummaryOpen || (this.isMoveMode = !1, this.isResizeMode = !1, this.isTextMode = !1, this.isWriting = !1, this.activeShape = void 0, this.showCaret = !1, this.isDeleteMode = !1, this.isWriting = !1), this.$emit("toggleOpenState", { isOpen: this.isSummaryOpen }); }, walkTheDOM(t, i) { for (i(t), t = t.firstChild; t; ) this.walkTheDOM(t, i), t = t.nextSibling; }, save() { this.$emit("saveAnnotations", { shapes: this.shapes, lastSelectedShape: this.lastSelectedShape }); } } }, T = { class: "vue-ui-annotator" }, R = { "data-html2canvas-ignore": "" }, D = { class: "tool-selection", style: { "margin-top": "24px" } }, z = ["disabled"], H = ["disabled"], W = ["disabled"], P = ["disabled"], B = { style: { width: "80%" }, viewBox: "0 0 24 24" }, V = ["disabled"], E = { style: { width: "80%" }, viewBox: "0 0 2