vue-data-ui
Version:
A user-empowering data visualization Vue 3 components library for eloquent data storytelling
550 lines (549 loc) • 20.3 kB
JavaScript
import { computed as g, onMounted as Ye, ref as k, watch as De, createElementBlock as c, openBlock as i, unref as u, normalizeStyle as x, normalizeClass as ye, createBlock as I, createCommentVNode as w, createSlots as Ge, withCtx as y, renderSlot as p, normalizeProps as M, guardReactiveProps as z, createVNode as be, createElementVNode as Y, Fragment as F, renderList as A, toDisplayString as W, createTextVNode as Ue, nextTick as Ve } from "vue";
import { u as Be, o as je, e as Re, c as ke, t as Xe, p as q, a as We, b as qe, v as f, f as we, X as Ze, G as Ce, L as Je, i as Ke, q as Qe, r as et } from "./index-CHWA6Lnw.js";
import { _ as tt } from "./Title-BwZtefYd.js";
import { u as ot, U as lt } from "./usePrinter-DibtVl2x.js";
import { D as at } from "./DataTable-B4YF6guk.js";
import nt from "./vue-ui-accordion-gHGrRoVr.js";
import st from "./vue-ui-skeleton-BSUFPx4a.js";
import { u as $e } from "./useNestedProp-ByBiJC9_.js";
import { _ as ut } from "./PackageVersion-DcMafJMi.js";
import { P as rt } from "./PenAndPaper-ljJaW1FE.js";
import { u as it } from "./useUserOptionState-BIvW1Kz7.js";
import { u as ct } from "./useChartAccessibility-BWojgys7.js";
import { _ as dt } from "./_plugin-vue_export-helper-CHgC5LLL.js";
const vt = ["id"], ft = {
key: 1,
ref: "noTitle",
class: "vue-data-ui-no-title-space",
style: "height:36px; width: 100%;background:transparent"
}, ht = {
key: 2,
style: "width:100%;background:transparent;padding-bottom:24px"
}, gt = ["xmlns", "viewBox"], pt = ["width", "height"], mt = ["id"], yt = ["stop-color"], bt = ["stop-color"], kt = ["d", "fill", "stroke", "stroke-width"], wt = ["x", "y", "height", "width", "fill", "stroke", "stroke-width", "onMouseenter"], Ct = ["x", "y", "font-size", "fill"], $t = ["x", "y", "font-size", "fill"], xt = {
key: 4,
class: "vue-data-ui-watermark"
}, _t = {
key: 6,
ref: "source",
dir: "auto"
}, Nt = ["innerHTML"], Tt = {
__name: "vue-ui-flow",
props: {
config: {
type: Object,
default() {
return {};
}
},
dataset: {
type: Array,
default() {
return [];
}
}
},
setup(xe, { expose: _e }) {
const { vue_ui_flow: Ne } = Be(), m = xe, D = g(() => !!m.dataset && m.dataset.length);
Ye(() => {
Z();
});
function Z() {
je(m.dataset) && Re({
componentName: "VueUiFlow",
type: "dataset"
});
}
const G = k(ke()), J = k(null), K = k(0), Q = k(0), T = k(!1);
function Te(t) {
T.value = t, K.value += 1;
}
const e = g({
get: () => le(),
set: (t) => t
}), { userOptionsVisible: U, setUserOptionsVisibility: ee, keepUserOptionState: te } = it({ config: e.value }), { svgRef: oe } = ct({ config: e.value.style.chart.title });
function le() {
const t = $e({
userConfig: m.config,
defaultConfig: Ne
});
return t.theme ? {
...$e({
userConfig: We.vue_ui_flow[t.theme] || m.config,
defaultConfig: t
}),
customPalette: Xe[t.theme] || q
} : t;
}
De(() => m.config, (t) => {
e.value = le(), U.value = !e.value.userOptions.showOnChartHover, Z(), Q.value += 1, O.value.showTable = e.value.table.show;
}, { deep: !0 });
const { isPrinting: ae, isImaging: ne, generatePdf: se, generateImage: ue } = ot({
elementId: `flow_${G.value}`,
fileName: e.value.style.chart.title.text || "vue-ui-flow"
}), Oe = g(() => e.value.userOptions.show && !e.value.style.chart.title.text), V = g(() => qe(e.value.customPalette)), re = g(() => e.value.style.chart.nodes.gap), _ = g(() => e.value.style.chart.nodes.width), O = k({
showTable: e.value.table.show
}), ie = g(() => e.value.style.chart.links.width), B = g(() => !m.dataset || !m.dataset.length ? [] : m.dataset.map((t) => [
t[0],
t[1],
f(t[2])
])), ce = g(() => {
const t = {};
function l(a) {
t[a] || (t[a] = { inflow: 0, outflow: 0 });
}
B.value.forEach(([a, n, v]) => {
l(a), l(n), t[a].outflow += v, t[n].inflow += v;
});
let o = 0;
for (const a in t) {
const n = Math.max(t[a].inflow, t[a].outflow);
o = Math.max(o, n);
}
return o;
});
function Pe(t) {
return t / ce.value * 100 + e.value.style.chart.nodes.minHeight;
}
function Ie(t) {
const l = e.value.style.chart.nodes.minHeight;
return (t - l) / 100 * ce.value;
}
function Fe(t) {
const l = {}, o = {};
function a(s, r) {
l[s] || (l[s] = { height: 0, level: null, inflow: 0, outflow: 0 }), l[s].level === null && (l[s].level = r), o[r] || (o[r] = []), o[r].includes(s) || o[r].push(s);
}
t.forEach(([s, r, h], N) => {
const $ = l[s] ? l[s].level : 0, E = $ + 1;
a(s, $), a(r, E), l[s].children || (l[s].children = []), l[s].children.push({ target: r, value: h }), l[s].outflow += h, l[r].inflow += h;
}), Object.keys(l).forEach((s, r) => {
l[s].color = V.value[r] || V.value[r % V.value.length] || q[r] || q[r % d.length];
});
for (const s in l)
l[s].height = Pe(Math.max(l[s].inflow, l[s].outflow)), l[s].name = s;
const n = {};
for (const s in o) {
let r = 0;
o[s].forEach((h, N) => {
const $ = l[h].height;
n[h] = {
x: parseInt(s, 10) * ie.value + e.value.style.chart.padding.left,
y: r,
absoluteY: r,
height: $,
i: N,
color: l[h].color,
value: Ie($)
}, r += $ + re.value;
});
}
const v = [];
for (const s in l) {
let r = n[s].absoluteY + e.value.style.chart.padding.top;
l[s].children && l[s].children.forEach(({ target: h, value: N }, $) => {
const E = n[h].y + e.value.style.chart.padding.top, R = n[s], X = n[h], he = f(r), ge = f(r + N / l[s].outflow * R.height), pe = f(E), me = f(E + N / l[h].inflow * X.height), ze = {
id: ke(),
source: s,
target: h,
path: `M ${f(R.x) + f(_.value)} ${he} L ${f(R.x) + f(_.value)} ${ge} L ${f(X.x)} ${me} L ${f(X.x)} ${pe} Z`,
value: N,
sourceColor: l[s].color,
targetColor: l[h].color
};
v.push(ze), r += ge - he, n[h].y += me - pe;
});
}
return { nodeCoordinates: n, links: v };
}
const b = g(() => {
const t = Fe(m.dataset);
return {
nodes: Object.keys(t.nodeCoordinates).map((l, o) => ({
...t.nodeCoordinates[l],
name: l
})),
links: t.links
};
}), Ae = g(() => Le(b.value.nodes));
function Le(t) {
const l = {};
for (const a in t) {
const { x: n, height: v } = t[a];
l[n] || (l[n] = 0), l[n] += v + re.value;
}
return Math.max(...Object.values(l));
}
const P = g(() => {
const { top: t, right: l, left: o, bottom: a } = e.value.style.chart.padding, n = B.value.length * ie.value;
return {
height: Ae.value + t + a,
width: l + Math.max(...b.value.nodes.map((v) => v.x)) + _.value,
left: o,
top: t,
right: n - l,
p_top: t,
p_bottom: a
};
});
function He(t) {
const l = {}, o = {}, a = /* @__PURE__ */ new Set();
return B.value.forEach(([n, v, s]) => {
l[n] || (l[n] = []), o[v] || (o[v] = []), l[n].push(v), o[v].push(n);
}), l[t] && l[t].forEach((n) => a.add(n)), o[t] && o[t].forEach((n) => a.add(n)), Array.from(a).concat(t);
}
const C = k(null), L = k(null);
function Se(t) {
C.value = He(t.name), L.value = t.name;
}
function Ee() {
C.value = null, L.value = null;
}
const de = g(() => b.value.links.map(({ source: t, target: l, sourceColor: o, targetColor: a, value: n }) => ({
source: t,
target: l,
sourceColor: o,
targetColor: a,
value: n
})));
function ve() {
Ve(() => {
const t = de.value.map((a, n) => [
[a.source],
[a.target],
[a.value]
]), l = [
[e.value.style.chart.title.text],
[e.value.style.chart.title.subtitle.text],
[
[e.value.table.columnNames.source],
[e.value.table.columnNames.target],
[e.value.table.columnNames.value]
]
].concat(t), o = Qe(l);
et({
csvContent: o,
title: e.value.style.chart.title.text || "vue-ui-flow"
});
});
}
const H = g(() => {
const t = [
e.value.table.columnNames.source,
e.value.table.columnNames.target,
e.value.table.columnNames.value
], l = de.value.map((n, v) => [
{
color: n.sourceColor,
name: n.source
},
{
color: n.targetColor,
name: n.target
},
we({
p: e.value.style.chart.nodes.labels.prefix,
v: n.value,
s: e.value.style.chart.nodes.labels.suffix,
r: e.value.style.chart.nodes.labels.rounding
})
]), o = {
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.source,
e.value.table.columnNames.target,
e.value.table.columnNames.value
],
head: t,
body: l,
config: o
};
});
function Me() {
return b.value;
}
function fe() {
O.value.showTable = !O.value.showTable;
}
const S = k(!1);
function j() {
S.value = !S.value;
}
return _e({
getData: Me,
generateCsv: ve,
generateImage: ue,
generatePdf: se,
toggleTable: fe,
toggleAnnotator: j
}), (t, l) => (i(), c("div", {
ref_key: "flowChart",
ref: J,
class: ye(`vue-ui-flow ${T.value ? "vue-data-ui-wrapper-fullscreen" : ""}`),
style: x(`font-family:${e.value.style.fontFamily};width:100%; text-align:center;background:${e.value.style.chart.backgroundColor}`),
id: `flow_${G.value}`,
onMouseenter: l[2] || (l[2] = () => u(ee)(!0)),
onMouseleave: l[3] || (l[3] = () => u(ee)(!1))
}, [
e.value.userOptions.buttons.annotator ? (i(), I(rt, {
key: 0,
svgRef: u(oe),
backgroundColor: e.value.style.chart.backgroundColor,
color: e.value.style.chart.color,
active: S.value,
onClose: j
}, null, 8, ["svgRef", "backgroundColor", "color", "active"])) : w("", !0),
Oe.value ? (i(), c("div", ft, null, 512)) : w("", !0),
e.value.style.chart.title.text ? (i(), c("div", ht, [
(i(), I(tt, {
key: `title_${Q.value}`,
config: {
title: {
cy: "flow-title",
...e.value.style.chart.title
},
subtitle: {
cy: "flow-subtitle",
...e.value.style.chart.title.subtitle
}
}
}, null, 8, ["config"]))
])) : w("", !0),
e.value.userOptions.show && D.value && (u(te) || u(U)) ? (i(), I(lt, {
ref: "details",
key: `user_option_${K.value}`,
backgroundColor: e.value.style.chart.backgroundColor,
color: e.value.style.chart.color,
isPrinting: u(ae),
isImaging: u(ne),
uid: G.value,
hasPdf: e.value.userOptions.buttons.pdf,
hasXls: e.value.userOptions.buttons.csv,
hasImg: e.value.userOptions.buttons.img,
hasTable: e.value.userOptions.buttons.table,
hasFullscreen: e.value.userOptions.buttons.fullscreen,
isFullscreen: T.value,
titles: { ...e.value.userOptions.buttonTitles },
chartElement: J.value,
position: e.value.userOptions.position,
hasAnnotator: e.value.userOptions.buttons.annotator,
isAnnotation: S.value,
onToggleFullscreen: Te,
onGeneratePdf: u(se),
onGenerateCsv: ve,
onGenerateImage: u(ue),
onToggleTable: fe,
onToggleAnnotator: j,
style: x({
visibility: u(te) ? u(U) ? "visible" : "hidden" : "visible"
})
}, Ge({ _: 2 }, [
t.$slots.menuIcon ? {
name: "menuIcon",
fn: y(({ isOpen: o, color: a }) => [
p(t.$slots, "menuIcon", M(z({ isOpen: o, color: a })), void 0, !0)
]),
key: "0"
} : void 0,
t.$slots.optionPdf ? {
name: "optionPdf",
fn: y(() => [
p(t.$slots, "optionPdf", {}, void 0, !0)
]),
key: "1"
} : void 0,
t.$slots.optionCsv ? {
name: "optionCsv",
fn: y(() => [
p(t.$slots, "optionCsv", {}, void 0, !0)
]),
key: "2"
} : void 0,
t.$slots.optionImg ? {
name: "optionImg",
fn: y(() => [
p(t.$slots, "optionImg", {}, void 0, !0)
]),
key: "3"
} : void 0,
t.$slots.optionTable ? {
name: "optionTable",
fn: y(() => [
p(t.$slots, "optionTable", {}, void 0, !0)
]),
key: "4"
} : void 0,
t.$slots.optionFullscreen ? {
name: "optionFullscreen",
fn: y(({ toggleFullscreen: o, isFullscreen: a }) => [
p(t.$slots, "optionFullscreen", M(z({ toggleFullscreen: o, isFullscreen: a })), void 0, !0)
]),
key: "5"
} : void 0,
t.$slots.optionAnnotator ? {
name: "optionAnnotator",
fn: y(({ toggleAnnotator: o, isAnnotator: a }) => [
p(t.$slots, "optionAnnotator", M(z({ toggleAnnotator: o, isAnnotator: a })), void 0, !0)
]),
key: "6"
} : void 0
]), 1032, ["backgroundColor", "color", "isPrinting", "isImaging", "uid", "hasPdf", "hasXls", "hasImg", "hasTable", "hasFullscreen", "isFullscreen", "titles", "chartElement", "position", "hasAnnotator", "isAnnotation", "onGeneratePdf", "onGenerateImage", "style"])) : w("", !0),
(i(), c("svg", {
ref_key: "svgRef",
ref: oe,
xmlns: u(Ze),
viewBox: `0 0 ${P.value.width} ${P.value.height}`,
class: ye({ "vue-data-ui-fullscreen--on": T.value, "vue-data-ui-fulscreen--off": !T.value }),
style: x(`max-width:100%; overflow: visible; background:transparent;color:${e.value.style.chart.color}`)
}, [
be(ut),
t.$slots["chart-background"] ? (i(), c("foreignObject", {
key: 0,
x: 0,
y: 0,
width: P.value.width,
height: P.value.height,
style: {
pointerEvents: "none"
}
}, [
p(t.$slots, "chart-background", {}, void 0, !0)
], 8, pt)) : w("", !0),
Y("defs", null, [
(i(!0), c(F, null, A(b.value.links, (o, a) => (i(), c("linearGradient", {
id: o.id,
x1: "0%",
y1: "0%",
x2: "100%",
y2: "0%"
}, [
Y("stop", {
offset: "0%",
"stop-color": o.sourceColor
}, null, 8, yt),
Y("stop", {
offset: "100%",
"stop-color": o.targetColor
}, null, 8, bt)
], 8, mt))), 256))
]),
(i(!0), c(F, null, A(b.value.links, (o) => (i(), c("path", {
class: "vue-ui-flow-link",
d: o.path,
fill: `url(#${o.id})`,
stroke: e.value.style.chart.links.stroke,
"stroke-width": e.value.style.chart.links.strokeWidth,
style: x(`opacity:${L.value ? [o.target, o.source].includes(L.value) ? 1 : 0.3 : e.value.style.chart.links.opacity}`)
}, null, 12, kt))), 256)),
(i(!0), c(F, null, A(b.value.nodes, (o, a) => (i(), c("rect", {
class: "vue-ui-flow-node",
x: o.x,
y: u(f)(o.absoluteY) + e.value.style.chart.padding.top,
height: u(f)(o.height),
width: _.value,
fill: o.color,
stroke: e.value.style.chart.nodes.stroke,
"stroke-width": e.value.style.chart.nodes.strokeWidth,
onMouseenter: (n) => Se(o),
onMouseleave: l[0] || (l[0] = (n) => Ee()),
style: x(`opacity:${C.value ? C.value.includes(o.name) ? 1 : 0.2 : 1}`)
}, null, 44, wt))), 256)),
(i(!0), c(F, null, A(b.value.nodes, (o, a) => (i(), c("text", {
x: o.x + _.value / 2,
y: u(f)(o.absoluteY + o.height / 2 - e.value.style.chart.nodes.labels.fontSize / 4) + e.value.style.chart.padding.top,
"font-size": e.value.style.chart.nodes.labels.fontSize,
fill: u(Ce)(o.color),
"text-anchor": "middle",
style: x(`pointer-events: none; opacity:${C.value ? C.value.includes(o.name) ? 1 : 0 : 1}`)
}, W(e.value.style.chart.nodes.labels.abbreviation.use ? u(Je)({ source: o.name, length: e.value.style.chart.nodes.labels.abbreviation.length }) : o.name), 13, Ct))), 256)),
(i(!0), c(F, null, A(b.value.nodes, (o, a) => (i(), c("text", {
x: o.x + _.value / 2,
y: u(f)(o.absoluteY + o.height / 2 + e.value.style.chart.nodes.labels.fontSize) + e.value.style.chart.padding.top,
"font-size": e.value.style.chart.nodes.labels.fontSize,
fill: u(Ce)(o.color),
"text-anchor": "middle",
style: x(`pointer-events: none; opacity:${C.value ? C.value.includes(o.name) ? 1 : 0 : 1}`)
}, W(u(Ke)(
e.value.style.chart.nodes.labels.formatter,
o.value,
u(we)({
p: e.value.style.chart.nodes.labels.prefix,
v: o.value,
s: e.value.style.chart.nodes.labels.suffix,
r: e.value.style.chart.nodes.labels.rounding
}),
{ datapoint: o, seriesIndex: a }
)), 13, $t))), 256)),
p(t.$slots, "svg", { svg: P.value }, void 0, !0)
], 14, gt)),
t.$slots.watermark ? (i(), c("div", xt, [
p(t.$slots, "watermark", M(z({ isPrinting: u(ae) || u(ne) })), void 0, !0)
])) : w("", !0),
D.value ? w("", !0) : (i(), I(st, {
key: 5,
config: {
type: "flow",
style: {
backgroundColor: e.value.style.chart.backgroundColor
}
}
}, null, 8, ["config"])),
t.$slots.source ? (i(), c("div", _t, [
p(t.$slots, "source", {}, void 0, !0)
], 512)) : w("", !0),
D.value ? (i(), I(nt, {
key: 7,
hideDetails: "",
config: {
open: O.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: y(() => [
be(at, {
colNames: H.value.colNames,
head: H.value.head,
body: H.value.body,
config: H.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[1] || (l[1] = (o) => O.value.showTable = !1)
}, {
th: y(({ th: o }) => [
Y("div", {
innerHTML: o,
style: { display: "flex", "align-items": "center" }
}, null, 8, Nt)
]),
td: y(({ td: o }) => [
Ue(W(o.name || o), 1)
]),
_: 1
}, 8, ["colNames", "head", "body", "config", "title"])
]),
_: 1
}, 8, ["config"])) : w("", !0)
], 46, vt));
}
}, Gt = /* @__PURE__ */ dt(Tt, [["__scopeId", "data-v-0482669d"]]);
export {
Gt as default
};