动态配置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>