vue-data-ui
Version:
A user-empowering data visualization Vue 3 components library for eloquent data storytelling
646 lines (645 loc) • 23.6 kB
JavaScript
import { useCssVars as Ge, computed as y, createElementBlock as m, openBlock as r, createElementVNode as N, renderSlot as i, createVNode as ne, normalizeStyle as J, ref as n, watch as H, onMounted as Le, onBeforeUnmount as Xe, unref as c, createBlock as M, createCommentVNode as k, createSlots as je, withCtx as h, normalizeProps as S, guardReactiveProps as F, normalizeClass as $e, Fragment as qe, renderList as He, toDisplayString as xe, createTextVNode as Ye, nextTick as Te } from "vue";
import { u as Je, c as Se, a5 as Ke, v as Qe, t as Ze, p as Y, a as et, o as tt, e as Fe, g as ot, f as at, X as lt, q as st, r as nt, x as rt } from "./index-CHWA6Lnw.js";
import { _ as ut } from "./Title-BwZtefYd.js";
import { u as it, U as ct } from "./usePrinter-DibtVl2x.js";
import { d as dt, t as vt, u as ht } from "./useResponsive-vZgZwV-S.js";
import mt from "./vue-ui-accordion-gHGrRoVr.js";
import { D as ft } from "./DataTable-B4YF6guk.js";
import pt from "./BaseIcon-AmoKryXo.js";
import { _ as ze } from "./_plugin-vue_export-helper-CHgC5LLL.js";
import { u as Ne } from "./useNestedProp-ByBiJC9_.js";
import { _ as gt } from "./PackageVersion-DcMafJMi.js";
import { _ as yt } from "./Tooltip-eCCz9HFo.js";
import { P as bt } from "./PenAndPaper-ljJaW1FE.js";
import { u as Ct } from "./useUserOptionState-BIvW1Kz7.js";
import { u as kt } from "./useChartAccessibility-BWojgys7.js";
const wt = { "data-html2canvas-ignore": "" }, $t = {
key: 0,
class: "reset-wrapper"
}, xt = {
key: 1,
class: "reset-wrapper"
}, Tt = { class: "mono-slicer" }, St = ["min", "max", "value"], Ft = {
__name: "MonoSlicer",
props: {
min: {
type: Number,
default: 0
},
max: {
type: Number,
default: 0
},
inputColor: {
type: String,
default: "#1A1A1A"
},
background: {
type: String,
default: "#FFFFFF"
},
borderColor: {
type: String,
default: "#FFFFFF"
},
selectColor: {
type: String,
default: "#4A4A4A"
},
textColor: {
type: String,
default: "#1A1A1A"
},
useResetSlot: {
type: Boolean,
default: !1
},
value: {
type: Number,
default: 0
},
source: {
type: Number,
default: 0
}
},
emits: ["update:value", "reset"],
setup(f, { emit: K }) {
Ge((x) => ({
"782b8172": d.value,
"102109e6": V.value,
"642212d7": _.value,
"1f5369d4": f.selectColor,
"22b98ab8": z.value
}));
const p = f, d = y(() => p.inputColor), z = y(() => p.background), _ = y(() => `${p.selectColor}33`), V = y(() => p.borderColor), w = K;
function R() {
w("reset");
}
const B = y(() => {
const x = p.max - p.min, b = 0, T = (p.value - p.min) / x * 100;
return {
left: `${b}%`,
width: `${T - b}%`,
background: p.selectColor
};
});
return (x, b) => (r(), m("div", wt, [
f.value !== f.source ? (r(), m("div", $t, [
f.useResetSlot ? i(x.$slots, "reset-action", {
key: 1,
reset: R
}, void 0, !0) : (r(), m("button", {
key: 0,
"data-cy-reset": "",
tabindex: "0",
role: "button",
class: "vue-data-ui-refresh-button",
onClick: R
}, [
ne(pt, {
name: "refresh",
stroke: f.textColor
}, null, 8, ["stroke"])
]))
])) : (r(), m("div", xt)),
N("div", Tt, [
b[1] || (b[1] = N("div", { class: "slider-track" }, null, -1)),
N("div", {
class: "range-highlight",
style: J(B.value)
}, null, 4),
N("input", {
type: "range",
min: f.min,
max: f.max,
value: Number(f.value),
onInput: b[0] || (b[0] = (T) => w("update:value", Number(T.target.value)))
}, null, 40, St)
])
]));
}
}, Nt = /* @__PURE__ */ ze(Ft, [["__scopeId", "data-v-b4e6aee9"]]), zt = ["id"], At = ["xmlns", "viewBox"], Ot = ["width", "height"], Pt = ["transform"], It = ["fill", "font-weight", "x", "y", "font-size", "transform", "onMouseover"], Mt = {
key: 4,
class: "vue-data-ui-watermark"
}, _t = ["innerHTML"], Rt = {
__name: "vue-ui-word-cloud",
props: {
config: {
type: Object,
default() {
return {};
}
},
dataset: {
type: [Array, String],
default() {
return [];
}
}
},
setup(f, { expose: K }) {
const { vue_ui_word_cloud: p } = Je(), d = f, z = y({
get() {
return !!d.dataset && d.dataset.length;
},
set(t) {
return t;
}
}), _ = n(Se()), V = n(0), w = n(null), R = n(null), B = n(null), x = n(0), b = n(0), T = n(!1), e = y({
get: () => de(),
set: (t) => t
}), A = n(re());
function re() {
return typeof d.dataset == "string" ? Ke(d.dataset) : d.dataset.map((t, a) => ({
...t,
value: Qe(t.value)
}));
}
H(() => d.dataset, () => {
A.value = re(), E();
});
const { userOptionsVisible: Q, setUserOptionsVisibility: ue, keepUserOptionState: ie } = Ct({ config: e.value }), { svgRef: ce } = kt({ config: e.value.style.chart.title });
function de() {
const t = Ne({
userConfig: d.config,
defaultConfig: p
});
return t.theme ? {
...Ne({
userConfig: et.vue_ui_word_cloud[t.theme] || d.config,
defaultConfig: t
}),
customPalette: Ze[t.theme] || Y
} : t;
}
H(() => d.config, (t) => {
e.value = de(), Q.value = !e.value.userOptions.showOnChartHover, he(), x.value += 1, b.value += 1, Z(), v.value.showTable = e.value.table.show, v.value.showTooltip = e.value.style.chart.tooltip.show;
}, { deep: !0 });
const ve = n(null), O = n(0), s = n({
width: e.value.style.chart.width,
height: e.value.style.chart.height,
maxFontSize: e.value.style.chart.words.maxFontSize,
minFontSize: e.value.style.chart.words.minFontSize
}), Ae = vt(() => {
const { width: t, height: a } = ht({
chart: w.value,
title: e.value.style.chart.title.text ? R.value : null,
slicer: e.value.style.chart.zoom.show && ve.value,
source: B.value
});
requestAnimationFrame(() => {
s.value.width = t, s.value.height = a, Te(E);
});
});
H(() => O.value, () => {
Oe();
});
const Oe = dt(() => {
E();
}, 10);
function Z() {
O.value = ee.value;
}
const D = n(null);
Le(() => {
he(), Z();
});
function he() {
tt(d.dataset) ? Fe({
componentName: "VueUiWordCloud",
type: "dataset"
}) : A.value.forEach((t, a) => {
ot({
datasetObject: t,
requiredAttributes: ["name", "value"]
}).forEach((o) => {
z.value = !1, Fe({
componentName: "VueUiWordCloud",
type: "datasetSerieAttribute",
property: o,
index: a
});
});
}), e.value.responsive && (D.value = new ResizeObserver(Ae), D.value.observe(w.value.parentNode));
}
Xe(() => {
D.value && D.value.disconnect();
});
const { isPrinting: me, isImaging: fe, generatePdf: pe, generateImage: ge } = it({
elementId: `wordCloud_${_.value}`,
fileName: e.value.style.chart.title.text || "vue-ui-word-cloud"
}), v = n({
showTable: e.value.table.show,
showTooltip: e.value.style.chart.tooltip.show
});
function Pe(t, a, o = "Arial") {
const l = document.createElement("canvas").getContext("2d");
return l.font = `${a}px ${e.value.style.chart.words.bold ? "bold" : "normal"} ${o}`, {
width: l.measureText(t).width + e.value.style.chart.words.proximity,
height: a
};
}
function Ie(t, a) {
return t.x < a.x + a.width && t.x + t.width > a.x && t.y < a.y + a.height && t.y + t.height > a.y;
}
function Me(t, a, o) {
const u = [], l = { x: -a / 2, y: -o / 2, width: a, height: o }, g = 0, C = 0;
return t.forEach((I) => {
let le = !1;
for (let q = 0; q < Math.max(a, o) / 2 && !le; q += e.value.style.chart.words.packingWeight)
for (let se = 0; se < 360 && !le; se += e.value.style.chart.words.packingWeight) {
const we = se * Math.PI / 180, Ue = g + q * Math.cos(we) - I.width / 2, Ve = C + q * Math.sin(we) - I.height / 2, $ = { ...I, x: Ue, y: Ve }, Be = $.x >= l.x && $.y >= l.y && $.x + $.width <= l.x + l.width && $.y + $.height <= l.y + l.height, De = u.some((Ee) => Ie($, Ee));
Be && !De && (u.push($), le = !0);
}
}), u;
}
const W = n([]);
H(() => d.dataset, E, { immediate: !0 });
const ee = y(() => Math.round(Math.min(...A.value.map((t) => t.value)))), ye = y(() => Math.round(Math.max(...A.value.map((t) => t.value))));
function E() {
const t = [...A.value].filter((l) => l.value >= O.value).map((l) => l.value), a = Math.max(...t), o = Math.min(...t), u = [...A.value].filter((l) => l.value >= O.value).map((l, g) => {
let C = (l.value - o) / (a - o) * (s.value.maxFontSize - s.value.minFontSize) + s.value.minFontSize;
C = isNaN(C) ? s.value.minFontSize : C;
const I = Pe(l.name, C);
return {
...l,
id: Se(),
fontSize: C,
width: I.width,
height: I.height,
color: e.value.style.chart.words.usePalette ? e.value.customPalette[g] || e.value.customPalette[g % e.value.customPalette.length] || Y[g] || Y[g % Y.length] : e.value.style.chart.words.color
};
});
W.value = Me(u, s.value.width, s.value.height).sort((l, g) => g.fontSize - l.fontSize);
}
const G = y(() => {
const t = W.value.map((o) => ({
name: o.name,
color: o.color
})), a = W.value.map((o) => o.value);
return { head: t, body: a };
});
function be() {
Te(() => {
const t = G.value.head.map((u, l) => [[
u.name
], [G.value.body[l]]]), a = [[e.value.style.chart.title.text], [e.value.style.chart.title.subtitle.text], [[""], [e.value.table.columnNames.value]]].concat(t), o = st(a);
nt({ csvContent: o, title: e.value.style.chart.title.text || "vue-ui-word-cloud" });
});
}
const L = y(() => {
const t = [
e.value.table.columnNames.series,
e.value.table.columnNames.value
], a = G.value.head.map((l, g) => {
const C = at({ p: e.value.table.td.prefix, v: G.value.body[g], s: e.value.table.td.suffix, r: e.value.table.td.roundingValue });
return [
{
color: l.color,
name: l.name
},
C
];
}), 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.series,
e.value.table.columnNames.value
],
head: t,
body: a,
config: o
};
}), X = n(!1);
function _e(t) {
X.value = t, V.value += 1;
}
function Re() {
return W.value;
}
function Ce() {
v.value.showTable = !v.value.showTable;
}
function ke() {
v.value.showTooltip = !v.value.showTooltip;
}
const j = n(!1);
function te() {
j.value = !j.value;
}
K({
getData: Re,
generateCsv: be,
generatePdf: pe,
generateImage: ge,
toggleTable: Ce,
toggleTooltip: ke,
toggleAnnotator: te
});
const P = n(null), U = n(!1), oe = n(""), ae = n(null);
function We(t) {
if (!v.value.showTooltip) return;
P.value = t.id, ae.value = { datapoint: t, config: e.value };
const a = e.value.style.chart.tooltip.customFormat;
if (U.value = !1, rt(a))
try {
const o = a({
datapoint: t,
config: e.value
});
typeof o == "string" && (oe.value = o, U.value = !0);
} catch {
console.warn("Custom format cannot be applied."), U.value = !1;
}
if (!U.value) {
let o = `<svg viewBox="0 0 10 10" height="${e.value.style.chart.tooltip.fontSize}"><circle cx="5" cy="5" r="5" fill="${t.color}"/></svg><span>${t.name}:</span><b>${(t.value || 0).toFixed(e.value.style.chart.tooltip.roundingValue)}</b>`;
oe.value = `<div dir="auto" style="display:flex; gap:4px; align-items:center; jsutify-content:center;">${o}</div>`;
}
T.value = !0;
}
return (t, a) => (r(), m("div", {
class: "vue-ui-word-cloud",
ref_key: "wordCloudChart",
ref: w,
id: `wordCloud_${_.value}`,
style: J(`width: 100%; font-family:${e.value.style.fontFamily};background:${e.value.style.chart.backgroundColor};${e.value.responsive ? "height:100%" : ""}`),
onMouseenter: a[3] || (a[3] = () => c(ue)(!0)),
onMouseleave: a[4] || (a[4] = () => c(ue)(!1))
}, [
e.value.userOptions.buttons.annotator ? (r(), M(bt, {
key: 0,
svgRef: c(ce),
backgroundColor: e.value.style.chart.backgroundColor,
color: e.value.style.chart.color,
active: j.value,
onClose: te
}, null, 8, ["svgRef", "backgroundColor", "color", "active"])) : k("", !0),
e.value.style.chart.title.text ? (r(), m("div", {
key: 1,
ref_key: "chartTitle",
ref: R,
style: "width:100%;background:transparent;padding-bottom:24px"
}, [
(r(), M(ut, {
key: `title_${x.value}`,
config: {
title: {
...e.value.style.chart.title
},
subtitle: {
...e.value.style.chart.title.subtitle
}
}
}, null, 8, ["config"]))
], 512)) : k("", !0),
e.value.userOptions.show && z.value && (c(ie) || c(Q)) ? (r(), M(ct, {
ref: "details",
key: `user_option_${V.value}`,
backgroundColor: e.value.style.chart.backgroundColor,
color: e.value.style.chart.color,
isPrinting: c(me),
isImaging: c(fe),
uid: _.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: X.value,
titles: { ...e.value.userOptions.buttonTitles },
chartElement: w.value,
position: e.value.userOptions.position,
hasTooltip: e.value.style.chart.tooltip.show && e.value.userOptions.buttons.tooltip,
isTooltip: v.value.showTooltip,
hasAnnotator: e.value.userOptions.buttons.annotator,
isAnnotation: j.value,
onToggleFullscreen: _e,
onGeneratePdf: c(pe),
onGenerateCsv: be,
onGenerateImage: c(ge),
onToggleTable: Ce,
onToggleTooltip: ke,
onToggleAnnotator: te,
style: J({
visibility: c(ie) ? c(Q) ? "visible" : "hidden" : "visible"
})
}, je({ _: 2 }, [
t.$slots.menuIcon ? {
name: "menuIcon",
fn: h(({ isOpen: o, color: u }) => [
i(t.$slots, "menuIcon", S(F({ isOpen: o, color: u })), void 0, !0)
]),
key: "0"
} : void 0,
t.$slots.optionPdf ? {
name: "optionPdf",
fn: h(() => [
i(t.$slots, "optionPdf", {}, void 0, !0)
]),
key: "1"
} : void 0,
t.$slots.optionCsv ? {
name: "optionCsv",
fn: h(() => [
i(t.$slots, "optionCsv", {}, void 0, !0)
]),
key: "2"
} : void 0,
t.$slots.optionImg ? {
name: "optionImg",
fn: h(() => [
i(t.$slots, "optionImg", {}, void 0, !0)
]),
key: "3"
} : void 0,
t.$slots.optionTable ? {
name: "optionTable",
fn: h(() => [
i(t.$slots, "optionTable", {}, void 0, !0)
]),
key: "4"
} : void 0,
t.$slots.optionFullscreen ? {
name: "optionFullscreen",
fn: h(({ toggleFullscreen: o, isFullscreen: u }) => [
i(t.$slots, "optionFullscreen", S(F({ toggleFullscreen: o, isFullscreen: u })), void 0, !0)
]),
key: "5"
} : void 0,
t.$slots.optionAnnotator ? {
name: "optionAnnotator",
fn: h(({ toggleAnnotator: o, isAnnotator: u }) => [
i(t.$slots, "optionAnnotator", S(F({ toggleAnnotator: o, isAnnotator: u })), void 0, !0)
]),
key: "6"
} : void 0
]), 1032, ["backgroundColor", "color", "isPrinting", "isImaging", "uid", "hasPdf", "hasXls", "hasImg", "hasTable", "hasFullscreen", "isFullscreen", "titles", "chartElement", "position", "hasTooltip", "isTooltip", "hasAnnotator", "isAnnotation", "onGeneratePdf", "onGenerateImage", "style"])) : k("", !0),
z.value ? (r(), m("svg", {
key: 3,
ref_key: "svgRef",
ref: ce,
class: $e({ "vue-data-ui-fullscreen--on": X.value, "vue-data-ui-fulscreen--off": !X.value }),
xmlns: c(lt),
viewBox: `0 0 ${s.value.width <= 0 ? 10 : s.value.width} ${s.value.height <= 0 ? 10 : s.value.height}`,
style: "overflow:visible;background:transparent;"
}, [
ne(gt),
t.$slots["chart-background"] ? (r(), m("foreignObject", {
key: 0,
x: 0,
y: 0,
width: s.value.width <= 0 ? 10 : s.value.width,
height: s.value.height <= 0 ? 10 : s.value.height,
style: {
pointerEvents: "none"
}
}, [
i(t.$slots, "chart-background", {}, void 0, !0)
], 8, Ot)) : k("", !0),
N("g", {
transform: `translate(${(s.value.width <= 0 ? 10 : s.value.width) / 2}, ${(s.value.height <= 0 ? 10 : s.value.height) / 2})`
}, [
(r(!0), m(qe, null, He(W.value, (o, u) => (r(), m("g", null, [
(r(), m("text", {
fill: o.color,
"font-weight": e.value.style.chart.words.bold ? "bold" : "normal",
key: u,
x: o.x,
y: o.y,
"font-size": o.fontSize,
transform: `translate(${o.width / 2}, ${o.height / 2})`,
class: $e({ animated: e.value.useCssAnimation, "word-selected": P.value && P.value === o.id && v.value.showTooltip, "word-not-selected": P.value && P.value !== o.id && v.value.showTooltip }),
"text-anchor": "middle",
"dominant-baseline": "central",
onMouseover: (l) => We(o),
onMouseleave: a[0] || (a[0] = (l) => {
P.value = null, T.value = !1;
}),
style: J(`animation-delay:${u * e.value.animationDelayMs}ms !important;`)
}, xe(o.name), 47, It))
]))), 256))
], 8, Pt),
i(t.$slots, "svg", {
svg: { height: s.value.height, width: s.value.width }
}, void 0, !0)
], 10, At)) : k("", !0),
t.$slots.watermark ? (r(), m("div", Mt, [
i(t.$slots, "watermark", S(F({ isPrinting: c(me) || c(fe) })), void 0, !0)
])) : k("", !0),
ne(yt, {
show: v.value.showTooltip && T.value,
backgroundColor: e.value.style.chart.tooltip.backgroundColor,
color: e.value.style.chart.tooltip.color,
fontSize: e.value.style.chart.tooltip.fontSize,
borderRadius: e.value.style.chart.tooltip.borderRadius,
borderColor: e.value.style.chart.tooltip.borderColor,
borderWidth: e.value.style.chart.tooltip.borderWidth,
backgroundOpacity: e.value.style.chart.tooltip.backgroundOpacity,
position: e.value.style.chart.tooltip.position,
offsetY: e.value.style.chart.tooltip.offsetY,
parent: w.value,
content: oe.value,
isCustom: U.value
}, {
"tooltip-before": h(() => [
i(t.$slots, "tooltip-before", S(F({ ...ae.value })), void 0, !0)
]),
"tooltip-after": h(() => [
i(t.$slots, "tooltip-after", S(F({ ...ae.value })), void 0, !0)
]),
_: 3
}, 8, ["show", "backgroundColor", "color", "fontSize", "borderRadius", "borderColor", "borderWidth", "backgroundOpacity", "position", "offsetY", "parent", "content", "isCustom"]),
N("div", {
ref_key: "chartSlicer",
ref: ve,
style: "width:100%;background:transparent",
"data-html2canvas-ignore": ""
}, [
e.value.style.chart.zoom.show && ee.value < ye.value ? (r(), M(Nt, {
key: 0,
value: O.value,
"onUpdate:value": a[1] || (a[1] = (o) => O.value = o),
min: ee.value,
max: ye.value,
textColor: e.value.style.chart.color,
inputColor: e.value.style.chart.zoom.color,
selectColor: e.value.style.chart.zoom.highlightColor,
useResetSlot: e.value.style.chart.zoom.useResetSlot,
background: e.value.style.chart.zoom.color,
borderColor: e.value.style.chart.backgroundColor,
source: e.value.style.chart.width,
onReset: Z
}, {
"reset-action": h(({ reset: o }) => [
i(t.$slots, "reset-action", S(F({ reset: o })), void 0, !0)
]),
_: 3
}, 8, ["value", "min", "max", "textColor", "inputColor", "selectColor", "useResetSlot", "background", "borderColor", "source"])) : k("", !0)
], 512),
t.$slots.source ? (r(), m("div", {
key: 5,
ref_key: "source",
ref: B,
dir: "auto"
}, [
i(t.$slots, "source", {}, void 0, !0)
], 512)) : k("", !0),
z.value ? (r(), M(mt, {
key: 6,
hideDetails: "",
config: {
open: v.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: h(() => [
(r(), M(ft, {
key: `table_${b.value}`,
colNames: L.value.colNames,
head: L.value.head,
body: L.value.body,
config: L.value.config,
title: `${e.value.style.chart.title.text}${e.value.style.chart.title.subtitle.text ? ` : ${e.value.style.chart.title.subtitle.text}` : ""}`,
onClose: a[2] || (a[2] = (o) => v.value.showTable = !1)
}, {
th: h(({ th: o }) => [
N("div", {
innerHTML: o,
style: { display: "flex", "align-items": "center" }
}, null, 8, _t)
]),
td: h(({ td: o }) => [
Ye(xe(o.name || o), 1)
]),
_: 1
}, 8, ["colNames", "head", "body", "config", "title"]))
]),
_: 1
}, 8, ["config"])) : k("", !0)
], 44, zt));
}
}, Qt = /* @__PURE__ */ ze(Rt, [["__scopeId", "data-v-e87563ab"]]);
export {
Qt as default
};