UNPKG

vue-data-ui

Version:

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

621 lines (620 loc) • 24.9 kB
import { useCssVars as De, computed as d, defineAsyncComponent as O, ref as h, shallowRef as ge, onMounted as Re, onBeforeUnmount as Me, watch as Be, createElementBlock as i, openBlock as n, unref as s, normalizeStyle as _, normalizeClass as z, createBlock as N, createCommentVNode as b, createSlots as Ee, withCtx as g, renderSlot as m, normalizeProps as E, guardReactiveProps as V, createVNode as Ve, createElementVNode as w, mergeProps as J, Fragment as U, renderList as G, toDisplayString as j, createTextVNode as Ue, nextTick as Ge } from "vue"; import { u as je, c as He, o as Xe, e as pe, g as qe, d as Ye, l as We, i as H, f as X, X as Je, F as Ke, E as K, a as Qe, q as Ze, r as et } from "./index-BLtEpj8j.js"; import { u as ke } from "./useNestedProp-Bw1KcAmj.js"; import { u as tt } from "./usePrinter-DnRwTdvS.js"; import { t as at, u as lt } from "./useResponsive-DfdjqQps.js"; import { u as st } from "./useUserOptionState-BIvW1Kz7.js"; import { u as ot } from "./useChartAccessibility-9icAAmYg.js"; import nt from "./Title-DkG60EPg.js"; import rt from "./img-D-vWHxhM.js"; import { _ as ut } from "./_plugin-vue_export-helper-CHgC5LLL.js"; const it = ["id"], ct = ["xmlns", "viewBox"], vt = ["width", "height"], dt = ["id"], ht = ["stop-color"], ft = ["stop-color"], bt = ["stop-color"], mt = ["stroke", "stroke-width"], yt = ["stroke", "stroke-width"], gt = ["x", "y", "font-size", "fill", "font-weight"], pt = ["points", "fill"], kt = ["stroke", "stroke-width", "rx"], Ct = ["x", "y", "font-size", "fill", "font-weight"], wt = ["x", "y", "font-size", "fill", "font-weight"], $t = { key: 5, class: "vue-data-ui-watermark" }, xt = ["innerHTML"], Lt = { __name: "vue-ui-funnel", props: { config: { type: Object, default() { return {}; } }, dataset: { type: Array, default() { return []; } } }, setup(Ce, { expose: we }) { De((t) => ({ 83613044: Pe.value })); const $e = O(() => import("./vue-ui-accordion-B6Svdk-2.js")), xe = O(() => import("./DataTable-CS_V_Adx.js")), Le = O(() => import("./PackageVersion-CnRyWKP-.js")), _e = O(() => import("./PenAndPaper-7BWf7zgA.js")), Ae = O(() => import("./vue-ui-skeleton-CsMU8DwQ.js")), Te = O(() => import("./UserOptions-DGw0HvSp.js")), { vue_ui_funnel: Se } = je(), y = Ce, $ = h(null), P = h(He()), Q = h(0), Z = h(0), ee = h(0), te = h(null), ae = h(null), le = h(null), C = ge(null), A = ge(null), x = h(!1), T = d(() => !!y.dataset && y.dataset.length); Re(se); function se() { if (Xe(y.dataset) ? pe({ componentName: "VueUiFunnel", type: "dataset" }) : y.dataset.forEach((t, l) => { qe({ datasetObject: t, requiredAttributes: ["name", "value"] }).forEach((a) => { T.value = !1, pe({ componentName: "VueUiFunnel", type: "datasetSerieAttribute", property: a, index: l }); }); }), e.value.responsive) { const t = at(() => { const { width: l, height: a } = lt({ chart: $.value, title: e.value.style.chart.title.text ? le.value : null, source: ae.value, noTitle: te.value }); requestAnimationFrame(() => { v.value.height = a, v.value.width = l, k.value = he(), e.value.responsiveProportionalSizing ? (c.value.circles = K({ relator: Math.min(l, a), adjuster: 600, source: e.value.style.chart.circles.dataLabels.fontSize, threshold: 10, fallback: 10 }), c.value.names = K({ relator: Math.min(l, a), adjuster: 600, source: e.value.style.chart.bars.dataLabels.name.fontSize, threshold: 10, fallback: 10 }), c.value.values = K({ relator: Math.min(l, a), adjuster: 600, source: e.value.style.chart.bars.dataLabels.value.fontSize, threshold: 10, fallback: 10 })) : (c.value.circles = e.value.style.chart.circles.dataLabels.fontSize, c.value.names = e.value.style.chart.bars.dataLabels.name.fontSize, c.value.values = e.value.style.chart.bars.dataLabels.value.fontSize); }); }); C.value && (A.value && C.value.unobserve(A.value), C.value.disconnect()), C.value = new ResizeObserver(t), A.value = $.value.parentNode, C.value.observe(A.value); } } Me(() => { C.value && (A.value && C.value.unobserve(A.value), C.value.disconnect()); }); function oe() { const t = ke({ userConfig: y.config, defaultConfig: Se }); return t.theme ? { ...ke({ userConfig: Qe.vue_ui_funnel[t.theme] || y.config, defaultConfig: t }) } : t; } const e = d({ get: () => oe(), set: (t) => t }), { userOptionsVisible: q, setUserOptionsVisibility: ne, keepUserOptionState: re } = st({ config: e.value }), { svgRef: ue } = ot({ config: e.value.style.chart.title }); Be(() => y.config, (t) => { e.value = oe(), q.value = !e.value.userOptions.showOnChartHover, se(), Z.value += 1, ee.value += 1, c.value.circles = e.value.style.chart.circles.dataLabels.fontSize, c.value.names = e.value.style.chart.bars.dataLabels.name.fontSize, c.value.values = e.value.style.chart.bars.dataLabels.value.fontSize, I.value.showTable = e.value.table.show; }, { deep: !0 }); const { isPrinting: ie, isImaging: ce, generatePdf: ve, generateImage: de } = tt({ elementId: `funnel_${P.value}`, fileName: e.value.style.chart.title.text || "vue-ui-funnel", options: e.value.userOptions.print }), Oe = d(() => e.value.userOptions.show && !e.value.style.chart.title.text), I = h({ showTable: e.value.table.show }), c = h({ circles: e.value.style.chart.circles.dataLabels.fontSize, names: e.value.style.chart.bars.dataLabels.name.fontSize, values: e.value.style.chart.bars.dataLabels.value.fontSize }), v = d({ get: () => ({ height: e.value.style.chart.height, width: e.value.style.chart.width }), set: (t) => t }), p = d(() => T.value ? y.dataset.map((t, l) => ({ ...t, color: t.color ? Ye(t.color) : We(e.value.style.chart.bars.defaultColor, l / y.dataset.length) })) : []); setTimeout(() => { x.value = !0; }, p.value.length * 150); function he() { const t = e.value.style.chart.padding.left, l = e.value.style.chart.padding.top; return { left: t, top: l, right: v.value.width - e.value.style.chart.padding.right, bottom: v.value.height - e.value.style.chart.padding.bottom, width: v.value.width - t - e.value.style.chart.padding.right, height: v.value.height - l - e.value.style.chart.padding.bottom }; } const k = h(he()), S = d(() => k.value.height / y.dataset.length), L = d(() => S.value * e.value.style.chart.bars.gapRatio), fe = d(() => k.value.width * e.value.style.chart.barCircleSpacingRatio), r = d(() => p.value.map((t, l) => { const a = S.value - L.value, o = k.value.top + L.value / 2 * l + (S.value - L.value / 2) * l + L.value / 2, f = t.value / p.value[0].value, u = (k.value.width - a - fe.value) * (t.value / p.value[0].value); return { ...t, cx: k.value.left + a / 2, cy: o + a / 2, datapointIndex: l, fill: t.color, height: Math.max(a, 0), proportion: f, r: Math.max(a / 2, 0), width: Math.max(u, 0), x: k.value.left + a + fe.value, y: o }; })), ze = d(() => { const t = r.value.map((l) => `${l.x + l.width},${l.y + (S.value - L.value) / 2}`); return `${r.value[0].x},${r.value[0].y + (S.value - L.value) / 2} ${t.toString()} ${r.value.at(-1).x},${r.value.at(-1).y + (S.value - L.value) / 2}`; }), Ne = d(() => ({ x1: r.value[0].cx, y1: r.value[0].cy, x2: r.value.at(-1).cx, y2: r.value.at(-1).cy })), F = h(!1); function be(t) { F.value = t, Q.value += 1; } const Pe = d(() => `${p.value.length * 150}ms`), M = h(!1); function Y() { M.value = !M.value; } function me() { I.value.showTable = !I.value.showTable; } const D = d(() => { const t = p.value.map((a) => ({ name: a.name, color: a.color })), l = p.value.map((a) => a.value); return { head: t, body: l }; }), B = d(() => { const t = [ e.value.table.columnNames.series, e.value.table.columnNames.value, e.value.table.columnNames.percentage ], l = D.value.head.map((f, u) => { const R = H( e.value.style.chart.bars.dataLabels.value.formatter, D.value.body[u], X({ p: e.value.style.chart.bars.dataLabels.value.prefix, v: D.value.body[u], s: e.value.style.chart.bars.dataLabels.value.suffix, r: e.value.table.td.roundingValue }), { datapoint: r.value[u] } ), W = H( e.value.style.chart.circles.dataLabels.formatter, r.value[u].proportion * 100, X({ v: r.value[u].proportion * 100, s: "%", r: e.value.table.td.roundingPercentage }), { datapoint: r.value[u] } ); return [ { color: f.color, name: f.name }, R, W ]; }), a = { th: { backgroundColor: e.value.table.th.backgroundColor, color: e.value.table.th.color, outline: e.value.table.th.outline }, td: { backgroundColor: e.value.table.td.backgroundColor, color: e.value.table.td.color, outline: e.value.table.td.outline }, breakpoint: e.value.table.responsiveBreakpoint }; return { colNames: [ e.value.table.columnNames.series, e.value.table.columnNames.value, e.value.table.columnNames.percentage ], head: t, body: l, config: a }; }); function ye(t = null) { Ge(() => { const l = D.value.head.map((f, u) => [[ f.name ], [D.value.body[u]], [r.value[u].proportion * 100]]), a = [[e.value.style.chart.title.text], [e.value.style.chart.title.subtitle.text], [[e.value.table.columnNames.series], [e.value.table.columnNames.value], ["%"]]].concat(l), o = Ze(a); t ? t(o) : et({ csvContent: o, title: e.value.style.chart.title.text || "vue-ui-funnel" }); }); } function Ie() { return p.value; } async function Fe({ scale: t = 2 } = {}) { if (!$.value) return; const { width: l, height: a } = $.value.getBoundingClientRect(), o = l / a, { imageUri: f, base64: u } = await rt({ domElement: $.value, base64: !0, img: !0, scale: t }); return { imageUri: f, base64: u, title: e.value.style.chart.title.text, width: l, height: a, aspectRatio: o }; } return we({ getData: Ie, getImage: Fe, generatePdf: ve, generateCsv: ye, generateImage: de, toggleTable: me, toggleAnnotator: Y, toggleFullscreen: be }), (t, l) => (n(), i("div", { ref_key: "funnelChart", ref: $, class: z(`vue-ui-funnel ${F.value ? "vue-data-ui-wrapper-fullscreen" : ""} ${e.value.useCssAnimation ? "" : "vue-ui-dna"}`), style: _(`font-family:${e.value.style.fontFamily};width:100%; ${e.value.responsive ? "height:100%;" : ""} text-align:center;background:${e.value.style.chart.backgroundColor}`), id: `funnel_${P.value}`, onMouseenter: l[1] || (l[1] = () => s(ne)(!0)), onMouseleave: l[2] || (l[2] = () => s(ne)(!1)) }, [ e.value.userOptions.buttons.annotator ? (n(), N(s(_e), { key: 0, svgRef: s(ue), backgroundColor: e.value.style.chart.backgroundColor, color: e.value.style.chart.color, active: M.value, onClose: Y }, null, 8, ["svgRef", "backgroundColor", "color", "active"])) : b("", !0), Oe.value ? (n(), i("div", { key: 1, ref_key: "noTitle", ref: te, class: "vue-data-ui-no-title-space", style: "height:36px; width: 100%;background:transparent" }, null, 512)) : b("", !0), e.value.style.chart.title.text ? (n(), i("div", { key: 2, ref_key: "chartTitle", ref: le, style: "width:100%;background:transparent;padding-bottom:24px" }, [ (n(), N(nt, { key: `title_${Z.value}`, config: { title: { cy: "funnel-div-title", ...e.value.style.chart.title }, subtitle: { cy: "funnel-div-subtitle", ...e.value.style.chart.title.subtitle } } }, null, 8, ["config"])) ], 512)) : b("", !0), e.value.userOptions.show && T.value && (s(re) || s(q)) ? (n(), N(s(Te), { ref: "details", key: `user_option_${Q.value}`, backgroundColor: e.value.style.chart.backgroundColor, color: e.value.style.chart.color, isPrinting: s(ie), isImaging: s(ce), uid: P.value, hasTooltip: !1, hasPdf: e.value.userOptions.buttons.pdf, hasImg: e.value.userOptions.buttons.img, hasXls: e.value.userOptions.buttons.csv, hasTable: e.value.userOptions.buttons.table, hasLabel: !1, hasFullscreen: e.value.userOptions.buttons.fullscreen, isFullscreen: F.value, chartElement: $.value, position: e.value.userOptions.position, titles: { ...e.value.userOptions.buttonTitles }, hasAnnotator: e.value.userOptions.buttons.annotator, isAnnotation: M.value, callbacks: e.value.userOptions.callbacks, printScale: e.value.userOptions.print.scale, onToggleAnnotator: Y, onToggleFullscreen: be, onGeneratePdf: s(ve), onGenerateImage: s(de), onToggleTable: me, onGenerateCsv: ye, style: _({ visibility: s(re) ? s(q) ? "visible" : "hidden" : "visible" }) }, Ee({ _: 2 }, [ t.$slots.menuIcon ? { name: "menuIcon", fn: g(({ isOpen: a, color: o }) => [ m(t.$slots, "menuIcon", E(V({ isOpen: a, color: o })), void 0, !0) ]), key: "0" } : void 0, t.$slots.optionPdf ? { name: "optionPdf", fn: g(() => [ m(t.$slots, "optionPdf", {}, void 0, !0) ]), key: "1" } : void 0, t.$slots.optionCsv ? { name: "optionCsv", fn: g(() => [ m(t.$slots, "optionCsv", {}, void 0, !0) ]), key: "2" } : void 0, t.$slots.optionImg ? { name: "optionImg", fn: g(() => [ m(t.$slots, "optionImg", {}, void 0, !0) ]), key: "3" } : void 0, t.$slots.optionTable ? { name: "optionTable", fn: g(() => [ m(t.$slots, "optionTable", {}, void 0, !0) ]), key: "4" } : void 0, t.$slots.optionFullscreen ? { name: "optionFullscreen", fn: g(({ toggleFullscreen: a, isFullscreen: o }) => [ m(t.$slots, "optionFullscreen", E(V({ toggleFullscreen: a, isFullscreen: o })), void 0, !0) ]), key: "5" } : void 0, t.$slots.optionAnnotator ? { name: "optionAnnotator", fn: g(({ toggleAnnotator: a, isAnnotator: o }) => [ m(t.$slots, "optionAnnotator", E(V({ toggleAnnotator: a, isAnnotator: o })), void 0, !0) ]), key: "6" } : void 0 ]), 1032, ["backgroundColor", "color", "isPrinting", "isImaging", "uid", "hasPdf", "hasImg", "hasXls", "hasTable", "hasFullscreen", "isFullscreen", "chartElement", "position", "titles", "hasAnnotator", "isAnnotation", "callbacks", "printScale", "onGeneratePdf", "onGenerateImage", "style"])) : b("", !0), T.value ? (n(), i("svg", { key: 4, ref_key: "svgRef", ref: ue, xmlns: s(Je), class: z({ "vue-data-ui-fullscreen--on": F.value, "vue-data-ui-fulscreen--off": !F.value }), viewBox: `0 0 ${v.value.width <= 0 ? 10 : v.value.width} ${v.value.height <= 0 ? 10 : v.value.height}`, style: _(`max-width:100%; overflow: visible; background:transparent;color:${e.value.style.chart.color}`) }, [ Ve(s(Le)), t.$slots["chart-background"] ? (n(), i("foreignObject", { key: 0, x: 0, y: 0, width: v.value.width <= 0 ? 10 : v.value.width, height: v.value.height <= 0 ? 10 : v.value.height, style: { pointerEvents: "none" } }, [ m(t.$slots, "chart-background", {}, void 0, !0) ], 8, vt)) : b("", !0), w("defs", null, [ w("linearGradient", { id: `funnel_area_${P.value}`, x1: "0%", x2: "100%", y1: "0%", y2: "0%" }, [ w("stop", { offset: "0%", "stop-color": e.value.style.chart.backgroundColor, "stop-opacity": 0 }, null, 8, ht), w("stop", { offset: "20%", "stop-color": e.value.style.chart.area.color }, null, 8, ft), w("stop", { offset: "100%", "stop-color": e.value.style.chart.area.color }, null, 8, bt) ], 8, dt) ]), e.value.style.chart.circleLinks.show ? (n(), i("line", J({ key: 1 }, Ne.value, { stroke: e.value.style.chart.circleLinks.color, "stroke-width": 12 * e.value.style.chart.circleLinks.widthRatio, "stroke-linecap": "round", class: { animated: e.value.useCssAnimation }, style: { strokeDasharray: e.value.useCssAnimation ? k.value.height : 0, strokeDashoffset: e.value.useCssAnimation ? k.value.height : 0 } }), null, 16, mt)) : b("", !0), (n(!0), i(U, null, G(r.value, ({ cx: a, cy: o, r: f, fill: u }, R) => (n(), i("circle", J({ ref_for: !0 }, { cx: a, cy: o, r: f, fill: u }, { stroke: e.value.style.chart.circles.stroke, "stroke-width": e.value.style.chart.circles.strokeWidth, class: { animated: e.value.useCssAnimation && !x.value }, style: { animationDelay: `${150 * R}ms` } }), null, 16, yt))), 256)), (n(!0), i(U, null, G(r.value, (a, o) => (n(), i("text", { x: a.cx, y: a.cy + c.value.circles / 3 + e.value.style.chart.circles.dataLabels.offsetY, "text-anchor": "middle", "font-size": c.value.circles, fill: e.value.style.chart.circles.dataLabels.adaptColorToBackground ? s(Ke)(a.color) : e.value.style.chart.circles.dataLabels.color, "font-weight": e.value.style.chart.circles.dataLabels.bold ? "bold" : "normal", class: z({ animated: e.value.useCssAnimation && !x.value }), style: _({ animationDelay: `${150 * o}ms` }) }, j(s(H)( e.value.style.chart.circles.dataLabels.formatter, a.proportion * 100, s(X)({ v: a.proportion * 100, s: "%", r: e.value.style.chart.circles.dataLabels.rounding }), { datapoint: a } )), 15, gt))), 256)), e.value.style.chart.area.show ? (n(), i("polygon", { key: 2, points: ze.value, fill: `url(#funnel_area_${P.value})`, class: z({ animated: e.value.useCssAnimation && !x.value }), style: _({ transition: e.value.useCssAnimation ? `all ${150 * p.value.length}ms ease-in` : "none" }) }, null, 14, pt)) : b("", !0), (n(!0), i(U, null, G(r.value, ({ x: a, y: o, height: f, width: u, fill: R }, W) => (n(), i("rect", J({ ref_for: !0 }, { x: a, y: o, height: f, width: u, fill: R }, { stroke: e.value.style.chart.bars.stroke, "stroke-width": e.value.style.chart.bars.strokeWidth, rx: e.value.style.chart.bars.borderRadius, class: { animated: e.value.useCssAnimation && !x.value }, style: { animationDelay: `${150 * W}ms` } }), null, 16, kt))), 256)), (n(!0), i(U, null, G(r.value, (a, o) => (n(), i("g", null, [ w("text", { x: a.x + a.width + e.value.style.chart.bars.dataLabels.name.offsetX + 12, y: a.cy - c.value.names / 2 + e.value.style.chart.bars.dataLabels.name.offsetY, "text-anchor": "start", "font-size": c.value.names, fill: e.value.style.chart.bars.dataLabels.name.color, "font-weight": e.value.style.chart.bars.dataLabels.name.bold ? "bold" : "normal", class: z({ animated: e.value.useCssAnimation && !x.value }), style: _({ animationDelay: `${150 * o}ms` }) }, j(a.name), 15, Ct), w("text", { x: a.x + a.width + e.value.style.chart.bars.dataLabels.value.offsetX + 12, y: a.cy + c.value.values + e.value.style.chart.bars.dataLabels.value.offsetY, "text-anchor": "start", "font-size": c.value.values, fill: e.value.style.chart.bars.dataLabels.value.color, "font-weight": e.value.style.chart.bars.dataLabels.value.bold ? "bold" : "normal", class: z({ animated: e.value.useCssAnimation && !x.value }), style: _({ animationDelay: `${150 * o}ms` }) }, j(s(H)( e.value.style.chart.bars.dataLabels.value.formatter, a.value, s(X)({ p: e.value.style.chart.bars.dataLabels.value.prefix, v: a.value, s: e.value.style.chart.bars.dataLabels.value.suffix, r: e.value.style.chart.bars.dataLabels.value.rounding }), { datapoint: a } )), 15, wt) ]))), 256)), m(t.$slots, "svg", { svg: v.value }, void 0, !0) ], 14, ct)) : b("", !0), t.$slots.watermark ? (n(), i("div", $t, [ m(t.$slots, "watermark", E(V({ isPrinting: s(ie) || s(ce) })), void 0, !0) ])) : b("", !0), T.value ? b("", !0) : (n(), N(s(Ae), { key: 6, config: { type: "verticalBar", style: { backgroundColor: e.value.style.chart.backgroundColor, verticalBar: { axis: { color: "#CCCCCC" }, color: "#CCCCCC" } } } }, null, 8, ["config"])), t.$slots.source ? (n(), i("div", { key: 7, ref_key: "source", ref: ae, dir: "auto" }, [ m(t.$slots, "source", {}, void 0, !0) ], 512)) : b("", !0), T.value ? (n(), N(s($e), { key: 8, hideDetails: "", config: { open: I.value.showTable, maxHeight: 1e4, body: { backgroundColor: e.value.style.chart.backgroundColor, color: e.value.style.chart.color }, head: { backgroundColor: e.value.style.chart.backgroundColor, color: e.value.style.chart.color } } }, { content: g(() => [ (n(), N(s(xe), { key: `table_${ee.value}`, colNames: B.value.colNames, head: B.value.head, body: B.value.body, config: B.value.config, title: `${e.value.style.chart.title.text}${e.value.style.chart.title.subtitle.text ? ` : ${e.value.style.chart.title.subtitle.text}` : ""}`, onClose: l[0] || (l[0] = (a) => I.value.showTable = !1) }, { th: g(({ th: a }) => [ w("div", { innerHTML: a, style: { display: "flex", "align-items": "center" } }, null, 8, xt) ]), td: g(({ td: a }) => [ Ue(j(a.name ? a.name : a), 1) ]), _: 1 }, 8, ["colNames", "head", "body", "config", "title"])) ]), _: 1 }, 8, ["config"])) : b("", !0) ], 46, it)); } }, Dt = /* @__PURE__ */ ut(Lt, [["__scopeId", "data-v-08e58142"]]); export { Dt as default };