UNPKG

vue-data-ui

Version:

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

751 lines (750 loc) • 32.2 kB
import { isRef as Lt, ref as Ct, onMounted as Pt, watch as Rt, nextTick as Wt, unref as Vt } from "vue"; const et = "http://www.w3.org/2000/svg", yt = "http://www.w3.org/1999/xlink", Bt = 'system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif'; let At = /* @__PURE__ */ new WeakMap(); function gt(N) { let v = At.get(N); return v || (v = getComputedStyle(N), At.set(N, v)), v; } function Mt() { At = /* @__PURE__ */ new WeakMap(); } function P(N) { return document.createElementNS(et, N); } function wt(N) { return `${N}, ${Bt}`; } function Ot({ svg: N, // ref title: v, // computed legend: F, // computed legendItems: rt, // computed backgroundColor: ot, // computed stretchTitle: I = !1, // bool (when rotateX is applied on the svg like in VueUiWheel, title transform style needs to be compensated) titleEmbedded: at = !1 // when title is already part of the svg (VueUiChestnut) }) { const lt = Lt(N) ? N : Ct(N), nt = Ct(!1), W = [ "fill", "fill-opacity", "stroke", "stroke-width", "stroke-opacity", "opacity", "color", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-dasharray", "stroke-dashoffset", "font-family", "font-size", "font-style", "font-weight", "font-variant", "letter-spacing", "word-spacing", "text-anchor", "dominant-baseline", "shape-rendering", "vector-effect", "paint-order", "mix-blend-mode", "isolation", "filter", "clip-path", "mask", "transform", "transform-origin", "visibility", "display" ], j = /* @__PURE__ */ new Set(["font-family"]); async function b({ timeoutMs: e = 4e3, log: o = "warn" } = {}) { if (typeof window > "u" || typeof document > "u") return console.warn("SVG export only works in the browser."), null; const h = performance.now() + e, u = () => { const C = Vt(lt); return C && document.contains(C) ? C : null; }; let c = u(); if (c) return c; let t = !1; const S = (C) => { if (!t && C) try { C.disconnect(); } catch { } t = !0; }; let w; const A = new Promise((C) => { try { w = new MutationObserver(() => { const M = u(); M && (S(w), C(M)); }), w.observe(document.documentElement, { childList: !0, subtree: !0 }); } catch { C(null); } }); for (; performance.now() < h; ) { const C = await Promise.race([ A, new Promise((M) => requestAnimationFrame(M)) ]); if (await Wt(), c = u() || C, c) return S(w), c; } return S(w), console.warn("SVG element not found or not mounted (timed out)."), null; } Pt(async () => { try { await b(), nt.value = !0; } catch { nt.value = !1; } }), Rt(lt, async () => { try { await b(), nt.value = !0; } catch { nt.value = !1; } }); const f = /* @__PURE__ */ new Map(); function y(e) { if (f.has(e)) return f.get(e); const o = P("svg"); o.setAttribute("width", "0"), o.setAttribute("height", "0"), o.style.position = "absolute", o.style.left = "-99999px", o.style.top = "-99999px"; const h = P(e); o.appendChild(h), document.body.appendChild(o); const u = window.getComputedStyle(h), c = {}; for (const t of W) c[t] = u.getPropertyValue(t); return document.body.removeChild(o), f.set(e, c), c; } function $(e) { const o = gt(e), h = y(e.tagName.toLowerCase()), u = []; for (const c of W) { let t = o.getPropertyValue(c) || ""; const S = h[c] || ""; if (j.has(c)) { c === "font-family" && t && (t = wt(t)), t && u.push(`${c}:${t};`); continue; } t && t !== S && u.push(`${c}:${t};`); } return u.join(""); } function z(e, o) { e.getAttribute("width") && o.setAttribute("width", e.getAttribute("width")), e.getAttribute("height") && o.setAttribute("height", e.getAttribute("height")), e.getAttribute("viewBox") && o.setAttribute("viewBox", e.getAttribute("viewBox")); const h = [e, ...Array.from(e.querySelectorAll("*"))], u = [o, ...Array.from(o.querySelectorAll("*"))]; for (let c = 0; c < h.length; c += 1) { const t = h[c], S = u[c], w = $(t); w && S.setAttribute("style", w), ["fill", "stroke", "filter", "clip-path", "mask"].forEach((A) => { const C = t.getAttribute(A); C && S.setAttribute(A, C); }); } } function L(e) { const o = e.getAttribute("viewBox"); if (!o) return null; const [h, u, c, t] = o.split(/\s+|,/).map(Number); return [h, u, c, t].some((S) => Number.isNaN(S)) ? null : { minX: h, minY: u, width: c, height: t }; } function O(e) { e.getAttribute("xmlns") || e.setAttribute("xmlns", et), e.getAttribute("xmlns:xlink") || e.setAttribute("xmlns:xlink", yt), e.getAttribute("xml:space") || e.setAttribute("xml:space", "preserve"); } function it(e) { const o = document.createElement("div"); return o.style.position = "absolute", o.style.left = "-99999px", o.style.top = "-99999px", o.style.width = "0", o.style.height = "0", document.body.appendChild(o), o.appendChild(e), o; } function st(e) { try { e.remove(); } catch { } } function dt(e, o, h, u, c) { if (!v.value || !v.value.text) return 0; const t = { text: v.value.text || "", color: v.value.color || "#111", fontSize: v.value.fontSize || 20, bold: !!v.value.bold, textAlign: (v.value?.textAlign || "center").toLowerCase(), paddingLeft: v.value.paddingLeft ?? 0, paddingRight: v.value.paddingRight ?? 0, subtitle: v.value.subtitle || null }, S = P("g"); S.setAttribute("id", "__vdu_export_title"), e.appendChild(S); const w = h + t.paddingLeft, A = h + o - (t.paddingRight || 0), C = h + o / 2; let M = "start", X = w; t.textAlign === "center" ? (M = "middle", X = C) : t.textAlign === "right" && (M = "end", X = A); const D = u, T = Math.round(t.fontSize * 0.4), R = P("text"); R.setAttribute("x", String(X)), R.setAttribute("y", String(D + t.fontSize)), R.setAttribute("text-anchor", M), R.setAttribute("dominant-baseline", "ideographic"), R.setAttribute("style", `font-family:${c}; font-size:${t.fontSize}px; font-weight:${t.bold ? "700" : "400"}; fill:${t.color}; ${I ? "transform: scale(0.65, 1); transform-origin: center;" : ""}`), R.textContent = t.text, S.appendChild(R); let J = t.fontSize; if (t.subtitle && t.subtitle.text) { const E = { color: t.subtitle.color || "#666", text: t.subtitle.text, fontSize: t.subtitle.fontSize || Math.max(12, Math.round(t.fontSize * 0.8)), bold: !!t.subtitle.bold }, V = P("text"); V.setAttribute("x", String(X)), V.setAttribute("y", String(D + t.fontSize + T + E.fontSize)), V.setAttribute("text-anchor", M), V.setAttribute("dominant-baseline", "ideographic"), V.setAttribute("style", `font-family:${c}; font-size:${E.fontSize}px; font-weight:${E.bold ? "600" : "400"}; fill:${E.color}; ${I ? "transform: scale(0.65, 1); transform-origin: center;" : ""}`), V.textContent = E.text, S.appendChild(V), J += T + E.fontSize; } return J + Math.round(t.fontSize * 0.4); } function q(e, o, h, u, c) { if (!F.value || !F.value.show || !Array.isArray(rt.value) || !rt.value.length) return 0; const t = { bold: !!F.value.bold, backgroundColor: F.value.backgroundColor || "transparent", color: F.value.color || "#111", fontSize: F.value.fontSize || 14, paddingX: 14, paddingY: 10, itemGapX: 18, itemGapY: 12, markerSize: Math.max(8, Math.round((F.value.fontSize || 14) * 0.9)), markerTextGap: 8, lineHeight: Math.round((F.value.fontSize || 14) * 1.2), maxWidth: o }, S = P("g"); S.setAttribute("id", "__vdu_export_legend"), S.setAttribute("transform", `translate(${h}, ${u})`), e.appendChild(S); const w = P("rect"); w.setAttribute("rx", "6"), w.setAttribute("ry", "6"), w.setAttribute("fill", t.backgroundColor), S.appendChild(w); const A = P("g"); S.appendChild(A); const C = P("text"); C.setAttribute("x", "0"), C.setAttribute("y", "0"), C.setAttribute("style", `font-family:${c}; font-size:${t.fontSize}px; font-weight:${t.bold ? "600" : "400"}; opacity:0;`), A.appendChild(C); const M = (s) => (C.textContent = s || "", C.getComputedTextLength()), X = Math.max(1, t.maxWidth - t.paddingX * 2); function D(s, a) { const l = String(s || "").split(/\s+/).filter(Boolean), m = []; if (!l.length) return [""]; let d = l.shift(); for (; l.length; ) { const g = `${d} ${l[0]}`; if (M(g) <= a) d = g, l.shift(); else if (M(d) > a && d.length > 1) { let x = ""; for (const H of d) { const Q = x + H; if (M(Q) <= a) x = Q; else break; } const _ = d.slice(x.length); m.push(x), d = _.length ? _ : l.shift() || ""; } else m.push(d), d = l.shift() || ""; } d && m.push(d); const k = m[m.length - 1] || ""; if (M(k) > a && k.length > 1) { let g = ""; for (const _ of k) { const H = g + _; if (M(H) <= a) g = H; else break; } const x = k.slice(g.length); m[m.length - 1] = g, x && m.push(x); } return m; } const T = Math.PI / 180; function R(s, a, l, m, d = -90) { const k = d * T; let g = ""; for (let x = 0; x < l; x += 1) { const _ = k + x * 2 * Math.PI / l, H = s + Math.cos(_) * m, Q = a + Math.sin(_) * m; g += (x === 0 ? "M" : "L") + H + "," + Q; } return g + "Z"; } function J(s, a, l = 5, m, d) { const k = -90 * T; let g = ""; for (let x = 0; x < l * 2; x += 1) { const _ = x % 2 === 0 ? m : d, H = k + x * Math.PI / l, Q = s + Math.cos(H) * _, Y = a + Math.sin(H) * _; g += (x === 0 ? "M" : "L") + Q + "," + Y; } return g + "Z"; } const E = rt.value.map((s) => { const a = Math.max(1, X - (t.markerSize + t.markerTextGap)), l = D(s.name || "", a), m = Math.max(...l.map(M), 0), d = t.markerSize + t.markerTextGap + m, k = Math.max(t.markerSize, l.length * t.lineHeight); return { ...s, lines: l, itemW: d, itemH: k }; }), V = []; let n = { items: [], width: 0, height: 0 }; for (const s of E) { const a = (n.items.length ? t.itemGapX : 0) + s.itemW; n.items.length && n.width + a > X ? (V.push(n), n = { items: [s], width: s.itemW, height: s.itemH }) : (n.items.push(s), n.width += a, n.height = Math.max(n.height, s.itemH)); } n.items.length && V.push(n); let r = t.paddingY; for (const s of V) { let l = Math.max(t.paddingX, (t.maxWidth - s.width) / 2); for (let m = 0; m < s.items.length; m += 1) { const d = s.items[m], k = l + t.markerSize / 2, g = r + s.height / 2.5, x = t.markerSize / 2, _ = String(d.shape || "rect").toLowerCase(); if (_ === "circle") { const p = P("circle"); p.setAttribute("cx", String(k)), p.setAttribute("cy", String(g)), p.setAttribute("r", String(x * 0.8)), p.setAttribute("fill", d.color || "#000"), A.appendChild(p); } else if (_ === "rect" || _ === "square") { const p = P("path"); p.setAttribute("d", R(k, g, 4, x, -45)), p.setAttribute("fill", d.color || "#000"), A.appendChild(p); } else if (_ === "diamond") { const p = P("path"); p.setAttribute("d", R(k, g, 4, x, 45)), p.setAttribute("fill", d.color || "#000"), A.appendChild(p); } else if (_ === "triangle") { const p = P("path"); p.setAttribute("d", R(k, g, 3, x, -90)), p.setAttribute("fill", d.color || "#000"), A.appendChild(p); } else if (_ === "pentagon") { const p = P("path"); p.setAttribute("d", R(k, g, 5, x, -90)), p.setAttribute("fill", d.color || "#000"), A.appendChild(p); } else if (_ === "hexagon") { const p = P("path"); p.setAttribute("d", R(k, g, 6, x, 0)), p.setAttribute("fill", d.color || "#000"), A.appendChild(p); } else if (_ === "star") { const p = P("path"), tt = x, pt = x * 0.5; p.setAttribute("d", J(k, g, 5, tt, pt)), p.setAttribute("fill", d.color || "#000"), A.appendChild(p); } else { const p = P("rect"); p.setAttribute("x", String(l)), p.setAttribute("y", String(r + (s.height - t.markerSize) / 2)), p.setAttribute("width", String(t.markerSize)), p.setAttribute("height", String(t.markerSize)), p.setAttribute("fill", d.color || "#000"), A.appendChild(p); } const H = l + t.markerSize + t.markerTextGap, Q = r + (s.height - d.lines.length * t.lineHeight) / 2 + t.fontSize, Y = P("text"); Y.setAttribute("x", String(H)), Y.setAttribute("y", String(Q)), Y.setAttribute("style", `font-family:${c}; font-size:${t.fontSize}px; font-weight:${t.bold ? "600" : "400"}; fill:${t.color};`), Y.setAttribute("dominant-baseline", "ideographic"); let mt = !0; for (const p of d.lines) { const tt = P("tspan"); mt || tt.setAttribute("dy", String(t.lineHeight)), tt.setAttribute("x", String(H)), tt.textContent = p, Y.appendChild(tt), mt = !1; } A.appendChild(Y), l += d.itemW + (m < s.items.length - 1 ? t.itemGapX : 0); } r += s.height + t.itemGapY; } V.length && (r -= t.itemGapY); const i = r + t.paddingY; return w.setAttribute("x", "0"), w.setAttribute("y", "0"), w.setAttribute("width", String(t.maxWidth)), w.setAttribute("height", String(i)), C.remove(), i + Math.round(t.fontSize * 0.4); } function ht(e) { const o = e.cloneNode(!0); return o.querySelectorAll("script").forEach((h) => h.remove()), z(e, o), O(o), o; } function B(e) { const o = Array.from(e.childNodes).filter((c) => c.nodeType === 1 && c.nodeName.toLowerCase() === "defs"), h = Array.from(e.childNodes).filter((c) => !(c.nodeType === 1 && c.nodeName.toLowerCase() === "defs")), u = document.createElementNS(et, "g"); u.setAttribute("id", "__vdu_export_content"); for (const c of h) u.appendChild(c); for (const c of o) e.appendChild(c); return e.appendChild(u), u; } function K(e, o) { o <= 0 || e.setAttribute("transform", `translate(0, ${o})`); } function ct(e, o) { if (o <= 0) return; const h = L(e), u = e.getAttribute("height"); if (h) e.setAttribute("viewBox", `${h.minX} ${h.minY} ${h.width} ${h.height + o}`), u && e.setAttribute("height", String(Number(u) + o)); else if (u) e.setAttribute("height", String(Number(u) + o)); else { const c = e.getBBox(); e.setAttribute("viewBox", `0 0 ${Math.max(1, c.width)} ${Math.max(1, c.height + o)}`); } } function U(e) { const o = L(e); if (o) return o.width; const h = Number(e.getAttribute("width")); return !Number.isNaN(h) && h > 0 ? h : e.getBBox().width || 0; } function G(e) { const o = L(e); if (o) return o.height; const h = Number(e.getAttribute("height")); return !Number.isNaN(h) && h > 0 ? h : e.getBBox().height || 0; } async function ut(e) { const o = it(e); Mt(); try { if (document.fonts?.ready) try { await Promise.race([document.fonts.ready, new Promise((T) => setTimeout(T, 4e3))]); } catch { } const h = B(e), u = L(e), c = u ? u.minX : 0, t = u ? u.minY : 0, S = Math.max(1, U(e)), w = Math.max(1, G(e)), A = wt(gt(e).getPropertyValue("font-family") || ""); let M = (at ? null : dt(e, S, c, t, A)) ?? 0; const X = F && F.value && F.value.position ? String(F.value.position).toLowerCase() : "top"; F && F.value && F.value.show && X === "top" && (M += q(e, S, c, t + M, A)), K(h, M); let D = 0; F && F.value && F.value.show && X === "bottom" && (D += q(e, S, c, t + M + w, A)), ct(e, M + D), e.style.backgroundColor = ot.value ?? "#FFF", await Et(e, { mode: "raster" }), Tt(e, v.value.text ? -6 : -48); } finally { st(o), Mt(); } } async function Z() { const e = await b(), o = ht(e); await ut(o); const u = `<?xml version="1.0" standalone="no"?> ${new XMLSerializer().serializeToString(o)}`, c = new Blob([u], { type: "image/svg+xml;charset=utf-8" }), t = URL.createObjectURL(c), S = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(u)}`; return { blob: c, url: t, text: u, dataUrl: S }; } async function ft(e) { const { url: o } = await Z(), h = e || v.value?.text || "chart", u = document.createElement("a"); u.href = o, u.download = h.endsWith(".svg") ? h : `${h}.svg`, document.body.appendChild(u), u.click(), document.body.removeChild(u), URL.revokeObjectURL(o); } return { ready: nt, getSvg: Z, exportSvg: ft }; } function Tt(N, v = -50) { if (!v) return; const F = N.getAttribute("viewBox"), rt = (W) => { if (!W) return; const j = N.getAttribute("height"); if (!j) return; const b = /^(\d+(\.\d+)?)(px)?$/.exec(j.trim()); if (!b) return; const f = parseFloat(b[1]) || 0, y = Math.max(1, f + W); N.setAttribute("height", String(y)); }; if (F) { const W = F.trim().split(/\s+|,/).map(Number); if (W.length !== 4 || W.some((O) => !Number.isFinite(O))) return; const [j, b, f, y] = W, $ = b + v, z = -v, L = Math.max(1, y + z); N.setAttribute("viewBox", `${j} ${$} ${f} ${L}`), rt(z); return; } let ot = Number(N.getAttribute("width")), I = Number(N.getAttribute("height")); if (!(ot > 0 && I > 0)) { const W = N.getBBox(); ot = Math.max(1, W.width || 1), I = Math.max(1, W.height || 1); } const at = v, lt = -v, nt = Math.max(1, I + lt); N.setAttribute("viewBox", `0 ${at} ${ot} ${nt}`), (function() { const j = N.getAttribute("height"); if (!j) return; const b = /^(\d+(\.\d+)?)(px)?$/.exec(j.trim()); if (!b) return; const f = parseFloat(b[1]) || 0, y = Math.max(1, f + lt); N.setAttribute("height", String(y)); })(); } async function Et(N, { mode: v = "raster" } = {}) { const F = Array.from(N.querySelectorAll("foreignObject")); if (!F.length) return { converted: 0, rasterized: 0, skipped: 0, errors: 0 }; let rt = 0, ot = 0, I = 0, at = 0; const lt = (b) => ["div", "p", "span", "strong", "em", "b", "i", "br"].includes(b), nt = (b) => { try { const f = b.firstElementChild; if (!f) return !1; const y = [f]; for (; y.length; ) { const $ = y.pop(); if ($.nodeType === 3) continue; if ($.nodeType !== 1) return !1; const z = ($.tagName || "").toLowerCase(); if (!lt(z) || $.querySelector?.("img,svg,canvas,video,foreignObject")) return !1; for (const L of Array.from($.childNodes)) y.push(L); } return !0; } catch { return !1; } }; function W(b) { try { const f = b.firstElementChild; if (!f) return null; const y = (n, r = 0) => Number.isFinite(+n) ? +n : r, $ = y(b.getAttribute("x"), 0), z = y(b.getAttribute("y"), 0); let L = y(b.getAttribute("width"), NaN); if (!Number.isFinite(L) || L <= 0) { const n = b.getBBox?.(); L = Math.max(1, y(n?.width, 0)); } const O = (n, r) => { if (!n) return Math.round(r * 1.2); const i = n.trim().toLowerCase(); if (i === "normal") return Math.round(r * 1.2); if (i.endsWith("px")) return parseFloat(i) || Math.round(r * 1.2); if (i.endsWith("%")) return parseFloat(i) / 100 * r || Math.round(r * 1.2); if (i.endsWith("em")) return (parseFloat(i) || 1) * r; if (i.endsWith("rem")) { const a = parseFloat(getComputedStyle(document.documentElement).fontSize) || r; return (parseFloat(i) || 1) * a; } const s = Number(i); return Number.isFinite(s) ? s * r : Math.round(r * 1.2); }, it = (n) => { const r = (s) => { const a = (s || "").trim().toLowerCase(); if (a.endsWith("px")) return parseFloat(a) || 0; if (a.endsWith("rem")) { const m = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16; return (parseFloat(a) || 0) * m; } if (a.endsWith("em")) { const m = parseFloat(getComputedStyle(document.body).fontSize) || 16; return (parseFloat(a) || 0) * m; } const l = Number(a); return Number.isFinite(l) ? l : 0; }, i = (n || "").split(/\s+/).map(r).filter(Number.isFinite); return i.length ? i.length === 1 ? [i[0], i[0], i[0], i[0]] : i.length === 2 ? [i[0], i[1], i[0], i[1]] : i.length === 3 ? [i[0], i[1], i[2], i[1]] : [i[0], i[1], i[2], i[3]] : [0, 0, 0, 0]; }, st = (n, r) => { const i = gt(n); let s = i.getPropertyValue("font-family") || r?.ff || "system-ui"; s = wt(s); let a = parseFloat(i.getPropertyValue("font-size")); Number.isFinite(a) || (a = r?.fs || 14); const l = i.getPropertyValue("font-weight") || r?.fw || "400", m = i.getPropertyValue("font-style") || r?.fsty || "normal", d = i.getPropertyValue("font-stretch") || r?.fstc || "normal", k = i.getPropertyValue("letter-spacing") || r?.lsp || "normal", g = i.getPropertyValue("word-spacing") || r?.wsp || "0px", x = i.getPropertyValue("font-kerning") || r?.kern || "auto", _ = i.getPropertyValue("font-variant-ligatures") || r?.liga || "normal", H = i.getPropertyValue("text-transform") || r?.ttfm || "none", Q = i.getPropertyValue("color") || r?.fill || "#000", Y = i.getPropertyValue("line-height"), mt = !Y || Y.trim().toLowerCase() === "normal" ? r?.lh ?? Math.round(a * 1.2) : O(Y, a), p = (i.getPropertyValue("text-align") || r?.ta || "start").trim().toLowerCase(); let tt = parseFloat(i.getPropertyValue("padding-top")) || 0, pt = parseFloat(i.getPropertyValue("padding-right")) || 0, bt = parseFloat(i.getPropertyValue("padding-bottom")) || 0, xt = parseFloat(i.getPropertyValue("padding-left")) || 0; const St = i.getPropertyValue("padding"); if (St && tt === 0 && pt === 0 && bt === 0 && xt === 0) { const [kt, Ft, _t, zt] = it(St); tt = kt, pt = Ft, bt = _t, xt = zt; } const Nt = parseFloat(i.getPropertyValue("border-left-width")) || 0, vt = parseFloat(i.getPropertyValue("border-right-width")) || 0, $t = i.getPropertyValue("box-sizing") || "content-box"; return { ff: s, fs: a, fw: l, fsty: m, fstc: d, lsp: k, wsp: g, kern: x, liga: _, ttfm: H, fill: Q, lh: mt, ta: p, padL: xt, padR: pt, padT: tt, padB: bt, bL: Nt, bR: vt, box: $t }; }, dt = (n) => /^(div|p|section|article|ul|ol|li|h[1-6])$/.test(n), q = { __para__: !0 }, ht = { __br__: !0 }, B = [], K = st(f), ct = (n, r, i) => { if (n.nodeType === 3) { const m = (n.nodeValue || "").replace(/\s+/g, " ").trim(); m && B.push({ text: m, style: r, path: i.slice() }); return; } if (n.nodeType !== 1) return; const s = n.tagName.toLowerCase(); if (s === "br") { B.push({ ...ht, path: i.slice() }); return; } const a = st(n, r); i.push(n); for (const l of Array.from(n.childNodes)) ct(l, a, i); i.pop(), dt(s) && B.push({ ...q, path: i.slice() }); }; for (ct(f, K, [f]); B.length && (B.at(-1).__para__ || B.at(-1).__br__); ) B.pop(); if (!B.length) return null; const U = B.filter((n) => !n.__para__ && !n.__br__), G = (() => { if (!U.length) return [f]; const n = U.map((s) => s.path), r = Math.min(...n.map((s) => s.length)); let i = 0; for (; i < r; ) { const s = n[0][i]; if (n.every((a) => a[i] === s)) i += 1; else break; } return n[0].slice(0, Math.max(1, i)); })(), ut = G[G.length - 1] || f, Z = st(ut); let ft = 0, e = 0, o = 0; for (const n of G) { const r = st(n); ft += r.padL, e += r.padR, o += r.padT; } const h = [Math.max(1, L - ft - e)]; for (const n of G) try { const r = gt(n); if (n.clientWidth && n.clientWidth > 0) { const a = parseFloat(r.paddingLeft) || 0, l = parseFloat(r.paddingRight) || 0, m = Math.max(1, n.clientWidth - a - l); h.push(m); } const i = r.width, s = parseFloat(i); if (Number.isFinite(s) && s > 0) { const a = r.boxSizing || r.getPropertyValue("box-sizing") || "content-box", l = parseFloat(r.paddingLeft) || 0, m = parseFloat(r.paddingRight) || 0, d = parseFloat(r.borderLeftWidth) || 0, k = parseFloat(r.borderRightWidth) || 0, g = a === "border-box" ? Math.max(1, s - l - m - d - k) : Math.max(1, s); h.push(g); } } catch { } let u = Math.floor(Math.min(...h.filter(Number.isFinite))) - 1; u > 0 || (u = 1); let c = "start", t = $ + ft; Z.ta === "center" ? (c = "middle", t = $ + ft + u / 2) : (Z.ta === "right" || Z.ta === "end") && (c = "end", t = $ + (L - e)); const S = b.ownerSVGElement || b.closest("svg"), w = document.createElementNS(et, "text"); w.setAttribute("x", String(t)), w.setAttribute("y", String(z + o)), w.setAttribute("text-anchor", c), w.setAttribute("dominant-baseline", "text-before-edge"), w.setAttribute("xml:space", "preserve"); const A = document.createElementNS(et, "text"); A.setAttribute("x", "0"), A.setAttribute("y", "0"), A.setAttribute("opacity", "0"), (S || b).appendChild(A); const C = (n) => `font-family:${n.ff}; font-size:${n.fs}px; font-weight:${n.fw}; font-style:${n.fsty}; font-stretch:${n.fstc}; letter-spacing:${n.lsp}; word-spacing:${n.wsp}; font-kerning:${n.kern}; font-variant-ligatures:${n.liga}; text-transform:${n.ttfm};`, M = (n, r) => (A.textContent = n || "", A.setAttribute("style", C(r)), A.getComputedTextLength()), X = (n) => M(" ", n), D = []; let T = [], R = 0; const J = () => { T.length && D.push({ segs: T.slice() }), T = [], R = 0; }, E = (n, r, i) => { let s = M(n, r); if (i) { const a = X(r); s += a, T.push({ text: " ", ...r, w: a, isSpace: !0 }); } T.push({ text: n, ...r, w: s }), R += s; }, V = (n, r, i) => { let s = ""; for (const a of n) { const l = s + a; if (M(l, r) <= i) s = l; else break; } return s || n[0] || ""; }; for (const n of B) { if (n.__para__ || n.__br__) { J(); continue; } const r = n.style, i = n.text.split(/(\s+)/).filter((l) => l.length > 0), s = (l, m) => { if (!l) return; const d = Math.max(1, u), k = M(l, r) + (m ? X(r) : 0); if (T.length === 0) if (k <= d) E(l, r, !1); else { let g = l; for (; g; ) { const x = V(g, r, d); E(x, r, !1), g = g.slice(x.length), g && J(); } } else if (R + k <= d) E(l, r, m); else if (J(), M(l, r) <= d) E(l, r, !1); else { let g = l; for (; g; ) { const x = V(g, r, d); E(x, r, !1), g = g.slice(x.length), g && J(); } } }; let a = !1; for (const l of i) { if (/^\s+$/.test(l)) { a = !0; continue; } s(l, a), a = !1; } } J(); for (let n = 0; n < D.length; n += 1) { const r = D[n].segs, i = Math.max(...r.map((a) => a.fs || Z.fs), Z.fs); let s = !0; for (const a of r) { const l = document.createElementNS(et, "tspan"); s && (l.setAttribute("x", String(t)), n > 0 && l.setAttribute("dy", String(i)), s = !1), l.setAttribute("style", `${C(a)} fill:${a.fill};`), l.textContent = a.text, w.appendChild(l); } if (!r.length && n > 0) { const a = document.createElementNS(et, "tspan"); a.setAttribute("x", String(t)), a.setAttribute("dy", String(i)), a.textContent = "", w.appendChild(a); } } try { A.remove(); } catch { } return w; } catch { return null; } } const j = (b) => { try { const f = document.createElement("div"); f.style.position = "absolute", f.style.left = "-99999px", f.style.top = "-99999px", f.style.visibility = "hidden", f.style.pointerEvents = "none", f.style.width = "auto", f.style.height = "auto"; const y = b.cloneNode(!0); y.style.width = "auto", y.style.height = "auto", y.style.display = "inline-block", y.style.maxWidth = "none", y.style.maxHeight = "none", y.style.boxSizing = "content-box", document.body.appendChild(f), f.appendChild(y); const $ = y.getBoundingClientRect(), z = Math.ceil($.width || y.scrollWidth || 0), L = Math.ceil($.height || y.scrollHeight || 0); return f.remove(), { w: Math.max(1, z), h: Math.max(1, L) }; } catch { return { w: 0, h: 0 }; } }; for (const b of F) try { if (b.hasAttribute("data-no-svg-export")) { b.remove(), I += 1; continue; } if (nt(b)) { const f = W(b); if (f) { b.parentNode.replaceChild(f, b), rt += 1; continue; } } I += 1; } catch { at += 1; } if (v === "raster") { const b = Array.from(N.querySelectorAll("foreignObject")); for (const f of b) try { if (f.hasAttribute("data-no-svg-export")) { f.remove(), I += 1; continue; } await new Promise((G) => requestAnimationFrame(G)); const y = f.getBBox(); let $ = Math.max(1, Math.ceil(y.width)), z = Math.max(1, Math.ceil(y.height)); const L = f.firstElementChild; if (L) { const G = j(L), ut = parseFloat(f.getAttribute("width") || "0") || 0, Z = parseFloat(f.getAttribute("height") || "0") || 0; $ = Math.max($, ut, G.w), z = Math.max(z, Z, G.h); } if (!($ > 0 && z > 0)) { I += 1; continue; } const O = document.createElementNS(et, "svg"); O.setAttribute("xmlns", et), O.setAttribute("xmlns:xlink", yt), O.setAttribute("width", String($)), O.setAttribute("height", String(z)), O.setAttribute("viewBox", `0 0 ${$} ${z}`); const it = f.cloneNode(!0); it.setAttribute("x", "0"), it.setAttribute("y", "0"), it.setAttribute("width", String($)), it.setAttribute("height", String(z)), O.appendChild(it); const st = new XMLSerializer().serializeToString(O), dt = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(st), q = document.createElement("canvas"), ht = 2; q.width = Math.max(1, Math.floor($ * ht)), q.height = Math.max(1, Math.floor(z * ht)); const B = q.getContext("2d"), K = new Image(); K.decoding = "sync", K.crossOrigin = "anonymous", await new Promise((G, ut) => { K.onload = G, K.onerror = ut, K.src = dt; }), B.drawImage(K, 0, 0, q.width, q.height); const ct = q.toDataURL("image/png"), U = document.createElementNS(et, "image"); U.setAttributeNS(yt, "href", ct), U.setAttribute("href", ct), U.setAttribute("x", f.getAttribute("x") || String(y.x)), U.setAttribute("y", f.getAttribute("y") || String(y.y)), U.setAttribute("width", String($)), U.setAttribute("height", String(z)), f.parentNode.replaceChild(U, f), ot += 1; } catch { at += 1; } } return { converted: rt, rasterized: ot, skipped: I, errors: at }; } export { Ot as u };