1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
- /**
- * AUTO-GENERATED FILE. DO NOT MODIFY.
- */
- /*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
- import { __extends } from "tslib"; // FIXME step not support polar
- import * as zrUtil from 'zrender/lib/core/util.js';
- import SymbolDraw from '../helper/SymbolDraw.js';
- import SymbolClz from '../helper/Symbol.js';
- import lineAnimationDiff from './lineAnimationDiff.js';
- import * as graphic from '../../util/graphic.js';
- import * as modelUtil from '../../util/model.js';
- import { ECPolyline, ECPolygon } from './poly.js';
- import ChartView from '../../view/Chart.js';
- import { prepareDataCoordInfo, getStackedOnPoint } from './helper.js';
- import { createGridClipPath, createPolarClipPath } from '../helper/createClipPathFromCoordSys.js';
- import { isCoordinateSystemType } from '../../coord/CoordinateSystem.js';
- import { setStatesStylesFromModel, setStatesFlag, toggleHoverEmphasis, SPECIAL_STATES } from '../../util/states.js';
- import { setLabelStyle, getLabelStatesModels, labelInner } from '../../label/labelStyle.js';
- import { getDefaultLabel, getDefaultInterpolatedLabel } from '../helper/labelHelper.js';
- import { getECData } from '../../util/innerStore.js';
- import { createFloat32Array } from '../../util/vendor.js';
- import { convertToColorString } from '../../util/format.js';
- import { lerp } from 'zrender/lib/tool/color.js';
- function isPointsSame(points1, points2) {
- if (points1.length !== points2.length) {
- return;
- }
- for (var i = 0; i < points1.length; i++) {
- if (points1[i] !== points2[i]) {
- return;
- }
- }
- return true;
- }
- function bboxFromPoints(points) {
- var minX = Infinity;
- var minY = Infinity;
- var maxX = -Infinity;
- var maxY = -Infinity;
- for (var i = 0; i < points.length;) {
- var x = points[i++];
- var y = points[i++];
- if (!isNaN(x)) {
- minX = Math.min(x, minX);
- maxX = Math.max(x, maxX);
- }
- if (!isNaN(y)) {
- minY = Math.min(y, minY);
- maxY = Math.max(y, maxY);
- }
- }
- return [[minX, minY], [maxX, maxY]];
- }
- function getBoundingDiff(points1, points2) {
- var _a = bboxFromPoints(points1),
- min1 = _a[0],
- max1 = _a[1];
- var _b = bboxFromPoints(points2),
- min2 = _b[0],
- max2 = _b[1]; // Get a max value from each corner of two boundings.
- 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]));
- }
- function getSmooth(smooth) {
- return zrUtil.isNumber(smooth) ? smooth : smooth ? 0.5 : 0;
- }
- function getStackedOnPoints(coordSys, data, dataCoordInfo) {
- if (!dataCoordInfo.valueDim) {
- return [];
- }
- var len = data.count();
- var points = createFloat32Array(len * 2);
- for (var idx = 0; idx < len; idx++) {
- var pt = getStackedOnPoint(dataCoordInfo, coordSys, data, idx);
- points[idx * 2] = pt[0];
- points[idx * 2 + 1] = pt[1];
- }
- return points;
- }
- function turnPointsIntoStep(points, coordSys, stepTurnAt, connectNulls) {
- var baseAxis = coordSys.getBaseAxis();
- var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1;
- var stepPoints = [];
- var i = 0;
- var stepPt = [];
- var pt = [];
- var nextPt = [];
- var filteredPoints = [];
- if (connectNulls) {
- for (i = 0; i < points.length; i += 2) {
- if (!isNaN(points[i]) && !isNaN(points[i + 1])) {
- filteredPoints.push(points[i], points[i + 1]);
- }
- }
- points = filteredPoints;
- }
- for (i = 0; i < points.length - 2; i += 2) {
- nextPt[0] = points[i + 2];
- nextPt[1] = points[i + 3];
- pt[0] = points[i];
- pt[1] = points[i + 1];
- stepPoints.push(pt[0], pt[1]);
- switch (stepTurnAt) {
- case 'end':
- stepPt[baseIndex] = nextPt[baseIndex];
- stepPt[1 - baseIndex] = pt[1 - baseIndex];
- stepPoints.push(stepPt[0], stepPt[1]);
- break;
- case 'middle':
- var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2;
- var stepPt2 = [];
- stepPt[baseIndex] = stepPt2[baseIndex] = middle;
- stepPt[1 - baseIndex] = pt[1 - baseIndex];
- stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];
- stepPoints.push(stepPt[0], stepPt[1]);
- stepPoints.push(stepPt2[0], stepPt2[1]);
- break;
- default:
- // default is start
- stepPt[baseIndex] = pt[baseIndex];
- stepPt[1 - baseIndex] = nextPt[1 - baseIndex];
- stepPoints.push(stepPt[0], stepPt[1]);
- }
- } // Last points
- stepPoints.push(points[i++], points[i++]);
- return stepPoints;
- }
- /**
- * Clip color stops to edge. Avoid creating too large gradients.
- * Which may lead to blurry when GPU acceleration is enabled. See #15680
- *
- * The stops has been sorted from small to large.
- */
- function clipColorStops(colorStops, maxSize) {
- var newColorStops = [];
- var len = colorStops.length; // coord will always < 0 in prevOutOfRangeColorStop.
- var prevOutOfRangeColorStop;
- var prevInRangeColorStop;
- function lerpStop(stop0, stop1, clippedCoord) {
- var coord0 = stop0.coord;
- var p = (clippedCoord - coord0) / (stop1.coord - coord0);
- var color = lerp(p, [stop0.color, stop1.color]);
- return {
- coord: clippedCoord,
- color: color
- };
- }
- for (var i = 0; i < len; i++) {
- var stop_1 = colorStops[i];
- var coord = stop_1.coord;
- if (coord < 0) {
- prevOutOfRangeColorStop = stop_1;
- } else if (coord > maxSize) {
- if (prevInRangeColorStop) {
- newColorStops.push(lerpStop(prevInRangeColorStop, stop_1, maxSize));
- } else if (prevOutOfRangeColorStop) {
- // If there are two stops and coord range is between these two stops
- newColorStops.push(lerpStop(prevOutOfRangeColorStop, stop_1, 0), lerpStop(prevOutOfRangeColorStop, stop_1, maxSize));
- } // All following stop will be out of range. So just ignore them.
- break;
- } else {
- if (prevOutOfRangeColorStop) {
- newColorStops.push(lerpStop(prevOutOfRangeColorStop, stop_1, 0)); // Reset
- prevOutOfRangeColorStop = null;
- }
- newColorStops.push(stop_1);
- prevInRangeColorStop = stop_1;
- }
- }
- return newColorStops;
- }
- function getVisualGradient(data, coordSys, api) {
- var visualMetaList = data.getVisual('visualMeta');
- if (!visualMetaList || !visualMetaList.length || !data.count()) {
- // When data.count() is 0, gradient range can not be calculated.
- return;
- }
- if (coordSys.type !== 'cartesian2d') {
- if (process.env.NODE_ENV !== 'production') {
- console.warn('Visual map on line style is only supported on cartesian2d.');
- }
- return;
- }
- var coordDim;
- var visualMeta;
- for (var i = visualMetaList.length - 1; i >= 0; i--) {
- var dimInfo = data.getDimensionInfo(visualMetaList[i].dimension);
- coordDim = dimInfo && dimInfo.coordDim; // Can only be x or y
- if (coordDim === 'x' || coordDim === 'y') {
- visualMeta = visualMetaList[i];
- break;
- }
- }
- if (!visualMeta) {
- if (process.env.NODE_ENV !== 'production') {
- console.warn('Visual map on line style only support x or y dimension.');
- }
- return;
- } // If the area to be rendered is bigger than area defined by LinearGradient,
- // the canvas spec prescribes that the color of the first stop and the last
- // stop should be used. But if two stops are added at offset 0, in effect
- // browsers use the color of the second stop to render area outside
- // LinearGradient. So we can only infinitesimally extend area defined in
- // LinearGradient to render `outerColors`.
- var axis = coordSys.getAxis(coordDim); // dataToCoord mapping may not be linear, but must be monotonic.
- var colorStops = zrUtil.map(visualMeta.stops, function (stop) {
- // offset will be calculated later.
- return {
- coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),
- color: stop.color
- };
- });
- var stopLen = colorStops.length;
- var outerColors = visualMeta.outerColors.slice();
- if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {
- colorStops.reverse();
- outerColors.reverse();
- }
- var colorStopsInRange = clipColorStops(colorStops, coordDim === 'x' ? api.getWidth() : api.getHeight());
- var inRangeStopLen = colorStopsInRange.length;
- if (!inRangeStopLen && stopLen) {
- // All stops are out of range. All will be the same color.
- return colorStops[0].coord < 0 ? outerColors[1] ? outerColors[1] : colorStops[stopLen - 1].color : outerColors[0] ? outerColors[0] : colorStops[0].color;
- }
- var tinyExtent = 10; // Arbitrary value: 10px
- var minCoord = colorStopsInRange[0].coord - tinyExtent;
- var maxCoord = colorStopsInRange[inRangeStopLen - 1].coord + tinyExtent;
- var coordSpan = maxCoord - minCoord;
- if (coordSpan < 1e-3) {
- return 'transparent';
- }
- zrUtil.each(colorStopsInRange, function (stop) {
- stop.offset = (stop.coord - minCoord) / coordSpan;
- });
- colorStopsInRange.push({
- // NOTE: inRangeStopLen may still be 0 if stoplen is zero.
- offset: inRangeStopLen ? colorStopsInRange[inRangeStopLen - 1].offset : 0.5,
- color: outerColors[1] || 'transparent'
- });
- colorStopsInRange.unshift({
- offset: inRangeStopLen ? colorStopsInRange[0].offset : 0.5,
- color: outerColors[0] || 'transparent'
- });
- var gradient = new graphic.LinearGradient(0, 0, 0, 0, colorStopsInRange, true);
- gradient[coordDim] = minCoord;
- gradient[coordDim + '2'] = maxCoord;
- return gradient;
- }
- function getIsIgnoreFunc(seriesModel, data, coordSys) {
- var showAllSymbol = seriesModel.get('showAllSymbol');
- var isAuto = showAllSymbol === 'auto';
- if (showAllSymbol && !isAuto) {
- return;
- }
- var categoryAxis = coordSys.getAxesByScale('ordinal')[0];
- if (!categoryAxis) {
- return;
- } // Note that category label interval strategy might bring some weird effect
- // in some scenario: users may wonder why some of the symbols are not
- // displayed. So we show all symbols as possible as we can.
- if (isAuto // Simplify the logic, do not determine label overlap here.
- && canShowAllSymbolForCategory(categoryAxis, data)) {
- return;
- } // Otherwise follow the label interval strategy on category axis.
- var categoryDataDim = data.mapDimension(categoryAxis.dim);
- var labelMap = {};
- zrUtil.each(categoryAxis.getViewLabels(), function (labelItem) {
- var ordinalNumber = categoryAxis.scale.getRawOrdinalNumber(labelItem.tickValue);
- labelMap[ordinalNumber] = 1;
- });
- return function (dataIndex) {
- return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex));
- };
- }
- function canShowAllSymbolForCategory(categoryAxis, data) {
- // In most cases, line is monotonous on category axis, and the label size
- // is close with each other. So we check the symbol size and some of the
- // label size alone with the category axis to estimate whether all symbol
- // can be shown without overlap.
- var axisExtent = categoryAxis.getExtent();
- var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count();
- isNaN(availSize) && (availSize = 0); // 0/0 is NaN.
- // Sampling some points, max 5.
- var dataLen = data.count();
- var step = Math.max(1, Math.round(dataLen / 5));
- for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) {
- if (SymbolClz.getSymbolSize(data, dataIndex // Only for cartesian, where `isHorizontal` exists.
- )[categoryAxis.isHorizontal() ? 1 : 0] // Empirical number
- * 1.5 > availSize) {
- return false;
- }
- }
- return true;
- }
- function isPointNull(x, y) {
- return isNaN(x) || isNaN(y);
- }
- function getLastIndexNotNull(points) {
- var len = points.length / 2;
- for (; len > 0; len--) {
- if (!isPointNull(points[len * 2 - 2], points[len * 2 - 1])) {
- break;
- }
- }
- return len - 1;
- }
- function getPointAtIndex(points, idx) {
- return [points[idx * 2], points[idx * 2 + 1]];
- }
- function getIndexRange(points, xOrY, dim) {
- var len = points.length / 2;
- var dimIdx = dim === 'x' ? 0 : 1;
- var a;
- var b;
- var prevIndex = 0;
- var nextIndex = -1;
- for (var i = 0; i < len; i++) {
- b = points[i * 2 + dimIdx];
- if (isNaN(b) || isNaN(points[i * 2 + 1 - dimIdx])) {
- continue;
- }
- if (i === 0) {
- a = b;
- continue;
- }
- if (a <= xOrY && b >= xOrY || a >= xOrY && b <= xOrY) {
- nextIndex = i;
- break;
- }
- prevIndex = i;
- a = b;
- }
- return {
- range: [prevIndex, nextIndex],
- t: (xOrY - a) / (b - a)
- };
- }
- function anyStateShowEndLabel(seriesModel) {
- if (seriesModel.get(['endLabel', 'show'])) {
- return true;
- }
- for (var i = 0; i < SPECIAL_STATES.length; i++) {
- if (seriesModel.get([SPECIAL_STATES[i], 'endLabel', 'show'])) {
- return true;
- }
- }
- return false;
- }
- function createLineClipPath(lineView, coordSys, hasAnimation, seriesModel) {
- if (isCoordinateSystemType(coordSys, 'cartesian2d')) {
- var endLabelModel_1 = seriesModel.getModel('endLabel');
- var valueAnimation_1 = endLabelModel_1.get('valueAnimation');
- var data_1 = seriesModel.getData();
- var labelAnimationRecord_1 = {
- lastFrameIndex: 0
- };
- var during = anyStateShowEndLabel(seriesModel) ? function (percent, clipRect) {
- lineView._endLabelOnDuring(percent, clipRect, data_1, labelAnimationRecord_1, valueAnimation_1, endLabelModel_1, coordSys);
- } : null;
- var isHorizontal = coordSys.getBaseAxis().isHorizontal();
- var clipPath = createGridClipPath(coordSys, hasAnimation, seriesModel, function () {
- var endLabel = lineView._endLabel;
- if (endLabel && hasAnimation) {
- if (labelAnimationRecord_1.originalX != null) {
- endLabel.attr({
- x: labelAnimationRecord_1.originalX,
- y: labelAnimationRecord_1.originalY
- });
- }
- }
- }, during); // Expand clip shape to avoid clipping when line value exceeds axis
- if (!seriesModel.get('clip', true)) {
- var rectShape = clipPath.shape;
- var expandSize = Math.max(rectShape.width, rectShape.height);
- if (isHorizontal) {
- rectShape.y -= expandSize;
- rectShape.height += expandSize * 2;
- } else {
- rectShape.x -= expandSize;
- rectShape.width += expandSize * 2;
- }
- } // Set to the final frame. To make sure label layout is right.
- if (during) {
- during(1, clipPath);
- }
- return clipPath;
- } else {
- if (process.env.NODE_ENV !== 'production') {
- if (seriesModel.get(['endLabel', 'show'])) {
- console.warn('endLabel is not supported for lines in polar systems.');
- }
- }
- return createPolarClipPath(coordSys, hasAnimation, seriesModel);
- }
- }
- function getEndLabelStateSpecified(endLabelModel, coordSys) {
- var baseAxis = coordSys.getBaseAxis();
- var isHorizontal = baseAxis.isHorizontal();
- var isBaseInversed = baseAxis.inverse;
- var align = isHorizontal ? isBaseInversed ? 'right' : 'left' : 'center';
- var verticalAlign = isHorizontal ? 'middle' : isBaseInversed ? 'top' : 'bottom';
- return {
- normal: {
- align: endLabelModel.get('align') || align,
- verticalAlign: endLabelModel.get('verticalAlign') || verticalAlign
- }
- };
- }
- var LineView =
- /** @class */
- function (_super) {
- __extends(LineView, _super);
- function LineView() {
- return _super !== null && _super.apply(this, arguments) || this;
- }
- LineView.prototype.init = function () {
- var lineGroup = new graphic.Group();
- var symbolDraw = new SymbolDraw();
- this.group.add(symbolDraw.group);
- this._symbolDraw = symbolDraw;
- this._lineGroup = lineGroup;
- };
- LineView.prototype.render = function (seriesModel, ecModel, api) {
- var _this = this;
- var coordSys = seriesModel.coordinateSystem;
- var group = this.group;
- var data = seriesModel.getData();
- var lineStyleModel = seriesModel.getModel('lineStyle');
- var areaStyleModel = seriesModel.getModel('areaStyle');
- var points = data.getLayout('points') || [];
- var isCoordSysPolar = coordSys.type === 'polar';
- var prevCoordSys = this._coordSys;
- var symbolDraw = this._symbolDraw;
- var polyline = this._polyline;
- var polygon = this._polygon;
- var lineGroup = this._lineGroup;
- var hasAnimation = !ecModel.ssr && seriesModel.isAnimationEnabled();
- var isAreaChart = !areaStyleModel.isEmpty();
- var valueOrigin = areaStyleModel.get('origin');
- var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin);
- var stackedOnPoints = isAreaChart && getStackedOnPoints(coordSys, data, dataCoordInfo);
- var showSymbol = seriesModel.get('showSymbol');
- var connectNulls = seriesModel.get('connectNulls');
- var isIgnoreFunc = showSymbol && !isCoordSysPolar && getIsIgnoreFunc(seriesModel, data, coordSys); // Remove temporary symbols
- var oldData = this._data;
- oldData && oldData.eachItemGraphicEl(function (el, idx) {
- if (el.__temp) {
- group.remove(el);
- oldData.setItemGraphicEl(idx, null);
- }
- }); // Remove previous created symbols if showSymbol changed to false
- if (!showSymbol) {
- symbolDraw.remove();
- }
- group.add(lineGroup); // FIXME step not support polar
- var step = !isCoordSysPolar ? seriesModel.get('step') : false;
- var clipShapeForSymbol;
- if (coordSys && coordSys.getArea && seriesModel.get('clip', true)) {
- clipShapeForSymbol = coordSys.getArea(); // Avoid float number rounding error for symbol on the edge of axis extent.
- // See #7913 and `test/dataZoom-clip.html`.
- if (clipShapeForSymbol.width != null) {
- clipShapeForSymbol.x -= 0.1;
- clipShapeForSymbol.y -= 0.1;
- clipShapeForSymbol.width += 0.2;
- clipShapeForSymbol.height += 0.2;
- } else if (clipShapeForSymbol.r0) {
- clipShapeForSymbol.r0 -= 0.5;
- clipShapeForSymbol.r += 0.5;
- }
- }
- this._clipShapeForSymbol = clipShapeForSymbol;
- var visualColor = getVisualGradient(data, coordSys, api) || data.getVisual('style')[data.getVisual('drawType')]; // Initialization animation or coordinate system changed
- if (!(polyline && prevCoordSys.type === coordSys.type && step === this._step)) {
- showSymbol && symbolDraw.updateData(data, {
- isIgnore: isIgnoreFunc,
- clipShape: clipShapeForSymbol,
- disableAnimation: true,
- getSymbolPoint: function (idx) {
- return [points[idx * 2], points[idx * 2 + 1]];
- }
- });
- hasAnimation && this._initSymbolLabelAnimation(data, coordSys, clipShapeForSymbol);
- if (step) {
- // TODO If stacked series is not step
- points = turnPointsIntoStep(points, coordSys, step, connectNulls);
- if (stackedOnPoints) {
- stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step, connectNulls);
- }
- }
- polyline = this._newPolyline(points);
- if (isAreaChart) {
- polygon = this._newPolygon(points, stackedOnPoints);
- } // If areaStyle is removed
- else if (polygon) {
- lineGroup.remove(polygon);
- polygon = this._polygon = null;
- } // NOTE: Must update _endLabel before setClipPath.
- if (!isCoordSysPolar) {
- this._initOrUpdateEndLabel(seriesModel, coordSys, convertToColorString(visualColor));
- }
- lineGroup.setClipPath(createLineClipPath(this, coordSys, true, seriesModel));
- } else {
- if (isAreaChart && !polygon) {
- // If areaStyle is added
- polygon = this._newPolygon(points, stackedOnPoints);
- } else if (polygon && !isAreaChart) {
- // If areaStyle is removed
- lineGroup.remove(polygon);
- polygon = this._polygon = null;
- } // NOTE: Must update _endLabel before setClipPath.
- if (!isCoordSysPolar) {
- this._initOrUpdateEndLabel(seriesModel, coordSys, convertToColorString(visualColor));
- } // Update clipPath
- var oldClipPath = lineGroup.getClipPath();
- if (oldClipPath) {
- var newClipPath = createLineClipPath(this, coordSys, false, seriesModel);
- graphic.initProps(oldClipPath, {
- shape: newClipPath.shape
- }, seriesModel);
- } else {
- lineGroup.setClipPath(createLineClipPath(this, coordSys, true, seriesModel));
- } // Always update, or it is wrong in the case turning on legend
- // because points are not changed.
- showSymbol && symbolDraw.updateData(data, {
- isIgnore: isIgnoreFunc,
- clipShape: clipShapeForSymbol,
- disableAnimation: true,
- getSymbolPoint: function (idx) {
- return [points[idx * 2], points[idx * 2 + 1]];
- }
- }); // In the case data zoom triggered refreshing frequently
- // Data may not change if line has a category axis. So it should animate nothing.
- if (!isPointsSame(this._stackedOnPoints, stackedOnPoints) || !isPointsSame(this._points, points)) {
- if (hasAnimation) {
- this._doUpdateAnimation(data, stackedOnPoints, coordSys, api, step, valueOrigin, connectNulls);
- } else {
- // Not do it in update with animation
- if (step) {
- // TODO If stacked series is not step
- points = turnPointsIntoStep(points, coordSys, step, connectNulls);
- if (stackedOnPoints) {
- stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step, connectNulls);
- }
- }
- polyline.setShape({
- points: points
- });
- polygon && polygon.setShape({
- points: points,
- stackedOnPoints: stackedOnPoints
- });
- }
- }
- }
- var emphasisModel = seriesModel.getModel('emphasis');
- var focus = emphasisModel.get('focus');
- var blurScope = emphasisModel.get('blurScope');
- var emphasisDisabled = emphasisModel.get('disabled');
- polyline.useStyle(zrUtil.defaults( // Use color in lineStyle first
- lineStyleModel.getLineStyle(), {
- fill: 'none',
- stroke: visualColor,
- lineJoin: 'bevel'
- }));
- setStatesStylesFromModel(polyline, seriesModel, 'lineStyle');
- if (polyline.style.lineWidth > 0 && seriesModel.get(['emphasis', 'lineStyle', 'width']) === 'bolder') {
- var emphasisLineStyle = polyline.getState('emphasis').style;
- emphasisLineStyle.lineWidth = +polyline.style.lineWidth + 1;
- } // Needs seriesIndex for focus
- getECData(polyline).seriesIndex = seriesModel.seriesIndex;
- toggleHoverEmphasis(polyline, focus, blurScope, emphasisDisabled);
- var smooth = getSmooth(seriesModel.get('smooth'));
- var smoothMonotone = seriesModel.get('smoothMonotone');
- polyline.setShape({
- smooth: smooth,
- smoothMonotone: smoothMonotone,
- connectNulls: connectNulls
- });
- if (polygon) {
- var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');
- var stackedOnSmooth = 0;
- polygon.useStyle(zrUtil.defaults(areaStyleModel.getAreaStyle(), {
- fill: visualColor,
- opacity: 0.7,
- lineJoin: 'bevel',
- decal: data.getVisual('style').decal
- }));
- if (stackedOnSeries) {
- stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));
- }
- polygon.setShape({
- smooth: smooth,
- stackedOnSmooth: stackedOnSmooth,
- smoothMonotone: smoothMonotone,
- connectNulls: connectNulls
- });
- setStatesStylesFromModel(polygon, seriesModel, 'areaStyle'); // Needs seriesIndex for focus
- getECData(polygon).seriesIndex = seriesModel.seriesIndex;
- toggleHoverEmphasis(polygon, focus, blurScope, emphasisDisabled);
- }
- var changePolyState = function (toState) {
- _this._changePolyState(toState);
- };
- data.eachItemGraphicEl(function (el) {
- // Switch polyline / polygon state if element changed its state.
- el && (el.onHoverStateChange = changePolyState);
- });
- this._polyline.onHoverStateChange = changePolyState;
- this._data = data; // Save the coordinate system for transition animation when data changed
- this._coordSys = coordSys;
- this._stackedOnPoints = stackedOnPoints;
- this._points = points;
- this._step = step;
- this._valueOrigin = valueOrigin;
- if (seriesModel.get('triggerLineEvent')) {
- this.packEventData(seriesModel, polyline);
- polygon && this.packEventData(seriesModel, polygon);
- }
- };
- LineView.prototype.packEventData = function (seriesModel, el) {
- getECData(el).eventData = {
- componentType: 'series',
- componentSubType: 'line',
- componentIndex: seriesModel.componentIndex,
- seriesIndex: seriesModel.seriesIndex,
- seriesName: seriesModel.name,
- seriesType: 'line'
- };
- };
- LineView.prototype.highlight = function (seriesModel, ecModel, api, payload) {
- var data = seriesModel.getData();
- var dataIndex = modelUtil.queryDataIndex(data, payload);
- this._changePolyState('emphasis');
- if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) {
- var points = data.getLayout('points');
- var symbol = data.getItemGraphicEl(dataIndex);
- if (!symbol) {
- // Create a temporary symbol if it is not exists
- var x = points[dataIndex * 2];
- var y = points[dataIndex * 2 + 1];
- if (isNaN(x) || isNaN(y)) {
- // Null data
- return;
- } // fix #11360: shouldn't draw symbol outside clipShapeForSymbol
- if (this._clipShapeForSymbol && !this._clipShapeForSymbol.contain(x, y)) {
- return;
- }
- var zlevel = seriesModel.get('zlevel') || 0;
- var z = seriesModel.get('z') || 0;
- symbol = new SymbolClz(data, dataIndex);
- symbol.x = x;
- symbol.y = y;
- symbol.setZ(zlevel, z); // ensure label text of the temporary symbol is in front of line and area polygon
- var symbolLabel = symbol.getSymbolPath().getTextContent();
- if (symbolLabel) {
- symbolLabel.zlevel = zlevel;
- symbolLabel.z = z;
- symbolLabel.z2 = this._polyline.z2 + 1;
- }
- symbol.__temp = true;
- data.setItemGraphicEl(dataIndex, symbol); // Stop scale animation
- symbol.stopSymbolAnimation(true);
- this.group.add(symbol);
- }
- symbol.highlight();
- } else {
- // Highlight whole series
- ChartView.prototype.highlight.call(this, seriesModel, ecModel, api, payload);
- }
- };
- LineView.prototype.downplay = function (seriesModel, ecModel, api, payload) {
- var data = seriesModel.getData();
- var dataIndex = modelUtil.queryDataIndex(data, payload);
- this._changePolyState('normal');
- if (dataIndex != null && dataIndex >= 0) {
- var symbol = data.getItemGraphicEl(dataIndex);
- if (symbol) {
- if (symbol.__temp) {
- data.setItemGraphicEl(dataIndex, null);
- this.group.remove(symbol);
- } else {
- symbol.downplay();
- }
- }
- } else {
- // FIXME
- // can not downplay completely.
- // Downplay whole series
- ChartView.prototype.downplay.call(this, seriesModel, ecModel, api, payload);
- }
- };
- LineView.prototype._changePolyState = function (toState) {
- var polygon = this._polygon;
- setStatesFlag(this._polyline, toState);
- polygon && setStatesFlag(polygon, toState);
- };
- LineView.prototype._newPolyline = function (points) {
- var polyline = this._polyline; // Remove previous created polyline
- if (polyline) {
- this._lineGroup.remove(polyline);
- }
- polyline = new ECPolyline({
- shape: {
- points: points
- },
- segmentIgnoreThreshold: 2,
- z2: 10
- });
- this._lineGroup.add(polyline);
- this._polyline = polyline;
- return polyline;
- };
- LineView.prototype._newPolygon = function (points, stackedOnPoints) {
- var polygon = this._polygon; // Remove previous created polygon
- if (polygon) {
- this._lineGroup.remove(polygon);
- }
- polygon = new ECPolygon({
- shape: {
- points: points,
- stackedOnPoints: stackedOnPoints
- },
- segmentIgnoreThreshold: 2
- });
- this._lineGroup.add(polygon);
- this._polygon = polygon;
- return polygon;
- };
- LineView.prototype._initSymbolLabelAnimation = function (data, coordSys, clipShape) {
- var isHorizontalOrRadial;
- var isCoordSysPolar;
- var baseAxis = coordSys.getBaseAxis();
- var isAxisInverse = baseAxis.inverse;
- if (coordSys.type === 'cartesian2d') {
- isHorizontalOrRadial = baseAxis.isHorizontal();
- isCoordSysPolar = false;
- } else if (coordSys.type === 'polar') {
- isHorizontalOrRadial = baseAxis.dim === 'angle';
- isCoordSysPolar = true;
- }
- var seriesModel = data.hostModel;
- var seriesDuration = seriesModel.get('animationDuration');
- if (zrUtil.isFunction(seriesDuration)) {
- seriesDuration = seriesDuration(null);
- }
- var seriesDelay = seriesModel.get('animationDelay') || 0;
- var seriesDelayValue = zrUtil.isFunction(seriesDelay) ? seriesDelay(null) : seriesDelay;
- data.eachItemGraphicEl(function (symbol, idx) {
- var el = symbol;
- if (el) {
- var point = [symbol.x, symbol.y];
- var start = void 0;
- var end = void 0;
- var current = void 0;
- if (clipShape) {
- if (isCoordSysPolar) {
- var polarClip = clipShape;
- var coord = coordSys.pointToCoord(point);
- if (isHorizontalOrRadial) {
- start = polarClip.startAngle;
- end = polarClip.endAngle;
- current = -coord[1] / 180 * Math.PI;
- } else {
- start = polarClip.r0;
- end = polarClip.r;
- current = coord[0];
- }
- } else {
- var gridClip = clipShape;
- if (isHorizontalOrRadial) {
- start = gridClip.x;
- end = gridClip.x + gridClip.width;
- current = symbol.x;
- } else {
- start = gridClip.y + gridClip.height;
- end = gridClip.y;
- current = symbol.y;
- }
- }
- }
- var ratio = end === start ? 0 : (current - start) / (end - start);
- if (isAxisInverse) {
- ratio = 1 - ratio;
- }
- var delay = zrUtil.isFunction(seriesDelay) ? seriesDelay(idx) : seriesDuration * ratio + seriesDelayValue;
- var symbolPath = el.getSymbolPath();
- var text = symbolPath.getTextContent();
- el.attr({
- scaleX: 0,
- scaleY: 0
- });
- el.animateTo({
- scaleX: 1,
- scaleY: 1
- }, {
- duration: 200,
- setToFinal: true,
- delay: delay
- });
- if (text) {
- text.animateFrom({
- style: {
- opacity: 0
- }
- }, {
- duration: 300,
- delay: delay
- });
- }
- symbolPath.disableLabelAnimation = true;
- }
- });
- };
- LineView.prototype._initOrUpdateEndLabel = function (seriesModel, coordSys, inheritColor) {
- var endLabelModel = seriesModel.getModel('endLabel');
- if (anyStateShowEndLabel(seriesModel)) {
- var data_2 = seriesModel.getData();
- var polyline = this._polyline; // series may be filtered.
- var points = data_2.getLayout('points');
- if (!points) {
- polyline.removeTextContent();
- this._endLabel = null;
- return;
- }
- var endLabel = this._endLabel;
- if (!endLabel) {
- endLabel = this._endLabel = new graphic.Text({
- z2: 200 // should be higher than item symbol
- });
- endLabel.ignoreClip = true;
- polyline.setTextContent(this._endLabel);
- polyline.disableLabelAnimation = true;
- } // Find last non-NaN data to display data
- var dataIndex = getLastIndexNotNull(points);
- if (dataIndex >= 0) {
- setLabelStyle(polyline, getLabelStatesModels(seriesModel, 'endLabel'), {
- inheritColor: inheritColor,
- labelFetcher: seriesModel,
- labelDataIndex: dataIndex,
- defaultText: function (dataIndex, opt, interpolatedValue) {
- return interpolatedValue != null ? getDefaultInterpolatedLabel(data_2, interpolatedValue) : getDefaultLabel(data_2, dataIndex);
- },
- enableTextSetter: true
- }, getEndLabelStateSpecified(endLabelModel, coordSys));
- polyline.textConfig.position = null;
- }
- } else if (this._endLabel) {
- this._polyline.removeTextContent();
- this._endLabel = null;
- }
- };
- LineView.prototype._endLabelOnDuring = function (percent, clipRect, data, animationRecord, valueAnimation, endLabelModel, coordSys) {
- var endLabel = this._endLabel;
- var polyline = this._polyline;
- if (endLabel) {
- // NOTE: Don't remove percent < 1. percent === 1 means the first frame during render.
- // The label is not prepared at this time.
- if (percent < 1 && animationRecord.originalX == null) {
- animationRecord.originalX = endLabel.x;
- animationRecord.originalY = endLabel.y;
- }
- var points = data.getLayout('points');
- var seriesModel = data.hostModel;
- var connectNulls = seriesModel.get('connectNulls');
- var precision = endLabelModel.get('precision');
- var distance = endLabelModel.get('distance') || 0;
- var baseAxis = coordSys.getBaseAxis();
- var isHorizontal = baseAxis.isHorizontal();
- var isBaseInversed = baseAxis.inverse;
- var clipShape = clipRect.shape;
- var xOrY = isBaseInversed ? isHorizontal ? clipShape.x : clipShape.y + clipShape.height : isHorizontal ? clipShape.x + clipShape.width : clipShape.y;
- var distanceX = (isHorizontal ? distance : 0) * (isBaseInversed ? -1 : 1);
- var distanceY = (isHorizontal ? 0 : -distance) * (isBaseInversed ? -1 : 1);
- var dim = isHorizontal ? 'x' : 'y';
- var dataIndexRange = getIndexRange(points, xOrY, dim);
- var indices = dataIndexRange.range;
- var diff = indices[1] - indices[0];
- var value = void 0;
- if (diff >= 1) {
- // diff > 1 && connectNulls, which is on the null data.
- if (diff > 1 && !connectNulls) {
- var pt = getPointAtIndex(points, indices[0]);
- endLabel.attr({
- x: pt[0] + distanceX,
- y: pt[1] + distanceY
- });
- valueAnimation && (value = seriesModel.getRawValue(indices[0]));
- } else {
- var pt = polyline.getPointOn(xOrY, dim);
- pt && endLabel.attr({
- x: pt[0] + distanceX,
- y: pt[1] + distanceY
- });
- var startValue = seriesModel.getRawValue(indices[0]);
- var endValue = seriesModel.getRawValue(indices[1]);
- valueAnimation && (value = modelUtil.interpolateRawValues(data, precision, startValue, endValue, dataIndexRange.t));
- }
- animationRecord.lastFrameIndex = indices[0];
- } else {
- // If diff <= 0, which is the range is not found(Include NaN)
- // Choose the first point or last point.
- var idx = percent === 1 || animationRecord.lastFrameIndex > 0 ? indices[0] : 0;
- var pt = getPointAtIndex(points, idx);
- valueAnimation && (value = seriesModel.getRawValue(idx));
- endLabel.attr({
- x: pt[0] + distanceX,
- y: pt[1] + distanceY
- });
- }
- if (valueAnimation) {
- var inner = labelInner(endLabel);
- if (typeof inner.setLabelText === 'function') {
- inner.setLabelText(value);
- }
- }
- }
- };
- /**
- * @private
- */
- // FIXME Two value axis
- LineView.prototype._doUpdateAnimation = function (data, stackedOnPoints, coordSys, api, step, valueOrigin, connectNulls) {
- var polyline = this._polyline;
- var polygon = this._polygon;
- var seriesModel = data.hostModel;
- var diff = lineAnimationDiff(this._data, data, this._stackedOnPoints, stackedOnPoints, this._coordSys, coordSys, this._valueOrigin, valueOrigin);
- var current = diff.current;
- var stackedOnCurrent = diff.stackedOnCurrent;
- var next = diff.next;
- var stackedOnNext = diff.stackedOnNext;
- if (step) {
- // TODO If stacked series is not step
- current = turnPointsIntoStep(diff.current, coordSys, step, connectNulls);
- stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step, connectNulls);
- next = turnPointsIntoStep(diff.next, coordSys, step, connectNulls);
- stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step, connectNulls);
- } // Don't apply animation if diff is large.
- // For better result and avoid memory explosion problems like
- // https://github.com/apache/incubator-echarts/issues/12229
- if (getBoundingDiff(current, next) > 3000 || polygon && getBoundingDiff(stackedOnCurrent, stackedOnNext) > 3000) {
- polyline.stopAnimation();
- polyline.setShape({
- points: next
- });
- if (polygon) {
- polygon.stopAnimation();
- polygon.setShape({
- points: next,
- stackedOnPoints: stackedOnNext
- });
- }
- return;
- }
- polyline.shape.__points = diff.current;
- polyline.shape.points = current;
- var target = {
- shape: {
- points: next
- }
- }; // Also animate the original points.
- // If points reference is changed when turning into step line.
- if (diff.current !== current) {
- target.shape.__points = diff.next;
- } // Stop previous animation.
- polyline.stopAnimation();
- graphic.updateProps(polyline, target, seriesModel);
- if (polygon) {
- polygon.setShape({
- // Reuse the points with polyline.
- points: current,
- stackedOnPoints: stackedOnCurrent
- });
- polygon.stopAnimation();
- graphic.updateProps(polygon, {
- shape: {
- stackedOnPoints: stackedOnNext
- }
- }, seriesModel); // If use attr directly in updateProps.
- if (polyline.shape.points !== polygon.shape.points) {
- polygon.shape.points = polyline.shape.points;
- }
- }
- var updatedDataInfo = [];
- var diffStatus = diff.status;
- for (var i = 0; i < diffStatus.length; i++) {
- var cmd = diffStatus[i].cmd;
- if (cmd === '=') {
- var el = data.getItemGraphicEl(diffStatus[i].idx1);
- if (el) {
- updatedDataInfo.push({
- el: el,
- ptIdx: i // Index of points
- });
- }
- }
- }
- if (polyline.animators && polyline.animators.length) {
- polyline.animators[0].during(function () {
- polygon && polygon.dirtyShape();
- var points = polyline.shape.__points;
- for (var i = 0; i < updatedDataInfo.length; i++) {
- var el = updatedDataInfo[i].el;
- var offset = updatedDataInfo[i].ptIdx * 2;
- el.x = points[offset];
- el.y = points[offset + 1];
- el.markRedraw();
- }
- });
- }
- };
- LineView.prototype.remove = function (ecModel) {
- var group = this.group;
- var oldData = this._data;
- this._lineGroup.removeAll();
- this._symbolDraw.remove(true); // Remove temporary created elements when highlighting
- oldData && oldData.eachItemGraphicEl(function (el, idx) {
- if (el.__temp) {
- group.remove(el);
- oldData.setItemGraphicEl(idx, null);
- }
- });
- this._polyline = this._polygon = this._coordSys = this._points = this._stackedOnPoints = this._endLabel = this._data = null;
- };
- LineView.type = 'line';
- return LineView;
- }(ChartView);
- export default LineView;
|