使用vue开发echarts柱状图和折线图基础组件 以及 自定义 tooltips
开发背景就不过多赘述了,直接先来几张效果图吧
1.首先在 package.json 中添加echarts:
{
"dependencies": {
"echarts": "^5.0.0",
}
}
2.然后执行 npm install;
3.接下来就开始编写相关组件文件,代码量较大,建议直接复制下来按步骤运行:
3.1.创建组件文件 barLineChartPY.vue 代码如下:
<template> <!-- 多折线图 圆滑转折点 面积渐变色 --> <div style="with: 100%; height: 100%;" :id="id"></div> </template> <script> export default { props: { "id": { type: String, default: "myChart" }, "title": { type: String, default: "" }, "color": { type: String, default: "" }, "chartData": { type: Object, default: undefined }, "units": { type: String, default: "" }, "yMax": { type: Number, default: undefined } }, data() { return { myChart: {}, colors: ['#3769C9', '#EB9C06', '#80FFA5', '#00DDFF', '#FF0087'], xData: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'], // 柱状图的 基础 series 本组件中的默认 series seriesBar: { name: '', type: 'bar', // barWidth: 10, // stack: 'total', // label: {show: false}, // itemStyle: { //这里设置柱形图圆角 [左上角,右上角,右下角,左下角] // barBorderRadius: 30, // 柱状图 柱子 渐变色 或 单色 // 前4个参数用于配置渐变色的起止位置, 这4个参数依次对应右/下/左/上四个方位. 而0 0 0 1则代表渐变色从正上方开始 // offset的范围是0 ~ 1, 用于表示位置 // color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{offset: 0, color: '#033BFF'}, {offset: 1, color: '#01B1FF'}]) // }, // emphasis: { // focus: 'series', // itemStyle: { // 柱状图 柱子 渐变色 或 单色 // color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{offset: 0, color: '#01B1FF'}, {offset: 1, color: '#033BFF'}]) // } // }, data: [123, 150, 100, 300, 500, 1000, 1300, 1100, 800, 600, 500, 350], data0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, // 折线图的 基础 series seriesLine: { name: '', //this.chartData.seriesName, type: "line", // smooth: true, // 圆滑的拐点 默认false // showSymbol: true, data: [123, 150, 100, 300, 500, 1000, 1300, 1100, 800, 600, 500, 350], // this.chartData.dataArr, data0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // lineStyle: { // color: "#00DDFF", // width: 1, // }, // areaStyle: { // color: "transparent", // 折线图 面积 渐变色 或 单色 // color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{offset: 0, color: "#00DDFFFF"}, {offset: 1, color: "#00DDFF00"}]) // }, // emphasis: { // focus: 'series' // } } } }, methods: { initChart() { var echarts = require("echarts"); // 基于准备好的dom,初始化echarts实例 this.myChart = echarts.init(document.getElementById(this.id)); // 绘制图表---横轴标识--xAxis.data=['1月','2月','3月'] this.xData = this.chartData.xData && this.chartData.xData.length > 0 ? this.chartData.xData : this.xData; // debugger var flag = false; const units = this.units; const series = this.getSeries(); for (var ii = 0, nn = series.length; ii < nn; ii++) { if (series[ii].type == 'bar') { flag = true; break; } } var left = 45; if (this.yMax && (this.yMax + '').length <= 3) { left = 30; } else if (this.yMax && (this.yMax + '').length <= 4) { left = 40; } else if (this.yMax && (this.yMax + '').length <= 6) { left = 55; } var option = { grid: {top: "30", bottom: '25', right: '30', left: left}, tooltip: { trigger: "axis", formatter: function(params) { // 自定义 tooltip // console.log(params); var txt = params[0].name; for (var i = 0, n = params.length; i < n; i++) { var sn = params[i].seriesName, cl = params[i].color, val = params[i].value; txt += '<div><span class="blue-dot middle" style="background: ' + cl + ';"></span><span>' + sn + ':' + val + units + '</span></div>'; } return txt; } }, legend: { show: true, left: 'right', // icon: "circle", // 修改形状 itemHeight: 8, // 修改icon图形大小 itemWidth: 16, // 修改icon图形大小 itemGap: 8, // 修改间距 textStyle: {color: '#fff', fontSize: 12}// padding: [0, -5, 0, 0], // 修改文字和图标距离 }, xAxis: { type: "category", data: this.xData, axisTick: {show: true}, axisLine: {show: true, lineStyle: {color: "#4e9bdf"}}, axisLabel: {textStyle: {color: "#365787"}, margin: 10, rotate: 0}, // rotate x轴标识 旋转角度 boundaryGap: flag, //false:x轴文字贴紧俩边 }, yAxis: { name: (this.units ? ("单位:" + this.units) : ""), type: "value", max: this.yMax, axisLabel: {textStyle: {color: "#ffffff"}}, //// margin: 10, axisLine: {show: true, lineStyle: {color: "#4e9bdf"}}, splitLine: {lineStyle: {color: "#4e9bdf", type: 'dashed'}}, // dashed-虚线 min: 0, }, series: series }; // console.log(`id -> ${this.id}\noption -> ${JSON.stringify(option)}`); this.myChart.setOption(option); //自适应屏幕 this.updateRsize(this.myChart); }, getSeries() { // 折线图折线数据 --- series[0].name-折线的名称 // series[0].data - 折线的数据 var optSeries = []; const seriesData = this.chartData.seriesData; // console.log(`seriesData.length -> ${seriesData.length}\nseriesData -> ${JSON.stringify(seriesData)}`); if (seriesData && seriesData.length > 0) { for (var i = 0, n = seriesData.length; i < n; i++) { // 判断传递过来的 seriesData[i] 中的要展示的echarts图类型 默认为 bar 类型 柱状图 const type = seriesData[i].type || 'bar'; var series = JSON.parse(JSON.stringify(this.seriesBar)); // 克隆对象 this.seriesBar 赋值给 series if ("bar" != type) series = JSON.parse(JSON.stringify(this.seriesLine)); // 克隆对象 this.seriesLine 赋值给 series // 判断并设置 series.name series.name = seriesData[i].name || series.name; // 判断并处理传递过来的 seriesData[i].data 并设置进 series 中 const tmpSeries = seriesData[i]; if (tmpSeries.data && tmpSeries.data.length > 0) { series.data = tmpSeries.data; // 当数据长度小于 x轴要展示的数据长度时 使用 0 进行补充 if (tmpSeries.data.length < this.xData.length) { for (var j = tmpSeries.data.length, m = this.xData.length; j < m; j++) { series.data.push(0); } } } // 判断并设置 series.stack 独立模式 留空不设置 或 堆叠模式 stack:'total' if (seriesData[i].stack) series.stack = seriesData[i].stack; // bar 类型的 if ('bar' == type) { // 判断并设置柱子宽度 series.barWidth if (seriesData[i].barWidth) series.barWidth = seriesData[i].barWidth; // 判断并设置 series.itemStyle. if (seriesData[i].itemStyle) { // 判断并设置 series.itemStyle.barBorderRadius if (seriesData[i].itemStyle.radius) { if (!series.itemStyle) series.itemStyle = {}; series["itemStyle"]["barBorderRadius"] = seriesData[i].itemStyle.radius } // 判断并设置 series.itemStyle.color const res = this.getItemStyleColor(seriesData[i].itemStyle.color, seriesData[i].itemStyle.colors); if (res) { if (!series.itemStyle) series.itemStyle = {}; series["itemStyle"]["color"] = res; } } } else { // line类型的 // 判断并设置 series.smooth 圆润拐点 series.smooth = seriesData[i].smooth || false; if (seriesData[i].color) series.color = seriesData[i].color // 判断并设置 series.lineStyle if (seriesData[i].lineStyle) { // 判断并设置 series.lineStyle.width if (seriesData[i].lineStyle.width) { if (!series.lineStyle) series.lineStyle = {}; series["lineStyle"]["width"] = seriesData[i].lineStyle.width; } // 判断并设置 series.lineStyle.color const res = this.getItemStyleColor(seriesData[i].lineStyle.color, seriesData[i].lineStyle.colors); if (res) { if (!series.lineStyle) series.lineStyle = {}; series["lineStyle"]["color"] = res; } } // 判断并设置 series.areaStyle if (seriesData[i].areaStyle) { // 判断并设置 series.areaStyle.color const res = this.getItemStyleColor(seriesData[i].areaStyle.color, seriesData[i].areaStyle.colors); if (res) { if (!series.areaStyle) series.areaStyle = {}; series["areaStyle"]["color"] = res; } } } // 判断并设置 series.emphasis if (seriesData[i].emphasis) { if (seriesData[i].emphasis.focus) { if (!series.emphasis) series.emphasis = {}; series["emphasis"]["focus"] = seriesData[i].emphasis.focus; } // 判断并设置 series.emphasis.color const res = this.getItemStyleColor(seriesData[i].emphasis.color, seriesData[i].emphasis.colors); if (res) { if (!series.emphasis) series.emphasis = {}; series["emphasis"]["color"] = res; } } optSeries.push(series); // console.log(`i -> ${i}\nseries -> ${JSON.stringify(series)}\noptSeries -> ${JSON.stringify(optSeries)}`); } } else { // this.seriesBar.data = this.seriesBar.data0; optSeries[0] = this.seriesBar; } // console.log(`optSeries -> ${JSON.stringify(optSeries)}`); return optSeries; }, getItemStyleColor(color, colors) { if (color) { return color; } else if (colors) { const cok = Object.keys(colors); const fx = colors.fx; var cos = []; for (var ii = 0, nn = cok.length; ii < nn; ii++) { if ('fx' != cok[ii] && 0 <= cok[ii] <= 1) cos.push({offset: cok[ii], color: colors[cok[ii]]}); } if (fx && fx.length == 4) { return new echarts.graphic.LinearGradient(fx[0], fx[1], fx[2], fx[3], cos); } else { return new echarts.graphic.LinearGradient(0, 0, 0, 1, cos); } } return undefined; } }, mounted() { // this.initChart(); }, watch: { //动态监听数据是否变化 chartData: { deep: true, //true为进行深度监听,false为不进行深度监听 handler() { this.initChart(); } }, }, }; </script> <style lang="less" scoped></style>
3.2.创建文件 maintenancefundsChart.vue 并引入刚创建的组件, 代码如下:
<template> <div class="cloud_wrap"> <border-tem-py :width="'100%'"> <!-- 插槽模板 --> <div class="title" slot="title">柱状折线图统计</div> <div class="content-box" slot="content"> <div class="layui-row layui-col-space10"> <div class="layui-col-md12"> <bar-line-chart-py :id="'mfChart'" :chartData="chartData" :units="'万元'" /> </div> </div> </div> </border-tem-py> </div> </template> <script> import barLineChartPy from '../../../../common/barLineChartPY.vue'; // 路径根据自己实际项目中的进行修改 export default { components: { barLineChartPy }, data() { return { active: 'y', chartData: { xData: [], seriesData: [ { name: '统计', // 必填 data: [123, 330, 236.5, 500, 360.6,188.8,669.0,115,188,55], // 必填 type: 'bar', // 非必填 默认 bar 柱状图 // stack: 'total', // 柱状图或折线图展示模式 独立模式 留空不设置 或 堆叠模式 stack:'total' 非必填 barWidth: 15, // 柱子宽度 非必填 itemStyle: { // 仅柱状图生效 非必填 // // radius: 30, // 柱状图圆角 数字 或 数字数组 [20, 20, 0, 0] [左上角,右上角,右下角,左下角] // // 柱子颜色 color 单色 colors 渐变色 (color / colors 二选一) // // fx 渐变方向 右/下/左/上四个方位. 而0 0 0 1则代表渐变色从正上方开始 // // 0、1 渐变的位置 以及 相应位置的颜色 取值范围 0~1 // // color: '', colors: {'fx': [0, 0, 0, 1], /* 渐变的方向 */ 0: '#2D96F3', 1: '#0B40C3'} }, // // 鼠标移动到柱条上时的样式 // emphasis: { // 柱状图 和 折线图均可 非必填 // focus: 'series', // // color 与 colors 参看 itemStyle 中的说明 // // color: '', // colors: {} // } }, { name: '统计2', // 必填 data: [230, 136, 500, 360, 288, 569, 315, 288, 155], // 必填 type: 'line', // 非必填 默认 bar 柱状图 // smooth: true, // 折线图 转折点是否圆润 默认false 非必填 // lineStyle: { // 仅折线图生效 非必填 // // width: 1, // // color 与 colors 参看 itemStyle 中的说明 // color: '#EB9C06', // // colors: {} // }, // areaStyle: { // 进折线图生效 折线图扫过的面积的样式 非必填 // // color 与 colors 参看 itemStyle 中的说明 // // color: '', // colors: {} // } } ] } }; }, methods:{ btnClick(val) { this.active = val; this.loadData(); }, loadData() { let params = { type: this.active }; this.content = JSON.stringify(params) // 随机数数组 赋值 生成echarts图 this.chartData.seriesData[0].data = this.$options.filters['randomNums'](0, 300, 12); this.chartData.seriesData[1].data = this.$options.filters['randomNums'](0, 600, 12); } }, mounted() { this.loadData(); // 定时器 模拟动态加载数据 实时渲染echarts 实现 实时动态echarts const interval = setInterval(() => { this.loadData(); }, 2000); // 通过$once来监听定时器,在beforeDestroy钩子可以被清除。 this.$once('hook:beforeDestroy', () => { clearInterval(interval); }); }, }; </script> <style scoped> * { font-family: MicrosoftYaHei; } .cloud_wrap{ z-index: 1; position: relative; cursor: pointer; } .cloud_wrap .layui-col-md12 { min-width: 175px; height: 230px; } </style>
3.3.然后再相关页面中再引入 maintenancefundsChart.vue 并使用即可;
小贴士:
百度Echarts官网:https://echarts.apache.org/examples/zh/index.html
html中的调色与透明度:https://www.cnblogs.com/jindao3691/p/16093404.html
vue中随机数、随机数数组过滤器方法以及在methods中调用:https://www.cnblogs.com/jindao3691/p/16122622.html
vue组件-echarts圆环图以及legend多列展示 和 legend分页展示:https://www.cnblogs.com/jindao3691/p/16093592.html
每天进步一点点,点滴记录,积少成多。
以此做个记录,
如有不足之处还望多多留言指教!