动态配置生成echarts图表
动态配置x轴和y轴的数据,并且可以选择柱状图、折线图、饼状图等图形
父组件代码:
<template> <div class="reportPicture"> <div class="reportPicture_inner"> <header> <span>图形设置</span> <ul> <li v-for="(item,index) in graphList" :key="item.id" :class="{ 'highLight':index == currentIndex }" @click="currentIndex = index;currentType = item.type" > <img :src="graphIcon(item.type)" /> <span>{{item.name}}</span> </li> </ul> </header> <main> <aside> <el-tabs v-model="activeTab"> <el-tab-pane label="X轴" name="x"> <div class="tab_item"> <ul> <el-scrollbar style="height: 100%"> <li v-for="item in xList" :key="item.id" :class="{'highLight':item.selected}" @click="toggleSeletX(item)" > {{item.name}} </li> </el-scrollbar> </ul> </div> </el-tab-pane> <el-tab-pane label="Y轴" name="y"> <div class="tab_item" v-show="showTwo"> <section> <span>柱状:</span> <ul> <el-scrollbar style="height: 100%"> <li v-for="item in barList" :key="item.id" :class="{'highLight':item.selected}" @click="toggleSelet(item)" > {{item.name}} </li> </el-scrollbar> </ul> </section> <section> <span>折线:</span> <ul> <el-scrollbar style="height: 100%"> <li v-for="item in lineList" :key="item.id" :class="{'highLight':item.selected}" @click="toggleSelet(item)" > {{item.name}} </li> </el-scrollbar> </ul> </section> </div> <ul v-show="!showTwo"> <el-scrollbar style="height: 100%"> <li v-for="item in yList" :key="item.id" :class="{'highLight':item.selected}" @click="toggleSelet(item)" > {{item.name}} </li> </el-scrollbar> </ul> </el-tab-pane> </el-tabs> <footer> <el-button size="mini" type="danger" plain @click="handle_addPicture" >生成图形</el-button > <el-button size="mini" type="danger" @click="saveImage" >保存图形</el-button > </footer> </aside> <main> <header> <div class="input_box"> <el-input size="mini" type="text" placeholder="请输入" v-model="chartData.title" clearable ></el-input> </div> </header> <div class="chart_box"> <div id="chart"> <line-chart ref="line" class="line" v-if="currentType == 'line'" :chartData="chartData" /> <pie-chart ref="pie" class="pie" v-if="currentType == 'pie'" :chartData="chartData" /> <bar-chart ref="bar2" class="bar2" v-if="currentType == 'bar2'" :chartData="chartData" /> <bar-chart-horizental ref="bar1" class="bar1" v-if="currentType == 'bar1'" :chartData="chartData" /> <line-bar-chart ref="lineBar" class="lineBar" v-if="currentType == 'lineBar'" :chartData="chartData" /> </div> </div> </main> </main> </div> </div> </template>
<script> 
import echarts from 'echarts';
import PieChart from '@/views/dashboard/PieChart';
import BarChart from '@/views/dashboard/BarChart';
import LineChart from '@/views/dashboard/LineChart';
import BarChartHorizental from '@/views/dashboard/BarChartHorizental';
import LineBarChart from '@/views/dashboard/LineBarChart';
export default {
	name: 'reportPicture',
	components: {
		LineChart, PieChart, BarChart, BarChartHorizental, LineBarChart
	},
	data() {
		return {
			activeTab: 'x',
			graphList: [{
				id: 1,
				type: 'pie',
				name: '饼状图'
			}, {
				id: 2,
				type: 'bar1',
				name: '柱状图(橫)'
			}, {
				id: 3,
				type: 'line',
				name: '折线图'
			}, {
				id: 4,
				type: 'bar2',
				name: '柱状图(竖)'
			}, {
				id: 5,
				type: 'lineBar',
				name: '柱状+折线'
			}],
			currentIndex: 0,
			xList: [{
				id: 1,
				name: '轴1',
				selected: false,
				children: ['江干区1', '西湖区1', '拱墅区1', '余杭区1', '临安1']
			}, {
				id: 2,
				name: '轴2',
				selected: false,
				children: ['江干区2', '西湖区2', '拱墅区2', '余杭区2', '临安2']
			}, {
				id: 3,
				name: '轴3',
				selected: false,
				children: ['江干区3', '西湖区3', '拱墅区3', '余杭区3', '临安3']
			}, {
				id: 4,
				name: '轴4',
				selected: false,
				children: ['江干区4', '西湖区4', '拱墅区4', '余杭区4', '临安4']
			}],
			yList: [{
				id: 1,
				name: '控件1',
				selected: false,
				seritesObj: {
					name: '控件1',
					data: [79, 254, 200, 334, 390, 320, 220],
					dataPie: [{
						value: 40,
						name: '江干区'
					}, {
						value: 38,
						name: '西湖区'
					}, {
						value: 32,
						name: '拱墅区'
					}, {
						value: 30,
						name: '余杭区'
					}, {
						value: 28,
						name: '临安'
					}]
				}
			}, {
				id: 2,
				name: '控件2',
				selected: false,
				seritesObj: {
					name: '控件2',
					data: [179, 52, 200, 334, 390, 330, 220],
					dataPie: [{
						value: 45,
						name: '江干区'
					}, {
						value: 38,
						name: '西湖区'
					}, {
						value: 32,
						name: '拱墅区'
					}, {
						value: 30,
						name: '余杭区'
					}, {
						value: 28,
						name: '临安'
					}]
				}
			}, {
				id: 3,
				name: '控件3',
				selected: false,
				seritesObj: {
					name: '控件3',
					data: [79, 452, 260, 334, 390, 350, 220],
					dataPie: [{
						value: 49,
						name: '江干区'
					}, {
						value: 38,
						name: '西湖区'
					}, {
						value: 32,
						name: '拱墅区'
					}, {
						value: 30,
						name: '余杭区'
					}, {
						value: 28,
						name: '临安'
					}]
				}
			}, {
				id: 4,
				name: '控件4',
				selected: false,
				seritesObj: {
					name: '控件4',
					data: [79, 52, 250, 334, 320, 330, 220],
					dataPie: [{
						value: 50,
						name: '江干区'
					}, {
						value: 38,
						name: '西湖区'
					}, {
						value: 32,
						name: '拱墅区'
					}, {
						value: 30,
						name: '余杭区'
					}, {
						value: 28,
						name: '临安'
					}]
				}
			}],
			barList: [{
				id: 1,
				chartType: 'bar',
				name: '控件1',
				selected: false,
				seritesObj: {
					name: '控件1',
					data: [79, 254, 200, 334, 390, 320, 220]
				}
			}, {
				id: 2,
				chartType: 'bar',
				name: '控件2',
				selected: false,
				seritesObj: {
					name: '控件2',
					data: [179, 52, 200, 334, 390, 330, 220]
				}
			}, {
				id: 3,
				chartType: 'bar',
				name: '控件3',
				selected: false,
				seritesObj: {
					name: '控件3',
					data: [79, 452, 260, 334, 390, 350, 220]
				}
			}, {
				id: 4,
				chartType: 'bar',
				name: '控件4',
				selected: false,
				seritesObj: {
					name: '控件4',
					data: [79, 52, 250, 334, 320, 330, 220]
				}
			}],
			lineList: [{
				id: 1,
				chartType: 'line',
				name: '控件1',
				selected: false,
				seritesObj: {
					name: '控件1',
					data: [79, 254, 200, 334, 390, 320, 220]
				}
			}, {
				id: 2,
				chartType: 'line',
				name: '控件2',
				selected: false,
				seritesObj: {
					name: '控件2',
					data: [179, 52, 200, 334, 390, 330, 220]
				}
			}, {
				id: 3,
				chartType: 'line',
				name: '控件3',
				selected: false,
				seritesObj: {
					name: '控件3',
					data: [79, 452, 260, 334, 390, 350, 220]
				}
			}, {
				id: 4,
				chartType: 'line',
				name: '控件4',
				selected: false,
				seritesObj: {
					name: '控件4',
					data: [79, 52, 250, 334, 320, 330, 220]
				}
			}],
			showTwo: false,
			currentType: 'pie',
			chartData: {
				xData: [],
				series: [],
				legend: [],
				title: ''
			},
			chartTitle: '',
			seritesObj: {},
			seritesObjBar: {},
			seritesObjLine: {}
		};
	},
	watch: {
		currentType: {
			handler(newVal, oldVal) {
				this.yList.map(item = > {
					item.selected = false;
				});
				this.chartData.series = [];
				this.chartData.legend = [];
				this.seritesObj.name = '';
				this.seritesObj.data = [];
				switch (newVal) {
				case 'pie':
					this.showTwo = false;
					break;
				case 'line':
					this.showTwo = false;
					break;
				case 'bar1':
					this.showTwo = false;
					break;
				case 'bar2':
					this.showTwo = false;
					break;
				case 'lineBar':
					this.showTwo = true;
					break;
				}
			}, deep: true,
			immediate: true
		}
	},
	methods: {
		graphIcon(type) {
			let img = '';
			switch (type) {
			case 'pie':
				img = require('@/assets/image/icon_pie.png');
				this.seritesObj = {
					type: 'pie',
					roseType: 'radius',
					// radius: [15, 95],
					center: ['50%', '50%'],
					animationEasing: 'cubicInOut',
					animationDuration: 2600
				};
				break;
			case 'line':
				img = require('@/assets/image/icon_line.png');
				this.seritesObj = {
					smooth: true,
					type: 'line',
					animationDuration: 2800,
					animationEasing: 'cubicInOut'
				};
				break;
			case 'bar1':
				img = require('@/assets/image/icon_bar_horizontal.png');
				this.seritesObj = {
					type: 'bar',
					stack: 'vistors',
					barWidth: '60%'
				};
				break;
			case 'bar2':
				img = require('@/assets/image/icon_bar_vertical.png');
				break;
			case 'lineBar':
				img = require('@/assets/image/icon_line.png');
				this.seritesObj = {
					type: 'bar',
					stack: 'vistors',
					barWidth: '60%'
				};
				break;
			}
			return img;
		}, 
		toggleSeletX(item) {
			this.xList.map(it = > {
				it.selected = false;
			});
			item.selected = true;
			this.chartData.xData = item.children;
			console.log(this.chartData.series, 'this.chartData.series');
			if (this.currentType == 'pie') {}
			if (this.chartData.series && this.chartData.series.length > 0) {
				this.chartData.series[0].data.map((ite, index) = > {
					item.children.map((it, i) = > {
						if (index == i) {
							ite.name = it;
						}
					});
				});
			}
		}, 
	        toggleSelet(item) {
			if (this.currentType == 'pie') {
				this.yList.map(it = > {
					it.selected = false;
				});
				item.selected = true;
			} else {
				item.selected = !item.selected;
			}
			switch (this.currentType) {
			case 'pie':
				this.seritesObj = {
					type: 'pie',
					roseType: 'radius',
					// radius: [15, 95],
					// center: ['50%', '50%'],
					animationEasing: 'cubicInOut',
					animationDuration: 2600
				};
				break;
			case 'line':
				this.seritesObj = {
					smooth: true,
					type: 'line',
					animationDuration: 2800,
					animationEasing: 'cubicInOut'
				};
				break;
			case 'bar1':
				this.seritesObj = {
					type: 'bar',
					stack: 'vistors',
					barWidth: '60%'
				};
				break;
			case 'bar2':
				this.seritesObj = {
					type: 'bar',
					stack: 'vistors',
					barWidth: '60%'
				};
				break;
			case 'lineBar':
				this.seritesObjBar = {
					type: 'bar',
					stack: 'vistors',
					barWidth: '60%',
					offset: 80
				};
				this.seritesObjLine = {
					smooth: true,
					type: 'line',
					animationDuration: 2800,
					animationEasing: 'cubicInOut'
				};
				break;
			}
			this.seritesObj.name = item.name;
			let $name_index = this.chartData.legend.indexOf(item.name);
			let arr = [];
			if (this.currentType == 'pie') {
				// 饼图
				this.chartData.xData.map((ite, index) = > {
					item.seritesObj.dataPie.map((it, i) = > {
						if (index == i) {
							it.name = ite;
						}
					});
				});
				this.seritesObj.data = item.seritesObj.dataPie;
				this.chartData.series = [];
				this.chartData.series.push(this.seritesObj);
			} else if (this.currentType == 'lineBar') {
				// 柱状+折线
				if (item.chartType == 'bar') {
					this.seritesObjBar.name = item.name;
				} else {
					this.seritesObjLine.name = item.name;
				}
				if (item.selected) {
					this.chartData.legend.push(item.name);
					if (item.chartType == 'bar') {
						this.seritesObjBar.data = item.seritesObj.data;
						this.chartData.series.push(this.seritesObjBar);
					} else {
						this.seritesObjLine.data = item.seritesObj.data;
						this.chartData.series.push(this.seritesObjLine);
					}
				} else {
					this.chartData.legend.splice($name_index, 1);
					console.log(this.chartData.series, 'this.chartData.series');
					this.chartData.series.map((it, i) = > {
						if (it.name == item.name) {
							this.chartData.series.splice(i, 1);
						}
					});
				}
				// console.log(this.chartData.series, 'this.chartData.series');
			} else {
				this.seritesObj.data = item.seritesObj.data;
				if (item.selected) {
					this.chartData.legend.push(item.name);
					this.chartData.series.push(this.seritesObj);
				} else {
					this.chartData.legend.splice($name_index, 1);
					this.chartData.series.map((it, i) = > {
						if (it.name == item.name) {
							this.chartData.series.splice(i, 1);
						}
					});
				}
			}
			this.chartData.legend = [...new Set(this.chartData.legend)];
		}, 
		handle_addPicture() {
			switch (this.currentType) {
			case 'pie':
				this.$refs.pie.initChart();
				break;
			case 'line':
				this.$refs.line.initChart();
				break;
			case 'bar1':
				this.$refs.bar1.initChart();
				break;
			case 'bar2':
				this.$refs.bar2.initChart();
				break;
			case 'lineBar':
				this.$refs.lineBar.initChart();
				break;
			}
		},
		// 保存图片
		saveImage() {
			// 请求接口成功后返回列表页面
			this.$message({
				type: 'success',
				message: '保存成功!'
			});
			this.$router.go(-1);
		},
		//下载图片
		downloadFile() {
			let aLink = document.createElement('a');
			let blob = this.base64ToBlob();
			let evt = document.createEvent('HTMLEvents');
			evt.initEvent('click', true, true);
			aLink.download = chartData.title ? chartData.title : '报表图形'; //下载图片的名称
			aLink.href = URL.createObjectURL(blob);
			aLink.click();
		}, 
		exportImg() {
			//echart返回一个 base64 的 URL
			let myChart = echarts.init(document.getElementsByClassName(this.currentType)[0]);
			console.log(myChart, 'myChart');
			return myChart.getDataURL({
				type: 'png',
				pixelRatio: 1,
				backgroundColor: '#fff'
			});
		}, 
		base64ToBlob() {
			//将base64转换blob
			let img = this.exportImg();
			let parts = img.split(';base64,');
			let contentType = parts[0].split(':')[1];
			let raw = window.atob(parts[1]);
			let rawLength = raw.length;
			let uInt8Array = new Uint8Array(rawLength);
			for (let i = 0; i < rawLength; ++i) {
				uInt8Array[i] = raw.charCodeAt(i);
			}
			return new Blob([uInt8Array], {
				type: contentType
			});
		}
	}
}; 
</script>    
<style lang="scss" scoped>
@import '@/assets/styles/variables.scss';
.reportPicture {
    width: 100%;
    height: 100%;
    padding: 12px 20px;
    background-color: #f7f7f7;
    .reportPicture_inner {
        width: 100%;
        height: 100%;
        border-radius: 6px;
        background-color: #fff;
        // padding: 20px 15px;
        & > header {
            padding: 20px 16px;
            display: flex;
            align-items: center;
            border-bottom: 1px solid #ececec;
            & > span {
                margin-right: 15px;
                font-size: 14px;
            }
            & > ul {
                display: flex;
                align-items: center;
                list-style: none;
                margin: 0;
                padding: 0;
                & > li {
                    padding: 0 12px;
                    min-width: 130px;
                    height: 38px;
                    border: 1px solid #e6e5e5;
                    background-color: #fff;
                    border-radius: 24px;
                    display: flex;
                    align-items: center;
                    margin-right: 10px;
                    cursor: pointer;
                    &.highLight {
                        border: 1px solid $themeColor;
                    }
                    img {
                        width: 20px;
                        margin-right: 10px;
                    }
                    span {
                        font-size: 14px;
                    }
                }
            }
        }
        & > main {
            padding: 20px;
            height: 80%;
            display: flex;
            .text {
                font-size: 14px;
                margin-right: 10px;
            }
            & > aside,
            & > main {
                background-color: #fff;
            }
            & > aside {
                width: 20%;
                height: 100%;
                display: flex;
                flex-direction: column;
                background-color: #fff;
                margin: 0;
                margin-right: 10px;
                padding: 0 12px;
                /deep/ .el-tabs {
                    display: flex;
                    flex-direction: column;
                    height: 100%;
                    .el-tabs__content {
                        flex: 1;
                        height: 100%;
                        .el-tab-pane {
                            height: 100%;
                        }
                    }
                    .el-tabs__item {
                        &.is-active,
                        &:hover {
                            color: $themeColor !important;
                        }
                    }
                    .el-tabs__active-bar {
                        background-color: $themeColor;
                    }
                }
                .tab_item {
                    height: 100%;
                }
                section {
                    display: flex;
                    margin-bottom: 20px;
                    height: 47%;
                    & > span {
                        font-size: 14px;
                    }
                }
                ul {
                    flex: 1;
                    height: 100%;
                    list-style: none;
                    padding: 0;
                    margin: 0;
                    border-radius: 4px;
                    border: solid 1px #e6e5e5;
                    /deep/.el-scrollbar__wrap {
                        overflow-x: hidden;
                    }
                    li {
                        line-height: 30px;
                        color: #333;
                        font-size: 14px;
                        padding-left: 10px;
                        border-radius: 3px;
                        margin-bottom: 4px;
                        cursor: pointer;
                        overflow: hidden;
                        text-overflow: ellipsis;
                        white-space: nowrap;
                        &.highLight {
                            background-color: $themeColor;
                            color: #fff;
                        }
                    }
                }
                & > footer {
                    height: 5%;
                    margin-top: 10px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                }
            }
            & > main {
                flex: 1;
                display: flex;
                flex-direction: column;
                border: solid 1px #e6e5e5;
                border-radius: 4px;
                & > header {
                    height: 42px;
                    background-color: #f9f9f9;
                    display: flex;
                    align-items: center;
                    padding-left: 10px;
                    .input_box {
                        width: 400px;
                    }
                }
                .chart_box {
                    flex: 1;
                    padding: 20px;
                    #chart {
                        width: 100%;
                        height: 100%;
                    }
                }
            }
        }
    }
}
</style>
子组件:
<template>
  <div :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts';
