Spaces:
Running
Running
/* | |
* 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; | |