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