一、utils/auth.js方法
/**
* @param {Function} func
* @param {number} wait
* @param {boolean} immediate
* @return {*}
*/
export function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result;
const later = function () {
// 据上一次触发时间间隔
const last = +new Date() - timestamp;
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
};
return function (...args) {
context = this;
timestamp = +new Date();
const callNow = immediate && !timeout;
// 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
}
return result;
};
}
二、Echarts子组件
// resize.js
import { debounce } from "@/utils/auth";
export default {
data() {
return {
$_sidebarElm: null,
$_resizeHandler: null
};
},
mounted() {
this.initListener();
},
activated() {
if (!this.$_resizeHandler) {
this.initListener();
}
this.resize();
},
beforeDestroy() {
this.destroyListener();
},
deactivated() {
this.destroyListener();
},
methods: {
$_sidebarResizeHandler(e) {
if (e.propertyName === "width") {
this.$_resizeHandler();
}
},
initListener() {
this.$_resizeHandler = debounce(() => {
this.resize();
}, 100);
window.addEventListener("resize", this.$_resizeHandler);
this.$_sidebarElm = document.getElementsByClassName("sidebar-container")[0];
this.$_sidebarElm &&
this.$_sidebarElm.addEventListener("transitionend", this.$_sidebarResizeHandler);
},
destroyListener() {
window.removeEventListener("resize", this.$_resizeHandler);
this.$_resizeHandler = null;
this.$_sidebarElm &&
this.$_sidebarElm.removeEventListener("transitionend", this.$_sidebarResizeHandler);
},
resize() {
const { chart } = this;
// this.resize()
chart && chart.resize();
}
}
};
// index.vue
<template>
<div :id="id" :class="className" :style="{ height: height, width: width }"></div>
</template>
<script>
// import echarts from "echarts"; //版本过高无法使用
import * as echarts from "echarts";
import resize from "./mixins/resize";
export default {
mixins: [resize],
props: {
// class类名
className: {
type: String,
default: "chart"
},
// 图表唯一标识,当id重复将会报错
id: {
type: String,
default: "chart"
},
// 图表宽度
width: {
type: String,
default: "100%"
},
// 图表高度
height: {
type: String,
default: "300px"
},
// 图表类型,提供三种(line:折线 bar:柱形 pie:饼图)
type: {
type: String,
default: "line"
},
// 默认配置数据
defaultData: {
type: Object,
default: () => ({
//图表标题
titleText: "访问量统计",
// 图表副标题
subText: "",
// x轴描述
xText: "类别",
// y轴描述
yText: "总访问量",
// 饼图类型 0:普通 1:环形图 2:玫瑰图
pieType: 0,
// 是否圆角环形图
isRadius: false,
// 是否为平滑曲线
smooth: false
})
},
// 传入的数据
chartData: {
type: [Object, Array],
default: () => {}
}
},
watch: {
chartData(val) {
switch (this.type) {
case "lie":
this.drawLine(val);
break;
case "bar":
this.drawBar(val);
break;
case "pie":
this.drawPie(val);
break;
default:
this.drawLine(val);
break;
}
}
},
mounted() {
switch (this.type) {
case "lie":
this.drawLine(this.chartData);
break;
case "bar":
this.drawBar(this.chartData);
break;
case "pie":
this.drawPie(this.chartData);
break;
default:
this.drawLine(this.chartData);
break;
}
},
data() {
return {
// 饼图配置数据
series: [],
chart: null
};
},
methods: {
// 绘制折线
drawLine(chartData) {
const _this = this;
this.chart = echarts.init(document.getElementById(this.id));
let xAxisData = chartData.list.map(function (item) {
return item.name;
});
let lineData = [];
chartData.list.forEach((item) => {
lineData.push({
name: item.name,
type: this.type,
// stack: this.type === "" ? "Total" : "",
data: item.data,
smooth: this.defaultData.smooth
});
});
this.chart.setOption({
title: {
text: this.defaultData.titleText,
subtext: this.defaultData.subText,
left: "left"
},
tooltip: {
trigger: "axis"
},
legend: {
data: xAxisData,
top: "6%",
type: "scroll"
},
grid: {
top: 100,
left: 0,
right: "10%",
bottom: 60,
containLabel: true
},
toolbox: {
show: true,
orient: "vertical",
// left: "right",
top: "center",
right: 20,
feature: {
dataView: {
show: true,
readOnly: false,
optionToContent: function (opt) {
// 绘制数据表格
let table = _this.getTable(opt);
return table;
}
},
magicType: {
type: ["line", "bar", "stack", "tiled"]
},
restore: {},
saveAsImage: {}
}
},
xAxis: [
{
name: chartData.xAxisTitle,
type: "category",
boundaryGap: this.type === "line" ? false : true,
data: chartData.xAxis,
axisTick: {
alignWithLabel: this.type === "line" ? false : true
}
}
],
yAxis: {
name: chartData.yAxisTitle,
type: "value"
},
dataZoom: [
{
type: "inside",
start: 0,
end: 100
},
{
start: 0,
end: 100
}
],
series: lineData
});
},
// 绘制柱形图
drawBar(chartData) {
this.drawLine(chartData);
},
// 绘制饼图
drawPie(chartData) {
this.chart = echarts.init(document.getElementById(this.id));
let xAxisData = chartData.map(function (item) {
return item.name;
});
let pieData = [];
chartData.forEach((v) => {
pieData.push({
name: v.name,
value: v.count
});
});
let series = [];
switch (this.defaultData.pieType) {
// 环形图
case 1:
series = [
{
name: this.defaultData.xText,
type: "pie",
radius: ["40%", "70%"],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: this.defaultData.isRadius ? 10 : "",
borderColor: this.defaultData.isRadius ? "#fff" : "",
borderWidth: this.defaultData.isRadius ? 2 : ""
},
label: {
show: false,
position: "center"
},
emphasis: {
label: {
show: true,
fontSize: "26",
fontWeight: "bold"
}
},
labelLine: {
show: false
},
data: pieData
}
];
break;
case 2:
series = [
{
name: this.defaultData.xText,
type: "pie",
radius: [50, 150],
center: ["50%", "50%"],
roseType: "area",
itemStyle: {
borderRadius: 8
},
data: pieData
}
];
break;
// 默认饼图
default:
series = [
{
name: this.defaultData.xText,
type: "pie",
radius: "55%",
center: ["50%", "60%"],
data: pieData,
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
];
break;
}
this.chart.setOption({
title: {
text: this.defaultData.titleText,
subtext: this.defaultData.subText,
left: "left"
},
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {
// orient: "vertical", //垂直展示
left: "center",
top: "6%",
type: "scroll",
data: xAxisData
},
series: series
});
},
// 绘制数据表格
getTable(opt) {
let axisData = opt.xAxis[0].data; //坐标数据
let series = opt.series; //折线图数据
let tdHeads = "<td>时间</td>"; //表头
let tdBodys = ""; //数据
series.forEach(function (item) {
//组装表头
tdHeads += `<td>${item.name}</td>`;
});
let table = `<table border="1" style="border-collapse:collapse;
font-size:14px;text-align:center;width:100%;"><tbody><tr>${tdHeads} </tr>`;
for (let i = 0, l = axisData.length; i < l; i++) {
for (let j = 0; j < series.length; j++) {
//组装表数据
tdBodys += `<td>${series[j].data[i]}</td>`;
}
table += `<tr><td style="padding: 0 20px">${axisData[i]}</td>${tdBodys}</tr>`;
tdBodys = "";
}
table += "</tbody></table>";
return table;
}
}
};
</script>
三、父组件使用
<template>
<div class="app-container">
<h1>饼图</h1>
<charts
:id="'pieCharts'"
:default-data="defaultData"
:chart-data="chartData"
:type="'pie'"
width="100%"
height="450px"
></charts>
<h1>折线图</h1>
<charts
:id="'lineCharts'"
:default-data="defaultData"
:chart-data="lineData"
:type="'line'"
width="100%"
height="500px"
></charts>
<h1>柱形图</h1>
<charts
:id="'barCharts'"
:default-data="defaultData"
:chart-data="lineData"
:type="'bar'"
width="100%"
height="500px"
></charts>
</div>
</template>
<script>
import Charts from "@/components/Echarts/index";
export default {
components: {
Charts
},
data() {
return {
// 默认配置
defaultData: {
titleText: "访问量统计",
subText: "",
xText: "类别",
yText: "总访问量",
type: "pie"
},
// 数据
chartData: [
{ name: "类别1", count: 10 },
{ name: "类别2", count: 20 },
{ name: "类别3", count: 30 },
{ name: "类别4", count: 40 },
{ name: "类别5", count: 50 },
{ name: "类别6", count: 60 },
{ name: "类别7", count: 70 },
{ name: "类别8", count: 80 }
],
// 折线数据
lineData: {
xAxisTitle: "周期/星期",
yAxisTitle: "访问量",
xAxis: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], //x轴
list: [
{
name: "Email",
data: [120, 132, 101, 134, 90, 230, 210]
},
{
name: "Union Ads",
data: [220, 182, 191, 234, 290, 330, 310]
},
{
name: "Video Ads",
data: [150, 232, 201, 154, 190, 330, 410]
},
{
name: "Direct",
data: [320, 332, 301, 334, 390, 330, 320]
},
{
name: "Search Engine",
data: [820, 932, 901, 934, 1290, 1330, 1320]
}
]
}
};
}
};
</script>
效果图