@v-charts2/sankey
Version:
echarts 桑葚图
924 lines (922 loc) • 24 kB
JavaScript
/* 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 { computed, h, nextTick, watch, onMounted, onBeforeUnmount } from "vue";
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: nextTick2
}) => {
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: nextTick2,
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: nextTick2,
echarts
}) => {
if (el.clientWidth || el.clientHeight) {
resize({
props: props2,
el,
echarts
});
} else {
nextTick2(() => {
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 });
}
};
const createChart = ({
name: name2,
chartHandler,
chartLib
}) => {
return {
name: name2,
props,
setup(props2, {
slots,
emit
}) {
let echarts = null;
const registeredEvents = [];
const _once = {};
const _store = {};
const _watchers = [];
let stateChangeHandler = null;
if (!changeHandler) {
stateChangeHandler = chartLib[props2.settings.type];
} else {
stateChangeHandler = changeHandler;
}
const canvasStyle = computed(() => {
return {
width: props2 == null ? void 0 : props2.width,
height: props2 == null ? void 0 : props2.height,
position: "relative"
};
});
const chartColor = computed(() => {
return (props2 == null ? void 0 : props2.colors) || (props2 == null ? void 0 : props2.theme) && (props2 == null ? void 0 : props2.theme.color) || DEFAULT_COLORS;
});
const DataEmpty = h("div", { class: "v-charts-data-empty" }, "\u6682\u65E0\u6570\u636E");
const Loading = h("div", { class: "v-charts-component-loading" }, [
h("div", { class: "loader" }, [
h("div", { class: "loading-spinner" }, [
h("svg", {
class: "circular",
viewBox: "25 25 50 50"
}, [
h("circle", {
class: "path",
cx: "50",
cy: "50",
r: "20",
fill: "none"
})
])
])
])
]);
const CANVAS = h("div", {
style: canvasStyle.value,
class: { "v-charts-mask-status": (props2 == null ? void 0 : props2.dataEmpty) || (props2 == null ? void 0 : props2.loading) }
});
const EL = h("div", {
class: [camelToKebab(name2)],
style: canvasStyle.value
}, [
CANVAS,
h(DataEmpty, { style: { display: (props2 == null ? void 0 : props2.dataEmpty) ? "" : "none" } }),
h(Loading, { style: { display: (props2 == null ? void 0 : props2.loading) ? "" : "none" } }),
slots.default
]);
const initPayload = {
echarts,
props: props2,
canvas: CANVAS.el,
options: {
el: EL.el,
registeredEvents,
chartHandler,
chartColor: chartColor.value,
_once,
_store,
readyCallback: (echarts2, chartOptions, echartsLib2) => {
emit("ready", echarts2, chartOptions, echartsLib2);
},
readyOnceCallback: (echarts2, chartOptions, echartsLib2) => {
emit("ready-once", echarts2, chartOptions, echartsLib2);
}
},
nextTick
};
const nextTickResize = () => {
nextTick(resize({
props: props2,
el: EL.el,
echarts
}));
};
watch(() => props2 == null ? void 0 : props2.data, (v) => {
if (v) {
stateChangeHandler({
props: props2,
options: initPayload.options,
echarts
});
}
}, { deep: true });
watch(() => props2 == null ? void 0 : props2.settings, (v) => {
if (v.type && chartLib)
chartHandler = chartLib[v.type];
initPayload.options.chartHandler = chartLib[v.type];
stateChangeHandler({
props: props2,
options: initPayload.options,
echarts
});
}, { deep: true });
watch(() => props2 == null ? void 0 : props2.width, () => nextTickResize());
watch(() => props2 == null ? void 0 : props2.height, () => nextTickResize());
watch(() => props2 == null ? void 0 : props2.events, () => createEventProxy({
registeredEvents,
echarts,
props: props2
}), { deep: true });
watch(() => props2 == null ? void 0 : props2.theme, () => {
nextTick(() => {
initPayload.canvas = CANVAS.el;
initPayload.options.el = EL.el;
themeChange(initPayload, props2);
});
}, { deep: true });
watch(() => props2 == null ? void 0 : props2.themeName, () => {
nextTick(() => {
initPayload.canvas = CANVAS.el;
initPayload.options.el = EL.el;
themeChange(initPayload, props2);
});
});
watch(() => props2 == null ? void 0 : props2.resizeable, (resizeable) => {
nextTick(() => {
resizeableHandler({
resizeable,
_once,
props: props2,
el: EL.el,
echarts
});
});
});
const addWatchToProps = ({
_watchers: _watchers2,
props: props3,
options,
echarts: echarts2
}) => {
const watchedVariable = _watchers2.map((watcher) => watcher.expression);
Object.keys(props3).forEach((prop) => {
if (!~watchedVariable.indexOf(prop) && !~STATIC_PROPS.indexOf(prop)) {
const opts = {};
if (~["[object Object]", "[object Array]"].indexOf(getType(props3[prop]))) {
opts.deep = true;
}
watch(() => prop, () => stateChangeHandler({
props: props3,
options,
echarts: echarts2
}), opts);
}
});
};
onMounted(() => {
initPayload.canvas = CANVAS.el;
initPayload.options.el = EL.el;
const { echarts: initEcharts } = init(initPayload);
echarts = initEcharts;
addWatchToProps({
_watchers,
props: props2,
options: initPayload.options,
echarts
});
});
onBeforeUnmount(() => {
clean({
echarts,
props: props2,
_once
});
});
return () => EL;
}
};
};
echartsLib.use([SankeyChart]);
const VeSankey = createChart({
name: "VeSankey",
chartHandler: sankey
});
VeSankey.install = (app) => {
logCopyRight(name, version);
app.component(VeSankey.name, VeSankey);
};
export { VeSankey as default };