UNPKG

vue-data-ui

Version:

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

520 lines (519 loc) 22.1 kB
import { toRef as ge, ref as g, computed as f, onMounted as ie, watch as q, createElementBlock as d, openBlock as n, normalizeStyle as z, renderSlot as M, nextTick as be, createCommentVNode as h, createBlock as ee, normalizeProps as te, guardReactiveProps as ae, createElementVNode as b, toDisplayString as T, unref as c, createVNode as me, Fragment as E, renderList as B, withCtx as ke, createTextVNode as xe } from "vue"; import { s as W, a0 as le, u as _e, c as we, a as $e, C as oe, a1 as G, o as Ne, e as ue, g as Le, w as F, a2 as Ce, a3 as Me, X as Se, S as se, R as Ie, a4 as re, i as X, f as j } from "./index-CHWA6Lnw.js"; import { u as ne } from "./useNestedProp-ByBiJC9_.js"; import Ve from "./vue-ui-skeleton-BSUFPx4a.js"; import { t as Re, u as ze } from "./useResponsive-vZgZwV-S.js"; import { _ as We } from "./PackageVersion-DcMafJMi.js"; import { u as Ae } from "./useChartAccessibility-BWojgys7.js"; import { _ as de } from "./_plugin-vue_export-helper-CHgC5LLL.js"; const Pe = { __name: "SparkTooltip", props: { svgRef: { type: Object }, x: { type: Number, required: !0 }, y: { type: Number, required: !0 }, prevX: { type: Number, required: !0 }, prevY: { type: Number, required: !0 }, offsetY: { type: Number, default: 0 }, background: { type: String }, backgroundOpacity: { type: Number, default: 100 }, borderRadius: { type: Number, default: 2 }, borderWidth: { type: Number, default: 0 }, borderColor: { type: String, default: "#FFFFFF" }, color: { type: String }, fontSize: { type: Number } }, setup(m) { const v = m, S = ge(v.svgRef), o = g(null), k = g(0), p = g(0), _ = g(!1), A = f(() => W(v.background, v.backgroundOpacity)), I = async () => { if (!S.value || !o.value) return; const e = le({ svgElement: S.value, element: o.value, x: v.x, y: v.y, offsetY: v.offsetY }), w = le({ svgElement: S.value, element: o.value, x: v.prevX, y: v.prevY, offsetY: v.offsetY }); !e || !w || (_.value = !1, k.value = w.top, p.value = w.left, await be(), setTimeout(() => { _.value = !0, k.value = e.top, p.value = e.left; }, 50)); }; return ie(I), q( () => [v.x, v.y, v.prevX, v.prevY], () => I(), { immediate: !0 } ), (e, w) => (n(), d("div", { ref_key: "tooltipRef", ref: o, class: "vue-data-ui-spark-tooltip", style: z({ position: "fixed", top: `${k.value}px`, left: `${p.value}px`, pointerEvents: "none", background: A.value, color: v.color, fontSize: `${v.fontSize}px`, borderRadius: `${v.borderRadius}px`, border: `${v.borderWidth}px solid ${v.borderColor}`, transition: _.value ? "top 0.3s ease-out, left 0.3s ease-out" : "none" }) }, [ M(e.$slots, "default", {}, void 0, !0) ], 4)); } }, Te = /* @__PURE__ */ de(Pe, [["__scopeId", "data-v-c8e27542"]]), Fe = ["id"], Oe = ["xmlns", "viewBox"], Ye = ["width", "height"], De = ["id"], Ee = ["stop-color"], Be = ["stop-color"], Ge = ["id"], Xe = ["stop-color"], je = ["stop-color"], qe = ["id"], Ue = ["stop-color"], Ze = ["stop-color"], He = { key: 1 }, Je = ["d", "fill"], Ke = ["d", "fill"], Qe = ["d", "stroke", "stroke-width"], et = ["d", "stroke", "stroke-width"], tt = ["x", "y", "width", "height", "fill", "rx"], at = ["x1", "x2", "y1", "y2", "stroke", "stroke-width", "stroke-dasharray"], lt = ["x1", "x2", "y1", "y2", "stroke", "stroke-dasharray", "stroke-width"], ot = ["cx", "cy", "r", "fill", "stroke", "stroke-width"], ut = ["x", "y", "font-size", "font-weight", "fill"], st = ["x", "y", "height", "width", "onMouseenter", "onClick"], rt = { __name: "vue-ui-sparkline", props: { config: { type: Object, default() { return {}; } }, dataset: { type: Array, default() { return []; } }, showInfo: { type: Boolean, default: !0 }, selectedIndex: { type: Number, default: void 0 }, heightRatio: { type: Number, default: 1 }, forcedPadding: { type: Number, default: 30 } }, emits: ["hoverIndex", "selectDatapoint"], setup(m, { emit: v }) { const { vue_ui_sparkline: S } = _e(), o = m, k = f(() => Array.isArray(o.dataset) && o.dataset.length > 0), p = g(we()), _ = g(null), A = g(null), I = g(null), e = f({ get: () => U(), set: (t) => t }), { svgRef: w } = Ae({ config: e.value.style.title }); function U() { const t = ne({ userConfig: o.config, defaultConfig: S }); let l = {}; return t.theme ? l = { ...ne({ userConfig: $e.vue_ui_sparkline[t.theme] || o.config, defaultConfig: t }) } : l = t, o.config && oe(o.config, "style.scaleMin") ? l.style.scaleMin = o.config.style.scaleMin : l.style.scaleMin = null, o.config && oe(o.config, "style.scaleMax") ? l.style.scaleMax = o.config.style.scaleMax : l.style.scaleMax = null, l; } const P = f(() => G({ data: o.dataset, threshold: e.value.downsample.threshold })); q(() => o.config, (t) => { e.value = U(), H(), u.value.chartWidth = e.value.style.chartWidth; }, { deep: !0 }), q(() => o.dataset, (t) => { $.value = G({ data: o.dataset.map((l) => ({ ...l, value: [void 0].includes(l.value) ? null : l.value })), threshold: e.value.downsample.threshold }); }, { deep: !0 }); const $ = g(ve()); function ve() { return G({ data: o.dataset.map((t) => e.value.style.animation.show && o.dataset.length > 1 ? { ...t, value: null } : { ...t, value: [void 0].includes(t.value) ? null : t.value }), threshold: e.value.downsample.threshold }); } const Z = g(null); ie(() => { if (H(), e.value.style.animation.show && o.dataset.length > 1) { let a = function() { l < P.value.length ? ($.value.push(P.value[l]), setTimeout(() => { requestAnimationFrame(a); }, t)) : $.value = P.value, l += 1; }; $.value = []; const t = e.value.style.animation.animationFrames / o.dataset.length; let l = 0; a(); } }); function H() { if (Ne(o.dataset) ? ue({ componentName: "VueUiSparkline", type: "dataset" }) : o.dataset.forEach((t, l) => { Le({ datasetObject: t, requiredAttributes: ["period", "value"] }).forEach((a) => { ue({ componentName: "VueUiSparkline", type: "datasetSerieAttribute", property: a, index: l }); }); }), e.value.responsive) { const t = Re(() => { const { width: l, height: a } = ze({ chart: _.value, title: e.value.style.title.show && o.showInfo ? A.value : null, source: I.value }); requestAnimationFrame(() => { u.value.width = l, u.value.height = a, u.value.chartWidth = e.value.style.chartWidth / 500 * l, u.value.padding = o.forcedPadding / 500 * l; }); }); Z.value = new ResizeObserver(t), Z.value.observe(_.value.parentNode); } } const u = g({ height: 80 * o.heightRatio, width: 500, chartWidth: e.value.style.chartWidth, padding: o.forcedPadding }), O = v, s = f(() => { const { top: t, right: l, bottom: a, left: r } = e.value.style.padding; return { top: t, left: r, right: u.value.width - l, bottom: u.value.height - a, start: o.showInfo && e.value.style.dataLabel.show && e.value.style.dataLabel.position === "left" ? u.value.width - u.value.chartWidth + r : u.value.padding + r, width: o.showInfo && e.value.style.dataLabel.show ? u.value.chartWidth - r - l : u.value.width - u.value.padding - r - l, height: u.value.height - t - a }; }), Y = f(() => [null, void 0].includes(e.value.style.scaleMin) ? Math.min(...$.value.map((t) => isNaN(t.value) || [void 0, null, "NaN", NaN, 1 / 0, -1 / 0].includes(t.value) ? 0 : t.value || 0)) : e.value.style.scaleMin), ce = f(() => [null, void 0].includes(e.value.style.scaleMax) ? Math.max(...$.value.map((t) => isNaN(t.value) || [void 0, null, "NaN", NaN, 1 / 0, -1 / 0].includes(t.value) ? 0 : t.value || 0)) : e.value.style.scaleMax), V = f(() => { const t = Y.value >= 0 ? 0 : Y.value; return Math.abs(t); }), J = f(() => ce.value + V.value), L = f(() => s.value.bottom - s.value.height * D(V.value)); function D(t) { return isNaN(t / J.value) ? 0 : t / J.value; } const N = f(() => P.value.length - 1), y = f(() => $.value.map((t, l) => { const a = isNaN(t.value) || [void 0, null, "NaN", NaN, 1 / 0, -1 / 0].includes(t.value) ? 0 : t.value || 0, r = s.value.width / (N.value + 1) > u.padding ? u.padding : s.value.width / (N.value + 1); return { absoluteValue: a, period: t.period, plotValue: a + V.value, toMax: D(a + V.value), x: s.value.start + l * (r > s.value.width / 12 ? s.value.width / 12 : r), y: s.value.bottom - s.value.height * D(a + V.value), id: `plot_${p.value}_${l}`, color: R.value ? e.value.style.bar.color : e.value.style.area.useGradient ? F(e.value.style.line.color, 0.05 * (1 - l / N.value)) : e.value.style.line.color, width: r > s.value.width / 12 ? s.value.width / 12 : r }; })), ye = f(() => { const t = { x: y.value[0].x || 0, y: (u.value.height || 0) - 6 }, l = { x: y.value[y.value.length - 1].x || 0, y: (u.value.height || 0) - 6 }, a = []; return y.value.forEach((r) => { a.push(`${r.x || 0},${r.y || 0} `); }), [t.x, t.y, ...a, l.x, l.y].toString(); }), i = g(void 0), C = g(void 0); function fe(t, l) { i.value = t, C.value || (C.value = t), O("hoverIndex", { index: l }); } function he() { C.value = i.value, i.value = void 0, O("hoverIndex", { index: void 0 }); } const x = f(() => { if (k.value) { const t = y.value.map((a) => a.absoluteValue), l = t.reduce((a, r) => a + r, 0); return { latest: y.value[y.value.length - 1].absoluteValue, sum: l, average: l / y.value.length, median: Me(t), trend: Ce(y.value.map(({ x: a, y: r, absoluteValue: Q }) => ({ x: a, y: r, value: Q }))).trend }; } else return { latest: null, sum: null, average: null, median: null, trend: null }; }), K = f(() => k.value ? e.value.style.dataLabel.valueType === "latest" ? x.value.latest : e.value.style.dataLabel.valueType === "sum" ? x.value.sum : e.value.style.dataLabel.valueType === "average" ? x.value.average : 0 : 0), R = f(() => e.value.type && e.value.type === "bar"); function pe(t, l) { O("selectDatapoint", { datapoint: t, index: l }); } return (t, l) => (n(), d("div", { ref_key: "sparklineChart", ref: _, class: "vue-ui-sparkline", id: p.value, style: z(`width:100%;font-family:${e.value.style.fontFamily};`) }, [ M(t.$slots, "before", te(ae({ selected: i.value, latest: x.value.latest, sum: x.value.sum, average: x.value.average, median: x.value.median, trend: x.value.trend })), void 0, !0), e.value.style.title.show && m.showInfo ? (n(), d("div", { key: 0, ref_key: "chartTitle", ref: A, class: "vue-ui-sparkline-title", style: z(`display:flex;align-items:center;width:100%;color:${e.value.style.title.color};background:${e.value.style.backgroundColor};justify-content:${e.value.style.title.textAlign === "left" ? "flex-start" : e.value.style.title.textAlign === "right" ? "flex-end" : "center"};height:${e.value.style.title.fontSize * 2}px;font-size:${e.value.style.title.fontSize}px;font-weight:${e.value.style.title.bold ? "bold" : "normal"};`) }, [ b("span", { style: z(`padding:${e.value.style.title.textAlign === "left" ? "0 0 0 12px" : e.value.style.title.textAlign === "right" ? "0 12px 0 0" : "0"}`) }, T(i.value ? i.value.period : e.value.style.title.text), 5) ], 4)) : h("", !0), k.value ? (n(), d("svg", { key: 1, ref_key: "svgRef", ref: w, xmlns: c(Se), viewBox: `0 0 ${u.value.width} ${u.value.height}`, style: z(`background:${e.value.style.backgroundColor};overflow:visible`), onMouseleave: l[0] || (l[0] = (a) => C.value = void 0) }, [ me(We), t.$slots["chart-background"] ? (n(), d("foreignObject", { key: 0, x: 0, y: 0, width: u.value.width <= 0 ? 10 : u.value.width, height: u.value.height <= 0 ? 10 : u.value.height, style: { pointerEvents: "none" } }, [ M(t.$slots, "chart-background", {}, void 0, !0) ], 8, Ye)) : h("", !0), b("defs", null, [ b("linearGradient", { x1: "0%", y1: "0%", x2: "100%", y2: "0%", id: `sparkline_gradient_${p.value}` }, [ b("stop", { offset: "0%", "stop-color": c(W)(c(F)(e.value.style.area.color, 0.05), e.value.style.area.opacity) }, null, 8, Ee), b("stop", { offset: "100%", "stop-color": c(W)(e.value.style.area.color, e.value.style.area.opacity) }, null, 8, Be) ], 8, De), b("linearGradient", { x2: "0%", y2: "100%", id: `sparkline_bar_gradient_pos_${p.value}` }, [ b("stop", { offset: "0%", "stop-color": e.value.style.bar.color }, null, 8, Xe), b("stop", { offset: "100%", "stop-color": c(F)(e.value.style.bar.color, 0.05) }, null, 8, je) ], 8, Ge), b("linearGradient", { x2: "0%", y2: "100%", id: `sparkline_bar_gradient_neg_${p.value}` }, [ b("stop", { offset: "0%", "stop-color": c(F)(e.value.style.bar.color, 0.05) }, null, 8, Ue), b("stop", { offset: "100%", "stop-color": e.value.style.bar.color }, null, 8, Ze) ], 8, qe) ]), e.value.style.area.show && !R.value && y.value[0] ? (n(), d("g", He, [ e.value.style.line.smooth ? (n(), d("path", { key: 0, d: `M ${y.value[0].x},${s.value.bottom} ${c(se)(y.value)} L ${y.value.at(-1).x},${s.value.bottom} Z`, fill: e.value.style.area.useGradient ? `url(#sparkline_gradient_${p.value})` : c(W)(e.value.style.area.color, e.value.style.area.opacity) }, null, 8, Je)) : (n(), d("path", { key: 1, d: `M${ye.value}Z`, fill: e.value.style.area.useGradient ? `url(#sparkline_gradient_${p.value})` : c(W)(e.value.style.area.color, e.value.style.area.opacity) }, null, 8, Ke)) ])) : h("", !0), e.value.style.line.smooth && !R.value ? (n(), d("path", { key: 2, d: `M ${c(se)(y.value)}`, stroke: e.value.style.line.color, fill: "none", "stroke-width": e.value.style.line.strokeWidth, "stroke-linecap": "round" }, null, 8, Qe)) : h("", !0), !e.value.style.line.smooth && !R.value ? (n(), d("path", { key: 3, d: `M ${c(Ie)(y.value)}`, stroke: e.value.style.line.color, fill: "none", "stroke-width": e.value.style.line.strokeWidth, "stroke-linecap": "round" }, null, 8, et)) : h("", !0), (n(!0), d(E, null, B(y.value, (a, r) => (n(), d("g", null, [ R.value ? (n(), d("rect", { key: 0, x: a.x - a.width / 2, y: isNaN(a.absoluteValue > 0 ? a.y : L.value) ? 0 : a.absoluteValue > 0 ? a.y : L.value, width: a.width, height: isNaN(Math.abs(a.y - L.value)) ? 0 : Math.abs(a.y - L.value), fill: a.absoluteValue > 0 ? `url(#sparkline_bar_gradient_pos_${p.value})` : `url(#sparkline_bar_gradient_neg_${p.value})`, rx: e.value.style.bar.borderRadius }, null, 8, tt)) : h("", !0), e.value.style.verticalIndicator.show && (i.value && a.id === i.value.id || m.selectedIndex === r) ? (n(), d("line", { key: 1, x1: a.x, x2: a.x, y1: s.value.top - 6, y2: s.value.bottom, stroke: e.value.style.verticalIndicator.color || a.color, "stroke-width": e.value.style.verticalIndicator.strokeWidth, "stroke-linecap": "round", "stroke-dasharray": e.value.style.verticalIndicator.strokeDasharray || 0 }, null, 8, at)) : h("", !0) ]))), 256)), Y.value < 0 ? (n(), d("line", { key: 4, x1: s.value.start, x2: s.value.start + s.value.width - 16, y1: c(re)(L.value, s.value.bottom), y2: c(re)(L.value, s.value.bottom), stroke: e.value.style.zeroLine.color, "stroke-dasharray": e.value.style.zeroLine.strokeWidth * 2, "stroke-width": e.value.style.zeroLine.strokeWidth, "stroke-linecap": "round" }, null, 8, lt)) : h("", !0), e.value.style.plot.show ? (n(!0), d(E, { key: 5 }, B(y.value, (a, r) => (n(), d("g", null, [ i.value && a.id === i.value.id || m.selectedIndex === r || m.dataset.length === 1 ? (n(), d("circle", { key: 0, cx: a.x, cy: a.y, r: e.value.style.plot.radius, fill: a.color, stroke: e.value.style.plot.stroke, "stroke-width": e.value.style.plot.strokeWidth }, null, 8, ot)) : h("", !0) ]))), 256)) : h("", !0), m.showInfo && e.value.style.dataLabel.show ? (n(), d("text", { key: 6, x: e.value.style.dataLabel.position === "left" ? 12 + e.value.style.dataLabel.offsetX : s.value.width + 12 + e.value.style.dataLabel.offsetX, y: u.value.height / 2 + e.value.style.dataLabel.fontSize / 2.5 + e.value.style.dataLabel.offsetY, "font-size": e.value.style.dataLabel.fontSize, "font-weight": e.value.style.dataLabel.bold ? "bold" : "normal", fill: e.value.style.dataLabel.color }, T(i.value ? c(X)( e.value.style.dataLabel.formatter, i.value.absoluteValue, c(j)({ p: e.value.style.dataLabel.prefix, v: i.value.absoluteValue, s: e.value.style.dataLabel.suffix, r: e.value.style.dataLabel.roundingValue }), { datapoint: i.value } ) : c(X)( e.value.style.dataLabel.formatter, K.value, c(j)({ p: e.value.style.dataLabel.prefix, v: K.value, s: e.value.style.dataLabel.suffix, r: e.value.style.dataLabel.roundingValue }) )), 9, ut)) : h("", !0), (n(!0), d(E, null, B(y.value, (a, r) => (n(), d("rect", { x: a.x - (s.value.width / (N.value + 1) > u.value.padding ? u.value.padding : s.value.width / (N.value + 1)) / 2, y: s.value.top - 6, height: s.value.height + 6, width: s.value.width / (N.value + 1) > u.value.padding ? u.value.padding : s.value.width / (N.value + 1), fill: "transparent", onMouseenter: (Q) => fe(a, r), onMouseleave: he, onClick: () => pe(a, r) }, null, 40, st))), 256)), M(t.$slots, "svg", { svg: u.value }, void 0, !0) ], 44, Oe)) : h("", !0), i.value && e.value.style.tooltip.show ? (n(), ee(Te, { key: 2, x: i.value.x, y: i.value.y, prevX: C.value.x, prevY: C.value.y, offsetY: e.value.style.plot.radius * 3 + e.value.style.tooltip.offsetY, svgRef: c(w), background: e.value.style.tooltip.backgroundColor, color: e.value.style.tooltip.color, fontSize: e.value.style.tooltip.fontSize, borderWidth: e.value.style.tooltip.borderWidth, borderColor: e.value.style.tooltip.borderColor, borderRadius: e.value.style.tooltip.borderRadius, backgroundOpacity: e.value.style.tooltip.backgroundOpacity }, { default: ke(() => [ M(t.$slots, "tooltip", te(ae({ ...i.value })), () => [ xe(T(i.value.period) + ": " + T(c(X)( e.value.style.dataLabel.formatter, i.value.absoluteValue, c(j)({ p: e.value.style.dataLabel.prefix, v: i.value.absoluteValue, s: e.value.style.dataLabel.suffix, r: e.value.style.dataLabel.roundingValue }), { datapoint: i.value } )), 1) ], !0) ]), _: 3 }, 8, ["x", "y", "prevX", "prevY", "offsetY", "svgRef", "background", "color", "fontSize", "borderWidth", "borderColor", "borderRadius", "backgroundOpacity"])) : h("", !0), t.$slots.source ? (n(), d("div", { key: 3, ref_key: "source", ref: I, dir: "auto" }, [ M(t.$slots, "source", {}, void 0, !0) ], 512)) : h("", !0), k.value ? h("", !0) : (n(), ee(Ve, { key: 4, config: { type: "sparkline", style: { backgroundColor: e.value.style.backgroundColor, sparkline: { color: "#CCCCCC" } } } }, null, 8, ["config"])) ], 12, Fe)); } }, pt = /* @__PURE__ */ de(rt, [["__scopeId", "data-v-246ce941"]]); export { pt as default };