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;
}

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