@v-charts2/sankey
Version:
echarts 桑葚图
951 lines (949 loc) • 23.3 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 { 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 };