eventRiver.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. define('echarts/chart/eventRiver', [
  2. 'require',
  3. './base',
  4. '../layout/eventRiver',
  5. 'zrender/shape/Polygon',
  6. '../component/axis',
  7. '../component/grid',
  8. '../component/dataZoom',
  9. '../config',
  10. '../util/ecData',
  11. '../util/date',
  12. 'zrender/tool/util',
  13. 'zrender/tool/color',
  14. '../chart'
  15. ], function (require) {
  16. var ChartBase = require('./base');
  17. var eventRiverLayout = require('../layout/eventRiver');
  18. var PolygonShape = require('zrender/shape/Polygon');
  19. require('../component/axis');
  20. require('../component/grid');
  21. require('../component/dataZoom');
  22. var ecConfig = require('../config');
  23. ecConfig.eventRiver = {
  24. zlevel: 0,
  25. z: 2,
  26. clickable: true,
  27. legendHoverLink: true,
  28. itemStyle: {
  29. normal: {
  30. borderColor: 'rgba(0,0,0,0)',
  31. borderWidth: 1,
  32. label: {
  33. show: true,
  34. position: 'inside',
  35. formatter: '{b}'
  36. }
  37. },
  38. emphasis: {
  39. borderColor: 'rgba(0,0,0,0)',
  40. borderWidth: 1,
  41. label: { show: true }
  42. }
  43. }
  44. };
  45. var ecData = require('../util/ecData');
  46. var ecDate = require('../util/date');
  47. var zrUtil = require('zrender/tool/util');
  48. var zrColor = require('zrender/tool/color');
  49. function EventRiver(ecTheme, messageCenter, zr, option, myChart) {
  50. ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
  51. var self = this;
  52. self._ondragend = function () {
  53. self.isDragend = true;
  54. };
  55. this.refresh(option);
  56. }
  57. EventRiver.prototype = {
  58. type: ecConfig.CHART_TYPE_EVENTRIVER,
  59. _buildShape: function () {
  60. var series = this.series;
  61. this.selectedMap = {};
  62. this._dataPreprocessing();
  63. var legend = this.component.legend;
  64. var eventRiverSeries = [];
  65. for (var i = 0; i < series.length; i++) {
  66. if (series[i].type === this.type) {
  67. series[i] = this.reformOption(series[i]);
  68. this.legendHoverLink = series[i].legendHoverLink || this.legendHoverLink;
  69. var serieName = series[i].name || '';
  70. this.selectedMap[serieName] = legend ? legend.isSelected(serieName) : true;
  71. if (!this.selectedMap[serieName]) {
  72. continue;
  73. }
  74. this.buildMark(i);
  75. eventRiverSeries.push(this.series[i]);
  76. }
  77. }
  78. eventRiverLayout(eventRiverSeries, this._intervalX, this.component.grid.getArea());
  79. this._drawEventRiver();
  80. this.addShapeList();
  81. },
  82. _dataPreprocessing: function () {
  83. var series = this.series;
  84. var xAxis;
  85. var evolutionList;
  86. for (var i = 0, iLen = series.length; i < iLen; i++) {
  87. if (series[i].type === this.type) {
  88. xAxis = this.component.xAxis.getAxis(series[i].xAxisIndex || 0);
  89. for (var j = 0, jLen = series[i].data.length; j < jLen; j++) {
  90. evolutionList = series[i].data[j].evolution;
  91. for (var k = 0, kLen = evolutionList.length; k < kLen; k++) {
  92. evolutionList[k].timeScale = xAxis.getCoord(ecDate.getNewDate(evolutionList[k].time) - 0);
  93. evolutionList[k].valueScale = Math.pow(evolutionList[k].value, 0.8);
  94. }
  95. }
  96. }
  97. }
  98. this._intervalX = Math.round(this.component.grid.getWidth() / 40);
  99. },
  100. _drawEventRiver: function () {
  101. var series = this.series;
  102. for (var i = 0; i < series.length; i++) {
  103. var serieName = series[i].name || '';
  104. if (series[i].type === this.type && this.selectedMap[serieName]) {
  105. for (var j = 0; j < series[i].data.length; j++) {
  106. this._drawEventBubble(series[i].data[j], i, j);
  107. }
  108. }
  109. }
  110. },
  111. _drawEventBubble: function (oneEvent, seriesIndex, dataIndex) {
  112. var series = this.series;
  113. var serie = series[seriesIndex];
  114. var serieName = serie.name || '';
  115. var data = serie.data[dataIndex];
  116. var queryTarget = [
  117. data,
  118. serie
  119. ];
  120. var legend = this.component.legend;
  121. var defaultColor = legend ? legend.getColor(serieName) : this.zr.getColor(seriesIndex);
  122. var normal = this.deepMerge(queryTarget, 'itemStyle.normal') || {};
  123. var emphasis = this.deepMerge(queryTarget, 'itemStyle.emphasis') || {};
  124. var normalColor = this.getItemStyleColor(normal.color, seriesIndex, dataIndex, data) || defaultColor;
  125. var emphasisColor = this.getItemStyleColor(emphasis.color, seriesIndex, dataIndex, data) || (typeof normalColor === 'string' ? zrColor.lift(normalColor, -0.2) : normalColor);
  126. var pts = this._calculateControlPoints(oneEvent);
  127. var eventBubbleShape = {
  128. zlevel: this.getZlevelBase(),
  129. z: this.getZBase(),
  130. clickable: this.deepQuery(queryTarget, 'clickable'),
  131. style: {
  132. pointList: pts,
  133. smooth: 'spline',
  134. brushType: 'both',
  135. lineJoin: 'round',
  136. color: normalColor,
  137. lineWidth: normal.borderWidth,
  138. strokeColor: normal.borderColor
  139. },
  140. highlightStyle: {
  141. color: emphasisColor,
  142. lineWidth: emphasis.borderWidth,
  143. strokeColor: emphasis.borderColor
  144. },
  145. draggable: 'vertical',
  146. ondragend: this._ondragend
  147. };
  148. eventBubbleShape = new PolygonShape(eventBubbleShape);
  149. this.addLabel(eventBubbleShape, serie, data, oneEvent.name);
  150. ecData.pack(eventBubbleShape, series[seriesIndex], seriesIndex, series[seriesIndex].data[dataIndex], dataIndex, series[seriesIndex].data[dataIndex].name);
  151. this.shapeList.push(eventBubbleShape);
  152. },
  153. _calculateControlPoints: function (oneEvent) {
  154. var intervalX = this._intervalX;
  155. var posY = oneEvent.y;
  156. var evolution = oneEvent.evolution;
  157. var n = evolution.length;
  158. if (n < 1) {
  159. return;
  160. }
  161. var time = [];
  162. var value = [];
  163. for (var i = 0; i < n; i++) {
  164. time.push(evolution[i].timeScale);
  165. value.push(evolution[i].valueScale);
  166. }
  167. var pts = [];
  168. pts.push([
  169. time[0],
  170. posY
  171. ]);
  172. var i = 0;
  173. for (i = 0; i < n - 1; i++) {
  174. pts.push([
  175. (time[i] + time[i + 1]) / 2,
  176. value[i] / -2 + posY
  177. ]);
  178. }
  179. pts.push([
  180. (time[i] + (time[i] + intervalX)) / 2,
  181. value[i] / -2 + posY
  182. ]);
  183. pts.push([
  184. time[i] + intervalX,
  185. posY
  186. ]);
  187. pts.push([
  188. (time[i] + (time[i] + intervalX)) / 2,
  189. value[i] / 2 + posY
  190. ]);
  191. for (i = n - 1; i > 0; i--) {
  192. pts.push([
  193. (time[i] + time[i - 1]) / 2,
  194. value[i - 1] / 2 + posY
  195. ]);
  196. }
  197. return pts;
  198. },
  199. ondragend: function (param, status) {
  200. if (!this.isDragend || !param.target) {
  201. return;
  202. }
  203. status.dragOut = true;
  204. status.dragIn = true;
  205. status.needRefresh = false;
  206. this.isDragend = false;
  207. },
  208. refresh: function (newOption) {
  209. if (newOption) {
  210. this.option = newOption;
  211. this.series = newOption.series;
  212. }
  213. this.backupShapeList();
  214. this._buildShape();
  215. }
  216. };
  217. zrUtil.inherits(EventRiver, ChartBase);
  218. require('../chart').define('eventRiver', EventRiver);
  219. return EventRiver;
  220. });define('echarts/layout/eventRiver', ['require'], function (require) {
  221. function eventRiverLayout(series, intervalX, area) {
  222. var space = 5;
  223. var scale = intervalX;
  224. function importanceSort(a, b) {
  225. var x = a.importance;
  226. var y = b.importance;
  227. return x > y ? -1 : x < y ? 1 : 0;
  228. }
  229. function indexOf(array, value) {
  230. if (array.indexOf) {
  231. return array.indexOf(value);
  232. }
  233. for (var i = 0, len = array.length; i < len; i++) {
  234. if (array[i] === value) {
  235. return i;
  236. }
  237. }
  238. return -1;
  239. }
  240. for (var i = 0; i < series.length; i++) {
  241. for (var j = 0; j < series[i].data.length; j++) {
  242. if (series[i].data[j].weight == null) {
  243. series[i].data[j].weight = 1;
  244. }
  245. var importance = 0;
  246. for (var k = 0; k < series[i].data[j].evolution.length; k++) {
  247. importance += series[i].data[j].evolution[k].valueScale;
  248. }
  249. series[i].data[j].importance = importance * series[i].data[j].weight;
  250. }
  251. series[i].data.sort(importanceSort);
  252. }
  253. for (var i = 0; i < series.length; i++) {
  254. if (series[i].weight == null) {
  255. series[i].weight = 1;
  256. }
  257. var importance = 0;
  258. for (var j = 0; j < series[i].data.length; j++) {
  259. importance += series[i].data[j].weight;
  260. }
  261. series[i].importance = importance * series[i].weight;
  262. }
  263. series.sort(importanceSort);
  264. var minTime = Number.MAX_VALUE;
  265. var maxTime = 0;
  266. for (var i = 0; i < series.length; i++) {
  267. for (var j = 0; j < series[i].data.length; j++) {
  268. for (var k = 0; k < series[i].data[j].evolution.length; k++) {
  269. var time = series[i].data[j].evolution[k].timeScale;
  270. minTime = Math.min(minTime, time);
  271. maxTime = Math.max(maxTime, time);
  272. }
  273. }
  274. }
  275. var root = segmentTreeBuild(Math.floor(minTime), Math.ceil(maxTime));
  276. var totalMaxY = 0;
  277. for (var i = 0; i < series.length; i++) {
  278. for (var j = 0; j < series[i].data.length; j++) {
  279. var e = series[i].data[j];
  280. e.time = [];
  281. e.value = [];
  282. for (var k = 0; k < series[i].data[j].evolution.length; k++) {
  283. e.time.push(series[i].data[j].evolution[k].timeScale);
  284. e.value.push(series[i].data[j].evolution[k].valueScale);
  285. }
  286. var mxIndex = indexOf(e.value, Math.max.apply(Math, e.value));
  287. var maxY = segmentTreeQuery(root, e.time[mxIndex], e.time[mxIndex + 1]);
  288. var k = 0;
  289. e.y = maxY + e.value[mxIndex] / 2 + space;
  290. for (k = 0; k < e.time.length - 1; k++) {
  291. var curMaxY = segmentTreeQuery(root, e.time[k], e.time[k + 1]);
  292. if (e.y - e.value[k] / 2 - space < curMaxY) {
  293. e.y = curMaxY + e.value[k] / 2 + space;
  294. }
  295. }
  296. var curMaxY = segmentTreeQuery(root, e.time[k], e.time[k] + scale);
  297. if (e.y - e.value[k] / 2 - space < curMaxY) {
  298. e.y = curMaxY + e.value[k] / 2 + space;
  299. }
  300. series[i].y = e.y;
  301. totalMaxY = Math.max(totalMaxY, e.y + e.value[mxIndex] / 2);
  302. for (k = 0; k < e.time.length - 1; k++) {
  303. segmentTreeInsert(root, e.time[k], e.time[k + 1], e.y + e.value[k] / 2);
  304. }
  305. segmentTreeInsert(root, e.time[k], e.time[k] + scale, e.y + e.value[k] / 2);
  306. }
  307. }
  308. scaleY(series, area, totalMaxY, space);
  309. }
  310. function scaleY(series, area, maxY, space) {
  311. var yBase = area.y;
  312. var yScale = (area.height - space) / maxY;
  313. for (var i = 0; i < series.length; i++) {
  314. series[i].y = series[i].y * yScale + yBase;
  315. var eventList = series[i].data;
  316. for (var j = 0; j < eventList.length; j++) {
  317. eventList[j].y = eventList[j].y * yScale + yBase;
  318. var evolutionList = eventList[j].evolution;
  319. for (var k = 0; k < evolutionList.length; k++) {
  320. evolutionList[k].valueScale *= yScale * 1;
  321. }
  322. }
  323. }
  324. }
  325. function segmentTreeBuild(left, right) {
  326. var root = {
  327. 'left': left,
  328. 'right': right,
  329. 'leftChild': null,
  330. 'rightChild': null,
  331. 'maxValue': 0
  332. };
  333. if (left + 1 < right) {
  334. var mid = Math.round((left + right) / 2);
  335. root.leftChild = segmentTreeBuild(left, mid);
  336. root.rightChild = segmentTreeBuild(mid, right);
  337. }
  338. return root;
  339. }
  340. function segmentTreeQuery(root, left, right) {
  341. if (right - left < 1) {
  342. return 0;
  343. }
  344. var mid = Math.round((root.left + root.right) / 2);
  345. var result = 0;
  346. if (left == root.left && right == root.right) {
  347. result = root.maxValue;
  348. } else if (right <= mid && root.leftChild != null) {
  349. result = segmentTreeQuery(root.leftChild, left, right);
  350. } else if (left >= mid && root.rightChild != null) {
  351. result = segmentTreeQuery(root.rightChild, left, right);
  352. } else {
  353. var leftValue = 0;
  354. var rightValue = 0;
  355. if (root.leftChild != null) {
  356. leftValue = segmentTreeQuery(root.leftChild, left, mid);
  357. }
  358. if (root.rightChild != null) {
  359. rightValue = segmentTreeQuery(root.rightChild, mid, right);
  360. }
  361. result = leftValue > rightValue ? leftValue : rightValue;
  362. }
  363. return result;
  364. }
  365. function segmentTreeInsert(root, left, right, value) {
  366. if (root == null) {
  367. return;
  368. }
  369. var mid = Math.round((root.left + root.right) / 2);
  370. root.maxValue = root.maxValue > value ? root.maxValue : value;
  371. if (Math.floor(left * 10) == Math.floor(root.left * 10) && Math.floor(right * 10) == Math.floor(root.right * 10)) {
  372. return;
  373. } else if (right <= mid) {
  374. segmentTreeInsert(root.leftChild, left, right, value);
  375. } else if (left >= mid) {
  376. segmentTreeInsert(root.rightChild, left, right, value);
  377. } else {
  378. segmentTreeInsert(root.leftChild, left, mid, value);
  379. segmentTreeInsert(root.rightChild, mid, right, value);
  380. }
  381. }
  382. return eventRiverLayout;
  383. });