封装了一个plotly图表组件,可以生成多个不同数据源的相同组件:
效果
客户想要的:
通过一个配置文件 来动态改变图表的数量,标题,接收的参数等
我的做法:
1,定义一个配置文件
title为图表名称 keyWord为该图表接收到的参数
该对象在tableConfig中的下标即是图表的上下顺序
2,解析该配置文件
//template内容:
<div v-for="(item, index) in tableConfig" :key="index" class="tabBox">
<LineBox
:option="potlyData"
:layout="layout"
:data_y="evalDealWith(`this.data_y[${index}]`)"
:data_ys="evalDealWith(`this.data_ys[${index}]`)"
:data_x="data_x"
:data_xs="data_xs"
:title="item.title"
:key="index"
/>
</div>
data(){
return :{
// 标准数据
data_y: [],
data_x: [],
// 实际数据
data_ys: [],
data_xs: [],
}
}
methods: {
// 由其他组件调用进行赋值
setStandardDasta() {
tableConfig.forEach((item, index) => {
this.data_y.push([]);
// 给每个数据源标准数据赋值
this.standardData.forEach((val) => {
this.data_y[index].push(val[item.keyWord]);
});
});
this.standardData.forEach((val) => {
this.data_x.push(val.FlyTime);
});
},
setData_ys(obj) {
// 给数据源实际数据赋值
tableConfig.forEach((item, index) => {
this.data_ys[index] = obj[item.keyWord];
});
// 横轴时间
this.data_xs = obj.FlyTime;
},
// 实现动态参数的处理方法:
evalDealWith(val) {
return eval(val);
},
},
我遇到的难点其实主要是 给封装的子组件LineBox赋值时,如何将vue的data数据动态的进行赋值
解决方法是 使用eval函数包裹字符串 :data_y="evalDealWith(`this.data_y[${index}]`)"
经过eval处理
效果其实就是:data_y="data_y[0/1/2/3/4]"
最终效果是
修改 tableConfig文件后 就会根据该文件的内容生成对应数量的图表
如:
附上封装的plotly图表组件:
<!--
* @Author: 老范
* @Date: 2022-03-22 11:18:05
* @LastEditors: 老范
* @LastEditTime: 2022-07-15 11:40:06
* @Description: 请填写简介
-->
<template>
<div class="lineBox">
<div class="lineChart" ref="lineRef"></div>
</div>
</template>
<script>
export default {
name: "LineBox",
props: [
"option",
"layout",
"data_y",
"data_ys",
"data_x",
"data_xs",
"title",
],
components: {},
data() {
return {
myLineDom: {},
myOption: {},
myLayout: {},
timer: 0,
};
},
created() {},
mounted() {
this.initData();
},
methods: {
initData() {
this.dovPot = this.$refs.lineRef;
this.myOption = JSON.parse(JSON.stringify(this.option)); // 数据深拷贝
this.myLayout = JSON.parse(JSON.stringify(this.layout)); // 数据深拷贝
this.myOption[0].x = this.data_x; // 赋值title
this.myOption[0].y = this.data_y; // 赋值title
this.myOption[1].x = [0]; // 赋值title
this.myOption[1].y = [0]; // 赋值title
this.myLayout.title.text = this.title;
Plotly.newPlot(this.dovPot, this.myOption, this.myLayout, {
scrollZoom: true,
responsive: true,
displaylogo: false,
modeBarButtonsToRemove: [
"toImage",
"toggleSpikelines",
"autoScale2d",
"select",
"select2d",
"lasso",
"lasso2d",
"zoomIn2d",
// "zoomInGeo",
// "zoomInMapbox",
"zoomOut2d",
// "zoomOutGeo",
// "zoomOutMapbox",
// "zoomin",
// "zoomout",
],
});
},
},
watch: {
data_ys(val) {
this.timer += 1;
// 监听实际数据的变化
this.myOption[1].y.push(val); // 更新实际数据
this.myOption[1].x.push(this.data_xs); // 更新实际数据
// 10次变化重绘一次
if (this.timer % 10 === 0) {
Plotly.redraw(this.dovPot, this.myOption, this.myLayout, {
scrollZoom: true,
responsive: true,
displaylogo: false,
});
}
},
},
};
</script>
<style scoped>
.lineBox {
flex: 1;
box-sizing: border-box;
margin: 8px 0;
width: 100%;
background: url("../../assets/bg.png") no-repeat;
background-size: 100% 100%;
}
.lineChart {
width: 100%;
height: 19.2407vh;
border: 1px solid #165588;
border-radius: 8px 8px 0 0;
overflow: hidden;
}
.js-plotly-plot .plotly .modebar {
bottom: 0;
}
.modebar-btn--logo {
display: none;
}
.js-plotly-plot .plotly .modebar.vertical {
flex-flow: wrap !important;
}
</style>