MarkLineView.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. var zrUtil = require("zrender/lib/core/util");
  2. var List = require("../../data/List");
  3. var numberUtil = require("../../util/number");
  4. var markerHelper = require("./markerHelper");
  5. var LineDraw = require("../../chart/helper/LineDraw");
  6. var MarkerView = require("./MarkerView");
  7. var markLineTransform = function (seriesModel, coordSys, mlModel, item) {
  8. var data = seriesModel.getData(); // Special type markLine like 'min', 'max', 'average'
  9. var mlType = item.type;
  10. if (!zrUtil.isArray(item) && (mlType === 'min' || mlType === 'max' || mlType === 'average' // In case
  11. // data: [{
  12. // yAxis: 10
  13. // }]
  14. || item.xAxis != null || item.yAxis != null)) {
  15. var valueAxis;
  16. var valueDataDim;
  17. var value;
  18. if (item.yAxis != null || item.xAxis != null) {
  19. valueDataDim = item.yAxis != null ? 'y' : 'x';
  20. valueAxis = coordSys.getAxis(valueDataDim);
  21. value = zrUtil.retrieve(item.yAxis, item.xAxis);
  22. } else {
  23. var axisInfo = markerHelper.getAxisInfo(item, data, coordSys, seriesModel);
  24. valueDataDim = axisInfo.valueDataDim;
  25. valueAxis = axisInfo.valueAxis;
  26. value = markerHelper.numCalculate(data, valueDataDim, mlType);
  27. }
  28. var valueIndex = valueDataDim === 'x' ? 0 : 1;
  29. var baseIndex = 1 - valueIndex;
  30. var mlFrom = zrUtil.clone(item);
  31. var mlTo = {};
  32. mlFrom.type = null;
  33. mlFrom.coord = [];
  34. mlTo.coord = [];
  35. mlFrom.coord[baseIndex] = -Infinity;
  36. mlTo.coord[baseIndex] = Infinity;
  37. var precision = mlModel.get('precision');
  38. if (precision >= 0 && typeof value === 'number') {
  39. value = +value.toFixed(Math.min(precision, 20));
  40. }
  41. mlFrom.coord[valueIndex] = mlTo.coord[valueIndex] = value;
  42. item = [mlFrom, mlTo, {
  43. // Extra option for tooltip and label
  44. type: mlType,
  45. valueIndex: item.valueIndex,
  46. // Force to use the value of calculated value.
  47. value: value
  48. }];
  49. }
  50. item = [markerHelper.dataTransform(seriesModel, item[0]), markerHelper.dataTransform(seriesModel, item[1]), zrUtil.extend({}, item[2])]; // Avoid line data type is extended by from(to) data type
  51. item[2].type = item[2].type || ''; // Merge from option and to option into line option
  52. zrUtil.merge(item[2], item[0]);
  53. zrUtil.merge(item[2], item[1]);
  54. return item;
  55. };
  56. function isInifinity(val) {
  57. return !isNaN(val) && !isFinite(val);
  58. } // If a markLine has one dim
  59. function ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) {
  60. var otherDimIndex = 1 - dimIndex;
  61. var dimName = coordSys.dimensions[dimIndex];
  62. return isInifinity(fromCoord[otherDimIndex]) && isInifinity(toCoord[otherDimIndex]) && fromCoord[dimIndex] === toCoord[dimIndex] && coordSys.getAxis(dimName).containData(fromCoord[dimIndex]);
  63. }
  64. function markLineFilter(coordSys, item) {
  65. if (coordSys.type === 'cartesian2d') {
  66. var fromCoord = item[0].coord;
  67. var toCoord = item[1].coord; // In case
  68. // {
  69. // markLine: {
  70. // data: [{ yAxis: 2 }]
  71. // }
  72. // }
  73. if (fromCoord && toCoord && (ifMarkLineHasOnlyDim(1, fromCoord, toCoord, coordSys) || ifMarkLineHasOnlyDim(0, fromCoord, toCoord, coordSys))) {
  74. return true;
  75. }
  76. }
  77. return markerHelper.dataFilter(coordSys, item[0]) && markerHelper.dataFilter(coordSys, item[1]);
  78. }
  79. function updateSingleMarkerEndLayout(data, idx, isFrom, seriesModel, api) {
  80. var coordSys = seriesModel.coordinateSystem;
  81. var itemModel = data.getItemModel(idx);
  82. var point;
  83. var xPx = numberUtil.parsePercent(itemModel.get('x'), api.getWidth());
  84. var yPx = numberUtil.parsePercent(itemModel.get('y'), api.getHeight());
  85. if (!isNaN(xPx) && !isNaN(yPx)) {
  86. point = [xPx, yPx];
  87. } else {
  88. // Chart like bar may have there own marker positioning logic
  89. if (seriesModel.getMarkerPosition) {
  90. // Use the getMarkerPoisition
  91. point = seriesModel.getMarkerPosition(data.getValues(data.dimensions, idx));
  92. } else {
  93. var dims = coordSys.dimensions;
  94. var x = data.get(dims[0], idx);
  95. var y = data.get(dims[1], idx);
  96. point = coordSys.dataToPoint([x, y]);
  97. } // Expand line to the edge of grid if value on one axis is Inifnity
  98. // In case
  99. // markLine: {
  100. // data: [{
  101. // yAxis: 2
  102. // // or
  103. // type: 'average'
  104. // }]
  105. // }
  106. if (coordSys.type === 'cartesian2d') {
  107. var xAxis = coordSys.getAxis('x');
  108. var yAxis = coordSys.getAxis('y');
  109. var dims = coordSys.dimensions;
  110. if (isInifinity(data.get(dims[0], idx))) {
  111. point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[isFrom ? 0 : 1]);
  112. } else if (isInifinity(data.get(dims[1], idx))) {
  113. point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[isFrom ? 0 : 1]);
  114. }
  115. } // Use x, y if has any
  116. if (!isNaN(xPx)) {
  117. point[0] = xPx;
  118. }
  119. if (!isNaN(yPx)) {
  120. point[1] = yPx;
  121. }
  122. }
  123. data.setItemLayout(idx, point);
  124. }
  125. var _default = MarkerView.extend({
  126. type: 'markLine',
  127. updateLayout: function (markLineModel, ecModel, api) {
  128. ecModel.eachSeries(function (seriesModel) {
  129. var mlModel = seriesModel.markLineModel;
  130. if (mlModel) {
  131. var mlData = mlModel.getData();
  132. var fromData = mlModel.__from;
  133. var toData = mlModel.__to; // Update visual and layout of from symbol and to symbol
  134. fromData.each(function (idx) {
  135. updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);
  136. updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api);
  137. }); // Update layout of line
  138. mlData.each(function (idx) {
  139. mlData.setItemLayout(idx, [fromData.getItemLayout(idx), toData.getItemLayout(idx)]);
  140. });
  141. this.markerGroupMap.get(seriesModel.id).updateLayout();
  142. }
  143. }, this);
  144. },
  145. renderSeries: function (seriesModel, mlModel, ecModel, api) {
  146. var coordSys = seriesModel.coordinateSystem;
  147. var seriesId = seriesModel.id;
  148. var seriesData = seriesModel.getData();
  149. var lineDrawMap = this.markerGroupMap;
  150. var lineDraw = lineDrawMap.get(seriesId) || lineDrawMap.set(seriesId, new LineDraw());
  151. this.group.add(lineDraw.group);
  152. var mlData = createList(coordSys, seriesModel, mlModel);
  153. var fromData = mlData.from;
  154. var toData = mlData.to;
  155. var lineData = mlData.line;
  156. mlModel.__from = fromData;
  157. mlModel.__to = toData; // Line data for tooltip and formatter
  158. mlModel.setData(lineData);
  159. var symbolType = mlModel.get('symbol');
  160. var symbolSize = mlModel.get('symbolSize');
  161. if (!zrUtil.isArray(symbolType)) {
  162. symbolType = [symbolType, symbolType];
  163. }
  164. if (typeof symbolSize === 'number') {
  165. symbolSize = [symbolSize, symbolSize];
  166. } // Update visual and layout of from symbol and to symbol
  167. mlData.from.each(function (idx) {
  168. updateDataVisualAndLayout(fromData, idx, true);
  169. updateDataVisualAndLayout(toData, idx, false);
  170. }); // Update visual and layout of line
  171. lineData.each(function (idx) {
  172. var lineColor = lineData.getItemModel(idx).get('lineStyle.normal.color');
  173. lineData.setItemVisual(idx, {
  174. color: lineColor || fromData.getItemVisual(idx, 'color')
  175. });
  176. lineData.setItemLayout(idx, [fromData.getItemLayout(idx), toData.getItemLayout(idx)]);
  177. lineData.setItemVisual(idx, {
  178. 'fromSymbolSize': fromData.getItemVisual(idx, 'symbolSize'),
  179. 'fromSymbol': fromData.getItemVisual(idx, 'symbol'),
  180. 'toSymbolSize': toData.getItemVisual(idx, 'symbolSize'),
  181. 'toSymbol': toData.getItemVisual(idx, 'symbol')
  182. });
  183. });
  184. lineDraw.updateData(lineData); // Set host model for tooltip
  185. // FIXME
  186. mlData.line.eachItemGraphicEl(function (el, idx) {
  187. el.traverse(function (child) {
  188. child.dataModel = mlModel;
  189. });
  190. });
  191. function updateDataVisualAndLayout(data, idx, isFrom) {
  192. var itemModel = data.getItemModel(idx);
  193. updateSingleMarkerEndLayout(data, idx, isFrom, seriesModel, api);
  194. data.setItemVisual(idx, {
  195. symbolSize: itemModel.get('symbolSize') || symbolSize[isFrom ? 0 : 1],
  196. symbol: itemModel.get('symbol', true) || symbolType[isFrom ? 0 : 1],
  197. color: itemModel.get('itemStyle.normal.color') || seriesData.getVisual('color')
  198. });
  199. }
  200. lineDraw.__keep = true;
  201. lineDraw.group.silent = mlModel.get('silent') || seriesModel.get('silent');
  202. }
  203. });
  204. /**
  205. * @inner
  206. * @param {module:echarts/coord/*} coordSys
  207. * @param {module:echarts/model/Series} seriesModel
  208. * @param {module:echarts/model/Model} mpModel
  209. */
  210. function createList(coordSys, seriesModel, mlModel) {
  211. var coordDimsInfos;
  212. if (coordSys) {
  213. coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) {
  214. var info = seriesModel.getData().getDimensionInfo(seriesModel.coordDimToDataDim(coordDim)[0]) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys
  215. info.name = coordDim;
  216. return info;
  217. });
  218. } else {
  219. coordDimsInfos = [{
  220. name: 'value',
  221. type: 'float'
  222. }];
  223. }
  224. var fromData = new List(coordDimsInfos, mlModel);
  225. var toData = new List(coordDimsInfos, mlModel); // No dimensions
  226. var lineData = new List([], mlModel);
  227. var optData = zrUtil.map(mlModel.get('data'), zrUtil.curry(markLineTransform, seriesModel, coordSys, mlModel));
  228. if (coordSys) {
  229. optData = zrUtil.filter(optData, zrUtil.curry(markLineFilter, coordSys));
  230. }
  231. var dimValueGetter = coordSys ? markerHelper.dimValueGetter : function (item) {
  232. return item.value;
  233. };
  234. fromData.initData(zrUtil.map(optData, function (item) {
  235. return item[0];
  236. }), null, dimValueGetter);
  237. toData.initData(zrUtil.map(optData, function (item) {
  238. return item[1];
  239. }), null, dimValueGetter);
  240. lineData.initData(zrUtil.map(optData, function (item) {
  241. return item[2];
  242. }));
  243. lineData.hasItemOption = true;
  244. return {
  245. from: fromData,
  246. to: toData,
  247. line: lineData
  248. };
  249. }
  250. module.exports = _default;