前端可视化封装柱线图
- html
这里没有用echarts自带的图例;自己写了一个所以出现了这么多html;
<template>
<div class="barLineChart">
<div ref="barLineChart" :style="{ width: `${width}px`, height: `${height}px` }" @mouseover="chartsMouseOver" @mouseout="chartsMouseOut"></div>
<div class="legend" :style="{right:legendStyle}" v-show="showLegend">
<div class="barlegend" v-if="legends.length && hasData">
<div class="legendItem" v-for="(val, index) in legends" :key="index">
<div class="block" :style="{ 'background-color': val.from }"></div>
<div class="text" v-text="val.name"></div>
</div>
</div>
<div class="linelegend" v-if="linelegends.length && hasLineData">
<div class="legendItem" v-for="(val, index) in linelegends" :key="index">
<div class="line" :style="{ 'background-color': val.color }"></div>
<div class="text" v-text="val.name"></div>
</div>
</div>
</div>
</div>
</template>
- js**
<script>
export default {
props: {
height: { type: String, default: '100%' }, //高度
width: { type: String, default: '100%' }, //宽度
leftunit: { type: String, default: '个' }, //左侧单位
rightunit: { type: String, default: '%' }, //右侧单位
showJudge: { type: Boolean, default: true }, //y轴右侧是否显示
rowData: {
type: Array,
default: () => {
return [
{ legend: '类型1', measure: 152, dimension: '2016' },
{ legend: '类型1', measure: 101, dimension: '2017' },
{ legend: '类型1', measure: 90, dimension: '2018' },
{ legend: '类型1', measure: 101, dimension: '2019' },
{ legend: '类型1', measure: 152, dimension: '2020' },
{ legend: '类型1', measure: 101, dimension: '2021' },
];
}
},
lineData: {
type: Array,
default: () => {
return [
{ legend: '类型1', measure: 152, dimension: '2016' },
{ legend: '类型1', measure: 101, dimension: '2017' },
{ legend: '类型1', measure: 90, dimension: '2018' },
{ legend: '类型1', measure: 101, dimension: '2019' },
{ legend: '类型1', measure: 152, dimension: '2020' },
{ legend: '类型1', measure: 101, dimension: '2021' },
];
}
},
showLegend: { type: Boolean, default: true }, //显示图例
legends: {
type: Array,
default: () => {
return [
{ name: "类型1", from: "#0095BF", to: "#0FC9FF" }
];
}
}, //图例数据
linelegends: {
type: Array,
default: () => {
return [{ name: '类型1', color: '#E3CF42' }];
}
}, //图例数据
linestack: {
type: Boolean,
default: false
}, //折线图是否堆积
stack: {
type: Boolean,
default: true
}, //是否堆积
barWidth: {
type: String,
default: '10%'
}, //柱子宽度
gridTop: {
type: String,
default: '30%'
},
gridRight: {
type: String,
default: '3%'
},
gridLeft: {
type: String,
default: '0%'
},
gridBottom: {
type: String,
default: '10%'
},
active: {
type: Boolean,
default: false
}, //是否交互
activeobj: {
type: String,
default: ''
}, //关联图层
showToolTip: { type: Boolean, default: true }, //是否显示动画
// x轴字体大小
xAxisFontSize: {
type: [Number, String],
default: '17'
},
// y轴字体大小
yAxisFontSize: {
type: [Number, String],
default: '17'
},
// 单位字体大小
unitFontSize: {
type: [Number, String],
default: '16'
},
// x轴文字是否换行
xWrap: {
type: [Number, String], //是数字时为每行的显示字数,是字符时为以指定的字符为分隔符
default: 0
},
// x文字是否倾斜
axisLabelRotate: {
type: [Number, String],
default: 0
},
// x轴文字是否间隔显示
xLabelInterval: {
type: [Number, String],
default: 'auto'
},
// 显示柱图顶部数据气泡
showLabelBar: {
type: Boolean,
default: false
},
// 显示线图顶部数据气泡
showLabelLine: {
type: Boolean,
default: false
},
// 显示y轴轴线
showYaxisLine: {
type: Boolean,
default: true
},
// 显示X轴滚动条
xScroll: {
type: Boolean,
default: false
},
//是否显示折线图
isShowLine: {
type: Boolean,
default: true
},
// x轴显示个数
dataZoomEnd: {
type: Number,
default: 1000
},
//图例距离右侧距离
legendStyle:{
type:String,
default:'25%'
}
},
data() {
return {
barLineChart: null,
option: null,
xData: [],
yData: [],
yData1: [],
hasData: true,
hasLineData: true,
selectItemName: '', //选中柱子的名称
isChangeColor: false //控制点击变色
};
},
mounted() {
let that = this;
that.$nextTick(() => {
if (that.rowData && that.lineData) {
that.transformData(that.rowData);
that.transformData1(that.lineData);
that.drawChart();
// that.tooltipShuffling();
}
});
},
methods: {
chartsMouseOver() {
clearInterval(this.setTime);
},
chartsMouseOut() {
// this.tooltipShuffling();
},
drawChart() {
var that = this;
// 基于准备好的dom,初始化echarts实例
this.barLineChart = this.$echarts.init(this.$refs.barLineChart);
this.option = this.initOption();
this.barLineChart.setOption(this.option, true);
that.barLineChart.on('click', function(params) {
if (that.active) {
var selectObj = {};
selectObj.activeObj = that.activeobj;
//当前选中柱子
if (that.selectItemName != params.name) {
that.isChangeColor = true;
that.selectItemName = params.name;
selectObj.value = params;
} else {
that.isChangeColor = false;
that.selectItemName = '';
selectObj.value = null;
}
that.barLineChart.setOption(that.option, true);
that.$eventBus.$emit('selectedMapPoint', selectObj);
}
});
},
initOption() {
let that = this;
if (!that.yData || (that.yData.length == 0 && !that.yData1) || that.yData1.length == 0) {
that.option = {
title: {
text: `暂无数据`,
show: true,
textStyle: {
align: 'center',
color: '#fff',
fontSize: 32
},
top: 'center',
left: 'center'
}
};
that.xData = [];
that.hasData = false;
that.hasLineData = false;
return that.option;
} else {
that.hasData = true;
that.hasLineData = true;
that.option = {
tooltip: {
show: that.showToolTip,
trigger: 'axis',
textStyle: {
fontSize: 18
},
axisPointer: {
type: 'cross',
animation: false,
label: {
backgroundColor: '#505765',
fontSize: 18
}
}
},
grid: {
left: that.gridLeft,
right: that.gridRight,
bottom: that.gridBottom,
top: that.gridTop,
containLabel: true
},
xAxis: [
{
type: 'category',
axisTick: { show: false },
data: this.xData,
axisLine: {
lineStyle: {
color: '#BFECFF'
}
},
axisLabel: {
color: '#BFECFF',
fontSize: this.xAxisFontSize,
rotate: this.axisLabelRotate,
interval: this.xLabelInterval,
formatter: function(params) {
if ((typeof that.xWrap).toLowerCase() === 'number') {
if (that.xWrap === 0) return params;
let length = params.length / that.xWrap;
let result = '';
for (let i = 0; i < length; i++) {
let start = i * that.xWrap;
let end = i + that.xWrap;
result += params.slice(start, end) + '\n';
}
return result;
} else {
let newArr = params.split(that.xWrap);
let resStr = '';
newArr.forEach((item, index) => {
if (index !== newArr.length - 1) {
resStr += `${item}\n${that.xWrap}`;
} else {
resStr += item;
}
});
return resStr;
}
}
}
}
],
yAxis: [
{
type: 'value',
axisLine: {
show: that.showYaxisLine,
lineStyle:{
color: '#BFECFF',
}
},
axisTick: {
show: false,
},
axisLabel: {
color: '#BFECFF',
fontSize: this.yAxisFontSize
},
//隔行换色
splitArea: {
show: true,
areaStyle: {
color: ['transparent', 'rgba(238,238,238,.1)']
}
},
splitLine: {
show: false
}
},
{
type: 'value',
axisLine: {
show: that.showYaxisLine,
lineStyle:{
color: '#BFECFF',
}
},
axisTick: {
show: false,
},
show: this.showJudge,
axisLabel: {
color: '#BFECFF',
fontSize: this.yAxisFontSize
},
//隔行换色
splitArea: {
show: false,
areaStyle: {
color: ['transparent', 'rgba(238,238,238,.1)']
}
},
splitLine: {
show: false
}
}
],
title: [
{
text: `${this.leftunit}`,
padding: [5, 0, 0, 0],
textStyle: {
color: '#BFECFF',
fontSize: this.unitFontSize,
fontWeight: 400
},
top: 'top',
left: 'left'
},
{
text: `${this.rightunit}`,
padding: [5, 5, 0, 0],
textStyle: {
color: '#BFECFF',
fontSize: this.unitFontSize,
fontWeight: 400
},
show: this.showJudge,
top: 'top',
left: 'right'
}
],
dataZoom: [
{
show: this.xScroll,
height: 8,
xAxisIndex: [0],
bottom: 0,
start: 0,
end: that.dataZoomEnd,
backgroundColor: 'rgba(41,53,91)',
handleIcon: 'path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z',
handleSize: '110%',
handleStyle: {
color: 'rgba(41,53,91)'
},
handleIconSize: 0,
moveHandleStyle: {
color: 'transparent'
},
textStyle: {
color: '#fff'
},
borderColor: 'transparent'
}
],
series: []
};
that.option.xAxis[0].data = that.xData;
that.option.series = [];
that.yData.forEach((d, index) => {
let serie = {
type: 'bar',
yAxisIndex: 0,
data: d,
barWidth: that.barWidth
};
serie.itemStyle = {
normal: {
color: function(params) {
//判断选中的名字改变柱子的颜色样式
if (that.isChangeColor && that.selectItemName === params.name) {
return new that.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0.5,
color: '#FFFF00'
},
{
offset: 1,
color: '#00000000'
}
]);
} else {
return new that.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0.5,
color: that.legends[index].from
},
{
offset: 1,
color: that.legends[index].to
}
]);
}
}
}
};
serie.label = {
show: this.showLabelBar,
position: 'top',
padding: 3,
borderColor: '#FFFFFF',
borderWidth: 1,
fontSize: 16,
fontFamily: '微软雅黑',
color: '#FFFFFF',
backgroundColor: 'rgba(0,0,0,0.3)'
};
if (that.stack) {
serie.stack = '0';
}
that.option.series.push(serie);
});
if (that.isShowLine) {
that.yData1.forEach((d, index) => {
let serie = {
type: 'line',
yAxisIndex: 1,
data: d
};
serie.itemStyle = {
normal: {
color: that.linelegends[index].color
}
};
serie.label = {
show: this.showLabelLine,
position: 'top',
padding: 3,
borderColor: '#FFFFFF',
borderWidth: 1,
fontSize: 16,
fontFamily: '微软雅黑',
color: '#FFFFFF',
backgroundColor: 'rgba(0,0,0,0.3)'
};
if (that.linestack) {
serie.stack = '0';
}
that.option.series.push(serie);
});
}
}
return that.option;
},
tooltipShuffling() {
clearInterval(this.setTime);
let count = 0;
this.setTime = setInterval(() => {
if (count == this.xData.length) {
count = 0;
}
this.barLineChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: count
});
count++;
}, 1000);
},
transformData(rowData) {
let that = this;
//获取类别去重
let dimensions = Array.from(
new Set(
rowData.map((r) => {
return r.dimension;
})
)
);
that.xData = dimensions;
that.yData = [];
let legends = Array.from(
new Set(
rowData.map((r) => {
return r.legend;
})
)
);
legends.forEach((l) => {
let array = [];
dimensions.forEach((d) => {
let data = rowData.find((r) => r.dimension == d && r.legend == l);
array.push(data.measure);
});
that.yData.push(array);
});
},
transformData1(lineData) {
let that = this;
//获取类别去重
let dimensions = Array.from(
new Set(
lineData.map((r) => {
return r.dimension;
})
)
);
that.xData = dimensions;
that.yData1 = [];
let legends = Array.from(
new Set(
lineData.map((r) => {
return r.legend;
})
)
);
legends.forEach((l) => {
let array = [];
dimensions.forEach((d) => {
let data = lineData.find((r) => r.dimension == d && r.legend == l);
array.push(data.measure);
});
that.yData1.push(array);
});
}
},
watch: {
rowData: {
handler(neVal) {
let that = this;
console.log('更新柱图数据');
that.transformData(neVal);
that.option = that.initOption(that.option);
that.$nextTick(() => {
that.yData.forEach((n, index) => {
that.option.series[index].data = n;
});
that.yData1.forEach((n, index) => {
that.option.series[index].data = n;
});
that.barLineChart.setOption(that.option);
});
},
deep: false
},
lineData: {
handler(neVal) {
let that = this;
console.log('更新折线图数据');
that.transformData1(neVal);
that.option = that.initOption(that.option);
that.$nextTick(() => {
that.yData1.forEach((n, index) => {
that.option.series[index].data = n;
});
that.yData.forEach((n, index) => {
that.option.series[index].data = n;
});
that.barLineChart.setOption(that.option);
});
},
deep: false
}
},
destroyed() {
this.setTime && clearInterval(this.setTime);
this.debounce && clearTimeout(this.debounce);
this.barLineChart = null;
this.option = null;
}
};
</script>
3.css
<style lang="scss" scoped>
.barLineChart {
width: 100%;
position: relative;
overflow: hidden;
.legend {
width: 100%;
display: flex;
position: absolute;
top: 3px;
right: 25%;
justify-content: flex-end;
line-height: 18px;
.legendItem {
display: flex;
.block {
width: 5px;
height: 18px;
}
.text {
margin: 0 5px;
color: #bfebff;
font-size: 16px;
}
}
}
}
.barlegend {
display: flex;
}
.linelegend {
display: flex;
}
.line {
width: 18px;
height: 5px;
margin-top: 4px;
}
</style>
其实大家可以去自己配置,自己想要的图表只是数据处理这块可能费点事,其余都还好,再说还有echars社区里面也有人提供了大量自己配置的图表。
社区链接:https://www.makeapie.com/explore.html