UNPKG

vue-data-ui-hq

Version:

A user-empowering data visualization Vue 3 components library for eloquent data storytelling

516 lines (515 loc) 20.9 kB
import { useCssVars as Ge, unref as e, computed as h, ref as u, watch as Ve, onMounted as We, onBeforeUnmount as De, openBlock as r, createElementBlock as l, normalizeStyle as C, createBlock as S, createCommentVNode as y, createSlots as Xe, withCtx as F, renderSlot as g, normalizeProps as V, guardReactiveProps as W, normalizeClass as D, createVNode as Ye, createElementVNode as qe, Fragment as P, renderList as L, mergeProps as ve, toDisplayString as B } from "vue"; import { u as He, c as Je, t as Ke, a as Qe, p as me, b as Ze, o as et, e as ke, g as tt, X as st, G as pe, i as X, f as Y, F as q } from "./index-WrV3SAID.js"; import { t as it, u as nt } from "./useResponsive-CoxXLe23.js"; import { _ as rt } from "./Title-BR-xoRp4.js"; import { u as lt, U as ot } from "./usePrinter-kVpf1iV8.js"; import at from "./vue-ui-skeleton-Qec_XSRf.js"; import { u as we } from "./useNestedProp-Cj0kHD7k.js"; import { _ as ut } from "./PackageVersion-1NslmM8M.js"; import { P as ct } from "./PenAndPaper-BF1ZRVm3.js"; import { u as dt } from "./useUserOptionState-BIvW1Kz7.js"; import { _ as yt } from "./_plugin-vue_export-helper-CHgC5LLL.js"; const ft = ["id"], ht = ["xmlns", "viewBox"], gt = ["width", "height"], vt = ["cx", "cy", "r", "stroke", "stroke-width"], mt = { key: 1 }, kt = ["stroke", "d", "stroke-width"], pt = { style: { "pointer-events": "none" } }, wt = ["cx", "cy", "fill", "r", "stroke"], xt = ["x", "y", "fill", "font-size"], bt = { key: 2 }, $t = ["stroke", "stroke-width", "x1", "x2", "y1", "y2"], _t = { style: { "pointer-events": "none" } }, Ct = ["cx", "cy", "fill", "r", "stroke"], Pt = ["x", "y", "fill", "font-size"], Lt = ["text-anchor", "transform", "x", "y", "onClick", "font-weight", "font-size", "fill"], Ot = ["cx", "cy", "fill", "stroke", "onClick", "r"], zt = { key: 5, class: "vue-data-ui-watermark" }, At = { __name: "vue-ui-relation-circle", props: { dataset: { type: Array, default() { return []; } }, config: { type: Object, default() { return {}; } } }, setup(xe, { expose: be }) { Ge((t) => ({ "53ece6fb": e(Oe), "2901835a": e(Le), "1f5525bc": e(ze) })); const { vue_ui_relation_circle: $e } = He(), p = xe, E = h(() => !!p.dataset && Object.keys(p.dataset).length), O = u(Je()), H = u(0), z = u(null), J = u(null), K = u(null), Q = u(null), Z = u(0), i = h({ get: () => se(), set: (t) => t }), { userOptionsVisible: T, setUserOptionsVisibility: ee, keepUserOptionState: te } = dt({ config: i.value }); function se() { const t = we({ userConfig: p.config, defaultConfig: $e }); return t.theme ? { ...we({ userConfig: Ke.vue_ui_relation_circle[t.theme] || p.config, defaultConfig: t }), customPalette: Qe[t.theme] || me } : t; } Ve(() => p.config, (t) => { i.value = se(), T.value = !i.value.showOnChartHover, ce(), Z.value += 1; }, { deep: !0 }); const { isPrinting: ie, isImaging: ne, generatePdf: re, generateImage: le } = lt({ elementId: `relation_circle_${O.value}`, fileName: i.value.style.title.text || "vue-ui-relation-circle" }), _e = h(() => i.value.userOptions.show && !i.value.style.title.text), oe = h(() => Ze(i.value.customPalette)), x = u([]), v = u([]), c = u({}), m = u([]), Ce = u(0), N = h(() => p.dataset.slice(0, i.value.style.limit)), $ = u(i.value.style.size), k = u(i.value.style.weightLabels.size), ae = u(i.value.style.plot.radius), ue = u(i.value.style.labels.fontSize), a = u({ height: i.value.style.size, width: i.value.style.size }), b = h({ get() { return $.value * i.value.style.circle.radiusProportion; }, set(t) { return t; } }), Pe = h(() => i.value.style.links.curved), Le = h(() => `${i.value.style.animation.speedMs}ms`), Oe = h(() => b.value * 2), ze = h(() => b.value * 4), A = u(null); We(() => { ce(), document.getElementById(`relation_circle_${O.value}`).addEventListener("click", de); }); function ce() { if (et(p.dataset) ? ke({ componentName: "VueUiRelationCircle", type: "dataset" }) : p.dataset.forEach((t, n) => { tt({ datasetObject: t, requiredAttributes: ["id", "label", "relations", "weights"] }).forEach((s) => { ke({ componentName: "VueUiRelationCircle", type: "datasetSerieAttribute", property: s, index: n }); }); }), i.value.responsive) { const t = it(() => { const { width: n, height: s } = nt({ chart: z.value, title: i.value.style.title.text ? J.value : null, source: K.value, noTitle: Q.value }); $.value = Math.min(n, s), a.value.width = n, a.value.height = s, b.value = $.value * i.value.style.circle.radiusProportion, x.value = [], v.value = [], ye(), fe(), k.value = q({ relator: $.value, adjuster: i.value.style.size, source: i.value.style.weightLabels.size, threshold: 6, fallback: 6 }), ae.value = q({ relator: $.value, adjuster: i.value.style.size, source: i.value.style.plot.radius, threshold: 1, fallback: 1 }), ue.value = q({ relator: $.value, adjuster: i.value.style.size, source: i.value.style.labels.fontSize, threshold: 6, fallback: 6 }); }); A.value = new ResizeObserver(t), A.value.observe(z.value.parentNode); } else x.value = [], v.value = [], ye(), fe(); } De(() => { document.getElementById(`relation_circle_${O.value}`).removeEventListener("click", de), A.value && A.value.disconnect(); }); function de(t) { const n = t.target; n && Array.from(n.classList).includes("vue-ui-user-options") || n && Array.from(n.classList).includes("vue-ui-user-options-summary") || n && Array.from(n.classList).includes("vue-data-ui-button") || n && Array.from(n.classList).includes("vue-ui-relation-circle-legend") || (c.value = {}, m.value = []); } function ye() { const t = 6.28319 / N.value.length, n = 360 / N.value.length; let s = 0, o = 0; N.value.forEach((f, d) => { const U = f.weights.reduce((je, Ue) => je + Ue, 0), G = b.value * Math.cos(s) + a.value.width / 2, Re = b.value * Math.sin(s) + a.value.height / 2 + i.value.style.circle.offsetY; x.value.push({ x: G, y: Re, ...f, color: f.color ? f.color : oe.value[d] ? oe.value[d] : me[d], regAngle: o, totalWeight: U }), s += t, o += n; }); } function Ae(t, n) { const s = (t.x + n.x) / 2, o = (t.y + n.y) / 2; return { x: s, y: o }; } function fe() { v.value = [], x.value.forEach((t) => { x.value.filter((s) => s.relations.includes(t.id)).forEach((s, o) => { const f = s.relations.indexOf(t.id); v.value.push({ weight: s.weights[f] ? s.weights[f] : 0, relationId: `${t.id}_${s.id}`, x1: t.x, y1: t.y, x2: s.x, y2: s.y, colorSource: t.color, colorTarget: s.color, midPointLine: Ae({ x: t.x, y: t.y }, { x: s.x, y: s.y }), midPointBezier: Ie({ x1: t.x, x2: s.x, y1: t.y, y2: s.y }), ...t }); }); }); } function Ie(t) { const n = { x: t.x1, y: t.y1 }, s = { x: t.x2, y: t.y2 }, o = { x: t.x1, y: t.y1 }, f = { x: a.value.width / 2, y: a.value.height / 2 + i.value.style.circle.offsetY }, d = 0.5, U = Math.pow(1 - d, 3) * n.x + 3 * Math.pow(1 - d, 2) * d * o.x + 3 * (1 - d) * Math.pow(d, 2) * f.x + Math.pow(d, 3) * s.x, G = Math.pow(1 - d, 3) * n.y + 3 * Math.pow(1 - d, 2) * d * o.y + 3 * (1 - d) * Math.pow(d, 2) * f.y + Math.pow(d, 3) * s.y; return { x: U, y: G }; } const Me = h(() => Math.max(...v.value.map((t) => t.weight))); function Se(t) { return Object.hasOwn(c.value, "x") ? m.value.includes(t.id) ? "opacity:1" : "opacity:0.1" : "opacity:1"; } function w(t) { return t.colorSource; } function he(t) { return Object.hasOwn(c.value, "x") ? m.value.includes(t.id) && t.relationId === `${t.id}_${c.value.id}` || t.relationId === `${c.value.id}_${t.id}` ? `opacity:1;stroke-width:${R(t)}` : "opacity: 0" : "opacity: 1"; } function _(t) { return Object.hasOwn(c.value, "x") ? !!(m.value.includes(t.id) && t.relationId === `${t.id}_${c.value.id}` || t.relationId === `${c.value.id}_${t.id}`) : !1; } function Fe(t) { return t.regAngle > 90 && t.regAngle < 270 ? "end" : "start"; } function Be(t) { return t.regAngle > 90 && t.regAngle < 270 ? t.x - 5 : t.x + 5; } function Ee(t) { return Object.hasOwn(c.value, "x") ? c.value.id === t.id || m.value.includes(t.id) ? "opacity:1" : "opacity:0.2" : "opacity:1"; } function Te(t) { return t.regAngle > 90 && t.regAngle < 270 ? `rotate(${t.regAngle + 180},${t.x},${t.y})` : `rotate(${t.regAngle},${t.x},${t.y})`; } function ge(t) { Ce.value = 360 - t.regAngle, c.value.id && t.id === c.value.id ? (c.value = {}, m.value = []) : (c.value = t, m.value = [...t.relations]); } function R(t) { const n = t.weight / Me.value * i.value.style.links.maxWidth; return Math.max(0.3, n); } const I = u(!1); function Ne(t) { I.value = t, H.value += 1; } const M = u(!1); function j() { M.value = !M.value; } return be({ generatePdf: re, generateImage: le, toggleAnnotator: j }), (t, n) => (r(), l("div", { ref_key: "relationCircleChart", ref: z, class: "vue-ui-relation-circle", style: C(`width:100%;background:${e(i).style.backgroundColor};text-align:center;${e(i).responsive ? "height: 100%" : ""}`), id: `relation_circle_${e(O)}`, onMouseenter: n[0] || (n[0] = () => e(ee)(!0)), onMouseleave: n[1] || (n[1] = () => e(ee)(!1)) }, [ e(i).userOptions.buttons.annotator ? (r(), S(ct, { key: 0, parent: e(z), backgroundColor: e(i).style.backgroundColor, color: e(i).style.color, active: e(M), onClose: j }, null, 8, ["parent", "backgroundColor", "color", "active"])) : y("", !0), e(_e) ? (r(), l("div", { key: 1, ref_key: "noTitle", ref: Q, class: "vue-data-ui-no-title-space", style: "height:36px; width: 100%;background:transparent" }, null, 512)) : y("", !0), e(i).style.title.text ? (r(), l("div", { key: 2, ref_key: "chartTitle", ref: J, style: "width:100%;background:transparent" }, [ (r(), S(rt, { key: `title_${e(Z)}`, config: { title: { cy: "relation-div-title", ...e(i).style.title }, subtitle: { cy: "relation-div-subtitle", ...e(i).style.title.subtitle } } }, null, 8, ["config"])) ], 512)) : y("", !0), e(i).userOptions.show && e(E) && (e(te) || e(T)) ? (r(), S(ot, { ref: "details", key: `user_options_${e(H)}`, backgroundColor: e(i).style.backgroundColor, color: e(i).style.color, isPrinting: e(ie), isImaging: e(ne), uid: e(O), hasPdf: e(i).userOptions.buttons.pdf, hasImg: e(i).userOptions.buttons.img, hasFullscreen: e(i).userOptions.buttons.img, hasXls: !1, isFullscreen: e(I), titles: { ...e(i).userOptions.buttonTitles }, chartElement: e(z), position: e(i).userOptions.position, hasAnnotator: e(i).userOptions.buttons.annotator, isAnnotation: e(M), onToggleFullscreen: Ne, onGeneratePdf: e(re), onGenerateImage: e(le), onToggleAnnotator: j, style: C({ visibility: e(te) ? e(T) ? "visible" : "hidden" : "visible" }) }, Xe({ _: 2 }, [ t.$slots.optionPdf ? { name: "optionPdf", fn: F(() => [ g(t.$slots, "optionPdf", {}, void 0, !0) ]), key: "0" } : void 0, t.$slots.optionImg ? { name: "optionImg", fn: F(() => [ g(t.$slots, "optionImg", {}, void 0, !0) ]), key: "1" } : void 0, t.$slots.optionFullscreen ? { name: "optionFullscreen", fn: F(({ toggleFullscreen: s, isFullscreen: o }) => [ g(t.$slots, "optionFullscreen", V(W({ toggleFullscreen: s, isFullscreen: o })), void 0, !0) ]), key: "2" } : void 0, t.$slots.optionAnnotator ? { name: "optionAnnotator", fn: F(({ toggleAnnotator: s, isAnnotator: o }) => [ g(t.$slots, "optionAnnotator", V(W({ toggleAnnotator: s, isAnnotator: o })), void 0, !0) ]), key: "3" } : void 0 ]), 1032, ["backgroundColor", "color", "isPrinting", "isImaging", "uid", "hasPdf", "hasImg", "hasFullscreen", "isFullscreen", "titles", "chartElement", "position", "hasAnnotator", "isAnnotation", "onGeneratePdf", "onGenerateImage", "style"])) : y("", !0), e(E) ? (r(), l("svg", { key: 4, xmlns: e(st), class: D([{ "vue-data-ui-fullscreen--on": e(I), "vue-data-ui-fulscreen--off": !e(I) }, "relation-circle"]), viewBox: `0 0 ${e(a).width <= 0 ? 10 : e(a).width} ${e(a).height <= 0 ? 10 : e(a).height}`, width: "100%", style: "user-select:none; background:transparent" }, [ Ye(ut), t.$slots["chart-background"] ? (r(), l("foreignObject", { key: 0, x: 0, y: 0, width: e(a).width <= 0 ? 10 : e(a).width, height: e(a).height <= 0 ? 10 : e(a).height, style: { pointerEvents: "none" } }, [ g(t.$slots, "chart-background", {}, void 0, !0) ], 8, gt)) : y("", !0), qe("circle", { cx: (e(a).width <= 0 ? 1e-4 : e(a).width) / 2, cy: (e(a).height <= 0 ? 1e-4 : e(a).height) / 2 + e(i).style.circle.offsetY, r: e(b) <= 0 ? 1e-4 : e(b), stroke: e(i).style.circle.stroke, "stroke-width": e(i).style.circle.strokeWidth, fill: "transparent", class: "main-circle" }, null, 8, vt), e(Pe) ? (r(), l("g", mt, [ (r(!0), l(P, null, L(e(v), (s, o) => (r(), l("path", { key: `relation_${o}`, style: C(he(s)), stroke: w(s), class: D(["relation", { "vue-ui-relation-circle-selected": e(c).hasOwnProperty("id") && e(m).includes(s.id) }]), d: `M${s.x1},${s.y1} C${s.x1},${s.y1} ${e(a).width / 2},${e(a).height / 2 + e(i).style.circle.offsetY} ${s.x2},${s.y2}`, fill: "none", "stroke-width": R(s), "stroke-linecap": "round" }, null, 14, kt))), 128)), (r(!0), l(P, null, L(e(v), (s, o) => (r(), l("g", pt, [ _(s) ? g(t.$slots, "dataLabel", ve({ key: 0, ref_for: !0 }, { x: s.midPointBezier.x, y: s.midPointBezier.y, color: w(s), weight: s.weight, fontSize: e(k) }), void 0, !0) : y("", !0), _(s) && !t.$slots.dataLabel ? (r(), l("circle", { key: 1, cx: s.midPointBezier.x, cy: s.midPointBezier.y, fill: w(s), r: e(k), stroke: e(i).style.backgroundColor, "stroke-width": "1" }, null, 8, wt)) : y("", !0), _(s) && !t.$slots.dataLabel ? (r(), l("text", { key: 2, x: s.midPointBezier.x, y: s.midPointBezier.y + e(k) / 3, fill: e(pe)(w(s)), "text-anchor": "middle", "font-size": e(k) }, B(e(X)( e(i).style.weightLabels.formatter, s.weight, e(Y)({ p: e(i).style.weightLabels.prefix, v: s.weight, s: e(i).style.weightLabels.suffix, r: e(i).style.weightLabels.rounding }), { ...s } )), 9, xt)) : y("", !0) ]))), 256)) ])) : (r(), l("g", bt, [ (r(!0), l(P, null, L(e(v), (s, o) => (r(), l("line", { key: `relation_${o}`, stroke: w(s), "stroke-width": R(s), style: C(he(s)), x1: s.x1, x2: s.x2, y1: s.y1, y2: s.y2, class: D({ "vue-ui-relation-circle-selected": e(c).hasOwnProperty("id") && e(m).includes(s.id) }), "stroke-linecap": "round" }, null, 14, $t))), 128)), (r(!0), l(P, null, L(e(v), (s, o) => (r(), l("g", _t, [ _(s) ? g(t.$slots, "dataLabel", ve({ key: 0, ref_for: !0 }, { x: s.midPointLine.x, y: s.midPointLine.y, color: w(s), weight: s.weight, fontSize: e(k) }), void 0, !0) : y("", !0), _(s) && !t.$slots.dataLabel && e(i).style.weightLabels.show ? (r(), l("circle", { key: 1, cx: s.midPointLine.x, cy: s.midPointLine.y, fill: w(s), r: e(k), stroke: e(i).style.backgroundColor, "stroke-width": "1" }, null, 8, Ct)) : y("", !0), _(s) && !t.$slots.dataLabel && e(i).style.weightLabels.show ? (r(), l("text", { key: 2, x: s.midPointLine.x, y: s.midPointLine.y + e(k) / 3, fill: e(pe)(w(s)), "text-anchor": "middle", "font-size": e(k) }, B(e(X)( e(i).style.weightLabels.formatter, s.weight, e(Y)({ p: e(i).style.weightLabels.prefix, v: s.weight, s: e(i).style.weightLabels.suffix, r: e(i).style.weightLabels.rounding }), { ...s } )), 9, Pt)) : y("", !0) ]))), 256)) ])), (r(!0), l(P, null, L(e(x), (s, o) => (r(), l("text", { key: `plot_text_${o}`, "text-anchor": Fe(s), transform: Te(s), x: Be(s), y: s.y + 5, onClick: (f) => ge(s), class: "vue-ui-relation-circle-legend", "transform-origin": "start", "font-weight": e(c).id === s.id ? "900" : "400", style: C(`font-family:${e(i).style.fontFamily};${Ee(s)}`), "font-size": e(ue), fill: e(i).style.labels.color }, B(s.label) + " (" + B(e(X)( e(i).style.weightLabels.formatter, s.totalWeight, e(Y)({ p: e(i).style.weightLabels.prefix, v: s.totalWeight, s: e(i).style.weightLabels.suffix, r: e(i).style.weightLabels.rounding }), { ...s } )) + ") ", 13, Lt))), 128)), (r(!0), l(P, null, L(e(x), (s, o) => (r(), l("circle", { cx: s.x, cy: s.y, key: `plot_${o}`, style: C(Se(s)), class: "vue-ui-relation-circle-plot", fill: e(i).style.plot.useSerieColor ? s.color : e(i).style.plot.color, stroke: e(i).style.backgroundColor, "stroke-width": "1", onClick: (f) => ge(s), r: e(ae) }, null, 12, Ot))), 128)), g(t.$slots, "svg", { svg: e(a) }, void 0, !0) ], 10, ht)) : y("", !0), t.$slots.watermark ? (r(), l("div", zt, [ g(t.$slots, "watermark", V(W({ isPrinting: e(ie) || e(ne) })), void 0, !0) ])) : y("", !0), t.$slots.source ? (r(), l("div", { key: 6, ref_key: "source", ref: K, dir: "auto" }, [ g(t.$slots, "source", {}, void 0, !0) ], 512)) : y("", !0), e(E) ? y("", !0) : (r(), S(at, { key: 7, config: { type: "relationCircle", style: { backgroundColor: e(i).style.backgroundColor, relationCircle: { color: "#CCCCCC" } } } }, null, 8, ["config"])) ], 44, ft)); } }, Gt = /* @__PURE__ */ yt(At, [["__scopeId", "data-v-c22c6dc6"]]); export { Gt as default };