一、目标:生成如下的柱状图。配置组件,实现代码复用。
二、对series、横纵坐标参数分析
this.chart.setOption({
title: {
text: '部门疾病类型统计数',
x: '33%',
top: '20',
textStyle: {
color: '#000',
fontSize: '18'
},
},
legend: {
data: ["CT","US","XRAY"],//对应series的名称
},
series: [ //每一个series的详细数据,由于有多个series,可以单独拿出来遍历
{
name: "US",//当前series名字
type: "bar",
itemStyle: {
normal: {
color: "#00c0ef",
lineStyle: {
color: "#00c0ef",
width: 2,
},
areaStyle: {
color: "#f3f8ff",
},
},
},
barWidth: "20",
data: [1,0,0],//当前series与xAxis一一对应的数据
},
],
xAxis: [{
type: 'category',
axisLine: {
lineStyle: {
color: '#90979c'
}
},
splitLine: {
show: false
},
axisTick: {
show: false
},
splitArea: {
show: false
},
axisLabel: {
interval: 0
},
data: ['颅内肿瘤','选项3','异常'] //x轴数据
}],
yAxis: [{
type: 'value',
axisLine: {
lineStyle: {
color: '#90979c'
}
},
axisTick: {
show: false
},
}],
grid: {
borderWidth: 0,
top: 110,
bottom: 95,
textStyle: {
color: '#fff'
}
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "cross",
},
padding: [5, 10],
},
});
通过上述代码,可以看出,我们可以处理一下数据,这样一个配置可以传入不同数据展示不同的echart,实现配置复用。
需要有:1、x坐标名称;2、每个series名称;3、每个series的各个x坐标的值
也就是将下面的接口数据改成适合传入echarts的数据格式。
后端获取数据:
//接口数据
{
{seriesName: "CT",seriesValue: 1,xAxisName: "异常"},
{seriesName: "CT",seriesValue: 1,xAxisName: "选项3"},
{seriesName: "CT",seriesValue: 3,xAxisName: "颅内肿瘤"},
{seriesName: "US",seriesValue: 1,xAxisName: "颅内肿瘤"},
{seriesName: "XRAY",seriesValue: 1,xAxisName: "颅内肿瘤"},
}
传入echarts的数据格式:
//传入echart的数据
{
seriesName:['CT','US','XRAY'],
seriesValue:{
"CT":[3,1,1],
"US":[1,0,0],
"XRAY":[1,0,0]
},
xAxisName:['颅内肿瘤','选项3','异常']
}
三、步骤与代码
1、安装依赖 npm install echarts --save
2、在目标文件目录下创建如下components文件夹。
resize.js
import {
debounce
} from "@/utils/debounce"
export default {
data() {
return {
$_sidebarElm: null
}
},
mounted() {
this.$_initResizeEvent()
this.$_initSidebarResizeEvent()
},
beforeDestroy() {
this.$_destroyResizeEvent()
this.$_destroySidebarResizeEvent()
},
// to fixed bug when cached by keep-alive
// https://github.com/PanJiaChen/vue-element-admin/issues/2116
activated() {
this.$_initResizeEvent()
this.$_initSidebarResizeEvent()
},
deactivated() {
this.$_destroyResizeEvent()
this.$_destroySidebarResizeEvent()
},
methods: {
// use $_ for mixins properties
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
$_resizeHandler() {
return debounce(() => {
if (this.chart) {
this.chart.resize()
}
}, 100)()
},
$_initResizeEvent() {
window.addEventListener('resize', this.$_resizeHandler)
},
$_destroyResizeEvent() {
window.removeEventListener('resize', this.$_resizeHandler)
},
$_sidebarResizeHandler(e) {
if (e.propertyName === 'width') {
this.$_resizeHandler()
}
},
$_initSidebarResizeEvent() {
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
},
$_destroySidebarResizeEvent() {
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
}
}
}
utils/debounce.js
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
}
}
chart.vue
<template>
<div :class="className" :id="id" :style="{height:height,width:width}"/>
</template>
<script>
import echarts from 'echarts'
import resize from './mixins/resize'
export default {
name:'chart',
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
},
title: {
type: String,
default: '图表'
},
chartData: {
type: Object,
required: true
}
},
data() {
return {
chart: null,
series:[]
}
},
mounted() {
this.initChart()
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
//防止数据改变以后不更新echarts
watch:{
chartData(cur, old){
this.initChart()
},
},
methods: {
initChart() {
console.log(this.chartData)
this.chart = echarts.init(document.getElementById(this.id))
if(!this.chartData.seriesName){
return
}
const xData = this.chartData.xAxisName
//更新echarts的时候先清除数据
this.series = []
for(let i = 0; i < this.chartData.seriesName.length; i++){
var r = Math.floor(Math.random()*256);
var g = Math.floor(Math.random()*256);
var b = Math.floor(Math.random()*256);
var rgba = 'rgba('+r+','+g+','+b+',1)';
this.series.push(
{
name: this.chartData.seriesName[i],
type: 'bar',
stack: 'total',
barMaxWidth: 35,
barGap: '10%',
itemStyle: {
normal: {
color: rgba,
label: {
show: true,
textStyle: {
color: '#fff'
},
position: 'insideTop',
formatter(p) {
return p.value > 0 ? p.value : ''
}
}
}
},
data: this.chartData.seriesValue[this.chartData.seriesName[i]]
}
)
}
this.chart.setOption({
backgroundColor: '#fff',
title: {
text: this.title,
x: '33%',
top: '20',
textStyle: {
color: '#000',
fontSize: '18'
},
subtextStyle: {
color: '#90979c',
fontSize: '16'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
textStyle: {
color: '#000'
}
}
},
grid: {
borderWidth: 0,
top: 110,
bottom: 95,
textStyle: {
color: '#fff'
}
},
legend: {
x: '25%',
top: '80%',
textStyle: {
color: '#90979c'
},
data: this.chartData.seriesName
},
calculable: true,
xAxis: [{
type: 'category',
axisLine: {
lineStyle: {
color: '#90979c'
}
},
splitLine: {
show: false
},
axisTick: {
show: false
},
splitArea: {
show: false
},
axisLabel: {
interval: 0
},
data: xData
}],
yAxis: [{
type: 'value',
splitLine: {
show: false
},
axisLine: {
lineStyle: {
color: '#90979c'
}
},
axisTick: {
show: false
},
axisLabel: {
interval: 0
},
splitArea: {
show: false
}
}],
series: this.series
})
}
}
}
</script>
deptStatistic.vue(使用echart的文件)
<template>
<div>
<el-card class="echart-wrap">
<line-chart v-if="Object.keys(patTypeChartData).length!=0" :id="'patTypeChart'" :title="'部门患者类型统计数'" :chart-data="patTypeChartData"/>
<div v-else>部门患者类型类型统计暂无数据</div>
</el-card>
<el-card class="echart-wrap">
<line-chart v-if="Object.keys(diseaseTypeChartData).length!=0" :id="'diseaseTypeChart'" :title="'部门疾病类型统计数'" :chart-data="diseaseTypeChartData"/>
<div v-else>部门疾病类型统计暂无数据</div>
</el-card>
</div>
</template>
<script>
import LineChart from './components/chart'
import { getStatisticsByPatType, getStatisticsByDiseaseType } from '@/api/api.js'
export default {
name:'deptStatisticsChart',
components: {
LineChart
},
data(){
return{
patTypeChartData:[],
diseaseTypeChartData:[],
}
},
created(){
this.fetchData()
},
methods:{
fetchData(){
getStatisticsByPatType(data).then(res=>{
if(res && res.code == 10000){
this.patTypeChartData = this.formatChartData(res.content.list)
}
})
getStatisticsByDiseaseType(data).then(res=>{
if(res && res.code == 10000){
this.diseaseTypeChartData = this.formatChartData(res.content.list)
}
})
},
//将数据转为echarts的形式
formatChartData(echartsData){
//没数据做判断
if(echartsData.length == 0) return {}
//需要提前将echartsData排序 避免存进去是乱序的
let data = echartsData.sort(this.objectArraySort('xAxisName'))
let xAxisName = []
let seriesName = []
let seriesValue = {}
for(let i = 0; i < data.length; i++){
xAxisName.push(data[i].xAxisName)
seriesName.push(data[i].seriesName)
}
xAxisName = this.getUnique(xAxisName)//x轴参数
seriesName = this.getUnique(seriesName)//图标参数
for(let j = 0; j < seriesName.length; j++){
//先提前占位
seriesValue[seriesName[j]] = Array.apply(0,{length:xAxisName.length})
//这里不仅要判断seriesName 还需要判断xAxisName 不存在的给0
data.map(item => {
if (item.seriesName == seriesName[j]) {
for(let k = 0; k < xAxisName.length; k++){
// 符合插入在相应的位置上
if(item.xAxisName == xAxisName[k]){
seriesValue[seriesName[j]][k] = item.seriesValue
}
}
}
});
}
let result = {
xAxisName: xAxisName,
seriesName: seriesName,
seriesValue: seriesValue
}
return result
},
objectArraySort(keyName) {
return function (objectN, objectM) {
var valueN = objectN[keyName]
var valueM = objectM[keyName]
if (valueN < valueM) return 1
else if (valueN > valueM) return -1
else return 0
}
},
//数组去重
getUnique(arr) {
var res = arr.filter(function (item, index, array) {
return arr.indexOf(item) === index;
});
return res;
},
}
</script>
<style lang="scss" scoped>
.echart-wrap{
display: inline-block;
width: 48%;
margin-right: 0px;
height: 310px;
line-height: 290px;
text-align: center;
}
</style>
四、遇到的问题
1、 Cannot read property ‘init‘ of undefined
解决办法:echarts从5.0.0换成4.8.0 ,并项目重启。