vue-data-ui
Version:
A user-empowering data visualization Vue 3 components library for eloquent data storytelling
520 lines (519 loc) • 22.1 kB
JavaScript
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
};