|  | /* | 
|  | * 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 * as graphic from '../../util/graphic'; | 
|  | import { setStatesStylesFromModel, toggleHoverEmphasis } from '../../util/states'; | 
|  | import ChartView from '../../view/Chart'; | 
|  | import SeriesData from '../../data/SeriesData'; | 
|  | import ParallelSeriesModel, { ParallelSeriesDataItemOption } from './ParallelSeries'; | 
|  | import GlobalModel from '../../model/Global'; | 
|  | import ExtensionAPI from '../../core/ExtensionAPI'; | 
|  | import { StageHandlerProgressParams, ParsedValue, Payload } from '../../util/types'; | 
|  | import Parallel from '../../coord/parallel/Parallel'; | 
|  | import { OptionAxisType } from '../../coord/axisCommonTypes'; | 
|  | import { numericToNumber } from '../../util/number'; | 
|  | import { eqNaN } from 'zrender/src/core/util'; | 
|  | import { saveOldStyle } from '../../animation/basicTransition'; | 
|  | import Element from 'zrender/src/Element'; | 
|  |  | 
|  | const DEFAULT_SMOOTH = 0.3; | 
|  |  | 
|  | interface ParallelDrawSeriesScope { | 
|  | smooth: number | 
|  | } | 
|  | class ParallelView extends ChartView { | 
|  | static type = 'parallel'; | 
|  | type = ParallelView.type; | 
|  |  | 
|  | private _dataGroup = new graphic.Group(); | 
|  |  | 
|  | private _data: SeriesData; | 
|  |  | 
|  | private _initialized = false; | 
|  |  | 
|  | private _progressiveEls: Element[]; | 
|  |  | 
|  | init() { | 
|  | this.group.add(this._dataGroup); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @override | 
|  | */ | 
|  | render( | 
|  | seriesModel: ParallelSeriesModel, | 
|  | ecModel: GlobalModel, | 
|  | api: ExtensionAPI, | 
|  | payload: Payload | 
|  | ) { | 
|  |  | 
|  | // Clear previously rendered progressive elements. | 
|  | this._progressiveEls = null; | 
|  |  | 
|  | const dataGroup = this._dataGroup; | 
|  | const data = seriesModel.getData(); | 
|  | const oldData = this._data; | 
|  | const coordSys = seriesModel.coordinateSystem; | 
|  | const dimensions = coordSys.dimensions; | 
|  | const seriesScope = makeSeriesScope(seriesModel); | 
|  |  | 
|  | data.diff(oldData) | 
|  | .add(add) | 
|  | .update(update) | 
|  | .remove(remove) | 
|  | .execute(); | 
|  |  | 
|  | function add(newDataIndex: number) { | 
|  | const line = addEl(data, dataGroup, newDataIndex, dimensions, coordSys); | 
|  | updateElCommon(line, data, newDataIndex, seriesScope); | 
|  | } | 
|  |  | 
|  | function update(newDataIndex: number, oldDataIndex: number) { | 
|  | const line = oldData.getItemGraphicEl(oldDataIndex) as graphic.Polyline; | 
|  |  | 
|  | const points = createLinePoints(data, newDataIndex, dimensions, coordSys); | 
|  | data.setItemGraphicEl(newDataIndex, line); | 
|  |  | 
|  | graphic.updateProps(line, {shape: {points: points}}, seriesModel, newDataIndex); | 
|  |  | 
|  | saveOldStyle(line); | 
|  |  | 
|  | updateElCommon(line, data, newDataIndex, seriesScope); | 
|  | } | 
|  |  | 
|  | function remove(oldDataIndex: number) { | 
|  | const line = oldData.getItemGraphicEl(oldDataIndex); | 
|  | dataGroup.remove(line); | 
|  | } | 
|  |  | 
|  | // First create | 
|  | if (!this._initialized) { | 
|  | this._initialized = true; | 
|  | const clipPath = createGridClipShape( | 
|  | coordSys, seriesModel, function () { | 
|  | // Callback will be invoked immediately if there is no animation | 
|  | setTimeout(function () { | 
|  | dataGroup.removeClipPath(); | 
|  | }); | 
|  | } | 
|  | ); | 
|  | dataGroup.setClipPath(clipPath); | 
|  | } | 
|  |  | 
|  | this._data = data; | 
|  | } | 
|  |  | 
|  | incrementalPrepareRender(seriesModel: ParallelSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) { | 
|  | this._initialized = true; | 
|  | this._data = null; | 
|  | this._dataGroup.removeAll(); | 
|  | } | 
|  |  | 
|  | incrementalRender(taskParams: StageHandlerProgressParams, seriesModel: ParallelSeriesModel, ecModel: GlobalModel) { | 
|  | const data = seriesModel.getData(); | 
|  | const coordSys = seriesModel.coordinateSystem; | 
|  | const dimensions = coordSys.dimensions; | 
|  | const seriesScope = makeSeriesScope(seriesModel); | 
|  | const progressiveEls: Element[] = this._progressiveEls = []; | 
|  |  | 
|  | for (let dataIndex = taskParams.start; dataIndex < taskParams.end; dataIndex++) { | 
|  | const line = addEl(data, this._dataGroup, dataIndex, dimensions, coordSys); | 
|  | line.incremental = true; | 
|  | updateElCommon(line, data, dataIndex, seriesScope); | 
|  | progressiveEls.push(line); | 
|  | } | 
|  | } | 
|  |  | 
|  | remove() { | 
|  | this._dataGroup && this._dataGroup.removeAll(); | 
|  | this._data = null; | 
|  | } | 
|  | } | 
|  |  | 
|  | function createGridClipShape(coordSys: Parallel, seriesModel: ParallelSeriesModel, cb: () => void) { | 
|  | const parallelModel = coordSys.model; | 
|  | const rect = coordSys.getRect(); | 
|  | const rectEl = new graphic.Rect({ | 
|  | shape: { | 
|  | x: rect.x, | 
|  | y: rect.y, | 
|  | width: rect.width, | 
|  | height: rect.height | 
|  | } | 
|  | }); | 
|  |  | 
|  | const dim = parallelModel.get('layout') === 'horizontal' ? 'width' as const : 'height' as const; | 
|  | rectEl.setShape(dim, 0); | 
|  | graphic.initProps(rectEl, { | 
|  | shape: { | 
|  | width: rect.width, | 
|  | height: rect.height | 
|  | } | 
|  | }, seriesModel, cb); | 
|  | return rectEl; | 
|  | } | 
|  |  | 
|  | function createLinePoints(data: SeriesData, dataIndex: number, dimensions: string[], coordSys: Parallel) { | 
|  | const points = []; | 
|  | for (let i = 0; i < dimensions.length; i++) { | 
|  | const dimName = dimensions[i]; | 
|  | const value = data.get(data.mapDimension(dimName), dataIndex); | 
|  | if (!isEmptyValue(value, coordSys.getAxis(dimName).type)) { | 
|  | points.push(coordSys.dataToPoint(value, dimName)); | 
|  | } | 
|  | } | 
|  | return points; | 
|  | } | 
|  |  | 
|  | function addEl( | 
|  | data: SeriesData, dataGroup: graphic.Group, dataIndex: number, dimensions: string[], coordSys: Parallel | 
|  | ) { | 
|  | const points = createLinePoints(data, dataIndex, dimensions, coordSys); | 
|  | const line = new graphic.Polyline({ | 
|  | shape: {points: points}, | 
|  | // silent: true, | 
|  | z2: 10 | 
|  | }); | 
|  | dataGroup.add(line); | 
|  | data.setItemGraphicEl(dataIndex, line); | 
|  | return line; | 
|  | } | 
|  |  | 
|  | function makeSeriesScope(seriesModel: ParallelSeriesModel): ParallelDrawSeriesScope { | 
|  | let smooth = seriesModel.get('smooth', true); | 
|  | smooth === true && (smooth = DEFAULT_SMOOTH); | 
|  | smooth = numericToNumber(smooth); | 
|  | eqNaN(smooth) && (smooth = 0); | 
|  |  | 
|  | return { smooth }; | 
|  | } | 
|  |  | 
|  | function updateElCommon( | 
|  | el: graphic.Polyline, | 
|  | data: SeriesData, | 
|  | dataIndex: number, | 
|  | seriesScope: ParallelDrawSeriesScope | 
|  | ) { | 
|  | el.useStyle(data.getItemVisual(dataIndex, 'style')); | 
|  | el.style.fill = null; | 
|  | el.setShape('smooth', seriesScope.smooth); | 
|  |  | 
|  | const itemModel = data.getItemModel<ParallelSeriesDataItemOption>(dataIndex); | 
|  | const emphasisModel = itemModel.getModel('emphasis'); | 
|  | setStatesStylesFromModel(el, itemModel, 'lineStyle'); | 
|  |  | 
|  | toggleHoverEmphasis( | 
|  | el, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled') | 
|  | ); | 
|  | } | 
|  |  | 
|  | // function simpleDiff(oldData, newData, dimensions) { | 
|  | //     let oldLen; | 
|  | //     if (!oldData | 
|  | //         || !oldData.__plProgressive | 
|  | //         || (oldLen = oldData.count()) !== newData.count() | 
|  | //     ) { | 
|  | //         return true; | 
|  | //     } | 
|  |  | 
|  | //     let dimLen = dimensions.length; | 
|  | //     for (let i = 0; i < oldLen; i++) { | 
|  | //         for (let j = 0; j < dimLen; j++) { | 
|  | //             if (oldData.get(dimensions[j], i) !== newData.get(dimensions[j], i)) { | 
|  | //                 return true; | 
|  | //             } | 
|  | //         } | 
|  | //     } | 
|  |  | 
|  | //     return false; | 
|  | // } | 
|  |  | 
|  | // FIXME put in common util? | 
|  | function isEmptyValue(val: ParsedValue, axisType: OptionAxisType) { | 
|  | return axisType === 'category' | 
|  | ? val == null | 
|  | : (val == null || isNaN(val as number)); // axisType === 'value' | 
|  | } | 
|  |  | 
|  | export default ParallelView; |