vue-data-ui
Version:
A user-empowering data visualization Vue 3 components library for eloquent data storytelling
666 lines (665 loc) • 27.9 kB
JavaScript
import { useCssVars as Fe, defineAsyncComponent as J, ref as p, useSlots as Ve, onMounted as me, computed as _, watch as be, shallowRef as Te, onBeforeUnmount as We, createElementBlock as c, openBlock as v, unref as u, normalizeClass as K, createCommentVNode as g, createElementVNode as f, normalizeStyle as r, toDisplayString as C, withDirectives as Me, createVNode as D, Fragment as Q, renderList as Y, createBlock as Ue, createSlots as Be, withCtx as P, renderSlot as O, mergeProps as ge, nextTick as Ee } from "vue";
import { u as ye } from "./useNestedProp-04aFeUYu.js";
import { u as Ge, c as Le, a as Re, p as T, b as He, d as Xe, o as qe, f as he, g as Je, a8 as Ke, e as Qe, k as W, i as M, v as Ye, w as Ze } from "./index-q-LPw2IT.js";
import { u as je } from "./usePrinter-DX7efa1s.js";
import { u as et } from "./useUserOptionState-BIvW1Kz7.js";
import { v as tt } from "./vClickOutside-C6WiFswA.js";
import { _ as at } from "./_plugin-vue_export-helper-CHgC5LLL.js";
const lt = ["id"], ot = { style: { "z-index": "1", "padding-right": "24px" } }, nt = {
key: 0,
style: {
display: "flex",
flexDirection: "row",
alignItems: "center"
}
}, ut = {
key: 0,
style: {
display: "flex",
flexDirection: "row",
alignItems: "center"
}
}, st = ["onClick"], rt = ["onClick"], it = ["data-cell"], dt = ["data-cell", "onPointerenter"], vt = ["data-cell"], ct = ["data-cell"], pt = ["data-cell"], ft = ["data-cell"], mt = {
key: 1,
ref: "source",
dir: "auto"
}, bt = {
__name: "vue-ui-table-sparkline",
props: {
config: {
type: Object,
default() {
return {};
}
},
dataset: {
type: Array,
default() {
return [];
}
}
},
setup(ke, { expose: _e }) {
Fe((t) => ({
"3ff44dec": t.tdo
}));
const Ce = J(() => import("./vue-ui-sparkline-ClRCVth4.js")), N = J(() => import("./BaseIcon-CCivwZUq.js")), xe = J(() => import("./UserOptions-DVzyjG-W.js")), { vue_ui_table_sparkline: we } = Ge(), x = ke, U = p(Le()), Z = p(0), B = p(0), E = p(null), Se = Ve();
me(() => {
Se["chart-background"] && console.warn("VueUiTableSparkline does not support the #chart-background slot.");
});
const e = _({
get: () => te(),
set: (t) => t
}), { userOptionsVisible: G, setUserOptionsVisibility: j, keepUserOptionState: ee } = et({ config: e.value });
function te() {
const t = ye({
userConfig: x.config,
defaultConfig: we
});
return t.theme ? {
...ye({
userConfig: He.vue_ui_table_sparkline[t.theme] || x.config,
defaultConfig: t
}),
customPalette: Re[t.theme] || T
} : t;
}
be(() => x.config, (t) => {
e.value = te(), G.value = !e.value.userOptions.showOnChartHover, ue(), B.value += 1;
}, { deep: !0 }), be(() => x.dataset, (t) => {
m.value = $.value, B.value += 1;
}, { deep: !0 });
const { isPrinting: ae, isImaging: le, generatePdf: oe, generateImage: ne } = je({
elementId: `table_${U.value}`,
fileName: e.value.title.text || "vue-ui-table-sparkline",
options: e.value.userOptions.print
}), Ie = _(() => Xe(e.value.customPalette)), F = p(null), L = p(!1), Ae = _(() => e.value.responsiveBreakpoint);
me(() => {
ue();
});
const R = p(e.value.colNames), I = Te(null);
function ue() {
qe(x.dataset) && he({
componentName: "VueUiTableSparkline",
type: "dataset"
}), I.value && I.value.disconnect(), I.value = new ResizeObserver((t) => {
t.forEach((l) => {
L.value = l.contentRect.width < Ae.value;
});
}), F.value && I.value.observe(F.value), R.value = [];
for (let t = 0; t < ie.value; t += 1)
R.value.push(e.value.colNames[t] || `col ${t}`);
}
We(() => {
I.value && I.value.disconnect();
});
const se = _(() => (x.dataset.forEach((t, l) => {
Je({
datasetObject: t,
requiredAttributes: ["name", "values"]
}).forEach((a) => {
he({
componentName: "VueUiTableSparkline",
type: "datasetSerieAttribute",
property: a,
index: l
});
});
}), x.dataset.map((t, l) => {
const a = (t.values || []).map((d) => isNaN(d) ? 0 : d ?? 0), n = a.reduce((d, i) => d + i, 0), s = n / a.length, o = Ke(a);
return {
...t,
values: t.values || [],
color: Qe(t.color) || Ie.value[l] || T[l] || T[l % T.length],
sum: n,
average: s,
median: o,
sparklineDataset: a.map((d, i) => ({
period: e.value.colNames[i] || `col ${i}`,
value: d || 0
}))
};
})));
function Oe(t) {
const a = (t[0].values || []).map(
(s, o) => t.map((d) => d.values[o] || [])
).map(
(s) => s.map((o, d) => [o, d]).sort((o, d) => d[0] - o[0]).map((o) => o[1])
);
return t.map((s, o) => ({
...s,
values: s.values || [],
orders: a[o]
}));
}
const $ = _(() => Oe(se.value)), m = p($.value), $e = _(() => Math.max(...m.value.map((t) => (t.values || []).length))), H = p(void 0), X = p(!1), b = p(void 0), re = p(1);
function A() {
X.value = !1, b.value = void 0, y.value = void 0, re.value = 1, z.value.forEach((t) => t.state = 1), w.value = {
name: 1,
sum: 1,
average: 1,
median: 1
}, m.value = $.value;
}
function V(t, l, a) {
if (["name", "sum", "average", "median"].includes(t.type)) {
ze(t.type, l, a);
return;
}
if (!ce(l)) return;
if (S.value = l, y.value = void 0, ![null, void 0].includes(b.value) && l !== b.value && (b.value = void 0, A()), z.value[l].state === a && b.value === l) {
b.value = void 0, A();
return;
}
X.value = !0, b.value = l;
const n = $.value.map((i) => i.values[l] || []), s = a;
z.value[l].state = s, re.value = s, l === H.value ? H.value = void 0 : H.value = l;
const d = n.map((i, h) => [h, i]).sort((i, h) => s * (h[1] - i[1])).map((i) => i[0]).map((i) => $.value[i]);
m.value = d, B.value += 1;
}
const ie = _(() => Math.max(...x.dataset.map((t) => (t.values || []).length))), k = _(() => {
let t = R.value.map((a) => ({
type: "reg",
value: a
}));
if (!t.length)
for (let a = 0; a < ie.value; a += 1)
t.push({ type: "reg", value: `col ${a + 1}` });
e.value.showTotal && (t = [...t, { type: "sum", value: e.value.translations.total }]);
let l;
return e.value.showAverage && e.value.showMedian ? l = [
...t,
{ type: "average", value: e.value.translations.average },
{ type: "median", value: e.value.translations.median }
] : e.value.showAverage && !e.value.showMedian ? l = [...t, { type: "average", value: e.value.translations.average }] : !e.value.showAverage && e.value.showMedian ? l = [...t, { type: "median", value: e.value.translations.median }] : l = t, e.value.showSparklines ? [...l, { type: "chart", value: e.value.translations.chart }] : l;
}), w = p({
name: 1,
sum: 1,
average: 1,
median: 1
}), y = p(void 0);
function ze(t, l, a) {
if (!m.value || m.value.length === 0 || !pe(t)) return;
if (y.value !== t && (y.value = void 0), ![null, void 0].includes(b.value) && l !== b.value && A(), b.value = void 0, w.value[t] === a && y.value) {
y.value = void 0, A();
return;
}
y.value = t, X.value = !0, w.value[t] = a, [null, void 0].includes(l) || (z.value[l].state = w.value[t]);
const n = w.value[t], s = [...m.value].sort((o, d) => {
const i = o[t] ?? (typeof o[t] == "number" ? 0 : ""), h = d[t] ?? (typeof d[t] == "number" ? 0 : "");
return typeof i == "string" && typeof h == "string" ? n === -1 ? i.localeCompare(h) : h.localeCompare(i) : typeof i == "number" && typeof h == "number" ? n === -1 ? i - h : h - i : 0;
});
m.value = s;
}
const S = p(void 0), q = p(void 0);
function De({ dataIndex: t, serieIndex: l }) {
S.value = t, q.value = l, E.value[t] && !L.value && E.value[t].scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
}
const de = p(!1);
function Pe(t) {
de.value = t, Z.value += 1;
}
function ve(t = null) {
Ee(() => {
const l = [e.value.translations.serie].concat(k.value), a = se.value.map((o, d) => [
[o.name],
o.values,
[o.sum],
[o.average],
[o.median]
]), n = [l].concat(a), s = Ye(n);
t ? t(s) : Ze({
csvContent: s,
title: e.value.title.text || "vue-ui-table-sparkline"
});
});
}
function ce(t) {
return e.value.sortedDataColumnIndices.includes(t);
}
function pe(t) {
return t.type === "name" || t === "name" ? e.value.sortedSeriesName : t.type === "sum" || t === "sum" ? e.value.sortedSum : t.type === "average" || t === "average" ? e.value.sortedAverage : t.type === "median" || t === "median" ? e.value.sortedMedian : !1;
}
function fe(t, l, a) {
return ["sum", "average", "median"].includes(l.type) ? y.value === l.type && w.value[l.type] === a ? 1 : 0.3 : t === b.value && z.value[t].state === a ? 1 : 0.3;
}
function Ne() {
e.value.resetSortOnClickOutside && A();
}
const z = _({
get: () => k.value.map((t) => ({ state: 1 })),
set: (t) => t
});
return _e({
generatePdf: oe,
generateImage: ne,
generateCsv: ve,
restoreOrder: A
}), (t, l) => (v(), c("div", {
ref_key: "tableContainer",
ref: F,
class: K({ "vue-ui-table-sparkline": !0, "vue-ui-responsive": L.value }),
style: { overflow: "hidden" },
id: `table_${U.value}`,
onMouseenter: l[3] || (l[3] = () => u(j)(!0)),
onMouseleave: l[4] || (l[4] = () => u(j)(!1))
}, [
e.value.title.text ? (v(), c("div", {
key: 0,
class: "vue-ui-table-sparkline-caption",
style: r({ backgroundColor: e.value.title.backgroundColor })
}, [
f("div", {
class: "atom-title",
style: r({
fontSize: `${e.value.title.fontSize}px`,
fontWeight: e.value.title.bold ? "bold" : "normal",
color: e.value.title.color,
textAlign: e.value.title.textAlign
})
}, C(e.value.title.text), 5),
e.value.title.subtitle.text ? (v(), c("div", {
key: 0,
class: "atom-subtitle",
style: r({
fontSize: `${e.value.title.subtitle.fontSize}px`,
fontWeight: e.value.title.subtitle.bold ? "bold" : "normal",
color: e.value.title.subtitle.color,
textAlign: e.value.title.textAlign
})
}, C(e.value.title.subtitle.text), 5)) : g("", !0)
], 4)) : g("", !0),
f("div", {
style: { overflow: "auto" },
onPointerleave: l[2] || (l[2] = (a) => {
q.value = void 0, S.value = void 0;
})
}, [
f("table", {
class: "vue-ui-data-table",
style: r({ fontFamily: e.value.fontFamily, position: "relative" })
}, [
f("thead", ot, [
Me((v(), c("tr", {
role: "row",
class: "vue-ui-data-table__thead-row",
style: r({
backgroundColor: e.value.thead.backgroundColor,
color: e.value.thead.color
})
}, [
f("th", {
role: "cell",
style: r({
backgroundColor: e.value.thead.backgroundColor,
border: e.value.thead.outline,
textAlign: e.value.thead.textAlign,
fontWeight: e.value.thead.bold ? "bold" : "normal"
}),
class: "sticky-col-first"
}, [
f("div", {
style: r({
display: "flex",
flexDirection: "row",
alignItems: "center",
gap: "3px",
justifyContent: e.value.thead.textAlign
})
}, [
f("span", null, C(e.value.translations.serie), 1),
m.value.length > 1 && e.value.sortedSeriesName ? (v(), c("div", nt, [
f("button", {
class: "vue-ui-table-sparkline-sorting-button vue-ui-table-sparkline-sorting-button-down",
onClick: l[0] || (l[0] = (a) => V({ type: "name" }, null, -1))
}, [
D(u(N), {
size: 12,
name: "arrowBottom",
stroke: e.value.thead.color,
style: r({
opacity: y.value === "name" && w.value.name === -1 ? 1 : 0.3
})
}, null, 8, ["stroke", "style"])
]),
f("button", {
class: "vue-ui-table-sparkline-sorting-button vue-ui-table-sparkline-sorting-button-up",
onClick: l[1] || (l[1] = (a) => V({ type: "name" }, null, 1))
}, [
D(u(N), {
size: 12,
name: "arrowTop",
stroke: e.value.thead.color,
style: r({
opacity: y.value === "name" && w.value.name === 1 ? 1 : 0.3
})
}, null, 8, ["stroke", "style"])
])
])) : g("", !0)
], 4)
], 4),
(v(!0), c(Q, null, Y(k.value, (a, n) => (v(), c("th", {
role: "cell",
style: r({
background: e.value.thead.backgroundColor,
border: e.value.thead.outline,
textAlign: e.value.thead.textAlign,
fontWeight: e.value.thead.bold ? "bold" : "normal",
minWidth: n === k.value.length - 1 ? `${e.value.sparkline.dimensions.width}px` : "48px",
paddingRight: n === k.value.length - 1 && e.value.userOptions.show ? "36px" : ""
}),
class: K({ "sticky-col": n === k.value.length - 1 && e.value.showSparklines })
}, [
f("div", {
style: r({
display: "flex",
flexDirection: "row",
alignItems: "center",
gap: "3px",
justifyContent: e.value.thead.textAlign
})
}, [
f("span", null, C(a.value), 1),
m.value.length > 1 && (ce(n) || pe(a)) ? (v(), c("div", ut, [
f("button", {
class: "vue-ui-table-sparkline-sorting-button vue-ui-table-sparkline-sorting-button-down",
onClick: () => V(a, n, -1)
}, [
D(u(N), {
size: 12,
name: "arrowBottom",
stroke: e.value.thead.color,
style: r({
opacity: fe(n, a, -1)
})
}, null, 8, ["stroke", "style"])
], 8, st),
f("button", {
class: "vue-ui-table-sparkline-sorting-button vue-ui-table-sparkline-sorting-button-up",
onClick: () => V(a, n, 1)
}, [
D(u(N), {
size: 12,
name: "arrowTop",
stroke: e.value.thead.color,
style: r({
opacity: fe(n, a, 1)
})
}, null, 8, ["stroke", "style"])
], 8, rt)
])) : g("", !0)
], 4),
e.value.userOptions.show && n === k.value.length - 1 && (u(ee) || u(G)) ? (v(), Ue(u(xe), {
ref_for: !0,
ref: "details",
key: `user_option_${Z.value}`,
backgroundColor: e.value.thead.backgroundColor,
color: e.value.thead.color,
isPrinting: u(ae),
isImaging: u(le),
uid: U.value,
hasPdf: e.value.userOptions.buttons.pdf,
hasXls: e.value.userOptions.buttons.csv,
hasImg: e.value.userOptions.buttons.img,
hasFullscreen: e.value.userOptions.buttons.fullscreen,
isFullscreen: de.value,
titles: { ...e.value.userOptions.buttonTitles },
chartElement: F.value,
position: e.value.userOptions.position,
callbacks: e.value.userOptions.callbacks,
printScale: e.value.userOptions.print.scale,
onToggleFullscreen: Pe,
onGeneratePdf: u(oe),
onGenerateImage: u(ne),
onGenerateCsv: ve,
style: r({
visibility: u(ee) ? u(G) ? "visible" : "hidden" : "visible"
})
}, Be({ _: 2 }, [
t.$slots.menuIcon ? {
name: "menuIcon",
fn: P(({ isOpen: s, color: o }) => [
O(t.$slots, "menuIcon", ge({ ref_for: !0 }, { isOpen: s, color: o }), void 0, !0)
]),
key: "0"
} : void 0,
t.$slots.optionPdf ? {
name: "optionPdf",
fn: P(() => [
O(t.$slots, "optionPdf", {}, void 0, !0)
]),
key: "1"
} : void 0,
t.$slots.optionCsv ? {
name: "optionCsv",
fn: P(() => [
O(t.$slots, "optionCsv", {}, void 0, !0)
]),
key: "2"
} : void 0,
t.$slots.optionImg ? {
name: "optionImg",
fn: P(() => [
O(t.$slots, "optionImg", {}, void 0, !0)
]),
key: "3"
} : void 0,
t.$slots.optionFullscreen ? {
name: "optionFullscreen",
fn: P(({ toggleFullscreen: s, isFullscreen: o }) => [
O(t.$slots, "optionFullscreen", ge({ ref_for: !0 }, { toggleFullscreen: s, isFullscreen: o }), void 0, !0)
]),
key: "4"
} : void 0
]), 1032, ["backgroundColor", "color", "isPrinting", "isImaging", "uid", "hasPdf", "hasXls", "hasImg", "hasFullscreen", "isFullscreen", "titles", "chartElement", "position", "callbacks", "printScale", "onGeneratePdf", "onGenerateImage", "style"])) : g("", !0)
], 6))), 256))
], 4)), [
[u(tt), Ne]
])
]),
f("tbody", null, [
(v(!0), c(Q, null, Y(m.value, (a, n) => (v(), c("tr", {
role: "row",
style: r({
backgroundColor: e.value.tbody.backgroundColor,
color: e.value.tbody.color
}),
class: K({ "vue-ui-data-table__tbody__row": !0, "vue-ui-data-table__tbody__row-even": n % 2 === 0, "vue-ui-data-table__tbody__row-odd": n % 2 !== 0 })
}, [
f("td", {
role: "cell",
style: r({
backgroundColor: e.value.tbody.backgroundColor,
border: e.value.tbody.outline,
fontSize: `${e.value.tbody.fontSize}px`,
fontWeight: e.value.tbody.bold ? "bold" : "normal",
textAlign: e.value.tbody.textAlign
}),
"data-cell": e.value.translations.serie,
class: "vue-ui-data-table__tbody__td sticky-col-first"
}, [
f("div", {
dir: "auto",
style: r({
display: "flex",
flexDirection: "row",
alignItems: "center",
gap: "6px",
justifyContent: e.value.tbody.textAlign
})
}, [
e.value.tbody.showColorMarker ? (v(), c("span", {
key: 0,
style: r({ color: a.color })
}, "⬤", 4)) : g("", !0),
f("span", null, C(a.name ?? "-"), 1)
], 4)
], 12, it),
(v(!0), c(Q, null, Y($e.value, (s, o) => (v(), c("td", {
dir: "auto",
role: "cell",
ref_for: !0,
ref_key: "TD",
ref: E,
style: r({
border: e.value.tbody.outline,
fontSize: `${e.value.tbody.fontSize}px`,
fontWeight: e.value.tbody.bold ? "bold" : "normal",
textAlign: e.value.tbody.textAlign,
background: S.value !== void 0 && o === S.value ? e.value.tbody.selectedColor.useSerieColor ? `${a.color.length > 7 ? a.color.slice(0, -2) : a.color}33` : e.value.tbody.selectedColor.fallback : ""
}),
"data-cell": k.value[o] ? k.value[o].value : "",
class: "vue-ui-data-table__tbody__td",
onPointerenter: (d) => {
q.value = n, S.value = o;
}
}, C([null, void 0].includes(a.values[o]) ? "-" : u(W)(
e.value.formatter,
Number(a.values[o]),
u(M)({
p: e.value.prefix,
v: Number(a.values[o]),
s: e.value.suffix,
r: e.value.roundingValues
}),
{ datapoint: a, seriesIndex: n, datapointIndex: o }
)), 45, dt))), 256)),
e.value.showTotal ? (v(), c("td", {
key: 0,
dir: "auto",
role: "cell",
style: r({
border: e.value.tbody.outline,
fontSize: `${e.value.tbody.fontSize}px`,
fontWeight: e.value.tbody.bold ? "bold" : "normal",
textAlign: e.value.tbody.textAlign
}),
"data-cell": e.value.translations.total,
class: "vue-ui-data-table__tbody__td"
}, C(u(W)(
e.value.formatter,
a.sum,
u(M)({
p: e.value.prefix,
v: a.sum,
s: e.value.suffix,
r: e.value.roundingTotal
}),
{ datapoint: a.sum, seriesIndex: n }
)), 13, vt)) : g("", !0),
e.value.showAverage ? (v(), c("td", {
key: 1,
dir: "auto",
role: "cell",
style: r({
border: e.value.tbody.outline,
fontSize: `${e.value.tbody.fontSize}px`,
fontWeight: e.value.tbody.bold ? "bold" : "normal",
textAlign: e.value.tbody.textAlign
}),
"data-cell": e.value.translations.average,
class: "vue-ui-data-table__tbody__td"
}, C(u(W)(
e.value.formatter,
a.average,
u(M)({
p: e.value.prefix,
v: a.average,
s: e.value.suffix,
r: e.value.roundingAverage
}),
{ datapoint: a.average, seriesIndex: n }
)), 13, ct)) : g("", !0),
e.value.showMedian ? (v(), c("td", {
key: 2,
dir: "auto",
role: "cell",
style: r({
border: e.value.tbody.outline,
fontSize: `${e.value.tbody.fontSize}px`,
fontWeight: e.value.tbody.bold ? "bold" : "normal",
textAlign: e.value.tbody.textAlign
}),
"data-cell": e.value.translations.median,
class: "vue-ui-data-table__tbody__td"
}, C(u(W)(
e.value.formatter,
a.median,
u(M)({
p: e.value.prefix,
v: a.median,
s: e.value.suffix,
r: e.value.roundingMedian
}),
{ datapoint: a.median, seriesIndex: n }
)), 13, pt)) : g("", !0),
e.value.showSparklines ? (v(), c("td", {
key: 3,
role: "cell",
"data-cell": e.value.translations.chart,
style: r({
border: e.value.tbody.outline,
fontSize: `${e.value.tbody.fontSize}px`,
fontWeight: e.value.tbody.bold ? "bold" : "normal",
textAlign: e.value.tbody.textAlign,
backgroundColor: e.value.tbody.backgroundColor,
padding: "0"
}),
class: "vue-ui-data-table__tbody__td sticky-col"
}, [
D(u(Ce), {
onHoverIndex: ({ index: s }) => De({ dataIndex: s, serieIndex: n }),
"height-ratio": e.value.sparkline.dimensions.heightRatio,
"forced-padding": 30,
dataset: a.sparklineDataset,
showInfo: !1,
selectedIndex: S.value,
config: {
type: e.value.sparkline.type,
style: {
backgroundColor: "transparent",
animation: {
show: e.value.sparkline.animation.show && !u(ae) && !u(le),
animationFrames: e.value.sparkline.animation.animationFrames
},
padding: {
right: 12
},
line: {
color: a.color,
smooth: e.value.sparkline.smooth,
strokeWidth: e.value.sparkline.strokeWidth
},
bar: {
color: a.color
},
area: {
color: a.color,
opacity: e.value.sparkline.showArea ? 16 : 0,
useGradient: e.value.sparkline.useGradient
},
verticalIndicator: {
color: a.color
},
plot: {
radius: 9,
stroke: e.value.tbody.backgroundColor,
strokeWidth: 3
}
}
}
}, null, 8, ["onHoverIndex", "height-ratio", "dataset", "selectedIndex", "config"])
], 12, ft)) : g("", !0)
], 6))), 256))
])
], 4)
], 32),
t.$slots.source ? (v(), c("div", mt, [
O(t.$slots, "source", {}, void 0, !0)
], 512)) : g("", !0)
], 42, lt));
}
}, wt = /* @__PURE__ */ at(bt, [["__scopeId", "data-v-a5b69075"]]);
export {
wt as default
};