/* * 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 LineDraw from '../helper/LineDraw'; import EffectLine from '../helper/EffectLine'; import Line from '../helper/Line'; import Polyline from '../helper/Polyline'; import EffectPolyline from '../helper/EffectPolyline'; import LargeLineDraw from '../helper/LargeLineDraw'; import linesLayout from './linesLayout'; import {createClipPath} from '../helper/createClipPathFromCoordSys'; import ChartView from '../../view/Chart'; import LinesSeriesModel from './LinesSeries'; import GlobalModel from '../../model/Global'; import ExtensionAPI from '../../core/ExtensionAPI'; import CanvasPainter from 'zrender/src/canvas/Painter'; import { StageHandlerProgressParams, StageHandlerProgressExecutor } from '../../util/types'; import SeriesData from '../../data/SeriesData'; import type Polar from '../../coord/polar/Polar'; import type Cartesian2D from '../../coord/cartesian/Cartesian2D'; import Element from 'zrender/src/Element'; class LinesView extends ChartView { static readonly type = 'lines'; readonly type = LinesView.type; private _lastZlevel: number; private _finished: boolean; private _lineDraw: LineDraw | LargeLineDraw; private _hasEffet: boolean; private _isPolyline: boolean; private _isLargeDraw: boolean; render(seriesModel: LinesSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) { const data = seriesModel.getData(); const lineDraw = this._updateLineDraw(data, seriesModel); const zlevel = seriesModel.get('zlevel'); const trailLength = seriesModel.get(['effect', 'trailLength']); const zr = api.getZr(); // Avoid the drag cause ghost shadow // FIXME Better way ? // SVG doesn't support const isSvg = zr.painter.getType() === 'svg'; if (!isSvg) { (zr.painter as CanvasPainter).getLayer(zlevel).clear(true); } // Config layer with motion blur if (this._lastZlevel != null && !isSvg) { zr.configLayer(this._lastZlevel, { motionBlur: false }); } if (this._showEffect(seriesModel) && trailLength > 0) { if (!isSvg) { zr.configLayer(zlevel, { motionBlur: true, lastFrameAlpha: Math.max(Math.min(trailLength / 10 + 0.9, 1), 0) }); } else if (__DEV__) { console.warn('SVG render mode doesn\'t support lines with trail effect'); } } lineDraw.updateData(data as SeriesData); const clipPath = seriesModel.get('clip', true) && createClipPath( (seriesModel.coordinateSystem as Polar | Cartesian2D), false, seriesModel ); if (clipPath) { this.group.setClipPath(clipPath); } else { this.group.removeClipPath(); } this._lastZlevel = zlevel; this._finished = true; } incrementalPrepareRender(seriesModel: LinesSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) { const data = seriesModel.getData(); const lineDraw = this._updateLineDraw(data, seriesModel); lineDraw.incrementalPrepareUpdate(data as any); this._clearLayer(api); this._finished = false; } incrementalRender( taskParams: StageHandlerProgressParams, seriesModel: LinesSeriesModel, ecModel: GlobalModel ) { this._lineDraw.incrementalUpdate(taskParams, seriesModel.getData() as any); this._finished = taskParams.end === seriesModel.getData().count(); } eachRendered(cb: (el: Element) => boolean | void) { this._lineDraw && this._lineDraw.eachRendered(cb); } updateTransform(seriesModel: LinesSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) { const data = seriesModel.getData(); const pipelineContext = seriesModel.pipelineContext; if (!this._finished || pipelineContext.large || pipelineContext.progressiveRender) { // TODO Don't have to do update in large mode. Only do it when there are millions of data. return { update: true } as const; } else { // TODO Use same logic with ScatterView. // Manually update layout const res = linesLayout.reset(seriesModel, ecModel, api) as StageHandlerProgressExecutor; if (res.progress) { res.progress({ start: 0, end: data.count(), count: data.count() }, data); } // Not in large mode (this._lineDraw as LineDraw).updateLayout(); this._clearLayer(api); } } _updateLineDraw(data: SeriesData, seriesModel: LinesSeriesModel) { let lineDraw = this._lineDraw; const hasEffect = this._showEffect(seriesModel); const isPolyline = !!seriesModel.get('polyline'); const pipelineContext = seriesModel.pipelineContext; const isLargeDraw = pipelineContext.large; if (__DEV__) { if (hasEffect && isLargeDraw) { console.warn('Large lines not support effect'); } } if (!lineDraw || hasEffect !== this._hasEffet || isPolyline !== this._isPolyline || isLargeDraw !== this._isLargeDraw ) { if (lineDraw) { lineDraw.remove(); } lineDraw = this._lineDraw = isLargeDraw ? new LargeLineDraw() : new LineDraw( isPolyline ? (hasEffect ? EffectPolyline : Polyline) : (hasEffect ? EffectLine : Line) ); this._hasEffet = hasEffect; this._isPolyline = isPolyline; this._isLargeDraw = isLargeDraw; } this.group.add(lineDraw.group); return lineDraw; } private _showEffect(seriesModel: LinesSeriesModel) { return !!seriesModel.get(['effect', 'show']); } _clearLayer(api: ExtensionAPI) { // Not use motion when dragging or zooming const zr = api.getZr(); const isSvg = zr.painter.getType() === 'svg'; if (!isSvg && this._lastZlevel != null) { (zr.painter as CanvasPainter).getLayer(this._lastZlevel).clear(true); } } remove(ecModel: GlobalModel, api: ExtensionAPI) { this._lineDraw && this._lineDraw.remove(); this._lineDraw = null; // Clear motion when lineDraw is removed this._clearLayer(api); } dispose(ecModel: GlobalModel, api: ExtensionAPI) { this.remove(ecModel, api); } } export default LinesView;