957ec121e317177c80bb201a27020c6e632d4679.svn-base 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /**
  2. * echarts图表类:事件河流图
  3. *
  4. * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
  5. * @author clmtulip (车丽美, clmtulip@gmail.com)
  6. *
  7. */
  8. define(function (require) {
  9. var ChartBase = require('./base');
  10. var eventRiverLayout = require('../layout/eventRiver');
  11. // 图形依赖
  12. var PolygonShape = require('zrender/shape/Polygon');
  13. // 组件依赖
  14. require('../component/axis');
  15. require('../component/grid');
  16. require('../component/dataZoom');
  17. var ecConfig = require('../config');
  18. // 事件河流图默认参数
  19. ecConfig.eventRiver = {
  20. zlevel: 0, // 一级层叠
  21. z: 2, // 二级层叠
  22. clickable: true,
  23. legendHoverLink: true,
  24. itemStyle: {
  25. normal: {
  26. // color: 各异,
  27. borderColor: 'rgba(0,0,0,0)',
  28. borderWidth: 1,
  29. label: {
  30. show: true,
  31. position: 'inside', // 可选为'left'|'right'|'top'|'bottom'
  32. formatter: '{b}'
  33. // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
  34. }
  35. },
  36. emphasis: {
  37. // color: 各异,
  38. borderColor: 'rgba(0,0,0,0)',
  39. borderWidth: 1,
  40. label: {
  41. show: true
  42. }
  43. }
  44. }
  45. };
  46. var ecData = require('../util/ecData');
  47. var ecDate = require('../util/date');
  48. var zrUtil = require('zrender/tool/util');
  49. var zrColor = require('zrender/tool/color');
  50. /**
  51. * 构造函数
  52. * @param {Object} messageCenter echart消息中心
  53. * @param {ZRender} zr zrender实例
  54. * @param {Object} option 数据
  55. * @param {Object} component 组件
  56. */
  57. function EventRiver(ecTheme, messageCenter, zr, option, myChart) {
  58. // 图表基类
  59. ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
  60. var self = this;
  61. self._ondragend = function () {
  62. self.isDragend = true;
  63. };
  64. this.refresh(option);
  65. }
  66. EventRiver.prototype = {
  67. type: ecConfig.CHART_TYPE_EVENTRIVER,
  68. _buildShape: function() {
  69. var series = this.series;
  70. this.selectedMap = {};
  71. // 数据预处理
  72. this._dataPreprocessing();
  73. var legend = this.component.legend;
  74. // 调用布局算法计算事件在Y轴上的位置
  75. var eventRiverSeries = [];
  76. for (var i = 0; i < series.length; i++) {
  77. if (series[i].type === this.type) {
  78. series[i] = this.reformOption(series[i]);
  79. this.legendHoverLink = series[i].legendHoverLink || this.legendHoverLink;
  80. var serieName = series[i].name || '';
  81. // 系列图例开关
  82. this.selectedMap[serieName] = legend ? legend.isSelected(serieName) : true;
  83. if (!this.selectedMap[serieName]) {
  84. continue;
  85. }
  86. this.buildMark(i);
  87. eventRiverSeries.push(this.series[i]);
  88. }
  89. }
  90. eventRiverLayout(
  91. eventRiverSeries,
  92. this._intervalX,
  93. this.component.grid.getArea()
  94. );
  95. // 绘制事件河
  96. this._drawEventRiver();
  97. this.addShapeList();
  98. },
  99. /**
  100. * 处理数据
  101. */
  102. _dataPreprocessing: function() {
  103. // 将年月日的时间转化为平面坐标
  104. var series = this.series;
  105. var xAxis;
  106. var evolutionList;
  107. for (var i = 0, iLen = series.length; i < iLen; i++) {
  108. if (series[i].type === this.type) {
  109. xAxis = this.component.xAxis.getAxis(series[i].xAxisIndex || 0);
  110. for (var j = 0, jLen = series[i].data.length; j < jLen; j++) {
  111. evolutionList = series[i].data[j].evolution;
  112. for (var k = 0, kLen = evolutionList.length; k < kLen; k++) {
  113. evolutionList[k].timeScale = xAxis.getCoord(
  114. ecDate.getNewDate(evolutionList[k].time) - 0
  115. );
  116. // evolutionList[k].valueScale = evolutionList[k].value;
  117. // modified by limei.che, to normalize the value range
  118. evolutionList[k].valueScale = Math.pow(evolutionList[k].value, 0.8);
  119. }
  120. }
  121. }
  122. }
  123. // 尾迹长度
  124. this._intervalX = Math.round(this.component.grid.getWidth() / 40);
  125. },
  126. /**
  127. * 绘制事件河流
  128. */
  129. _drawEventRiver: function(){
  130. var series = this.series;
  131. for (var i = 0; i < series.length; i++) {
  132. var serieName = series[i].name || '';
  133. if (series[i].type === this.type && this.selectedMap[serieName]) {
  134. for (var j = 0; j < series[i].data.length; j++) {
  135. this._drawEventBubble(series[i].data[j], i, j);
  136. }
  137. }
  138. }
  139. },
  140. /**
  141. * 绘制气泡图
  142. */
  143. _drawEventBubble: function(oneEvent, seriesIndex, dataIndex) {
  144. var series = this.series;
  145. var serie = series[seriesIndex];
  146. var serieName = serie.name || '';
  147. var data = serie.data[dataIndex];
  148. var queryTarget = [data, serie];
  149. var legend = this.component.legend;
  150. var defaultColor = legend ? legend.getColor(serieName) : this.zr.getColor(seriesIndex);
  151. // 多级控制
  152. var normal = this.deepMerge(queryTarget, 'itemStyle.normal') || {};
  153. var emphasis = this.deepMerge(queryTarget, 'itemStyle.emphasis') || {};
  154. var normalColor = this.getItemStyleColor(normal.color, seriesIndex, dataIndex, data)
  155. || defaultColor;
  156. var emphasisColor = this.getItemStyleColor(
  157. emphasis.color, seriesIndex, dataIndex, data
  158. )
  159. || (typeof normalColor === 'string'
  160. ? zrColor.lift(normalColor, -0.2)
  161. : normalColor
  162. );
  163. var pts = this._calculateControlPoints(oneEvent);
  164. var eventBubbleShape = {
  165. zlevel: serie.zlevel,
  166. z: serie.z,
  167. clickable: this.deepQuery(queryTarget, 'clickable'),
  168. style: {
  169. pointList: pts,
  170. smooth: 'spline',
  171. brushType: 'both',
  172. lineJoin : 'round',
  173. color: normalColor,
  174. lineWidth: normal.borderWidth,
  175. strokeColor: normal.borderColor
  176. },
  177. highlightStyle:{
  178. color: emphasisColor,
  179. lineWidth: emphasis.borderWidth,
  180. strokeColor: emphasis.borderColor
  181. },
  182. draggable: 'vertical',
  183. ondragend : this._ondragend
  184. };
  185. eventBubbleShape = new PolygonShape(eventBubbleShape);
  186. this.addLabel(eventBubbleShape, serie, data, oneEvent.name);
  187. ecData.pack(
  188. eventBubbleShape,
  189. series[seriesIndex], seriesIndex,
  190. series[seriesIndex].data[dataIndex], dataIndex,
  191. series[seriesIndex].data[dataIndex].name
  192. );
  193. this.shapeList.push(eventBubbleShape);
  194. },
  195. /**
  196. * 根据时间-热度,计算气泡形状的控制点
  197. */
  198. _calculateControlPoints: function(oneEvent) {
  199. var intervalX = this._intervalX;
  200. var posY = oneEvent.y;
  201. var evolution = oneEvent.evolution;
  202. var n = evolution.length;
  203. if (n < 1) {
  204. return;
  205. }
  206. var time = [];
  207. var value = [];
  208. for (var i = 0; i < n; i++) {
  209. time.push(evolution[i].timeScale);
  210. value.push(evolution[i].valueScale);
  211. }
  212. var pts = [];
  213. // 从左向右绘制气泡的上半部分控制点
  214. // 第一个矩形的左端点
  215. pts.push([time[0], posY]);
  216. // 从一个矩形 到 倒数第二个矩形 上半部分的中点
  217. var i = 0;
  218. for (i = 0; i < n - 1; i++) {
  219. pts.push([(time[i] + time[i + 1]) / 2.0, value[i] / -2.0 + posY]);
  220. }
  221. // 最后一个矩形上半部分的中点
  222. pts.push([(time[i] + (time[i] + intervalX)) / 2.0, value[i] / -2.0 + posY]);
  223. // 最后一个矩形的右端点
  224. pts.push([time[i] + intervalX, posY]);
  225. // 从右向左绘制气泡的下半部分控制点
  226. // 最后一个矩形下半部分的中点
  227. pts.push([(time[i] + (time[i] + intervalX)) / 2.0, value[i] / 2.0 + posY]);
  228. // 从倒数第二个矩形 到 一个矩形 下半部分的中点,由于polygon是闭合的,故不需要再加入左端点
  229. for (i = n - 1; i > 0; i--) {
  230. pts.push([(time[i] + time[i - 1]) / 2.0, value[i - 1] / 2.0 + posY]);
  231. }
  232. return pts;
  233. },
  234. /**
  235. * 数据项被拖拽出去
  236. */
  237. ondragend : function (param, status) {
  238. if (!this.isDragend || !param.target) {
  239. // 没有在当前实例上发生拖拽行为则直接返回
  240. return;
  241. }
  242. // 别status = {}赋值啊!!
  243. status.dragOut = true;
  244. status.dragIn = true;
  245. status.needRefresh = false; // 会有消息触发fresh,不用再刷一遍
  246. // 处理完拖拽事件后复位
  247. this.isDragend = false;
  248. },
  249. /**
  250. * 刷新
  251. */
  252. refresh: function(newOption) {
  253. if (newOption) {
  254. this.option = newOption;
  255. this.series = newOption.series;
  256. }
  257. this.backupShapeList();
  258. this._buildShape();
  259. }
  260. };
  261. zrUtil.inherits(EventRiver, ChartBase);
  262. // 图表注册
  263. require('../chart').define('eventRiver', EventRiver);
  264. return EventRiver;
  265. });