echart实现custom自定义色块功能

之前完成了一个比较复杂的功能。但是一直没有时间(懒)把这个代码分享出来,趁着一个人加班的机会顺便写个博客。下面是实现的具体展示。

这个图是用来展示机器在一定时间内参数修改的次数。就是说一定时间范围内,两次修改的间隔在五分钟之内,则把他们归为同一个色块。横座标是统计时间的跨度,纵座标是这段时间内修改的次数。

同样颜色的色块代表的是同一台机器,所以就可以非常直观明了的表现机器修改的次数,如果在比较短的时间内出现大量改动,那么就会出现非常细长的色块。我觉得这个功能非常好,虽然需求是领导从别的公司借鉴过来的,不过具体实现都是我自己完成的,花了我两天时间。

好了,不吹牛了,上代码。

首先是在后台统计,统计某时间内机器修改次数。主要就几个参数,机器id,开始时间,结束时间,持续时间,修改次数。统计过后按开始时间正序排序,不然的话形成的图形就比较乱。

然后是前台代码,这个是入口

$(function(){
    loadParaChart();
});
function loadParaChart(){//主方法
	var query = getFormData();//查询条件,主要是开始时间和结束时间
	query["top"] = 10;
	$.ajax({
		type:"get",
		url:url,
		data:query,
		dataType:"json",
		success:function(result){
			if(result.statusCode == 200){
				var list = result.data;
				var o = calculateDataChart(list);//将后台数据处理成echart需要的数据
                //总的开始时间
				var startTime = +new Date(query.startTime.replace("-","/"));
                //总的结束时间,因为是yyyy-MM-dd的格式,所以我加了一天
				var endTime = +new Date(query.endTime.replace("-","/")) + 24*60*60*1000;
				loadChart(o,startTime,endTime,o.max)//生成图表
			}else{
				commPageAjaxDone(result);
			}
		}
	});
}

 这个是计算色块的长宽和位置,主要是避免重叠,具体原理是把计算后的色块加入到列表里,然后新加入的色块先给个固定位置,然后遍历已有的色块,如果和某个色块重叠则把新色块的位置提到该色块的下面,然后重新遍历,直到新色块和所有旧色块不重叠为止。依次类推。当然还是有优化的空间的。我只做了初步的优化,比如先把横向方位不会重叠的色块排除。

var baseHeight = 0.5;//色块的基本长度
function getMax(count){//获得色块的长度
	return baseHeight + 0.05 * count;
}
function calculateDataChart(list){
	var data = [];
	var max = 1;
	var machineMap = {};
	var machines = [];
	var colorList = ["#588d81" ,"#a6fb52","#1871c6","#e18213","#60ec4c" ];//颜色列表,前五个机器固定颜色
	$.each(list,function(i, n){//将后台的数据处理后变成色块的位置信息
		var duration = n.duration;
		if(duration < 60000) duration = 60000;//色块有最小宽度,避免太窄而无法被选中
		var temp = getMax(n.count);//获得色块长度
		var color = "";
		if(machineMap.hasOwnProperty(n.machineId)){
			color = machineMap[n.machineId];
		}else{
			if(colorList.length > 0){
				color = colorList.shift();
			}else{
				color = randomColor();//颜色用完后,后面的机器随机颜色
			}
			machines.push({name:n.machineName,color:color});
			machineMap[n.machineId] = color;
		}
		var index = dealOverlay(data, n);//获得色块的y轴起始位置,核心代码
        //计算整个座标系的最大高度
		if(max < temp + baseHeight + index + 1) max = temp + baseHeight + index + 1;
		data.push({
            name: n.machineName,
            machineId:n.machineId,
            startTime:n.startTime,
            endTime:n.endTime,
            value: [
    			index,
    			n.startTime,
    			n.startTime + duration,
    			n.duration,
    			n.count
            ],
            itemStyle: {
                normal: {
                    color: color
                }
            },
            
        });
	});
	return {
		machines:machines,
		data:data,
		max:max
	};
}
//oldObject 已经被计算过确定位置的色块
//n 新加入的色块
function dealOverlay(oldObject, n){
	var data =$.grep(oldObject,function(o,i){//首先过滤掉时间轴不会重复的老色块,因为不会影响新色块的纵座标位置
		if (n.startTime > o.value[2] || n.endTime < o.value[1])
			return false;
		return true;
	});
	var index = 0.5;
	index = overlay(data, n, index);//重叠算法计算新色块的高度
	return index;
}
function overlay(data, n, index){//重叠算法
	$.each(data,function(i, o){//o 某色块对象
		var value = o.value;
        //index起始位置大于该色块的最大高度,或者新的色块最大高度小于该色块的起始位置,也就是不重复
		if(index > value[0] + getMax(value[4]) || index + getMax(n.count) < value[0]){
			return true;
		}else{//如果重复了,那么将index改成该色块的最大高度加上一个固定高度,然后再重新遍历计算
            //注意,index改变后必须重新遍历一遍,因为之前index不重叠的色块,index改变后有可能会重叠
			index = overlay(data, n, value[0] + getMax(value[4]) + baseHeight);
			return false;
		}
	});
	return index;
}

