ThemeRiverSeries.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. var SeriesModel = require("../../model/Series");
  20. var createDimensions = require("../../data/helper/createDimensions");
  21. var _dimensionHelper = require("../../data/helper/dimensionHelper");
  22. var getDimensionTypeByAxis = _dimensionHelper.getDimensionTypeByAxis;
  23. var List = require("../../data/List");
  24. var zrUtil = require("zrender/lib/core/util");
  25. var _model = require("../../util/model");
  26. var groupData = _model.groupData;
  27. var _format = require("../../util/format");
  28. var encodeHTML = _format.encodeHTML;
  29. var LegendVisualProvider = require("../../visual/LegendVisualProvider");
  30. /*
  31. * Licensed to the Apache Software Foundation (ASF) under one
  32. * or more contributor license agreements. See the NOTICE file
  33. * distributed with this work for additional information
  34. * regarding copyright ownership. The ASF licenses this file
  35. * to you under the Apache License, Version 2.0 (the
  36. * "License"); you may not use this file except in compliance
  37. * with the License. You may obtain a copy of the License at
  38. *
  39. * http://www.apache.org/licenses/LICENSE-2.0
  40. *
  41. * Unless required by applicable law or agreed to in writing,
  42. * software distributed under the License is distributed on an
  43. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  44. * KIND, either express or implied. See the License for the
  45. * specific language governing permissions and limitations
  46. * under the License.
  47. */
  48. var DATA_NAME_INDEX = 2;
  49. var ThemeRiverSeries = SeriesModel.extend({
  50. type: 'series.themeRiver',
  51. dependencies: ['singleAxis'],
  52. /**
  53. * @readOnly
  54. * @type {module:zrender/core/util#HashMap}
  55. */
  56. nameMap: null,
  57. /**
  58. * @override
  59. */
  60. init: function (option) {
  61. // eslint-disable-next-line
  62. ThemeRiverSeries.superApply(this, 'init', arguments); // Put this function here is for the sake of consistency of code style.
  63. // Enable legend selection for each data item
  64. // Use a function instead of direct access because data reference may changed
  65. this.legendVisualProvider = new LegendVisualProvider(zrUtil.bind(this.getData, this), zrUtil.bind(this.getRawData, this));
  66. },
  67. /**
  68. * If there is no value of a certain point in the time for some event,set it value to 0.
  69. *
  70. * @param {Array} data initial data in the option
  71. * @return {Array}
  72. */
  73. fixData: function (data) {
  74. var rawDataLength = data.length; // grouped data by name
  75. var groupResult = groupData(data, function (item) {
  76. return item[2];
  77. });
  78. var layData = [];
  79. groupResult.buckets.each(function (items, key) {
  80. layData.push({
  81. name: key,
  82. dataList: items
  83. });
  84. });
  85. var layerNum = layData.length;
  86. var largestLayer = -1;
  87. var index = -1;
  88. for (var i = 0; i < layerNum; ++i) {
  89. var len = layData[i].dataList.length;
  90. if (len > largestLayer) {
  91. largestLayer = len;
  92. index = i;
  93. }
  94. }
  95. for (var k = 0; k < layerNum; ++k) {
  96. if (k === index) {
  97. continue;
  98. }
  99. var name = layData[k].name;
  100. for (var j = 0; j < largestLayer; ++j) {
  101. var timeValue = layData[index].dataList[j][0];
  102. var length = layData[k].dataList.length;
  103. var keyIndex = -1;
  104. for (var l = 0; l < length; ++l) {
  105. var value = layData[k].dataList[l][0];
  106. if (value === timeValue) {
  107. keyIndex = l;
  108. break;
  109. }
  110. }
  111. if (keyIndex === -1) {
  112. data[rawDataLength] = [];
  113. data[rawDataLength][0] = timeValue;
  114. data[rawDataLength][1] = 0;
  115. data[rawDataLength][2] = name;
  116. rawDataLength++;
  117. }
  118. }
  119. }
  120. return data;
  121. },
  122. /**
  123. * @override
  124. * @param {Object} option the initial option that user gived
  125. * @param {module:echarts/model/Model} ecModel the model object for themeRiver option
  126. * @return {module:echarts/data/List}
  127. */
  128. getInitialData: function (option, ecModel) {
  129. var singleAxisModel = ecModel.queryComponents({
  130. mainType: 'singleAxis',
  131. index: this.get('singleAxisIndex'),
  132. id: this.get('singleAxisId')
  133. })[0];
  134. var axisType = singleAxisModel.get('type'); // filter the data item with the value of label is undefined
  135. var filterData = zrUtil.filter(option.data, function (dataItem) {
  136. return dataItem[2] !== undefined;
  137. }); // ??? TODO design a stage to transfer data for themeRiver and lines?
  138. var data = this.fixData(filterData || []);
  139. var nameList = [];
  140. var nameMap = this.nameMap = zrUtil.createHashMap();
  141. var count = 0;
  142. for (var i = 0; i < data.length; ++i) {
  143. nameList.push(data[i][DATA_NAME_INDEX]);
  144. if (!nameMap.get(data[i][DATA_NAME_INDEX])) {
  145. nameMap.set(data[i][DATA_NAME_INDEX], count);
  146. count++;
  147. }
  148. }
  149. var dimensionsInfo = createDimensions(data, {
  150. coordDimensions: ['single'],
  151. dimensionsDefine: [{
  152. name: 'time',
  153. type: getDimensionTypeByAxis(axisType)
  154. }, {
  155. name: 'value',
  156. type: 'float'
  157. }, {
  158. name: 'name',
  159. type: 'ordinal'
  160. }],
  161. encodeDefine: {
  162. single: 0,
  163. value: 1,
  164. itemName: 2
  165. }
  166. });
  167. var list = new List(dimensionsInfo, this);
  168. list.initData(data);
  169. return list;
  170. },
  171. /**
  172. * The raw data is divided into multiple layers and each layer
  173. * has same name.
  174. *
  175. * @return {Array.<Array.<number>>}
  176. */
  177. getLayerSeries: function () {
  178. var data = this.getData();
  179. var lenCount = data.count();
  180. var indexArr = [];
  181. for (var i = 0; i < lenCount; ++i) {
  182. indexArr[i] = i;
  183. }
  184. var timeDim = data.mapDimension('single'); // data group by name
  185. var groupResult = groupData(indexArr, function (index) {
  186. return data.get('name', index);
  187. });
  188. var layerSeries = [];
  189. groupResult.buckets.each(function (items, key) {
  190. items.sort(function (index1, index2) {
  191. return data.get(timeDim, index1) - data.get(timeDim, index2);
  192. });
  193. layerSeries.push({
  194. name: key,
  195. indices: items
  196. });
  197. });
  198. return layerSeries;
  199. },
  200. /**
  201. * Get data indices for show tooltip content
  202. * @param {Array.<string>|string} dim single coordinate dimension
  203. * @param {number} value axis value
  204. * @param {module:echarts/coord/single/SingleAxis} baseAxis single Axis used
  205. * the themeRiver.
  206. * @return {Object} {dataIndices, nestestValue}
  207. */
  208. getAxisTooltipData: function (dim, value, baseAxis) {
  209. if (!zrUtil.isArray(dim)) {
  210. dim = dim ? [dim] : [];
  211. }
  212. var data = this.getData();
  213. var layerSeries = this.getLayerSeries();
  214. var indices = [];
  215. var layerNum = layerSeries.length;
  216. var nestestValue;
  217. for (var i = 0; i < layerNum; ++i) {
  218. var minDist = Number.MAX_VALUE;
  219. var nearestIdx = -1;
  220. var pointNum = layerSeries[i].indices.length;
  221. for (var j = 0; j < pointNum; ++j) {
  222. var theValue = data.get(dim[0], layerSeries[i].indices[j]);
  223. var dist = Math.abs(theValue - value);
  224. if (dist <= minDist) {
  225. nestestValue = theValue;
  226. minDist = dist;
  227. nearestIdx = layerSeries[i].indices[j];
  228. }
  229. }
  230. indices.push(nearestIdx);
  231. }
  232. return {
  233. dataIndices: indices,
  234. nestestValue: nestestValue
  235. };
  236. },
  237. /**
  238. * @override
  239. * @param {number} dataIndex index of data
  240. */
  241. formatTooltip: function (dataIndex) {
  242. var data = this.getData();
  243. var htmlName = data.getName(dataIndex);
  244. var htmlValue = data.get(data.mapDimension('value'), dataIndex);
  245. if (isNaN(htmlValue) || htmlValue == null) {
  246. htmlValue = '-';
  247. }
  248. return encodeHTML(htmlName + ' : ' + htmlValue);
  249. },
  250. defaultOption: {
  251. zlevel: 0,
  252. z: 2,
  253. coordinateSystem: 'singleAxis',
  254. // gap in axis's orthogonal orientation
  255. boundaryGap: ['10%', '10%'],
  256. // legendHoverLink: true,
  257. singleAxisIndex: 0,
  258. animationEasing: 'linear',
  259. label: {
  260. margin: 4,
  261. show: true,
  262. position: 'left',
  263. color: '#000',
  264. fontSize: 11
  265. },
  266. emphasis: {
  267. label: {
  268. show: true
  269. }
  270. }
  271. }
  272. });
  273. var _default = ThemeRiverSeries;
  274. module.exports = _default;