前言
echarts与dataV作为看板开发模板,以本次项目为例,逐一实现项目中的难点问题一、ui图
首先这是ui图,也就是本次项目要实现的目标
二、分析
ui图中有大致五个区域,其中四个区域为轮播,也就是月度计划中的进度条,日计划的表格,以及下方的柱状图和饼图左右轮播。
三、实现
1.dataV轮播
这算是本次项目中最简单的一环,作为优秀的可视化ul组件,dataV给我们创造了很多便利,代码如下:
const config = {
header: [
this.headStyle('物料编码'),
this.headStyle('物料描述'),
this.headStyle('派工数量'),
this.headStyle('实际交付'),
this.headStyle('计划达成率'),
],
data,
align: ['center', 'center', 'center', 'center', 'center'],
rowNum: 5,
headerBGC: '#223764',
columnWidth: [80, 95, 80, 80, 90],
hoverPause: false,
oddRowBGC: '#203864',
evenRowBGC: '#374D74',
waitTime: second*1000,
};
这是轮播图dataV中的配置代码,其中的data需要我们从后端取值,较为可取的方法便是将其便利,再进行配置,代码如下:
const data = [];
const {dataSource, second} = this.props;
dataSource.map((list) => {
return data.push([
`<span title="${list.materialCode}" style='font-size:12px;display: inline-block;width: auto;'>${list.materialCode}</span>`,
`<span title="${list.materialName}" style='font-size:12px;display: inline-block;width: auto;'>${list.materialName}</span>`,
`<span title="${list.dispatchQty}" style='font-size:12px;display: inline-block;width: auto;'>${list.dispatchQty}</span>`,
`<span title="${list.actualDeliverQty}" style='font-size:12px;display: inline-block;width: auto;'>${list.actualDeliverQty}</span>`,
`<span title="${list.planReachRate}%" style='font-size:12px;display: inline-block;width: auto;'>${list.planReachRate}%</span>`,
]);
});
最终效果图:
2. 柱状图轮播
这是项目中较难的一环,原因在于柱状图的左右轮播不能再像dataV那样取现成的组件,而是需要自己写一些代码逻辑,去实现轮播,起初也是有一定的难度,但在经过一番思索和请教高人后,也是找到了解决方法:
- 首先我们需要用到父子组件,子组件需要接收来自父组件不同的数据,毕竟这是要与后端联调,所以刚开始就不能把数据写死,但若是测试数据则是行得通的。
- 引用hzero-ui的走马灯,也就是轮播图插件Carousel,
用div将子组件包裹,然后在父组件接收后端的值将其传给子组件。import { Carousel } from 'hzero-ui';
那么问题来了,如何进行轮播?
传统的轮播图是利用插件对图片轮播,但这次是数据,而且是格式尚不明确的数据,所以前端在刚开始开发的时候就要想到这一点,于是我将这次的轮播换了一个写法,先看一处代码:
const count = Math.floor(topList.length / 4);
const attr = [];
const leftAttr = [];
for (let i = 0; i < count; i++) {
attr.push(i);
}
const left = topList.length % 4;
for (let i = left - 1; i >= 0; i--) {
leftAttr.push(topList.length - 1 - i);
}
这是很简单的几行代码,但它却是这次项目中的核心,简单点说,我们会将整个屏幕分成24份,每一个柱状图区域占去6份:
这样一来,我们也就确定了一个页面一组数据有四个,那就简单了,上面的代码里面我们的操作便是取到后端的数据,将其数据长度除以4,然后得到商和余数,分别放进不同的数组之中,得到两种结果:
-
余数为0,也就是数据长度为4的倍数,不考虑其他因素,利用map函数循环,取出e的下标,然后给子组件分别传递不同下标的数据,像这样:
attr.map(e => { return ( <div> <Row> <Col span={6}> <ProcessNcChart data={topList[e]} /> </Col> <Col span={6}> <ProcessNcChart data={topList[e + 1]} /> </Col> <Col span={6}> <ProcessNcChart data={topList[e + 2]} /> </Col> <Col span={6}> <ProcessNcChart data={topList[e + 3]} /> </Col> </Row> </div> ); })
然后我们进入子组件中,就可以打印出此时获取到的不同数据,即可进行展示;这是第一种情况。
-
余数不为0,这个时候我们就要考虑,将剩下的数据紧紧跟在上一组数据之后,代码如下:
{left > 0 && ( <div> <Row> {leftAttr.map(e => { return ( <Col span={6}> <ProcessNcChart data={topList[e]} e={e} /> </Col> ); })} </Row> </div> )}
left这个数组即是我们之前拿到的余数数组,将其map循环,然后利用e下标传递给子组件不同的数组。
这就是两种不同的情况,代码写到这里基本已经完成,但还要注意一点,也是我写完代码现场业务人员测出来的问题,就是传递的下标问题,举个例子,业务那边要的是每一次轮播之后刷新四个柱状图数据,但是我之前的代码是只会刷新一个数据,具体是这样:
第一个页面之中,四组数据的下标是0,1,2,3,然后到轮播完成后的第二个页面中下标便会成为:1,2,3,4;问题原因便在于传递时代码逻辑错误:
所以只需要改变e为4*e即可
成品:
轮播的话大家自己脑补就可以了哈~这里没有截动态图片,
最后给上子组件的整体柱状图代码
import React, { PureComponent } from 'react';
import { isEmpty } from 'lodash';
import Chart from '@/utils/chart';
import styles from './index.less';
export default class InspectorInspectionCharts extends PureComponent {
constructor(props) {
super(props);
this.state = {
mount: '',
};
}
render() {
const {
data = [],
} = this.props;
const list = [];
const map = [];
let valuename;// top产线
let valuenames;// 直通率产线
if (data.chartsValueList.length !== 0) {
valuename = data.chartsValueList[0].prodLineName;
};
if (data.proLineName) {
valuenames = data.proLineName;// 直通率与top产线优先展示
this.setState({
mount: valuenames,
});
};
if (data.chartValueList) {
data.chartValueList.map((e) => {
return list.push([e.productionGroupCode]);
});
}
if (data.chartValueList) {
data.chartValueList.map((e) => {
return map.push(((e.throughRate) * 100).toFixed(0));
});
}
if (!data.proLineName) {
this.setState({
mount: valuename,
});
}
const option = {
// 设置柱状图位置,x:与左侧边界距离;y:与上侧边界距离;width:柱状图宽度;height:柱状图高度
grid: {
top: '20%',
left: '15%',
bottom: '25%',
right: '5%',
},
// 图表标题设置,其内容以及位置
title: {
text: this.state.mount,
textStyle: {
color: '#00ffff',
fontSize: 12,
},
left: 'center',
},
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
color: {
type: 'shadow',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: 'rgba(0, 255, 233,0)',
},
{
offset: 0.5,
color: 'rgba(255, 255, 255,1)',
},
{
offset: 1,
color: 'rgba(0, 255, 233,0)',
},
],
global: false,
},
},
type: 'shadow',
},
},
// X轴
xAxis: [
{
gridIndex: 0, // 定义index
type: 'category',
data: list,
axisLabel: {
rotate: 40,
show: true,
textStyle: {
color: '#2B92FD',
fontSize: 10,
},
formatter(value) {
if (value && value.length > 5) {
return `${value.slice(0, 5)}...`;
} else {
return value;
}
},
},
splitLine: {
show: false,
},
nameRotate: 30,
axisLine: {
lineStyle: {
color: '#2B92FD',
},
},
},
],
yAxis: [ // y轴
{
gridIndex: 0,
axisLabel: {
textStyle: {
fontFamily: 'PingFang-SC-Medium',
color: 'rgba(240, 235, 235, 0.5)',
fontSize: 10,
},
show: true,
interval: 'auto',
formatter: '{value} %',
},
splitLine: {
show: false,
},
axisLine: {
lineStyle: {
color: '#2B92FD',
},
},
}, // 定义y轴index
],
series: [
{
type: 'bar',
xAxisIndex: 0, // 使用x轴的index-0,y轴的index-0
yAxisIndex: 0,
show: false, // 是否进行展示
data: map,
barMaxWidth: 40,
barMinWidth: 10,
itemStyle: {
normal: {
color: '#2B92FD',
label: {
show: true,
formatter: `{c}%`,
position: 'top',
textStyle: {
color: '#2B92FD',
fontSize: 10,
},
},
},
},
},
],
};
return (
<div style={{ height: '3.2rem' }}>
{isEmpty(list) ? (
<div>
<div className={styles.directRate} style={{ marginBottom: '1rem' }}>{this.state.mount}</div>
<div className={styles.directRate}>暂无数据</div>
</div>
) : (
<Chart
option={option}
/>
)}
</div>
);
}
}
之后的代码里面包括饼图的左右轮播,进度条的上下轮播,也都是和柱状图一个道理哈!
最后给上ui图和成品图的对比: