一、引用方式:
<bar-chart key="Chart" :yName="'Y'" :legend="data.legend" :xAxis="data.xAxis" :lineColors="data.colorList" :series="data.series" :tLabel="{show:false}" :axisLabFmt='true' :isMix="true" :width="430" :height="260" :axisLineClr="'#2a72c1'" :splitLineClr="'rgba(42,114,193,0.35)'" :grid="{top:40,bottom:60,left:30,right:10}" :axisLalClr="'#9dc4dd'" legCrl="#fff" :avPosition="'start'">
</bar-chart>
二、組件:
<template> <div :class="classes" :style="styles" ref="barChart"></div> </template> <script> import eCharts from "echarts"; const prefixCls = "barChart"; export default { name: "barChart", props: { // 外盒寬度 width: { type: [Number, String], default: 500 }, // 外盒高度 height: { type: [Number, String], default: 300 }, // 圖例 legend: { type: Array, default() { return []; } }, // 圖例文字顏色 legCrl: { type: String, default: "#000" }, // 圖例位置 legPos: { type: String, default: "right", validator(value) { return oneOf(value, ["left", "center", "right"]); } }, // 柱寬 barWidth: { type: Number, default: 22 }, xAxis: { type: Array, default() { return []; } }, //是否堆疊 stack: { type: Boolean, default: false }, // Y軸單位 yName: String, // 折線Y軸的單位 lineName: String, // X軸單位 xName: String, // 是否增加右側Y軸 isY: { type: Boolean, default: false }, // 是否隱藏所有線條和刻度 isHidden: { type: Boolean, default: false }, colorList: { type: Array, default() { return ["#25d4e7", "#fe6b40", "#6bb592"]; } }, series: { type: Array, default() { return []; } }, // 圖表數據太多需要使用的滾動條和縮放效果,設置這個之后需要設置gridBottom,讓滾動條顯示在數據下方 isDataZoom: { type: Boolean, default: false }, // 滾動條填充顏色 zoomFillCrl: { type: String, default: "grey" }, // 滾動條背景色 zoomBgcCrl: { type: String, default: "#fff" }, // 滾動條邊框色 zoomBorCrl: { type: String, default: "grey" }, // 數據窗口范圍的起始百分比 zoomStart: { type: Number, default: 0 }, // 數據窗口范圍的結束百分比 zoomEnd: { type: Number, default: 50 }, // 整個圖標的寬高,以及距上下左右的邊距 grid: { type: Object, default: function() { return { height: Number, width: Number, top: 30, bottom: 5, left: 10, right: 15, containLabel: true }; } }, // 定義X軸刻度的格式(文字太多設置換行) axisLabFmt: { type: Boolean, default: false }, // 定義X軸刻度每行顯示的字數,默認為2個 wordsNum: Number, // 是否要給bar添加事件,以及事件類型 barEvent: { type: Object, default() { return { eventType: "", callBack: null }; } }, // 是否需要柱狀的背景色 isBgc: { type: Boolean, default: false }, // 與柱狀圖相對應的平均線 avDataBar: { type: Array, default() { return []; } }, // 與折線圖相對應的平均線 avDataLine: { type: Array, default() { return []; } }, // 折線平均線顏色 avLineCrl: { type: Array, default() { return ["#fe6b40", "#edea10"]; } }, // 柱子平均線顏色 avBarCrl: { type: Array, default() { return ["#edea10", "#fe6b40"]; } }, // 如果柱狀圖需要顯示所占百分比 percent: { type: Boolean, default: false }, // X軸Y軸刻度線顏色及文字背景色 axisLineClr: { type: String, default: "#000" }, // X軸Y軸的文字顏色 axisLalClr: { type: String, default: "#000" }, // 背景分割線顏色 splitLineClr: { type: String, default: "#ddd" }, // 更改圖表展示類型 changeDir: { type: Boolean, default: false }, // 數據單位 lUnit: String, // 設置圖表label的是否顯示,位置,顏色,內容 tLabel: { type: Object, default: function() { return { show: true, position: "top", formatter: "{c}" + this.lUnit, textStyle: { color: "#000" } }; } }, //是否顯示圖例 legShow: { type: Boolean, default: true }, // 是否需要隔行變色 isMix: { type: Boolean, default: false }, // 柱狀之間的距離 barGap: { type: String | Number, default: "30%" }, barCategoryGap: { type: String | Number, default: "20%" }, // 如果是折柱混合,且柱子的顏色是隔行變色,則需單獨設置line的顏色 lineColors: { type: Array, default() { return ["#F6D37E"]; } }, // 平均線數字的位置 avPosition: { type: String, default: "middle", validator(value) { return oneOf(value, ["start", "middle", "end"]); } }, // 自定義Y軸刻度文字的樣式 yAxisLabel: { type: Object, default: function() {} }, // Y軸方向的背景色 splitBgc: { type: Array, default: function() { return ["rgba(0,0,0,0)"]; } }, // Y軸是否反向 inverse: { type: Boolean, default: false }, // Y軸刻度單位 yUnit: { type: Array, default: function() { return ["", ""]; } }, // 多條折線是否堆疊 lineStack: { type: Boolean, default: true } }, data() { return { maxBar: [], splitLine: { lineStyle: { color: this.splitLineClr } }, chart: null }; }, computed: { classes() { return `${prefixCls}`; }, styles() { let style = {}; if (this.height) { style.height = `${this.height}px`; } if (this.width) { style.width = `${this.width}px`; } return style; } }, mounted() { setTimeout(() => { this.drawChart(); }, 200); }, updated() { this.$nextTick(() => { this.drawChart(); }); }, watch: { series(curVal, oldVal) { this.drawChart(); }, colorList(curVal, oldVal) { this.drawChart(); } }, methods: { oneOf(value, validList) { for (let i = 0; i < validList.length; i++) { if (value === validList[i]) { return true; } } return false; }, countMax(max) { const num = Math.ceil(max); let base = "1"; const len = Math.abs(num).toString().length - 1; for (let i = 0; i < len; i++) { base += "0"; } let maxNum = Math.ceil(parseFloat(num / parseInt(base))) * parseInt(base); if ((maxNum / parseInt(base)) % 3 != 0) { return Math.ceil(maxNum / parseInt(base) / 3) * 3 * parseInt(base); } return maxNum; }, drawChart() { let series = []; let isMulti = false; let o = 0; this.series.forEach((item, index) => { let sum = 0; item.data.forEach(i => { sum = sum + parseInt(i); }); const json = { name: this.legend[index], type: item.type, data: item.data, label: { normal: this.tLabel }, barWidth: this.barWidth, symbol: "circle", barGap: this.barGap, barCategoryGap: this.barCategoryGap, symbolSize: 8, itemStyle: { normal: { color: params => { if (this.isMix) { if (params.dataIndex % 2 === 0) { return this.colorList[0]; } else { return this.colorList[1]; } } else { return this.colorList[index]; } } } } }; if (item.type === "line") { json.yAxisIndex = 1; json.stack = this.lineStack; json.lineStyle = { normal: { color: this.isMix ? this.lineColors[o] : this.colorList[index] } }; json.itemStyle = { normal: { color: this.isMix ? this.lineColors[o++] : this.colorList[index] } }; isMulti = true; } if (this.percent) { json.label = { normal: { show: true, position: "top", formatter: params => { return this.percent ? parseInt((params.value / sum) * 100) + "%" : "{c}"; } } }; } if (this.stack) { json.stack = "總量"; } if (this.isBgc) { var jsonBgc = {}; for (var attr in json) { jsonBgc[attr] = json[attr]; } jsonBgc.barGap = "-100%"; jsonBgc.label = { normal: { show: false } }; jsonBgc.barWidth = this.barWidth; jsonBgc.silent = true; jsonBgc.tooltip = { show: false }; //顏色需要有透明度 jsonBgc.itemStyle = { normal: { color: "rgba(102, 102, 102,.2)" } }; //計算柱狀圖背景高度 let barMax = 0; json.data.forEach(item => { if (item >= barMax) { barMax = item; } }); const num = this.countMax(barMax); this.maxBar = []; json.data.forEach(item => { this.maxBar.push(num); }); //data填你需要的背景的值 jsonBgc.data = this.maxBar; series.push(jsonBgc); } if (this.avDataBar || this.avDataLine) { let avData = []; let color = ""; if (item.type === "bar") { this.avDataBar.forEach((item, index) => { avData.push({ yAxis: item, lineStyle: { normal: { color: this.avBarCrl[index] } } }); }); color = this.avBarCrl[index]; } else { this.avDataLine.forEach((item, index) => { avData.push({ yAxis: item, lineStyle: { normal: { color: this.avLineCrl[index] } } }); }); } json.markLine = { data: avData, symbolSize: 0, lineStyle: { normal: { color: color, type: "solid", width: 2, position: "right" } }, label: { normal: { position: this.avPosition } } }; } series.push(json); }); const option = { legend: { show: this.legShow, data: this.legend, textStyle: { color: this.legCrl }, itemWidth: 12, itemHeight: 12 }, tooltip: { trigger: "axis", axisPointer: { type: "cross", crossStyle: { color: "#999" } } }, animationEasing: "sinusoidalInOut", animationDuration: 1500, grid: this.grid, xAxis: [ { type: this.changeDir ? "value" : "category", axisLabel: { interval: 0, textStyle: { color: this.axisLalClr }, show: this.changeDir ? false : true }, axisLine: { lineStyle: { color: this.axisLineClr }, show: this.changeDir ? false : true }, axisTick: { show: false }, data: this.changeDir ? "" : this.xAxis, splitLine: this.splitLine } ], yAxis: [ { type: this.changeDir ? "category" : "value", data: this.changeDir ? this.xAxis : "", inverse: this.inverse, axisLabel: this.yAxisLabel ? this.yAxisLabel : { interval: 0, textStyle: { color: this.axisLalClr }, show: true, formatter: "{value}" + this.yUnit[0] }, axisLine: { lineStyle: { color: this.axisLineClr } }, axisTick: { show: false }, name: this.yName, nameTextStyle: { color: "#ffffff" }, splitLine: this.splitLine, splitArea: { show: true, areaStyle: { color: this.splitBgc } }, splitNumber: 3 } ], series: series }; // X軸的顯示字數是否要換行 if (this.axisLabFmt) { option.xAxis[0].axisLabel.formatter = params => { let newParamsName = ""; let paramsNameNumber = params.length; let provideNumber = this.wordsNum ? this.wordsNum : 2; let rowNumber = Math.ceil(paramsNameNumber / provideNumber); if (paramsNameNumber > provideNumber) { for (let p = 0; p < rowNumber; p++) { let tempStr = ""; let start = p * provideNumber; let end = start + provideNumber; if (p == rowNumber - 1) { tempStr = params.substring(start, paramsNameNumber); } else { tempStr = params.substring(start, end) + "\n"; } newParamsName += tempStr; } } else { newParamsName = params; } return newParamsName; }; } // 是否隱藏X和Y軸的刻度和線條 if (this.isHidden) { option.xAxis[0] = { type: "category", axisLabel: { interval: 0, textStyle: { color: this.axisLalClr } }, axisLine: { show: false }, axisTick: { show: false }, data: this.xAxis }; option.yAxis[0] = { type: "value", axisLabel: { show: false }, axisLine: { show: false }, axisTick: { show: false }, name: this.yName, nameTextStyle: { color: this.axisLalClr }, splitLine: { show: false } }; } // 是否需要右側Y軸刻度 if (isMulti && !this.isY) { option.yAxis.push({ type: "value", splitNumber: 3, show: false, // min: 0, // max: 100, axisLabel: { inside: true } }); } else if (this.isY) { option.yAxis.push({ type: "value", splitNumber: 3, name: this.lineName, nameTextStyle: { color: this.axisLalClr }, axisLine: { lineStyle: { color: this.axisLineClr } }, axisTick: { show: false }, splitLine: this.splitLine, axisLabel: { interval: 0, textStyle: { color: this.axisLalClr }, formatter: "{value}" + this.yUnit[1] }, formatter: "{value}%" }); } // 圖例位置 switch (this.legPos) { case "left": option.legend.left = 15; break; case "center": break; case "right": option.legend.right = 15; break; } // 設置Y軸名字 if (this.yName) { option.yAxis[0].name = this.yName; option.yAxis[0].nameTextStyle = { color: this.axisLalClr }; } // 設置X軸名字 if (this.xName) { option.xAxis[0].name = this.xName; option.xAxis[0].nameTextStyle = { color: this.axisLalClr }; option.xAxis[0].nameLocation = "start"; option.xAxis[0].nameGap = "20"; } // 設置柱狀背景色 if (this.isBgc) { option.xAxis.push({ type: "category", data: this.xAxis, tooltip: { show: false }, axisLine: { show: false }, axisTick: { show: false }, axisLabel: { show: false }, splitArea: { show: false }, splitLine: { show: false } }); } // 設置滾動條 if (this.isDataZoom) { option.dataZoom = [ { id: "dataZoomX", type: "slider", xAxisIndex: [0], filterMode: "weakFilter", // 設定為 'filter' 從而 X 的窗口變化會影響 Y 的范圍。 start: this.zoomStart ? this.zoomStart : 0, bottom: 10, end: this.zoomEnd ? this.zoomEnd : 50, height: 10, handleSize: 0, zoomLock: true, fillerColor: this.zoomFillCrl ? this.zoomFillCrl : "#114c91", backgroundColor: this.zoomBgcCrl ? this.zoomBgcCrl : "#434651", borderColor: this.zoomBorCrl ? this.zoomBorCrl : "rgba(0,0,0,0)", showDetail: false, showDataShadow: false }, { type: "inside", xAxisIndex: [0], filterMode: "weakFilter", start: this.zoomStart ? this.zoomStart : 0, end: this.zoomEnd ? this.zoomEnd : 50 } ]; } this.chart = eCharts.init(this.$refs.barChart); this.chart.on(this.barEvent.eventType, this.barEvent.callBack); this.chart.setOption(option); } } }; </script> <style> </style>