require('echarts/theme/macarons'); // echarts theme
import resize from './mixins/resize';
const animationDuration = 6000;
export default {
    mixins: [resize],
    props: {
        className: {
            type: String,
            default: 'chart'
        },
        width: {
            type: String,
            default: '100%'
        },
        height: {
            type: String,
            default: '100%'
        },
        chartData: {
            type: Object
        }
    },
    data() {
        return {
            chart: null
        };
    },
    mounted() {
        this.$nextTick(() => {
            this.initChart();
        });
    },
    beforeDestroy() {
        if (!this.chart) {
            return;
        }
        this.chart.dispose();
        this.chart = null;
    },
    methods: {
        initChart() {
            this.chart = echarts.init(this.$el);
            this.chart.clear();
            this.setOptions(this.chartData);
        },
        setOptions({ xData, series, legend, title } = {}) {
            this.chart.setOption({
                title: {
                    text: title
                },
                tooltip: {
                    trigger: 'axis',
                    axisPointer: {
                        // 坐标轴指示器,坐标轴触发有效
                        type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
                    }
                },
                grid: {
                    // top: 10,
                    left: '2%',
                    right: '2%',
                    bottom: '3%',
                    containLabel: true
                },
                legend: {
                    data: legend
                },
                xAxis: [
                    {
                        type: 'category',
                        data: xData,
                        axisTick: {
                            alignWithLabel: true
                        }
                    }
                ],
                yAxis: [
                    {
                        type: 'value',
                        axisTick: {
                            show: false
                        }
                    }
                ],
                series: series
            });
        }
    }
};
</script>
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号