UNPKG

@v-charts2/sankey

Version:

echarts 桑葚图

951 lines (949 loc) 23.3 kB
/* eslint-disable */ /** * name: @v-charts2/sankey * version: v1.0.1-alpha.4 * author: vxhly <pengchengou@gmail.com> */ var __defProp = Object.defineProperty; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; import numerify from "numerify"; import { isFunction, set, isArray, isObject, debounce, isEqual, cloneDeep, camelToKebab, getType } from "utils-lite"; import { TitleComponent, TooltipComponent, GridComponent, DatasetComponent, TransformComponent, LegendComponent } from "echarts/components"; import * as echartsLib from "echarts/core"; import { LabelLayout, UniversalTransition } from "echarts/features"; import { SVGRenderer, CanvasRenderer } from "echarts/renderers"; import { SankeyChart } from "echarts/charts"; const name$1 = "@v-charts2/core"; const version$1 = "1.0.1-alpha.4"; const DEFAULT_THEME = { categoryAxis: { axisLine: { show: false }, axisTick: { show: false }, splitLine: { show: false } }, valueAxis: { axisLine: { show: false } }, line: { smooth: true }, legend: { top: 20 }, grid: { containLabel: true, top: 100, left: 20, right: 20, bottom: 20 } }; const DEFAULT_COLORS = [ "#19d4ae", "#5ab1ef", "#fa6e86", "#ffb980", "#0067a6", "#c4b4e4", "#d87a80", "#9cbbff", "#d9d0c7", "#87a997", "#d49ea2", "#5b4947", "#7ba3a8" ]; const itemPoint = (color) => { return [ '<span style="', `background-color:${color};`, "display: inline-block;", "width: 10px;", "height: 10px;", "border-radius: 50%;", "margin-right:2px;", '"></span>' ].join(""); }; const STATIC_PROPS = [ "initOptions", "loading", "dataEmpty", "judgeWidth", "widthChangeDelay" ]; const ECHARTS_SETTINGS = [ "grid", "dataZoom", "visualMap", "toolbox", "title", "legend", "xAxis", "yAxis", "radar", "tooltip", "axisPointer", "brush", "geo", "timeline", "graphic", "series", "backgroundColor", "textStyle" ]; echartsLib.use([ TitleComponent, TooltipComponent, GridComponent, DatasetComponent, TransformComponent, LabelLayout, UniversalTransition, SVGRenderer, CanvasRenderer, LegendComponent ]); const getFormated = (val, type, digit, defaultVal = "-") => { if (isNaN(val)) return defaultVal; if (!type) return val; if (isFunction(type)) return type(val, numerify); digit = isNaN(digit) ? 0 : ++digit; const digitStr = `.[${new Array(digit).join(0)}]`; let formatter = type; switch (type) { case "KMB": formatter = digit ? `0,0${digitStr}a` : "0,0a"; break; case "normal": formatter = digit ? `0,0${digitStr}` : "0,0"; break; case "percent": formatter = digit ? `0,0${digitStr}%` : "0,0.[00]%"; break; } return numerify(val, formatter); }; function logCopyRight(packageName, packageVersion) { console.log(` %c author %c vxhly %c %c email %c <pengchengou@gmail.com> %c %c ${name$1} %c v${version$1} %c %c ${packageName} %c v${packageVersion} `, "color: #fff; background: #5A5A5A; padding:5px;", "color: #fff; background: #4FC921; padding:5px;", "content:' '", "color: #fff; background: #5A5A5A; padding:5px;", "color: #fff;background: #1890ff; padding:5px 0;", "content:' '", "color: #fff; background: #5A5A5A; padding:5px;", "color: #fff;background: #E77335; padding:5px 0;", "content:' '", "color: #fff; background: #5A5A5A; padding:5px;", "color: #fff;background: #E77335; padding:5px 0;"); } function getTooltip(args) { const { itemDataType, linksDataType, digit } = args; return { trigger: "item", formatter(item) { const tpl = []; const { name: name2, data, value, color } = item; tpl.push(itemPoint(color)); tpl.push(`${name2} : `); if (data && data.source) { tpl.push(`${getFormated(value, linksDataType, digit)}<br />`); } else { tpl.push(`${getFormated(value, itemDataType, digit)}<br />`); } return tpl.join(""); } }; } function getSeries(args) { const { rows, dimension, metrics, links, valueFull, useDataValue, label, itemStyle, lineStyle } = args; const dataMap = {}; const seriesData = rows.map((row) => { dataMap[row[dimension]] = row[metrics]; return { name: row[dimension], value: row[metrics] }; }); let innerLinks = null; if (useDataValue) { innerLinks = links.map((link) => { return Object.assign({}, link, { value: dataMap[link.target] }); }); } else if (!valueFull) { innerLinks = links.map((link) => { return link.value == null ? Object.assign({}, link, { value: dataMap[link.target] }) : link; }); } else { innerLinks = links; } const result = { type: "sankey", data: seriesData, links: innerLinks }; if (label) result.label = label; if (itemStyle) result.itemStyle = itemStyle; if (lineStyle) result.lineStyle = lineStyle; return [result]; } const sankey = (columns, rows, settings, extra) => { const { links, dimension = columns[0], metrics = columns[1], dataType = ["normal", "normal"], digit = 2, valueFull = false, useDataValue = false, label, itemStyle, lineStyle } = settings; if (!links) { console.warn("links is needed in settings!"); return; } const itemDataType = dataType[0]; const linksDataType = dataType[1]; const tooltip = getTooltip({ itemDataType, linksDataType, digit }); const series = getSeries({ rows, dimension, metrics, links, valueFull, useDataValue, label, itemStyle, lineStyle }); return { tooltip, series }; }; const name = "@v-charts2/sankey"; const version = "1.0.1-alpha.4"; const props = { data: { type: [Object, Array], default() { return {}; } }, settings: { type: Object, default() { return {}; } }, width: { type: String, default: "auto" }, height: { type: String, default: "400px" }, beforeConfig: { type: Function }, afterConfig: { type: Function }, afterSetOption: { type: Function }, afterSetOptionOnce: { type: Function }, events: { type: Object }, grid: { type: [Object, Array] }, colors: { type: Array }, tooltipVisible: { type: Boolean, default: true }, legendVisible: { type: Boolean, default: true }, legendPosition: { type: String }, markLine: { type: Object }, markArea: { type: Object }, markPoint: { type: Object }, visualMap: { type: [Object, Array] }, dataZoom: { type: [Object, Array] }, toolbox: { type: [Object, Array] }, initOptions: { type: Object, default() { return {}; } }, title: [Object, Array], legend: [Object, Array], xAxis: [Object, Array], yAxis: [Object, Array], radar: Object, tooltip: Object, axisPointer: [Object, Array], brush: [Object, Array], geo: [Object, Array], timeline: [Object, Array], graphic: [Object, Array], series: [Object, Array], backgroundColor: [Object, String], textStyle: [Object, Array], animation: Object, theme: Object, themeName: String, loading: Boolean, dataEmpty: Boolean, extend: Object, judgeWidth: { type: Boolean, default: false }, widthChangeDelay: { type: Number, default: 300 }, tooltipFormatter: { type: Function }, resizeable: { type: Boolean, default: true }, resizeDelay: { type: Number, default: 200 }, changeDelay: { type: Number, default: 0 }, setOptionOpts: { type: [Boolean, Object], default: true }, cancelResizeCheck: Boolean, notSetUnchange: Array, log: Boolean, renderer: { type: String, default: "canvas", validator: (val) => { return ["svg", "canvas"].indexOf(val) > -1; } } }; function setAnimation(options, animation) { Object.keys(animation).forEach((key) => { options[key] = animation[key]; }); } function setExtend(options, extend) { Object.keys(extend).forEach((attr) => { const value = extend[attr]; if (~attr.indexOf(".")) { set(options, attr, value); } else if (typeof value === "function") { options[attr] = value(options[attr]); } else { if (isArray(options[attr]) && isObject(options[attr][0])) { options[attr].forEach((option, index) => { options[attr][index] = Object.assign({}, option, value); }); } else if (isObject(options[attr])) { options[attr] = Object.assign({}, options[attr], value); } else { options[attr] = value; } } }); } function setMark(seriesItem, marks) { Object.keys(marks).forEach((key) => { if (marks[key]) seriesItem[key] = marks[key]; }); } const init = ({ echarts, props: props2, canvas, options } = {}) => { if (echarts) return; const { registeredEvents, _once, el } = options; const themeName = (props2 == null ? void 0 : props2.themeName) || (props2 == null ? void 0 : props2.theme) || DEFAULT_THEME; echarts = echartsLib.init(canvas, themeName, __spreadValues({ renderer: props2 == null ? void 0 : props2.renderer }, props2 == null ? void 0 : props2.initOptions)); if (props2 == null ? void 0 : props2.data) { changeHandler({ props: props2, options, echarts }); } createEventProxy({ registeredEvents, echarts, props: props2 }); if (props2 == null ? void 0 : props2.resizeable) { addResizeListener({ _once, props: props2, el, echarts }); } return { echarts }; }; const changeHandler = ({ props: props2, options, echarts } = {}) => { return debounce(dataHandler({ props: props2, options, echarts }), props2 == null ? void 0 : props2.changeDelay); }; const resizeHandler = ({ props: props2, el, echarts } = {}) => { return debounce(resize({ props: props2, el, echarts }), props2 == null ? void 0 : props2.resizeDelay); }; const createEventProxy = ({ registeredEvents, echarts, props: props2 }) => { const keys = Object.keys((props2 == null ? void 0 : props2.events) || {}); keys.length && keys.forEach((ev) => { if (registeredEvents.indexOf(ev) === -1) { registeredEvents.push(ev); echarts.on(ev, function(ev2) { return function(...args) { if (ev2 in props2.events) { props2 == null ? void 0 : props2.events[ev2].apply(null, args); } }; }(ev)); } }); }; const addResizeListener = ({ _once, props: props2, el, echarts }) => { window.addEventListener("resize", () => resizeHandler({ props: props2, el, echarts })); _once.onresize = true; }; const removeResizeListener = ({ _once }) => { window.removeEventListener("resize", resizeHandler); _once.onresize = false; }; const dataHandler = ({ props: props2, options, echarts } = {}) => { const { chartHandler, chartColor, _once } = options; if (!chartHandler) return; let data = props2 == null ? void 0 : props2.data; const { columns = [], rows = [] } = data; const extra = { tooltipVisible: props2 == null ? void 0 : props2.tooltipVisible, legendVisible: props2 == null ? void 0 : props2.legendVisible, echarts, color: chartColor, tooltipFormatter: props2 == null ? void 0 : props2.tooltipFormatter, _once }; if (props2 == null ? void 0 : props2.beforeConfig) data = props2 == null ? void 0 : props2.beforeConfig(data); const chartOptions = chartHandler(columns, rows, props2 == null ? void 0 : props2.settings, extra); if (chartOptions) { if (typeof chartOptions.then === "function") { chartOptions.then((res) => { optionsHandler({ chartOptions: res, props: props2, options, echarts }); }); } else { optionsHandler({ chartOptions, props: props2, options, echarts }); } } }; const optionsHandler = ({ chartOptions, props: props2, options, echarts, nextTick }) => { const { chartColor, _store, _once, el, readyCallback, readyOnceCallback } = options; if ((props2 == null ? void 0 : props2.legendPosition) && chartOptions.legend) { chartOptions.legend[props2 == null ? void 0 : props2.legendPosition] = 10; if (~["left", "right"].indexOf(props2 == null ? void 0 : props2.legendPosition)) { chartOptions.legend.top = "middle"; chartOptions.legend.orient = "vertical"; } } chartOptions.color = chartColor; ECHARTS_SETTINGS.forEach((setting) => { if (props2 == null ? void 0 : props2[setting]) chartOptions[setting] = props2 == null ? void 0 : props2[setting]; }); if (props2 == null ? void 0 : props2.animation) setAnimation(chartOptions, props2 == null ? void 0 : props2.animation); if ((props2 == null ? void 0 : props2.markArea) || (props2 == null ? void 0 : props2.markLine) || (props2 == null ? void 0 : props2.markPoint)) { const marks = { markArea: props2 == null ? void 0 : props2.markArea, markLine: props2 == null ? void 0 : props2.markLine, markPoint: props2 == null ? void 0 : props2.markPoint }; const series = chartOptions.series; if (isArray(series)) { series.forEach((item) => { setMark(item, marks); }); } else if (isObject(series)) { setMark(series, marks); } } if (props2 == null ? void 0 : props2.extend) setExtend(chartOptions, props2 == null ? void 0 : props2.extend); if (props2 == null ? void 0 : props2.afterConfig) chartOptions = props2 == null ? void 0 : props2.afterConfig(chartOptions); let setOptionOpts = props2 == null ? void 0 : props2.setOptionOpts; if (((props2 == null ? void 0 : props2.settings.bmap) || (props2 == null ? void 0 : props2.settings.amap)) && !isObject(setOptionOpts)) { setOptionOpts = false; } if ((props2 == null ? void 0 : props2.notSetUnchange) && (props2 == null ? void 0 : props2.notSetUnchange.length)) { props2 == null ? void 0 : props2.notSetUnchange.forEach((item) => { const value = chartOptions[item]; if (value) { if (isEqual(value, _store[item])) { chartOptions[item] = void 0; } else { _store[item] = cloneDeep(value); } } }); if (isObject(setOptionOpts)) { setOptionOpts.notMerge = false; } else { setOptionOpts = false; } } if (props2 == null ? void 0 : props2.log) console.log(chartOptions); echarts.setOption(chartOptions, setOptionOpts); readyCallback instanceof Function && readyCallback(echarts, chartOptions, echartsLib); if (!_once["ready-once"]) { _once["ready-once"] = true; readyOnceCallback instanceof Function && readyOnceCallback(echarts, chartOptions, echartsLib); } if (props2 == null ? void 0 : props2.judgeWidth) { judgeWidthHandler({ props: props2, el, nextTick, echarts }); } if (props2 == null ? void 0 : props2.afterSetOption) { props2 == null ? void 0 : props2.afterSetOption(echarts, chartOptions, echartsLib); } if ((props2 == null ? void 0 : props2.afterSetOptionOnce) && !_once.afterSetOptionOnce) { _once.afterSetOptionOnce = true; props2 == null ? void 0 : props2.afterSetOptionOnce(echarts, chartOptions, echartsLib); } }; const judgeWidthHandler = ({ props: props2, el, nextTick, echarts }) => { if (el.clientWidth || el.clientHeight) { resize({ props: props2, el, echarts }); } else { nextTick(() => { if (el.clientWidth || el.clientHeight) { resize({ props: props2, el, echarts }); } else { setTimeout(() => { resize({ props: props2, el, echarts }); if (!el.clientWidth || !el.clientHeight) { console.warn(" Can't get dom width or height "); } }, props2 == null ? void 0 : props2.widthChangeDelay); } }); } }; const resize = ({ props: props2, el, echarts } = {}) => { if (!(props2 == null ? void 0 : props2.cancelResizeCheck)) { if (el && el.clientWidth && el.clientHeight) { echartsResize(echarts); } } else { echartsResize(echarts); } }; const echartsResize = (echarts) => { echarts && echarts.resize(); }; const themeChange = (initPayload, props2) => { let { echarts, option: { _once } } = initPayload; clean({ echarts, props: props2, _once }); echarts = null; init(initPayload); }; const clean = ({ echarts, props: props2, _once }) => { if (props2 == null ? void 0 : props2.resizeable) { removeResizeListener({ _once }); } echarts && echarts.dispose(); }; const resizeableHandler = ({ resizeable, _once, props: props2, el, echarts }) => { if (resizeable && !_once.onresize) { addResizeListener({ _once, props: props2, el, echarts }); } if (!resizeable && _once.onresize) { removeResizeListener({ _once }); } }; var createChart = { render(h) { return h("div", { class: [ camelToKebab(this.$options.name || this.$options._componentTag) ], style: this.canvasStyle }, [ h("div", { style: this.canvasStyle, class: { "v-charts-mask-status": this.dataEmpty || this.loading }, ref: "canvas" }), h("div", { class: "v-charts-data-empty", style: { display: this.dataEmpty ? "" : "none" } }, "\u6682\u65E0\u6570\u636E"), h("div", { style: { display: this.loading ? "" : "none" }, class: "v-charts-component-loading" }, [ h("div", { class: "loader" }, [ h("div", { class: "loading-spinner" }, [ h("svg", { class: "circular", attrs: { viewBox: "25 25 50 50" } }, [ h("circle", { class: "path", attrs: { cx: "50", cy: "50", r: "20", fill: "none" } }) ]) ]) ]) ]), this.$slots.default ]); }, props, created() { this.echarts = null; this.registeredEvents = []; this._once = {}; this._store = {}; this._watchers = []; this.initPayload = {}; }, data() { return { chartLib: null, echarts: null, registeredEvents: [], _once: {}, _store: {}, _watchers: [], initPayload: {} }; }, watch: { data: { deep: true, handler(v) { if (v) { changeHandler({ props: this.$props, options: this.initPayload.options, echarts: this.echarts }); } } }, settings: { deep: true, handler(v) { if (v.type && this.chartLib) this.chartHandler = this.chartLib[v.type]; this.initPayload.options.chartHandler = this.chartLib[v.type]; changeHandler({ props: this.$props, options: this.initPayload.options, echarts: this.echarts }); } }, width: "nextTickResize", height: "nextTickResize", events: { deep: true, handler() { createEventProxy({ registeredEvents: this.registeredEvents, echarts: this.echarts, props: this.$props }); } }, theme: { deep: true, handler(val) { themeChange(this.initPayload, props); } }, themeName: (val) => { themeChange(globalThis.initPayload, props); }, resizeable: (val) => { globalThis.$nextTick(() => { resizeableHandler({ resizeable: globalThis.resizeable, _once: globalThis._once, props: globalThis.$props, el: globalThis.$el, echarts: globalThis.echarts }); }); } }, computed: { canvasStyle() { return { width: this.width, height: this.height, position: "relative" }; }, chartColor() { return this.colors || this.theme && this.theme.color || DEFAULT_COLORS; } }, mounted() { const { echarts, $props: props2, $el: el, registeredEvents, chartHandler, _once, _store, $nextTick: nextTick, _watchers } = this; const initPayload = { echarts, props: props2, canvas: this.$refs.canvas, options: { el, registeredEvents, chartHandler, chartColor: this.chartColor, _once, _store, readyCallback: (echarts2, chartOptions, echartsLib2) => { this.$emit("ready", echarts2, chartOptions, echartsLib2); }, readyOnceCallback: (echarts2, chartOptions, echartsLib2) => { this.$emit("ready-once", echarts2, chartOptions, echartsLib2); } }, nextTick }; const { echarts: initEcharts } = init(initPayload); this.echarts = initEcharts; this.initPayload = initPayload; this.addWatchToProps({ _watchers, props: props2, options: initPayload.options, echarts: this.echarts }); }, beforeDestroy() { clean({ echarts: this.echarts, props: this.$props, _once: this._once }); }, methods: { addWatchToProps() { const watchedVariable = this._watchers.map((watcher) => watcher.expression); Object.keys(this.$props).forEach((prop) => { if (!~watchedVariable.indexOf(prop) && !~STATIC_PROPS.indexOf(prop)) { const opts = {}; if (~["[object Object]", "[object Array]"].indexOf(getType(this.$props[prop]))) { opts.deep = true; } this.$watch(prop, () => { changeHandler({ props: this.$props, options: this.initPayload.options, echarts: this.echarts }); }, opts); } }); }, nextTickResize() { this.$nextTick(resize({ props: this.$props, el: this.$el, echarts: this.echarts })); } }, _numerify: numerify }; echartsLib.use([SankeyChart]); const VeSankey = Object.assign({}, createChart, { name: "VeSankey", data() { this.chartHandler = sankey; return {}; } }); VeSankey.install = (Vue) => { logCopyRight(name, version); Vue.component(VeSankey.name, VeSankey); }; export { VeSankey as default };