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