MarkLineView.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. import { __extends } from "tslib";
  41. import SeriesData from '../../data/SeriesData.js';
  42. import * as numberUtil from '../../util/number.js';
  43. import * as markerHelper from './markerHelper.js';
  44. import LineDraw from '../../chart/helper/LineDraw.js';
  45. import MarkerView from './MarkerView.js';
  46. import { getStackedDimension } from '../../data/helper/dataStackHelper.js';
  47. import { isCoordinateSystemType } from '../../coord/CoordinateSystem.js';
  48. import { getECData } from '../../util/innerStore.js';
  49. import MarkerModel from './MarkerModel.js';
  50. import { isArray, retrieve, retrieve2, clone, extend, logError, merge, map, curry, filter, isNumber } from 'zrender/lib/core/util.js';
  51. import { makeInner } from '../../util/model.js';
  52. import { getVisualFromData } from '../../visual/helper.js';
  53. var inner = makeInner();
  54. var markLineTransform = function (seriesModel, coordSys, mlModel, item) {
  55. var data = seriesModel.getData();
  56. var itemArray;
  57. if (!isArray(item)) {
  58. // Special type markLine like 'min', 'max', 'average', 'median'
  59. var mlType = item.type;
  60. if (mlType === 'min' || mlType === 'max' || mlType === 'average' || mlType === 'median'
  61. // In case
  62. // data: [{
  63. // yAxis: 10
  64. // }]
  65. || item.xAxis != null || item.yAxis != null) {
  66. var valueAxis = void 0;
  67. var value = void 0;
  68. if (item.yAxis != null || item.xAxis != null) {
  69. valueAxis = coordSys.getAxis(item.yAxis != null ? 'y' : 'x');
  70. value = retrieve(item.yAxis, item.xAxis);
  71. } else {
  72. var axisInfo = markerHelper.getAxisInfo(item, data, coordSys, seriesModel);
  73. valueAxis = axisInfo.valueAxis;
  74. var valueDataDim = getStackedDimension(data, axisInfo.valueDataDim);
  75. value = markerHelper.numCalculate(data, valueDataDim, mlType);
  76. }
  77. var valueIndex = valueAxis.dim === 'x' ? 0 : 1;
  78. var baseIndex = 1 - valueIndex;
  79. // Normized to 2d data with start and end point
  80. var mlFrom = clone(item);
  81. var mlTo = {
  82. coord: []
  83. };
  84. mlFrom.type = null;
  85. mlFrom.coord = [];
  86. mlFrom.coord[baseIndex] = -Infinity;
  87. mlTo.coord[baseIndex] = Infinity;
  88. var precision = mlModel.get('precision');
  89. if (precision >= 0 && isNumber(value)) {
  90. value = +value.toFixed(Math.min(precision, 20));
  91. }
  92. mlFrom.coord[valueIndex] = mlTo.coord[valueIndex] = value;
  93. itemArray = [mlFrom, mlTo, {
  94. type: mlType,
  95. valueIndex: item.valueIndex,
  96. // Force to use the value of calculated value.
  97. value: value
  98. }];
  99. } else {
  100. // Invalid data
  101. if (process.env.NODE_ENV !== 'production') {
  102. logError('Invalid markLine data.');
  103. }
  104. itemArray = [];
  105. }
  106. } else {
  107. itemArray = item;
  108. }
  109. var normalizedItem = [markerHelper.dataTransform(seriesModel, itemArray[0]), markerHelper.dataTransform(seriesModel, itemArray[1]), extend({}, itemArray[2])];
  110. // Avoid line data type is extended by from(to) data type
  111. normalizedItem[2].type = normalizedItem[2].type || null;
  112. // Merge from option and to option into line option
  113. merge(normalizedItem[2], normalizedItem[0]);
  114. merge(normalizedItem[2], normalizedItem[1]);
  115. return normalizedItem;
  116. };
  117. function isInfinity(val) {
  118. return !isNaN(val) && !isFinite(val);
  119. }
  120. // If a markLine has one dim
  121. function ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) {
  122. var otherDimIndex = 1 - dimIndex;
  123. var dimName = coordSys.dimensions[dimIndex];
  124. return isInfinity(fromCoord[otherDimIndex]) && isInfinity(toCoord[otherDimIndex]) && fromCoord[dimIndex] === toCoord[dimIndex] && coordSys.getAxis(dimName).containData(fromCoord[dimIndex]);
  125. }
  126. function markLineFilter(coordSys, item) {
  127. if (coordSys.type === 'cartesian2d') {
  128. var fromCoord = item[0].coord;
  129. var toCoord = item[1].coord;
  130. // In case
  131. // {
  132. // markLine: {
  133. // data: [{ yAxis: 2 }]
  134. // }
  135. // }
  136. if (fromCoord && toCoord && (ifMarkLineHasOnlyDim(1, fromCoord, toCoord, coordSys) || ifMarkLineHasOnlyDim(0, fromCoord, toCoord, coordSys))) {
  137. return true;
  138. }
  139. }
  140. return markerHelper.dataFilter(coordSys, item[0]) && markerHelper.dataFilter(coordSys, item[1]);
  141. }
  142. function updateSingleMarkerEndLayout(data, idx, isFrom, seriesModel, api) {
  143. var coordSys = seriesModel.coordinateSystem;
  144. var itemModel = data.getItemModel(idx);
  145. var point;
  146. var xPx = numberUtil.parsePercent(itemModel.get('x'), api.getWidth());
  147. var yPx = numberUtil.parsePercent(itemModel.get('y'), api.getHeight());
  148. if (!isNaN(xPx) && !isNaN(yPx)) {
  149. point = [xPx, yPx];
  150. } else {
  151. // Chart like bar may have there own marker positioning logic
  152. if (seriesModel.getMarkerPosition) {
  153. // Use the getMarkerPosition
  154. point = seriesModel.getMarkerPosition(data.getValues(data.dimensions, idx));
  155. } else {
  156. var dims = coordSys.dimensions;
  157. var x = data.get(dims[0], idx);
  158. var y = data.get(dims[1], idx);
  159. point = coordSys.dataToPoint([x, y]);
  160. }
  161. // Expand line to the edge of grid if value on one axis is Inifnity
  162. // In case
  163. // markLine: {
  164. // data: [{
  165. // yAxis: 2
  166. // // or
  167. // type: 'average'
  168. // }]
  169. // }
  170. if (isCoordinateSystemType(coordSys, 'cartesian2d')) {
  171. // TODO: TYPE ts@4.1 may still infer it as Axis instead of Axis2D. Not sure if it's a bug
  172. var xAxis = coordSys.getAxis('x');
  173. var yAxis = coordSys.getAxis('y');
  174. var dims = coordSys.dimensions;
  175. if (isInfinity(data.get(dims[0], idx))) {
  176. point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[isFrom ? 0 : 1]);
  177. } else if (isInfinity(data.get(dims[1], idx))) {
  178. point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[isFrom ? 0 : 1]);
  179. }
  180. }
  181. // Use x, y if has any
  182. if (!isNaN(xPx)) {
  183. point[0] = xPx;
  184. }
  185. if (!isNaN(yPx)) {
  186. point[1] = yPx;
  187. }
  188. }
  189. data.setItemLayout(idx, point);
  190. }
  191. var MarkLineView = /** @class */function (_super) {
  192. __extends(MarkLineView, _super);
  193. function MarkLineView() {
  194. var _this = _super !== null && _super.apply(this, arguments) || this;
  195. _this.type = MarkLineView.type;
  196. return _this;
  197. }
  198. MarkLineView.prototype.updateTransform = function (markLineModel, ecModel, api) {
  199. ecModel.eachSeries(function (seriesModel) {
  200. var mlModel = MarkerModel.getMarkerModelFromSeries(seriesModel, 'markLine');
  201. if (mlModel) {
  202. var mlData_1 = mlModel.getData();
  203. var fromData_1 = inner(mlModel).from;
  204. var toData_1 = inner(mlModel).to;
  205. // Update visual and layout of from symbol and to symbol
  206. fromData_1.each(function (idx) {
  207. updateSingleMarkerEndLayout(fromData_1, idx, true, seriesModel, api);
  208. updateSingleMarkerEndLayout(toData_1, idx, false, seriesModel, api);
  209. });
  210. // Update layout of line
  211. mlData_1.each(function (idx) {
  212. mlData_1.setItemLayout(idx, [fromData_1.getItemLayout(idx), toData_1.getItemLayout(idx)]);
  213. });
  214. this.markerGroupMap.get(seriesModel.id).updateLayout();
  215. }
  216. }, this);
  217. };
  218. MarkLineView.prototype.renderSeries = function (seriesModel, mlModel, ecModel, api) {
  219. var coordSys = seriesModel.coordinateSystem;
  220. var seriesId = seriesModel.id;
  221. var seriesData = seriesModel.getData();
  222. var lineDrawMap = this.markerGroupMap;
  223. var lineDraw = lineDrawMap.get(seriesId) || lineDrawMap.set(seriesId, new LineDraw());
  224. this.group.add(lineDraw.group);
  225. var mlData = createList(coordSys, seriesModel, mlModel);
  226. var fromData = mlData.from;
  227. var toData = mlData.to;
  228. var lineData = mlData.line;
  229. inner(mlModel).from = fromData;
  230. inner(mlModel).to = toData;
  231. // Line data for tooltip and formatter
  232. mlModel.setData(lineData);
  233. // TODO
  234. // Functionally, `symbolSize` & `symbolOffset` can also be 2D array now.
  235. // But the related logic and type definition are not finished yet.
  236. // Finish it if required
  237. var symbolType = mlModel.get('symbol');
  238. var symbolSize = mlModel.get('symbolSize');
  239. var symbolRotate = mlModel.get('symbolRotate');
  240. var symbolOffset = mlModel.get('symbolOffset');
  241. // TODO: support callback function like markPoint
  242. if (!isArray(symbolType)) {
  243. symbolType = [symbolType, symbolType];
  244. }
  245. if (!isArray(symbolSize)) {
  246. symbolSize = [symbolSize, symbolSize];
  247. }
  248. if (!isArray(symbolRotate)) {
  249. symbolRotate = [symbolRotate, symbolRotate];
  250. }
  251. if (!isArray(symbolOffset)) {
  252. symbolOffset = [symbolOffset, symbolOffset];
  253. }
  254. // Update visual and layout of from symbol and to symbol
  255. mlData.from.each(function (idx) {
  256. updateDataVisualAndLayout(fromData, idx, true);
  257. updateDataVisualAndLayout(toData, idx, false);
  258. });
  259. // Update visual and layout of line
  260. lineData.each(function (idx) {
  261. var lineStyle = lineData.getItemModel(idx).getModel('lineStyle').getLineStyle();
  262. // lineData.setItemVisual(idx, {
  263. // color: lineColor || fromData.getItemVisual(idx, 'color')
  264. // });
  265. lineData.setItemLayout(idx, [fromData.getItemLayout(idx), toData.getItemLayout(idx)]);
  266. if (lineStyle.stroke == null) {
  267. lineStyle.stroke = fromData.getItemVisual(idx, 'style').fill;
  268. }
  269. lineData.setItemVisual(idx, {
  270. fromSymbolKeepAspect: fromData.getItemVisual(idx, 'symbolKeepAspect'),
  271. fromSymbolOffset: fromData.getItemVisual(idx, 'symbolOffset'),
  272. fromSymbolRotate: fromData.getItemVisual(idx, 'symbolRotate'),
  273. fromSymbolSize: fromData.getItemVisual(idx, 'symbolSize'),
  274. fromSymbol: fromData.getItemVisual(idx, 'symbol'),
  275. toSymbolKeepAspect: toData.getItemVisual(idx, 'symbolKeepAspect'),
  276. toSymbolOffset: toData.getItemVisual(idx, 'symbolOffset'),
  277. toSymbolRotate: toData.getItemVisual(idx, 'symbolRotate'),
  278. toSymbolSize: toData.getItemVisual(idx, 'symbolSize'),
  279. toSymbol: toData.getItemVisual(idx, 'symbol'),
  280. style: lineStyle
  281. });
  282. });
  283. lineDraw.updateData(lineData);
  284. // Set host model for tooltip
  285. // FIXME
  286. mlData.line.eachItemGraphicEl(function (el) {
  287. getECData(el).dataModel = mlModel;
  288. el.traverse(function (child) {
  289. getECData(child).dataModel = mlModel;
  290. });
  291. });
  292. function updateDataVisualAndLayout(data, idx, isFrom) {
  293. var itemModel = data.getItemModel(idx);
  294. updateSingleMarkerEndLayout(data, idx, isFrom, seriesModel, api);
  295. var style = itemModel.getModel('itemStyle').getItemStyle();
  296. if (style.fill == null) {
  297. style.fill = getVisualFromData(seriesData, 'color');
  298. }
  299. data.setItemVisual(idx, {
  300. symbolKeepAspect: itemModel.get('symbolKeepAspect'),
  301. // `0` should be considered as a valid value, so use `retrieve2` instead of `||`
  302. symbolOffset: retrieve2(itemModel.get('symbolOffset', true), symbolOffset[isFrom ? 0 : 1]),
  303. symbolRotate: retrieve2(itemModel.get('symbolRotate', true), symbolRotate[isFrom ? 0 : 1]),
  304. // TODO: when 2d array is supported, it should ignore parent
  305. symbolSize: retrieve2(itemModel.get('symbolSize'), symbolSize[isFrom ? 0 : 1]),
  306. symbol: retrieve2(itemModel.get('symbol', true), symbolType[isFrom ? 0 : 1]),
  307. style: style
  308. });
  309. }
  310. this.markKeep(lineDraw);
  311. lineDraw.group.silent = mlModel.get('silent') || seriesModel.get('silent');
  312. };
  313. MarkLineView.type = 'markLine';
  314. return MarkLineView;
  315. }(MarkerView);
  316. function createList(coordSys, seriesModel, mlModel) {
  317. var coordDimsInfos;
  318. if (coordSys) {
  319. coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {
  320. var info = seriesModel.getData().getDimensionInfo(seriesModel.getData().mapDimension(coordDim)) || {};
  321. // In map series data don't have lng and lat dimension. Fallback to same with coordSys
  322. return extend(extend({}, info), {
  323. name: coordDim,
  324. // DON'T use ordinalMeta to parse and collect ordinal.
  325. ordinalMeta: null
  326. });
  327. });
  328. } else {
  329. coordDimsInfos = [{
  330. name: 'value',
  331. type: 'float'
  332. }];
  333. }
  334. var fromData = new SeriesData(coordDimsInfos, mlModel);
  335. var toData = new SeriesData(coordDimsInfos, mlModel);
  336. // No dimensions
  337. var lineData = new SeriesData([], mlModel);
  338. var optData = map(mlModel.get('data'), curry(markLineTransform, seriesModel, coordSys, mlModel));
  339. if (coordSys) {
  340. optData = filter(optData, curry(markLineFilter, coordSys));
  341. }
  342. var dimValueGetter = markerHelper.createMarkerDimValueGetter(!!coordSys, coordDimsInfos);
  343. fromData.initData(map(optData, function (item) {
  344. return item[0];
  345. }), null, dimValueGetter);
  346. toData.initData(map(optData, function (item) {
  347. return item[1];
  348. }), null, dimValueGetter);
  349. lineData.initData(map(optData, function (item) {
  350. return item[2];
  351. }));
  352. lineData.hasItemOption = true;
  353. return {
  354. from: fromData,
  355. to: toData,
  356. line: lineData
  357. };
  358. }
  359. export default MarkLineView;