然后是echart的代码

function loadChart(obj,startTime,endTime,max){
	var machines = obj.machines;
	data = obj.data;
	var duration = (endTime - startTime);
	var series = [{
        type: 'custom',//类型,自定义
        renderItem: renderItem,//自定义图形设置,关键代码
        itemStyle: {
            normal: {
                opacity: 0.8
            }
        },
        label:{
            normal: {
                show: true,
                position: 'inside',
                formatter:function(a){
                    var data = a.data;
                    if(a.value[3] > duration/20){
                    	var str = data.name + "在" +transformTime(a.value[3])+ "内修改了" +a.value[4] + "次";
                    	var n = parseInt(9 * 20 * a.value[3]/duration);
                    	var reg = eval("/.{"+n+"}\x01?/g");
                    	str=str.replace(/[^\x00-\xff]/g,"$&\x01").replace(reg,"$&\n").replace(/\x01/g,"");
	                    return str;
                    }
                    return "";
                },
                color:"black"
            }
        },
        encode: {
            x: [1, 2],
            y: 0
        },
        data: data
    },
    ];
	$.each(machines,function(i,n){//因为自定义模式没有图例,所以我借用了bar模式的图例
		series.push({
			name:n.name,
            type:'bar',
            itemStyle: {
                normal: {
                    color: n.color,  //这里的图例要注意,颜色设置和仪表盘的颜色对应起来
                }
            }
		});
	});
	// Generate mock data
	var option = {
	    tooltip: {
	        formatter: function (params) {
	            var startDate = new Date(params.value[1]).format("yyyy-MM-dd HH:mm:ss")
	            var endDate = new Date(params.value[2]).format("yyyy-MM-dd HH:mm:ss")
	            var result = params.marker + params.name + ' 修改了'+ params.value[4]+"次</br>"+ startDate+"到"+endDate;
	            return  result;
	        }
	    },
	    legend: {
	        data:machines,
	     	x: 'left',
			y: 'top',
	    },
	    grid: {
	        left:50,
	        right:50
	    },
	    xAxis: {
	        type:"time",
	        boundaryGap: false,
	        min: startTime,
	        max: endTime,
	        scale: true,
	        position:"top",
	        axisLabel: {
	            formatter: function (val) {
	                var date = new Date(val).format("MM-dd HH");
	                return date;
	            }
	        }
	    },
	    yAxis: {
	    	type:"value",
	    	inverse: true,
	    	show:false,
	        scale: true,
	        max:max,
	        minInterval: 1,
	    },
	    dataZoom:[{
	    	type:"inside",
	    	filter:"empty",
	        xAxisIndex: 0,
	    },
        {
            type: 'slider',
	    	filter:"empty",
            xAxisIndex: 0,
        },
        ],
	    series: series
	};
	
	var myChart = echarts.init(document.getElementById("paraDataChart"));
    window.onresize = function(){//适应屏幕的变化,重新计算图形
	    myChart.resize();
	}
	myChart.setOption(option);
	myChart.dispatchAction({
	    type: 'dataZoom',
	    // 可选,dataZoom 组件的 index,多个 dataZoom 组件时有用,默认为 0
	    dataZoomIndex: [0,1,2,3],
	    // 开始位置的百分比,0 - 100
	    start: 0,
	    // 结束位置的百分比,0 - 100
	    end: 100,
	})
	myChart.on('datazoom', function (params) {//忘了有什么用。。
		var opt = myChart.getOption();
		var dz = opt.dataZoom[0];
		duration = dz.endValue - dz.startValue;
	});
	myChart.on('legendselectchanged',function(params){//点击图例可以隐藏对应的机器色块
		console.log(params);
		var selected = params.selected;
		var opt = myChart.getOption();
		opt.series[0].data = $.grep(data,function(n,i){
			if(selected[n.name]){
				return true;
			}else{
				return false;
			}
		});
		myChart.setOption(opt,true);
	});
	myChart.on('click',function(params){//色块点击事件
		console.log(params.data);
		});
	});
}

下面是echart自定义模式的核心代码,其实就是烂大街的东西,直接官网看一下,然后自己尝试一下

function renderItem(params, api) {
    var categoryIndex = api.value(0);
    var count = api.value(4);
    var start = api.coord([api.value(1), 0]);//
    var end = api.coord([api.value(2), 0]);//
    var yheight = api.size([0, categoryIndex])[1];//色块y轴起始
    var height = api.size([0, getMax(count)])[1];//色块长度

    var rectShape = echarts.graphic.clipRectByRect({
        x: start[0],
        y: start[1] + yheight,
        width: end[0] - start[0],
        height: height
    }, {
        x: params.coordSys.x,
        y: params.coordSys.y,
        width: params.coordSys.width,
        height: params.coordSys.height
    });
    var style = api.style();
    var renderItem = rectShape && {
        type: 'rect',
        shape: rectShape,
        style: style
    };
    return renderItem;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章