动态配置生成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 {
     100%;
    height: 100%;
    padding: 12px 20px;
    background-color: #f7f7f7;
    .reportPicture_inner {
         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- 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 {
                         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 {
                 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 {
                         400px;
                    }
                }
                .chart_box {
                    flex: 1;
                    padding: 20px;
                    #chart {
                         100%;
                        height: 100%;
                    }
                }
            }
        }
    }
}
</style>

子组件:

<template>
  <div :class="className" :style="{height:height,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'
        },
         {
            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>

  

原文地址:https://www.cnblogs.com/florazeng/p/14622361.html