UNPKG

vue-data-ui

Version:

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

578 lines (577 loc) 20.8 kB
import { Ot as e, X as t, q as n, t as r } from "./lib-Bttd6u5E.js"; import { t as i } from "./_plugin-vue_export-helper-B3ysoDQm.js"; import { t as a } from "./BaseIcon-BfndwIWE.js"; import { t as o } from "./ColorPicker--ayG2YHf.js"; import { Fragment as s, computed as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createVNode as f, guardReactiveProps as p, nextTick as ee, normalizeClass as m, normalizeProps as h, normalizeStyle as g, onBeforeUnmount as te, onMounted as ne, openBlock as _, ref as v, renderList as y, renderSlot as b, toDisplayString as x, unref as re, vModelText as ie, watch as S, withCtx as ae, withDirectives as oe, withModifiers as se } from "vue"; //#region src/atoms/NonSvgPenAndPaper.vue var ce = ["disabled"], le = [ "data-mode", "xmlns", "viewBox" ], ue = [ "cx", "cy", "r", "fill" ], de = [ "x1", "y1", "x2", "y2", "stroke", "stroke-width" ], fe = [ "x1", "y1", "x2", "y2", "stroke", "stroke-width", "marker-end" ], pe = [ "d", "stroke", "stroke-width" ], me = [ "x", "y", "fill", "font-size" ], he = ["x", "dy"], ge = [ "d", "stroke", "stroke-width" ], _e = /*#__PURE__*/ i({ __name: "NonSvgPenAndPaper", props: { parent: { type: HTMLElement }, backgroundColor: { type: String, default: "#FFFFFF" }, color: { type: String, default: "#2D353C" }, active: { type: Boolean, default: !1 }, isCursorPointer: { type: Boolean, default: !1 } }, emits: ["close"], setup(i, { emit: _e }) { let C = i, ve = _e, w = v([]), T = v([]), ye = v("0 0 0 0"), E = v(C.color), D = v(1), O = v(null), k = v(!1), A = v(null), j = v({ x: 0, y: 0 }), M = v([""]), N = v({ row: 0, col: 0 }), P = v(16), be = 1, F = [ "arrow", "text", "line", "draw" ], I = v(0), L = c(() => F[I.value]), R = v(null); v(null), v(null); let z = v(`arrow-${n()}`), B = v(`arrow-def-${n()}`), xe = { arrow: "plotArrow", text: "text", line: "plotLine", draw: "annotator" }; function Se() { I.value + 1 >= F.length ? I.value = 0 : I.value += 1; } function V() { return be++; } function Ce(e) { let t = J.value; if (!t) return { x: 0, y: 0 }; let n = t.createSVGPoint(), r = e.touches?.length || e.changedTouches?.length ? e.touches?.[0] || e.changedTouches?.[0] : null, i = r ? r.clientX : e.clientX, a = r ? r.clientY : e.clientY; n.x = i, n.y = a; let o = t.getScreenCTM()?.inverse(); return o ? n.matrixTransform(o) : { x: 0, y: 0 }; } function H(e) { if (!O.value || L.value !== "text" || k.value) return; let { x: t, y: n } = Ce(e); j.value = { x: t, y: n }, M.value = [""], N.value = { row: 0, col: 0 }; let r = document.createElementNS("http://www.w3.org/2000/svg", "text"); r.setAttribute("x", t), r.setAttribute("y", n), r.setAttribute("fill", E.value), r.setAttribute("font-size", P.value), r.setAttribute("font-family", "sans-serif"), r.setAttribute("class", "vue-data-ui-doodle"), r.setAttribute("dominant-baseline", "hanging"), r.setAttribute("pointer-events", "all"); let i = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); i.setAttribute("x", t), i.setAttribute("dy", "0"), i.textContent = "", r.appendChild(i), r.style.pointerEvents = "none", r.style.userSelect = "none", O.value.appendChild(r), A.value = r, k.value = !0, window.addEventListener("keydown", we), window.addEventListener("mousedown", De, !0), Te(), Ee(); } function we(e) { if (!k.value) return; let { row: t, col: n } = N.value, r = M.value.slice(), i = !1; if (e.key === "Enter") { let a = r[t], o = a.slice(0, n), s = a.slice(n); r.splice(t, 1, o, s), t += 1, n = 0, i = !0, e.preventDefault(); } else if (e.key === "Backspace") { if (n > 0) r[t] = r[t].slice(0, n - 1) + r[t].slice(n), --n, i = !0; else if (t > 0) { let e = r[t - 1].length; r[t - 1] += r[t], r.splice(t, 1), --t, n = e, i = !0; } e.preventDefault(); } else if (e.key === "Delete") n < r[t].length ? (r[t] = r[t].slice(0, n) + r[t].slice(n + 1), i = !0) : t < r.length - 1 && (r[t] += r[t + 1], r.splice(t + 1, 1), i = !0), e.preventDefault(); else if (e.key === "ArrowLeft") n > 0 ? --n : t > 0 && (--t, n = r[t].length), i = !0, e.preventDefault(); else if (e.key === "ArrowRight") n < r[t].length ? n += 1 : t < r.length - 1 && (t += 1, n = 0), i = !0, e.preventDefault(); else if (e.key === "ArrowUp") t > 0 && (--t, n = Math.min(n, r[t].length), i = !0), e.preventDefault(); else if (e.key === "ArrowDown") t < r.length - 1 && (t += 1, n = Math.min(n, r[t].length), i = !0), e.preventDefault(); else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) r[t] = r[t].slice(0, n) + e.key + r[t].slice(n), n += 1, i = !0, e.preventDefault(); else if (e.key === "Escape") { Oe(!0); return; } else e.key === "Tab" && e.preventDefault(); i && (M.value = r, N.value = { row: t, col: n }, Te(), Ee()); } function Te() { let e = A.value, { x: t, y: n } = j.value; for (; e.firstChild;) e.removeChild(e.firstChild); M.value.forEach((n, r) => { let i = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); i.setAttribute("x", t), i.setAttribute("dy", r === 0 ? "0" : `${P.value * 1.2}`), i.textContent = n.length ? n : "​", e.appendChild(i); }); } function Ee() { let e = O.value.querySelector(".vue-data-ui-svg-caret"); e && O.value.removeChild(e); let t = A.value; if (!t) return; let { x: n, y: r } = j.value, { row: i, col: a } = N.value, o = P.value, s = t.childNodes[i]; if (!s) return; let c = s.textContent.slice(0, a); c.endsWith(" ") && (c += "\xA0"); let l = document.createElementNS("http://www.w3.org/2000/svg", "text"); l.setAttribute("x", n), l.setAttribute("y", r), l.setAttribute("font-size", o), l.setAttribute("font-family", "sans-serif"), l.textContent = c || "", O.value.appendChild(l); let u = l.getBBox(); O.value.removeChild(l); let d = r + i * o * 1.2, f = n + u.width, p = document.createElementNS("http://www.w3.org/2000/svg", "rect"); p.setAttribute("x", f), p.setAttribute("y", d), p.setAttribute("width", 1), p.setAttribute("height", o), p.setAttribute("fill", E.value), p.setAttribute("class", "vue-data-ui-svg-caret"), O.value.appendChild(p); } function De(e) { if (A.value && !A.value.contains(e.target)) { let e = A.value.children; e.length === 1 && (e[0].textContent === "" || e[0].textContent === "​") && A.value.remove(), Oe(!1); } } function Oe(e = !1) { window.removeEventListener("keydown", we), window.removeEventListener("mousedown", De, !0); let t = O.value?.querySelector(".vue-data-ui-svg-caret"); t && O.value.removeChild(t); let n = M.value.every((e) => !e || e === "​"); e || n || w.value.push({ id: V(), type: "text", x: j.value.x, y: j.value.y, color: E.value, fontSize: P.value, lines: M.value.map((e) => e) }), A.value && O.value && O.value.contains(A.value) && O.value.removeChild(A.value), k.value = !1, A.value = null, M.value = [""], N.value = { row: 0, col: 0 }; } let U = c(() => e(C.color, .6)); function W({ width: e, height: t }) { ye.value = `0 0 ${e} ${t}`; } let G = v(null); ne(() => { ee(() => { if (C.parent) { G.value = new ResizeObserver((e) => { for (let t of e) { let { width: e, height: n } = t.contentRect; W({ width: e, height: n }); } }), G.value.observe(C.parent); let { width: e, height: t } = C.parent.getBoundingClientRect(); W({ width: e, height: t }); } }), O.value = J.value.querySelector("g"); }), te(() => { G.value && G.value.disconnect(); }), S(() => C.parent, (e) => { if (!e) return; let { width: t, height: n } = C.parent.getBoundingClientRect(); W({ width: t, height: n }); }, { immediate: !0 }), S(L, (e) => { J.value && (J.value.removeEventListener("mousedown", H), J.value.removeEventListener("touchstart", H), e === "text" && (J.value.addEventListener("mousedown", H), J.value.addEventListener("touchstart", H, { passive: !1 }))); }); let K = v(!1), q = v(""), J = v(null), Y = v(!1), ke = v(null); S(() => C.active, (e) => { J.value && (J.value.style.touchAction = e ? "none" : ""); }, { immediate: !0 }); function Ae(e) { if (e.cancelable && e.preventDefault(), L.value !== "draw" || !J.value) return; K.value = !0; let { x: t, y: n } = Q(e); q.value = `M ${t} ${n}`; } function je(e) { if (e.cancelable && e.preventDefault(), L.value !== "draw" || !K.value || !J.value) return; let { x: t, y: n } = Q(e); q.value += ` ${t} ${n}`; } function Me() { let e = J.value; if (!e) return; let t = e.querySelector(`defs#${B.value}`); if (t || (t = document.createElementNS(r, "defs"), t.setAttribute("id", B.value), e.appendChild(t)), t.querySelector(`#${z.value}`)) return; let n = document.createElementNS(r, "marker"); n.setAttribute("id", z.value), n.setAttribute("markerUnits", "strokeWidth"), n.setAttribute("markerWidth", "6"), n.setAttribute("markerHeight", "6"), n.setAttribute("refX", "4"), n.setAttribute("refY", "3"), n.setAttribute("orient", "auto"), n.setAttribute("viewBox", "0 0 6 6"); let i = document.createElementNS(r, "path"); i.setAttribute("d", `M 0 0 L 6 ${6 / 2} L 0 6 z`), i.setAttribute("fill", "context-stroke"), i.setAttribute("stroke", "none"), n.appendChild(i), t.appendChild(n); } function Ne(e) { if (e.cancelable && e.preventDefault(), !["line", "arrow"].includes(L.value) || !J.value || !O.value) return; L.value === "arrow" && Me(), Y.value = !0; let { x: t, y: n } = Q(e); ke.value = { x: t, y: n }, R.value = document.createElementNS(r, "line"), R.value.setAttribute("x1", t), R.value.setAttribute("y1", n), R.value.setAttribute("x2", t), R.value.setAttribute("y2", n), R.value.setAttribute("stroke", E.value), R.value.setAttribute("stroke-width", D.value), R.value.setAttribute("stroke-linecap", "round"), R.value.setAttribute("class", "vue-data-ui-doodle"), L.value === "arrow" && R.value.setAttribute("marker-end", `url(#${z.value})`), O.value.appendChild(R.value); } function Pe(e) { if (e.cancelable && e.preventDefault(), !["line", "arrow"].includes(L.value) || !Y.value || !R.value) return; let { x: t, y: n } = Q(e); R.value.setAttribute("x2", t), R.value.setAttribute("y2", n); } function X(e) { if (e?.cancelable && e.preventDefault(), !Y.value || !R.value) return; let { x: t, y: n } = Q(e); R.value.setAttribute("x2", t), R.value.setAttribute("y2", n), w.value.push({ id: V(), type: L.value, x1: parseFloat(R.value.getAttribute("x1")), y1: parseFloat(R.value.getAttribute("y1")), x2: t, y2: n, strokeWidth: D.value, color: E.value }), T.value = [], O.value.contains(R.value) && O.value.removeChild(R.value), R.value = null, ke.value = null, Y.value = !1; } function Fe(e) { let t = e.trim().split(/\s+/); if (t.length < 4) return e; let n = t.slice(1).map(Number); if (n.length % 2 != 0) return e; let r = Ie(n), i = [`M ${r[0]} ${r[1]}`]; for (let e = 2; e < r.length - 2; e += 2) { let t = r[e - 2], n = r[e - 1], a = r[e], o = r[e + 1], s = (t + a) / 2, c = (n + o) / 2; i.push(`Q ${t} ${n} ${s} ${c}`); } let a = r[r.length - 2], o = r[r.length - 1]; return i.push(`L ${a} ${o}`), i.join(" "); } function Ie(e, t = 1) { let n = [...e]; for (let r = 2; r < e.length - 2; r += 2) { let i = e[r], a = e[r + 1], o = e[r - 2], s = e[r - 1], c = e[r + 2], l = e[r + 3]; n[r] = i + t * ((o + c) / 2 - i), n[r + 1] = a + t * ((s + l) / 2 - a); } return n; } function Le(e) { let t = e.trim().split(/\s+/), n = "", r = "", i = null, a = null; for (let e = 0; e < t.length; e += 1) { let o = t[e]; if (isNaN(o)) { if (r = o, r === "M" || r === "L") i = parseFloat(t[++e]), a = parseFloat(t[++e]), n += `${r}${i} ${a}`; else if (r === "Q") { let r = parseFloat(t[++e]), o = parseFloat(t[++e]), s = parseFloat(t[++e]), c = parseFloat(t[++e]); n += r === i && o === a ? `t${s - i} ${c - a}` : `q${r - i} ${o - a} ${s - i} ${c - a}`, i = s, a = c; } } else { let s = parseFloat(o), c = parseFloat(t[++e]); if (r === "L") { let e = s - i, t = c - a; n += e === 0 ? `v${t}` : t === 0 ? `h${e}` : `l${e} ${t}`, i = s, a = c; } else if (r === "Q") { let r = s, o = c, l = parseFloat(t[++e]), u = parseFloat(t[++e]); n += r === i && o === a ? `t${l - i} ${u - a}` : `q${r - i} ${o - a} ${l - i} ${u - a}`, i = l, a = u; } } } return n; } function Z(e) { e?.cancelable && e.preventDefault(), L.value === "draw" && (K.value && (w.value.push({ id: V(), strokeWidth: D.value, path: Le(Fe(q.value)), color: E.value }), T.value = [], q.value = ""), K.value = !1); } function Q(e) { if (!J.value) return { x: 0, y: 0 }; let t = J.value.getBoundingClientRect(), n = e.touches?.length || e.changedTouches?.length ? e.touches?.[0] || e.changedTouches?.[0] : null, r = n ? n.clientX : e.clientX, i = n ? n.clientY : e.clientY; return { x: r - t.left, y: i - t.top }; } function Re() { if (w.value.length > 0) { let e = w.value.pop(); T.value.push(e); } } function ze() { if (T.value.length > 0) { let e = T.value.pop(); w.value.push(e); } } function Be() { w.value = [], T.value = []; } let $ = v(null); return (e, n) => (_(), u(s, null, [i.active ? (_(), u("div", { key: 0, "data-dom-to-png-ignore": "", class: m({ "vue-ui-pen-and-paper-actions": !0, visible: i.active }), style: g({ backgroundColor: i.backgroundColor }) }, [ d("button", { class: "vue-ui-pen-and-paper-action", style: g({ backgroundColor: i.backgroundColor, border: `1px solid ${U.value}`, cursor: i.isCursorPointer ? "pointer" : "default" }), onClick: n[0] ||= (e) => ve("close") }, [b(e.$slots, "annotator-action-close", {}, () => [f(a, { name: "close", stroke: i.color }, null, 8, ["stroke"])], !0)], 4), d("button", { class: m({ "vue-ui-pen-and-paper-action": !0 }), style: g({ padding: "0 !important", cursor: i.isCursorPointer ? "pointer" : "default" }) }, [f(o, { value: E.value, "onUpdate:value": n[1] ||= (e) => E.value = e, backgroundColor: i.backgroundColor, buttonBorderColor: U.value }, { "annotator-action-color": ae(({ color: t }) => [b(e.$slots, "annotator-action-color", h(p({ color: t })), void 0, !0)]), _: 3 }, 8, [ "value", "backgroundColor", "buttonBorderColor" ])], 4), d("button", { class: m(["vue-ui-pen-and-paper-action", { "vue-ui-pen-and-paper-action-active": L.value === "text" }]), onClick: n[2] ||= (e) => Se(), style: g({ backgroundColor: i.backgroundColor, border: `1px solid ${U.value}`, cursor: i.isCursorPointer ? "pointer" : "default" }) }, [b(e.$slots, "annotator-action-draw", h(p({ mode: L.value })), () => [f(a, { name: xe[L.value], stroke: i.color }, null, 8, ["name", "stroke"])], !0), d("div", { style: g({ position: "absolute", bottom: "-20px", color: U.value, width: "100%", textAlign: "center", fontSize: "12px" }) }, x(re(t)({ v: L.value === "text" ? P.value : D.value, s: "px", r: 1 })), 5)], 6), d("button", { class: m({ "vue-ui-pen-and-paper-action": !0, "vue-ui-pen-and-paper-action-disabled": !w.value.length }), disabled: !w.value.length, style: g({ backgroundColor: i.backgroundColor, border: `1px solid ${U.value}`, marginTop: "20px", cursor: i.isCursorPointer ? "pointer" : "default" }), onClick: Re }, [b(e.$slots, "annotator-action-undo", h(p({ disabled: !w.value.length })), () => [f(a, { name: "refresh", stroke: i.color }, null, 8, ["stroke"])], !0)], 14, ce), d("button", { class: m({ "vue-ui-pen-and-paper-action": !0, "vue-ui-pen-and-paper-action-disabled": !T.value.length }), style: g({ backgroundColor: i.backgroundColor, border: `1px solid ${U.value}`, cursor: i.isCursorPointer ? "pointer" : "default" }), onClick: ze }, [b(e.$slots, "annotator-action-redo", h(p({ disabled: !T.value.length })), () => [f(a, { name: "refresh", stroke: i.color, style: { transform: "scaleX(-1)" } }, null, 8, ["stroke"])], !0)], 6), d("button", { class: m([{ "vue-ui-pen-and-paper-action": !0, "vue-ui-pen-and-paper-action-disabled": !w.value.length }, "vue-ui-pen-and-paper-action"]), style: g({ backgroundColor: i.backgroundColor, border: `1px solid ${U.value}`, cursor: i.isCursorPointer ? "pointer" : "default" }), onClick: Be }, [b(e.$slots, "annotator-action-delete", h(p({ disabled: !w.value.length })), () => [f(a, { name: "trash", stroke: i.color }, null, 8, ["stroke"])], !0)], 6), L.value === "draw" ? oe((_(), u("input", { key: 0, ref_key: "range", ref: $, type: "range", class: "vertical-range", min: .5, max: 12, step: .1, "onUpdate:modelValue": n[3] ||= (e) => D.value = e, style: g({ accentColor: i.color }) }, null, 4)), [[ie, D.value]]) : l("", !0), L.value === "text" ? oe((_(), u("input", { key: 1, ref_key: "range", ref: $, type: "range", class: "vertical-range", min: 3, max: 48, step: .1, "onUpdate:modelValue": n[4] ||= (e) => P.value = e, style: g({ accentColor: i.color }) }, null, 4)), [[ie, P.value]]) : l("", !0) ], 6)) : l("", !0), (_(), u("svg", { "data-mode": L.value, ref_key: "svgElement", ref: J, xmlns: re(r), viewBox: ye.value, class: m({ "vue-ui-pen-and-paper": !0, inactive: !i.active }), onMousedown: n[5] ||= (e) => L.value === "draw" ? Ae(e) : L.value === "line" || L.value === "arrow" ? Ne(e) : null, onMousemove: n[6] ||= (e) => L.value === "draw" ? je(e) : L.value === "line" || L.value === "arrow" ? Pe(e) : null, onMouseup: n[7] ||= (e) => L.value === "draw" ? Z(e) : L.value === "line" || L.value === "arrow" ? X(e) : null, onMouseleave: n[8] ||= (e) => L.value === "draw" ? Z(e) : L.value === "line" || L.value === "arrow" ? X(e) : null, onTouchstart: n[9] ||= se((e) => L.value === "draw" ? Ae(e) : L.value === "line" || L.value === "arrow" ? Ne(e) : null, ["prevent"]), onTouchmove: n[10] ||= se((e) => L.value === "draw" ? je(e) : L.value === "line" || L.value === "arrow" ? Pe(e) : null, ["prevent"]), onTouchend: n[11] ||= (e) => L.value === "draw" ? Z(e) : L.value === "line" || L.value === "arrow" ? X(e) : null, onTouchcancel: n[12] ||= (e) => L.value === "draw" ? Z(e) : L.value === "line" || L.value === "arrow" ? X(e) : null }, [d("g", { ref_key: "G", ref: O }, [(_(!0), u(s, null, y(w.value, (e) => (_(), u(s, { key: e.id }, [e.path && e.path.replace("M", "").split(" ").length === 2 ? (_(), u("circle", { key: 0, cx: e.path.replace("M", "").split(" ")[0], cy: e.path.replace("M", "").split(" ")[1], r: e.strokeWidth / 2, fill: e.color }, null, 8, ue)) : e.type === "line" ? (_(), u("line", { key: 1, class: "vue-ui-pen-and-paper-path", x1: e.x1, y1: e.y1, x2: e.x2, y2: e.y2, stroke: e.color, "stroke-width": e.strokeWidth }, null, 8, de)) : e.type === "arrow" ? (_(), u("line", { key: 2, class: "vue-ui-pen-and-paper-path", x1: e.x1, y1: e.y1, x2: e.x2, y2: e.y2, stroke: e.color, "stroke-width": e.strokeWidth, "marker-end": `url(#${z.value})` }, null, 8, fe)) : e.path ? (_(), u("path", { key: 3, class: "vue-ui-pen-and-paper-path", d: e.path, stroke: e.color, "stroke-width": e.strokeWidth, fill: "none" }, null, 8, pe)) : e.type === "text" ? (_(), u("text", { key: 4, x: e.x, y: e.y, fill: e.color, "font-size": e.fontSize, "font-family": "sans-serif", "dominant-baseline": "hanging", class: "vue-ui-pen-and-paper-text" }, [(_(!0), u(s, null, y(e.lines, (t, n) => (_(), u("tspan", { key: n, x: e.x, dy: n === 0 ? "0" : e.fontSize * 1.2 }, x(t.length ? t : "​"), 9, he))), 128))], 8, me)) : l("", !0)], 64))), 128))], 512), K.value ? (_(), u("path", { key: 0, class: "vue-ui-pen-and-paper-path vue-ui-pen-and-paper-path-drawing", d: Fe(q.value), stroke: E.value, "stroke-width": D.value * 1.1, fill: "none" }, null, 8, ge)) : l("", !0)], 42, le))], 64)); } }, [["__scopeId", "data-v-42e6ba29"]]); //#endregion export { _e as default };