/** * eventRiver 布局算法 * @module echarts/layout/eventRiver * @author clmtulip (车丽美, clmtulip@gmail.com) */ define(function(require) { function eventRiverLayout(series, intervalX, area) { var space = 5; var scale = intervalX; function importanceSort(a, b) { var x = a.importance; var y = b.importance; return ((x > y) ? -1 : ((x < y) ? 1 : 0)); } /** * 查询数组中元素的index */ function indexOf(array, value) { if (array.indexOf) { return array.indexOf(value); } for (var i = 0, len = array.length; i < len; i++) { if (array[i] === value) { return i; } } return -1; } // step 0. calculate event importance and sort descending for (var i = 0; i < series.length; i++) { for (var j = 0; j < series[i].data.length; j++) { if (series[i].data[j].weight == null) { series[i].data[j].weight = 1; } var importance = 0; for (var k = 0; k < series[i].data[j].evolution.length; k++) { importance += series[i].data[j].evolution[k].valueScale; } series[i].data[j].importance = importance * series[i].data[j].weight; } series[i].data.sort(importanceSort); } // step 1. 计算每个group的重要值importance,并按递减顺序排序 for (var i = 0; i < series.length; i++) { if (series[i].weight == null) { series[i].weight = 1; } var importance = 0; for (var j = 0; j < series[i].data.length; j++) { importance += series[i].data[j].weight; } series[i].importance = importance * series[i].weight; } // 根据importance对groups进行递减排序 series.sort(importanceSort); // step 3. set bubble positions in group order, then in event order // 找到包含所有事件的时间段,即最小和最大时间点 var minTime = Number.MAX_VALUE; var maxTime = 0; for (var i = 0; i < series.length; i++) { for (var j = 0; j < series[i].data.length; j++) { for (var k = 0; k < series[i].data[j].evolution.length; k++) { var time = series[i].data[j].evolution[k].timeScale; minTime = Math.min(minTime, time); maxTime = Math.max(maxTime, time); } } } // console.log('minTime: ' + minTime); // console.log('maxTime: ' + maxTime); // 建立线段树根节点 var root = segmentTreeBuild(Math.floor(minTime), Math.ceil(maxTime)); var totalMaxY = 0; for (var i = 0; i < series.length; i++) { for (var j = 0; j < series[i].data.length; j++) { var e = series[i].data[j]; e.time = []; e.value = []; for (var k = 0; k < series[i].data[j].evolution.length; k++) { e.time.push(series[i].data[j].evolution[k].timeScale); e.value.push(series[i].data[j].evolution[k].valueScale); } var mxIndex = indexOf(e.value, Math.max.apply(Math, e.value)); var maxY = segmentTreeQuery(root, e.time[mxIndex], e.time[mxIndex + 1]); var k = 0; e.y = maxY + e.value[mxIndex] / 2 + space; // 检测overlap,调整event.y for (k = 0; k < e.time.length - 1; k++) { var curMaxY = segmentTreeQuery(root, e.time[k], e.time[k + 1]); if (e.y - e.value[k] / 2 - space < curMaxY) { e.y = curMaxY + e.value[k] / 2 + space; } } var curMaxY = segmentTreeQuery(root, e.time[k], e.time[k] + scale); if (e.y - e.value[k] / 2 - space < curMaxY) { e.y = curMaxY + e.value[k] / 2 + space; } series[i].y = e.y; totalMaxY = Math.max(totalMaxY, e.y + e.value[mxIndex] / 2); // 确定位置后更新线段树 for (k = 0; k < e.time.length - 1; k++) { segmentTreeInsert(root, e.time[k], e.time[k+1], e.y + e.value[k] / 2); } segmentTreeInsert(root, e.time[k], e.time[k] + scale, e.y + e.value[k] / 2); } } // 映射到显示区域内 scaleY(series, area, totalMaxY, space); } /** * 映射到显示区域内 * @param {Object} series * @param {Object} area */ function scaleY(series, area, maxY, space) { var yBase = area.y; var yScale = (area.height - space) / maxY; for (var i = 0; i < series.length; i++) { series[i].y = series[i].y * yScale + yBase; var eventList = series[i].data; for (var j = 0; j < eventList.length; j++) { eventList[j].y = eventList[j].y * yScale + yBase; var evolutionList = eventList[j].evolution; for (var k = 0; k < evolutionList.length; k++) { evolutionList[k].valueScale *= yScale * 1; } } } } function segmentTreeBuild(left, right) { var root = { 'left': left, 'right': right, 'leftChild': null, 'rightChild': null, 'maxValue': 0 }; if (left + 1 < right) { var mid = Math.round( (left + right) / 2); root.leftChild = segmentTreeBuild(left, mid); root.rightChild = segmentTreeBuild(mid, right); } return root; } function segmentTreeQuery(root, left, right) { if (right - left < 1) { return 0; } var mid = Math.round( (root.left + root.right) / 2); var result = 0; if (left == root.left && right == root.right) { result = root.maxValue; } else if (right <= mid && root.leftChild != null) { result = segmentTreeQuery(root.leftChild, left, right); } else if (left >= mid && root.rightChild != null) { result = segmentTreeQuery(root.rightChild, left, right); } else { var leftValue = 0; var rightValue = 0; if (root.leftChild != null) { leftValue = segmentTreeQuery(root.leftChild, left, mid); } if (root.rightChild != null) { rightValue = segmentTreeQuery(root.rightChild, mid, right); } result = leftValue > rightValue ? leftValue : rightValue; } return result; } // 插入和更新线段树 function segmentTreeInsert(root, left, right, value) { if (root == null) { return ; } var mid = Math.round( (root.left + root.right) / 2); root.maxValue = root.maxValue > value ? root.maxValue : value; if (Math.floor(left * 10) == Math.floor(root.left * 10) && Math.floor(right * 10) == Math.floor(root.right * 10) ) { return; } else if (right <= mid) { segmentTreeInsert(root.leftChild, left, right, value); } else if (left >= mid) { segmentTreeInsert(root.rightChild, left, right, value); } else { segmentTreeInsert(root.leftChild, left, mid, value); segmentTreeInsert(root.rightChild, mid, right, value); } } return eventRiverLayout; });