LineView.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  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 _config = require("../../config");
  20. var __DEV__ = _config.__DEV__;
  21. var zrUtil = require("zrender/lib/core/util");
  22. var _bbox = require("zrender/lib/core/bbox");
  23. var fromPoints = _bbox.fromPoints;
  24. var SymbolDraw = require("../helper/SymbolDraw");
  25. var SymbolClz = require("../helper/Symbol");
  26. var lineAnimationDiff = require("./lineAnimationDiff");
  27. var graphic = require("../../util/graphic");
  28. var modelUtil = require("../../util/model");
  29. var _poly = require("./poly");
  30. var Polyline = _poly.Polyline;
  31. var Polygon = _poly.Polygon;
  32. var ChartView = require("../../view/Chart");
  33. var _helper = require("./helper");
  34. var prepareDataCoordInfo = _helper.prepareDataCoordInfo;
  35. var getStackedOnPoint = _helper.getStackedOnPoint;
  36. var _createClipPathFromCoordSys = require("../helper/createClipPathFromCoordSys");
  37. var createGridClipPath = _createClipPathFromCoordSys.createGridClipPath;
  38. var createPolarClipPath = _createClipPathFromCoordSys.createPolarClipPath;
  39. /*
  40. * Licensed to the Apache Software Foundation (ASF) under one
  41. * or more contributor license agreements. See the NOTICE file
  42. * distributed with this work for additional information
  43. * regarding copyright ownership. The ASF licenses this file
  44. * to you under the Apache License, Version 2.0 (the
  45. * "License"); you may not use this file except in compliance
  46. * with the License. You may obtain a copy of the License at
  47. *
  48. * http://www.apache.org/licenses/LICENSE-2.0
  49. *
  50. * Unless required by applicable law or agreed to in writing,
  51. * software distributed under the License is distributed on an
  52. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  53. * KIND, either express or implied. See the License for the
  54. * specific language governing permissions and limitations
  55. * under the License.
  56. */
  57. // FIXME step not support polar
  58. function isPointsSame(points1, points2) {
  59. if (points1.length !== points2.length) {
  60. return;
  61. }
  62. for (var i = 0; i < points1.length; i++) {
  63. var p1 = points1[i];
  64. var p2 = points2[i];
  65. if (p1[0] !== p2[0] || p1[1] !== p2[1]) {
  66. return;
  67. }
  68. }
  69. return true;
  70. }
  71. function getBoundingDiff(points1, points2) {
  72. var min1 = [];
  73. var max1 = [];
  74. var min2 = [];
  75. var max2 = [];
  76. fromPoints(points1, min1, max1);
  77. fromPoints(points2, min2, max2); // Get a max value from each corner of two boundings.
  78. return Math.max(Math.abs(min1[0] - min2[0]), Math.abs(min1[1] - min2[1]), Math.abs(max1[0] - max2[0]), Math.abs(max1[1] - max2[1]));
  79. }
  80. function getSmooth(smooth) {
  81. return typeof smooth === 'number' ? smooth : smooth ? 0.5 : 0;
  82. }
  83. /**
  84. * @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys
  85. * @param {module:echarts/data/List} data
  86. * @param {Object} dataCoordInfo
  87. * @param {Array.<Array.<number>>} points
  88. */
  89. function getStackedOnPoints(coordSys, data, dataCoordInfo) {
  90. if (!dataCoordInfo.valueDim) {
  91. return [];
  92. }
  93. var points = [];
  94. for (var idx = 0, len = data.count(); idx < len; idx++) {
  95. points.push(getStackedOnPoint(dataCoordInfo, coordSys, data, idx));
  96. }
  97. return points;
  98. }
  99. function turnPointsIntoStep(points, coordSys, stepTurnAt) {
  100. var baseAxis = coordSys.getBaseAxis();
  101. var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1;
  102. var stepPoints = [];
  103. for (var i = 0; i < points.length - 1; i++) {
  104. var nextPt = points[i + 1];
  105. var pt = points[i];
  106. stepPoints.push(pt);
  107. var stepPt = [];
  108. switch (stepTurnAt) {
  109. case 'end':
  110. stepPt[baseIndex] = nextPt[baseIndex];
  111. stepPt[1 - baseIndex] = pt[1 - baseIndex]; // default is start
  112. stepPoints.push(stepPt);
  113. break;
  114. case 'middle':
  115. // default is start
  116. var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2;
  117. var stepPt2 = [];
  118. stepPt[baseIndex] = stepPt2[baseIndex] = middle;
  119. stepPt[1 - baseIndex] = pt[1 - baseIndex];
  120. stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];
  121. stepPoints.push(stepPt);
  122. stepPoints.push(stepPt2);
  123. break;
  124. default:
  125. stepPt[baseIndex] = pt[baseIndex];
  126. stepPt[1 - baseIndex] = nextPt[1 - baseIndex]; // default is start
  127. stepPoints.push(stepPt);
  128. }
  129. } // Last points
  130. points[i] && stepPoints.push(points[i]);
  131. return stepPoints;
  132. }
  133. function getVisualGradient(data, coordSys) {
  134. var visualMetaList = data.getVisual('visualMeta');
  135. if (!visualMetaList || !visualMetaList.length || !data.count()) {
  136. // When data.count() is 0, gradient range can not be calculated.
  137. return;
  138. }
  139. if (coordSys.type !== 'cartesian2d') {
  140. return;
  141. }
  142. var coordDim;
  143. var visualMeta;
  144. for (var i = visualMetaList.length - 1; i >= 0; i--) {
  145. var dimIndex = visualMetaList[i].dimension;
  146. var dimName = data.dimensions[dimIndex];
  147. var dimInfo = data.getDimensionInfo(dimName);
  148. coordDim = dimInfo && dimInfo.coordDim; // Can only be x or y
  149. if (coordDim === 'x' || coordDim === 'y') {
  150. visualMeta = visualMetaList[i];
  151. break;
  152. }
  153. }
  154. if (!visualMeta) {
  155. return;
  156. } // If the area to be rendered is bigger than area defined by LinearGradient,
  157. // the canvas spec prescribes that the color of the first stop and the last
  158. // stop should be used. But if two stops are added at offset 0, in effect
  159. // browsers use the color of the second stop to render area outside
  160. // LinearGradient. So we can only infinitesimally extend area defined in
  161. // LinearGradient to render `outerColors`.
  162. var axis = coordSys.getAxis(coordDim); // dataToCoor mapping may not be linear, but must be monotonic.
  163. var colorStops = zrUtil.map(visualMeta.stops, function (stop) {
  164. return {
  165. coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),
  166. color: stop.color
  167. };
  168. });
  169. var stopLen = colorStops.length;
  170. var outerColors = visualMeta.outerColors.slice();
  171. if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {
  172. colorStops.reverse();
  173. outerColors.reverse();
  174. }
  175. var tinyExtent = 10; // Arbitrary value: 10px
  176. var minCoord = colorStops[0].coord - tinyExtent;
  177. var maxCoord = colorStops[stopLen - 1].coord + tinyExtent;
  178. var coordSpan = maxCoord - minCoord;
  179. if (coordSpan < 1e-3) {
  180. return 'transparent';
  181. }
  182. zrUtil.each(colorStops, function (stop) {
  183. stop.offset = (stop.coord - minCoord) / coordSpan;
  184. });
  185. colorStops.push({
  186. offset: stopLen ? colorStops[stopLen - 1].offset : 0.5,
  187. color: outerColors[1] || 'transparent'
  188. });
  189. colorStops.unshift({
  190. // notice colorStops.length have been changed.
  191. offset: stopLen ? colorStops[0].offset : 0.5,
  192. color: outerColors[0] || 'transparent'
  193. }); // zrUtil.each(colorStops, function (colorStop) {
  194. // // Make sure each offset has rounded px to avoid not sharp edge
  195. // colorStop.offset = (Math.round(colorStop.offset * (end - start) + start) - start) / (end - start);
  196. // });
  197. var gradient = new graphic.LinearGradient(0, 0, 0, 0, colorStops, true);
  198. gradient[coordDim] = minCoord;
  199. gradient[coordDim + '2'] = maxCoord;
  200. return gradient;
  201. }
  202. function getIsIgnoreFunc(seriesModel, data, coordSys) {
  203. var showAllSymbol = seriesModel.get('showAllSymbol');
  204. var isAuto = showAllSymbol === 'auto';
  205. if (showAllSymbol && !isAuto) {
  206. return;
  207. }
  208. var categoryAxis = coordSys.getAxesByScale('ordinal')[0];
  209. if (!categoryAxis) {
  210. return;
  211. } // Note that category label interval strategy might bring some weird effect
  212. // in some scenario: users may wonder why some of the symbols are not
  213. // displayed. So we show all symbols as possible as we can.
  214. if (isAuto // Simplify the logic, do not determine label overlap here.
  215. && canShowAllSymbolForCategory(categoryAxis, data)) {
  216. return;
  217. } // Otherwise follow the label interval strategy on category axis.
  218. var categoryDataDim = data.mapDimension(categoryAxis.dim);
  219. var labelMap = {};
  220. zrUtil.each(categoryAxis.getViewLabels(), function (labelItem) {
  221. labelMap[labelItem.tickValue] = 1;
  222. });
  223. return function (dataIndex) {
  224. return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex));
  225. };
  226. }
  227. function canShowAllSymbolForCategory(categoryAxis, data) {
  228. // In mose cases, line is monotonous on category axis, and the label size
  229. // is close with each other. So we check the symbol size and some of the
  230. // label size alone with the category axis to estimate whether all symbol
  231. // can be shown without overlap.
  232. var axisExtent = categoryAxis.getExtent();
  233. var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count();
  234. isNaN(availSize) && (availSize = 0); // 0/0 is NaN.
  235. // Sampling some points, max 5.
  236. var dataLen = data.count();
  237. var step = Math.max(1, Math.round(dataLen / 5));
  238. for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) {
  239. if (SymbolClz.getSymbolSize(data, dataIndex // Only for cartesian, where `isHorizontal` exists.
  240. )[categoryAxis.isHorizontal() ? 1 : 0] // Empirical number
  241. * 1.5 > availSize) {
  242. return false;
  243. }
  244. }
  245. return true;
  246. }
  247. function createLineClipPath(coordSys, hasAnimation, seriesModel) {
  248. if (coordSys.type === 'cartesian2d') {
  249. var isHorizontal = coordSys.getBaseAxis().isHorizontal();
  250. var clipPath = createGridClipPath(coordSys, hasAnimation, seriesModel); // Expand clip shape to avoid clipping when line value exceeds axis
  251. if (!seriesModel.get('clip', true)) {
  252. var rectShape = clipPath.shape;
  253. var expandSize = Math.max(rectShape.width, rectShape.height);
  254. if (isHorizontal) {
  255. rectShape.y -= expandSize;
  256. rectShape.height += expandSize * 2;
  257. } else {
  258. rectShape.x -= expandSize;
  259. rectShape.width += expandSize * 2;
  260. }
  261. }
  262. return clipPath;
  263. } else {
  264. return createPolarClipPath(coordSys, hasAnimation, seriesModel);
  265. }
  266. }
  267. var _default = ChartView.extend({
  268. type: 'line',
  269. init: function () {
  270. var lineGroup = new graphic.Group();
  271. var symbolDraw = new SymbolDraw();
  272. this.group.add(symbolDraw.group);
  273. this._symbolDraw = symbolDraw;
  274. this._lineGroup = lineGroup;
  275. },
  276. render: function (seriesModel, ecModel, api) {
  277. var coordSys = seriesModel.coordinateSystem;
  278. var group = this.group;
  279. var data = seriesModel.getData();
  280. var lineStyleModel = seriesModel.getModel('lineStyle');
  281. var areaStyleModel = seriesModel.getModel('areaStyle');
  282. var points = data.mapArray(data.getItemLayout);
  283. var isCoordSysPolar = coordSys.type === 'polar';
  284. var prevCoordSys = this._coordSys;
  285. var symbolDraw = this._symbolDraw;
  286. var polyline = this._polyline;
  287. var polygon = this._polygon;
  288. var lineGroup = this._lineGroup;
  289. var hasAnimation = seriesModel.get('animation');
  290. var isAreaChart = !areaStyleModel.isEmpty();
  291. var valueOrigin = areaStyleModel.get('origin');
  292. var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin);
  293. var stackedOnPoints = getStackedOnPoints(coordSys, data, dataCoordInfo);
  294. var showSymbol = seriesModel.get('showSymbol');
  295. var isIgnoreFunc = showSymbol && !isCoordSysPolar && getIsIgnoreFunc(seriesModel, data, coordSys); // Remove temporary symbols
  296. var oldData = this._data;
  297. oldData && oldData.eachItemGraphicEl(function (el, idx) {
  298. if (el.__temp) {
  299. group.remove(el);
  300. oldData.setItemGraphicEl(idx, null);
  301. }
  302. }); // Remove previous created symbols if showSymbol changed to false
  303. if (!showSymbol) {
  304. symbolDraw.remove();
  305. }
  306. group.add(lineGroup); // FIXME step not support polar
  307. var step = !isCoordSysPolar && seriesModel.get('step');
  308. var clipShapeForSymbol;
  309. if (coordSys && coordSys.getArea && seriesModel.get('clip', true)) {
  310. clipShapeForSymbol = coordSys.getArea(); // Avoid float number rounding error for symbol on the edge of axis extent.
  311. // See #7913 and `test/dataZoom-clip.html`.
  312. if (clipShapeForSymbol.width != null) {
  313. clipShapeForSymbol.x -= 0.1;
  314. clipShapeForSymbol.y -= 0.1;
  315. clipShapeForSymbol.width += 0.2;
  316. clipShapeForSymbol.height += 0.2;
  317. } else if (clipShapeForSymbol.r0) {
  318. clipShapeForSymbol.r0 -= 0.5;
  319. clipShapeForSymbol.r1 += 0.5;
  320. }
  321. }
  322. this._clipShapeForSymbol = clipShapeForSymbol; // Initialization animation or coordinate system changed
  323. if (!(polyline && prevCoordSys.type === coordSys.type && step === this._step)) {
  324. showSymbol && symbolDraw.updateData(data, {
  325. isIgnore: isIgnoreFunc,
  326. clipShape: clipShapeForSymbol
  327. });
  328. if (step) {
  329. // TODO If stacked series is not step
  330. points = turnPointsIntoStep(points, coordSys, step);
  331. stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);
  332. }
  333. polyline = this._newPolyline(points, coordSys, hasAnimation);
  334. if (isAreaChart) {
  335. polygon = this._newPolygon(points, stackedOnPoints, coordSys, hasAnimation);
  336. }
  337. lineGroup.setClipPath(createLineClipPath(coordSys, true, seriesModel));
  338. } else {
  339. if (isAreaChart && !polygon) {
  340. // If areaStyle is added
  341. polygon = this._newPolygon(points, stackedOnPoints, coordSys, hasAnimation);
  342. } else if (polygon && !isAreaChart) {
  343. // If areaStyle is removed
  344. lineGroup.remove(polygon);
  345. polygon = this._polygon = null;
  346. } // Update clipPath
  347. lineGroup.setClipPath(createLineClipPath(coordSys, false, seriesModel)); // Always update, or it is wrong in the case turning on legend
  348. // because points are not changed
  349. showSymbol && symbolDraw.updateData(data, {
  350. isIgnore: isIgnoreFunc,
  351. clipShape: clipShapeForSymbol
  352. }); // Stop symbol animation and sync with line points
  353. // FIXME performance?
  354. data.eachItemGraphicEl(function (el) {
  355. el.stopAnimation(true);
  356. }); // In the case data zoom triggerred refreshing frequently
  357. // Data may not change if line has a category axis. So it should animate nothing
  358. if (!isPointsSame(this._stackedOnPoints, stackedOnPoints) || !isPointsSame(this._points, points)) {
  359. if (hasAnimation) {
  360. this._updateAnimation(data, stackedOnPoints, coordSys, api, step, valueOrigin);
  361. } else {
  362. // Not do it in update with animation
  363. if (step) {
  364. // TODO If stacked series is not step
  365. points = turnPointsIntoStep(points, coordSys, step);
  366. stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);
  367. }
  368. polyline.setShape({
  369. points: points
  370. });
  371. polygon && polygon.setShape({
  372. points: points,
  373. stackedOnPoints: stackedOnPoints
  374. });
  375. }
  376. }
  377. }
  378. var visualColor = getVisualGradient(data, coordSys) || data.getVisual('color');
  379. polyline.useStyle(zrUtil.defaults( // Use color in lineStyle first
  380. lineStyleModel.getLineStyle(), {
  381. fill: 'none',
  382. stroke: visualColor,
  383. lineJoin: 'bevel'
  384. }));
  385. var smooth = seriesModel.get('smooth');
  386. smooth = getSmooth(seriesModel.get('smooth'));
  387. polyline.setShape({
  388. smooth: smooth,
  389. smoothMonotone: seriesModel.get('smoothMonotone'),
  390. connectNulls: seriesModel.get('connectNulls')
  391. });
  392. if (polygon) {
  393. var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');
  394. var stackedOnSmooth = 0;
  395. polygon.useStyle(zrUtil.defaults(areaStyleModel.getAreaStyle(), {
  396. fill: visualColor,
  397. opacity: 0.7,
  398. lineJoin: 'bevel'
  399. }));
  400. if (stackedOnSeries) {
  401. stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));
  402. }
  403. polygon.setShape({
  404. smooth: smooth,
  405. stackedOnSmooth: stackedOnSmooth,
  406. smoothMonotone: seriesModel.get('smoothMonotone'),
  407. connectNulls: seriesModel.get('connectNulls')
  408. });
  409. }
  410. this._data = data; // Save the coordinate system for transition animation when data changed
  411. this._coordSys = coordSys;
  412. this._stackedOnPoints = stackedOnPoints;
  413. this._points = points;
  414. this._step = step;
  415. this._valueOrigin = valueOrigin;
  416. },
  417. dispose: function () {},
  418. highlight: function (seriesModel, ecModel, api, payload) {
  419. var data = seriesModel.getData();
  420. var dataIndex = modelUtil.queryDataIndex(data, payload);
  421. if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) {
  422. var symbol = data.getItemGraphicEl(dataIndex);
  423. if (!symbol) {
  424. // Create a temporary symbol if it is not exists
  425. var pt = data.getItemLayout(dataIndex);
  426. if (!pt) {
  427. // Null data
  428. return;
  429. } // fix #11360: should't draw symbol outside clipShapeForSymbol
  430. if (this._clipShapeForSymbol && !this._clipShapeForSymbol.contain(pt[0], pt[1])) {
  431. return;
  432. }
  433. symbol = new SymbolClz(data, dataIndex);
  434. symbol.position = pt;
  435. symbol.setZ(seriesModel.get('zlevel'), seriesModel.get('z'));
  436. symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]);
  437. symbol.__temp = true;
  438. data.setItemGraphicEl(dataIndex, symbol); // Stop scale animation
  439. symbol.stopSymbolAnimation(true);
  440. this.group.add(symbol);
  441. }
  442. symbol.highlight();
  443. } else {
  444. // Highlight whole series
  445. ChartView.prototype.highlight.call(this, seriesModel, ecModel, api, payload);
  446. }
  447. },
  448. downplay: function (seriesModel, ecModel, api, payload) {
  449. var data = seriesModel.getData();
  450. var dataIndex = modelUtil.queryDataIndex(data, payload);
  451. if (dataIndex != null && dataIndex >= 0) {
  452. var symbol = data.getItemGraphicEl(dataIndex);
  453. if (symbol) {
  454. if (symbol.__temp) {
  455. data.setItemGraphicEl(dataIndex, null);
  456. this.group.remove(symbol);
  457. } else {
  458. symbol.downplay();
  459. }
  460. }
  461. } else {
  462. // FIXME
  463. // can not downplay completely.
  464. // Downplay whole series
  465. ChartView.prototype.downplay.call(this, seriesModel, ecModel, api, payload);
  466. }
  467. },
  468. /**
  469. * @param {module:zrender/container/Group} group
  470. * @param {Array.<Array.<number>>} points
  471. * @private
  472. */
  473. _newPolyline: function (points) {
  474. var polyline = this._polyline; // Remove previous created polyline
  475. if (polyline) {
  476. this._lineGroup.remove(polyline);
  477. }
  478. polyline = new Polyline({
  479. shape: {
  480. points: points
  481. },
  482. silent: true,
  483. z2: 10
  484. });
  485. this._lineGroup.add(polyline);
  486. this._polyline = polyline;
  487. return polyline;
  488. },
  489. /**
  490. * @param {module:zrender/container/Group} group
  491. * @param {Array.<Array.<number>>} stackedOnPoints
  492. * @param {Array.<Array.<number>>} points
  493. * @private
  494. */
  495. _newPolygon: function (points, stackedOnPoints) {
  496. var polygon = this._polygon; // Remove previous created polygon
  497. if (polygon) {
  498. this._lineGroup.remove(polygon);
  499. }
  500. polygon = new Polygon({
  501. shape: {
  502. points: points,
  503. stackedOnPoints: stackedOnPoints
  504. },
  505. silent: true
  506. });
  507. this._lineGroup.add(polygon);
  508. this._polygon = polygon;
  509. return polygon;
  510. },
  511. /**
  512. * @private
  513. */
  514. // FIXME Two value axis
  515. _updateAnimation: function (data, stackedOnPoints, coordSys, api, step, valueOrigin) {
  516. var polyline = this._polyline;
  517. var polygon = this._polygon;
  518. var seriesModel = data.hostModel;
  519. var diff = lineAnimationDiff(this._data, data, this._stackedOnPoints, stackedOnPoints, this._coordSys, coordSys, this._valueOrigin, valueOrigin);
  520. var current = diff.current;
  521. var stackedOnCurrent = diff.stackedOnCurrent;
  522. var next = diff.next;
  523. var stackedOnNext = diff.stackedOnNext;
  524. if (step) {
  525. // TODO If stacked series is not step
  526. current = turnPointsIntoStep(diff.current, coordSys, step);
  527. stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step);
  528. next = turnPointsIntoStep(diff.next, coordSys, step);
  529. stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step);
  530. } // Don't apply animation if diff is large.
  531. // For better result and avoid memory explosion problems like
  532. // https://github.com/apache/incubator-echarts/issues/12229
  533. if (getBoundingDiff(current, next) > 3000 || polygon && getBoundingDiff(stackedOnCurrent, stackedOnNext) > 3000) {
  534. polyline.setShape({
  535. points: next
  536. });
  537. if (polygon) {
  538. polygon.setShape({
  539. points: next,
  540. stackedOnPoints: stackedOnNext
  541. });
  542. }
  543. return;
  544. } // `diff.current` is subset of `current` (which should be ensured by
  545. // turnPointsIntoStep), so points in `__points` can be updated when
  546. // points in `current` are update during animation.
  547. polyline.shape.__points = diff.current;
  548. polyline.shape.points = current;
  549. graphic.updateProps(polyline, {
  550. shape: {
  551. points: next
  552. }
  553. }, seriesModel);
  554. if (polygon) {
  555. polygon.setShape({
  556. points: current,
  557. stackedOnPoints: stackedOnCurrent
  558. });
  559. graphic.updateProps(polygon, {
  560. shape: {
  561. points: next,
  562. stackedOnPoints: stackedOnNext
  563. }
  564. }, seriesModel);
  565. }
  566. var updatedDataInfo = [];
  567. var diffStatus = diff.status;
  568. for (var i = 0; i < diffStatus.length; i++) {
  569. var cmd = diffStatus[i].cmd;
  570. if (cmd === '=') {
  571. var el = data.getItemGraphicEl(diffStatus[i].idx1);
  572. if (el) {
  573. updatedDataInfo.push({
  574. el: el,
  575. ptIdx: i // Index of points
  576. });
  577. }
  578. }
  579. }
  580. if (polyline.animators && polyline.animators.length) {
  581. polyline.animators[0].during(function () {
  582. for (var i = 0; i < updatedDataInfo.length; i++) {
  583. var el = updatedDataInfo[i].el;
  584. el.attr('position', polyline.shape.__points[updatedDataInfo[i].ptIdx]);
  585. }
  586. });
  587. }
  588. },
  589. remove: function (ecModel) {
  590. var group = this.group;
  591. var oldData = this._data;
  592. this._lineGroup.removeAll();
  593. this._symbolDraw.remove(true); // Remove temporary created elements when highlighting
  594. oldData && oldData.eachItemGraphicEl(function (el, idx) {
  595. if (el.__temp) {
  596. group.remove(el);
  597. oldData.setItemGraphicEl(idx, null);
  598. }
  599. });
  600. this._polyline = this._polygon = this._coordSys = this._points = this._stackedOnPoints = this._data = null;
  601. }
  602. });
  603. module.exports = _default;