要求:一个图表中显示两个不同来源的数据,来源数据结构不一致,日期或数据均有缺失,每个日期对应数据要为之前数据总和且成一个上升的趋势。
思路:
- 两份数据转成统一结构(如果两份数值类型不一样还需要单独转成统一类型,我的项目excel返回的数值,需要自己算百分比)
- 合并数据
- 补齐日期和数据:比较数据日期取出最大值最小值,并计算出相差天数,补全缺失日期,再补全数据;
- 转为echarts可用格式
以下是用到的一些技术示例,非源代码(源代码太复杂懒得整理)
补齐数据日期
function fnFillTheDataDate(){
// 已合并后数据
var oData= {
"桩基":{"data":[5,10,15],"date":["2020-01-01","2020-01-10","2020-01-5"]},
"隧道":{"data":[1,5,10],"date":["2020-01-02","2020-01-5","2020-01-15"]},
"土方量":{"data":[10,15,20],"date":["2020-01-06","2020-01-2","2020-01-10"]}
}
var mixDate = []; // 每类最大日期and最小日期集合
var mixMaxTimestamp= 0, mixMinTimestamp = 0; // 最终的最大日期、最小日期
// 获取完整日期 2020-01-01 ~ 2020-01-15
for(var key in oData){
var dates = oData[key].date
oData[key]['timestamp'] = [];
for(var i=0; i<dates.length; i++){
oData[key]['timestamp'].push(new Date(dates[i]))
}
var minDate = Math.min.apply(null,oData[key]['timestamp'])
var maxDate = Math.max.apply(null,oData[key]['timestamp'])
mixDate.push(maxDate, minDate)
}
if(mixDate[0]){
var mixMinTimestamp = Math.min.apply(null,mixDate)
var mixMaxTimestamp= Math.max.apply(null,mixDate)
}
var d_value = (mixMaxTimestamp - mixMinTimestamp) / 1000 / 3600 / 24; // 日期差
var timeline = []; // 完整的日期
if(d_value){
for(var i=0; i<=d_value; i++){ //35
timeline.push(fnGetIntervalDate(i, mixMinTimestamp).date)
}
}
// 补充日期
if(timeline[0]){
for(var key in oData){
var oItem= oData[key];
var data = oItem.data;
var date = oItem.date;
for(var i=0; i<timeline.length; i++){
var hasDate = 0
for(var j=0; j<date.length; j++){
if(timeline[i] == date[j]){
hasDate ++;
break
}
}
if(hasDate == 0) {
date.push(timeline[i])
data.push('')
}
}
}
}
console.log(oData)
}
/** 获取间隔日期
* @Descripttion:
* @param {*} days 增减天数
* @param {*} startdate 开始日期
* @return {*}
* @Author: TinaZ
* @Date: 2021-02-01
*/
function fnGetIntervalDate(days, startdate) {
var days = days || 0;
var currDate = startdate ? new Date(startdate).getTime() : new Date().getTime();
var date = new Date(currDate + days*24*60*60*1000);
var Y = date.getFullYear();
var M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1);
var D = date.getDate()<10 ? '0'+date.getDate() : date.getDate();
var H = date.getHours()<10 ? '0'+date.getHours() : date.getHours();
var m = date.getMinutes()<10 ? '0'+date.getMinutes() : date.getMinutes();
var s = date.getSeconds()<10 ? '0'+date.getSeconds() : date.getSeconds();
var sDate = Y + '-' + M + '-' + D;
var sDatetime = Y + '-' + M + '-' + D + ' ' + H + ':' + m + ':' + s;
return {date: sDate, datetime: sDatetime};
}
按日期排序
实际项目中数据来源不同、结构不同,都需要转换成以下格式方可进行排序;
/** 排序并补齐缺失数据
* @Descripttion:
* @param {*}
* @return {*}
* @Author: TinaZ
* @Date: 2021-02-03
*/
function fnSortAndFillTheData(){
var oSourcedata = {
"桩基": {
"data": [5, 10, 15, "", "", "", "", "", "", "", "", "", "", "", "", ""],
"date": ["2020-01-01", "2020-01-10", "2020-01-16", "2020-01-02", "2020-01-03", "2020-01-04", "2020-01-05", "2020-01-06", "2020-01-07", "2020-01-08", "2020-01-09", "2020-01-11", "2020-01-12", "2020-01-13", "2020-01-14", "2020-01-15"],
},
"隧道": {
"data": [1, 5, 10, "", "", "", "", "", "", "", "", "", "", "", "", ""],
"date": ["2020-01-02", "2020-01-16", "2020-01-15", "2020-01-01", "2020-01-03", "2020-01-04", "2020-01-05", "2020-01-06", "2020-01-07", "2020-01-08", "2020-01-09", "2020-01-10", "2020-01-11", "2020-01-12", "2020-01-13", "2020-01-14"],
},
"土方量": {
"data": [10, 15, 20, "", "", "", "", "", "", "", "", "", "", "", "", ""],
"date": ["2020-01-06", "2020-01-16", "2020-01-10", "2020-01-01", "2020-01-02", "2020-01-03", "2020-01-04", "2020-01-05", "2020-01-07", "2020-01-08", "2020-01-09", "2020-01-11", "2020-01-12", "2020-01-13", "2020-01-14", "2020-01-15"],
}
}
var aNewData = []
// 转换格式
for(var key in oSourcedata){
var aItem = []
for(var i=0; i<oSourcedata[key].date.length; i++){
var oItem = {}
oItem['name'] = key
oItem['data'] = oSourcedata[key].data[i]
oItem['date'] = oSourcedata[key].date[i]
aItem.push(oItem)
}
aNewData.push(aItem)
}
console.log("排序前格式",JSON.parse(JSON.stringify(aNewData))[1])
// 排序
for(var i=0; i<aNewData.length; i++){
aNewData[i] = fnDateSort(aNewData[i])
}
console.log("排序后格式",JSON.parse(JSON.stringify(aNewData))[1])
// 补齐缺失数据
for(var i=0; i<aNewData.length; i++){
for(var j=0; j<aNewData[i].length; j++){
//对数据进行累加计算,并补齐
aNewData[i][j].data =
aNewData[i][j-1] && aNewData[i][j-1].data ?
(aNewData[i][j].data ? aNewData[i][j-1].data + aNewData[i][j].data : aNewData[i][j-1].data) : aNewData[i][j].data;
// aNewData[i][j].data = aNewData[i][j].data ? aNewData[i][j].data : aNewData[i][j-1]&&aNewData[i][j-1].data ? aNewData[i][j-1].data : aNewData[i][j].data;
}
}
console.log("补齐缺失数据",JSON.parse(JSON.stringify(aNewData[1])))
// 按周显示
var defaultday = new Date(aNewData[0][aNewData[0].length-1].date).getDay();
var aWeekData = [];
for(var k=0; k<aNewData.length; k++){
aWeekData.push([])
for(var n=0; n<aNewData[k].length; n++){
var day = new Date(aNewData[k][n].date).getDay()
if(day == defaultday){
aWeekData[k].push(aNewData[k][n])
}
}
}
console.log("获取周数据", JSON.parse(JSON.stringify(aWeekData[1])))
}
fnSortAndFillTheData();
/** 日期排序
* @Descripttion:
* @param {*} aData [{name:"",date:"",data:""},{name:"",date:"",data:""}]
* @return {*}
* @Author: TinaZ
* @Date: 2021-02-03
*/
function fnDateSort(aData){
return aData.sort(function(a,b){
return Date.parse(a.date.replace(/-/g,"/")) - Date.parse(b.date.replace(/-/g,"/"))
})
}
转为Echarts可用格式并创建图表
/** 创建图表
* @Descripttion:
* @param {*}
* @return {*}
* @Author: TinaZ
* @Date: 2021-02-03
*/
function fnCreateEchart(){
var aSourceData = [[{"name":"桩基","data":5,"date":"2020-01-02"},{"name":"桩基","data":5,"date":"2020-01-09"},{"name":"桩基","data":30,"date":"2020-01-16"}],[{"name":"隧道","data":1,"date":"2020-01-02"},{"name":"隧道","data":1,"date":"2020-01-09"},{"name":"隧道","data":16,"date":"2020-01-16"}],[{"name":"土方量","data":"","date":"2020-01-02"},{"name":"土方量","data":10,"date":"2020-01-09"},{"name":"土方量","data":45,"date":"2020-01-16"}]]
var xAxisData = [];
var legendData = [];
var series = [];
var oSeriesData = {};
// 重组为echart可用格式
for(var i=0; i<aSourceData.length; i++){
oSeriesData[aSourceData[i][0].name] = []
for(var j=0; j<aSourceData[i].length; j++){
if(i==0){
xAxisData.push(aSourceData[i][j].date)
}
if(j==0){
legendData.push(aSourceData[i][j].name)
}
oSeriesData[aSourceData[i][0].name].push(aSourceData[i][j].data)
}
}
var option = {}
option.legendData = legendData;
option.xAxisData = xAxisData;
option.series = fnSetSeires(oSeriesData)
option.domname = 'echarts'
fnSetOption(option)
}
function fnSetSeires(oSeriesData){
var series = []
for(var key in oSeriesData){
var serie = {}
serie.name = key;
serie.type = 'line';
serie.symbolSize = 10;
serie.data = oSeriesData[key];
series.push(serie);
}
return series
}
function fnSetOption(oData) {
var option = {
color: ['#c23531', '#61a0a8', '#6139a8', '#d48265', '#91c7ae', '#749f83', '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'],
title: {
show: false,
text: ''
},
tooltip: {
trigger: 'axis',
formatter: function (params) {
var relVal = params[0].name;
for (var i = 0; i < params.length; i++) {
relVal += '<br/>' + params[i].marker + params[i].seriesName + ' : ' + params[i].value + '%'
}
return relVal;
}
},
legend: {
textStyle:{
color: '#ffffff'
},
data: []
},
grid: {
top: '10%',
left: '3%',
right: '4%',
bottom: '15%',
containLabel: true
},
toolbox: {
show: false,
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: [],
axisLine: {
lineStyle: {
color: '#15b5cd'
}
},
axisLabel: {
color: '#ffffff',
interval: 0,
ritate: 40,
}
},
yAxis: {
type: 'value',
max: 100,
splitLine: {
show: true,
lineStyle: {
color: 'rgba(255,255,255,0.2)'
}
},
axisLine: {
lineStyle: {
color: '#15b5cd'
}
},
axisLabel: {
color: '#ffffff',
formatter:'{value}%'
},
},
dataZoom: [{
type: 'inside',
textStyle: {
color: '#fff'
},
start:0,
end:100
}, {
type: 'slider',
textStyle: {
color: '#fff'
}
}],
series: []
}
option.legend.data = oData.legendData;
option.xAxis.data = oData.xAxisData;
option.series = oData.series;
var dom = document.getElementById(oData.domname);
var echart = echarts.init(dom);
echart.clear();
echart.setOption(option,true);
}
fnCreateEchart()