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 * as graphic from '../../util/graphic'; | |
| import { setStatesStylesFromModel, toggleHoverEmphasis } from '../../util/states'; | |
| import ChartView from '../../view/Chart'; | |
| import FunnelSeriesModel, {FunnelDataItemOption} from './FunnelSeries'; | |
| import GlobalModel from '../../model/Global'; | |
| import ExtensionAPI from '../../core/ExtensionAPI'; | |
| import SeriesData from '../../data/SeriesData'; | |
| import { ColorString } from '../../util/types'; | |
| import { setLabelLineStyle, getLabelLineStatesModels } from '../../label/labelGuideHelper'; | |
| import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle'; | |
| import { saveOldStyle } from '../../animation/basicTransition'; | |
| const opacityAccessPath = ['itemStyle', 'opacity'] as const; | |
| /** | |
| * Piece of pie including Sector, Label, LabelLine | |
| */ | |
| class FunnelPiece extends graphic.Polygon { | |
| constructor(data: SeriesData, idx: number) { | |
| super(); | |
| const polygon = this; | |
| const labelLine = new graphic.Polyline(); | |
| const text = new graphic.Text(); | |
| polygon.setTextContent(text); | |
| this.setTextGuideLine(labelLine); | |
| this.updateData(data, idx, true); | |
| } | |
| updateData(data: SeriesData, idx: number, firstCreate?: boolean) { | |
| const polygon = this; | |
| const seriesModel = data.hostModel; | |
| const itemModel = data.getItemModel<FunnelDataItemOption>(idx); | |
| const layout = data.getItemLayout(idx); | |
| const emphasisModel = itemModel.getModel('emphasis'); | |
| let opacity = itemModel.get(opacityAccessPath); | |
| opacity = opacity == null ? 1 : opacity; | |
| if (!firstCreate) { | |
| saveOldStyle(polygon); | |
| } | |
| // Update common style | |
| polygon.useStyle(data.getItemVisual(idx, 'style')); | |
| polygon.style.lineJoin = 'round'; | |
| if (firstCreate) { | |
| polygon.setShape({ | |
| points: layout.points | |
| }); | |
| polygon.style.opacity = 0; | |
| graphic.initProps(polygon, { | |
| style: { | |
| opacity: opacity | |
| } | |
| }, seriesModel, idx); | |
| } | |
| else { | |
| graphic.updateProps(polygon, { | |
| style: { | |
| opacity: opacity | |
| }, | |
| shape: { | |
| points: layout.points | |
| } | |
| }, seriesModel, idx); | |
| } | |
| setStatesStylesFromModel(polygon, itemModel); | |
| this._updateLabel(data, idx); | |
| toggleHoverEmphasis( | |
| this, | |
| emphasisModel.get('focus'), | |
| emphasisModel.get('blurScope'), | |
| emphasisModel.get('disabled') | |
| ); | |
| } | |
| _updateLabel(data: SeriesData, idx: number) { | |
| const polygon = this; | |
| const labelLine = this.getTextGuideLine(); | |
| const labelText = polygon.getTextContent(); | |
| const seriesModel = data.hostModel; | |
| const itemModel = data.getItemModel<FunnelDataItemOption>(idx); | |
| const layout = data.getItemLayout(idx); | |
| const labelLayout = layout.label; | |
| const style = data.getItemVisual(idx, 'style'); | |
| const visualColor = style.fill as ColorString; | |
| setLabelStyle( | |
| // position will not be used in setLabelStyle | |
| labelText, | |
| getLabelStatesModels(itemModel), | |
| { | |
| labelFetcher: data.hostModel as FunnelSeriesModel, | |
| labelDataIndex: idx, | |
| defaultOpacity: style.opacity, | |
| defaultText: data.getName(idx) | |
| }, | |
| { normal: { | |
| align: labelLayout.textAlign, | |
| verticalAlign: labelLayout.verticalAlign | |
| } } | |
| ); | |
| polygon.setTextConfig({ | |
| local: true, | |
| inside: !!labelLayout.inside, | |
| insideStroke: visualColor, | |
| // insideFill: 'auto', | |
| outsideFill: visualColor | |
| }); | |
| const linePoints = labelLayout.linePoints; | |
| labelLine.setShape({ | |
| points: linePoints | |
| }); | |
| polygon.textGuideLineConfig = { | |
| anchor: linePoints ? new graphic.Point(linePoints[0][0], linePoints[0][1]) : null | |
| }; | |
| // Make sure update style on labelText after setLabelStyle. | |
| // Because setLabelStyle will replace a new style on it. | |
| graphic.updateProps(labelText, { | |
| style: { | |
| x: labelLayout.x, | |
| y: labelLayout.y | |
| } | |
| }, seriesModel, idx); | |
| labelText.attr({ | |
| rotation: labelLayout.rotation, | |
| originX: labelLayout.x, | |
| originY: labelLayout.y, | |
| z2: 10 | |
| }); | |
| setLabelLineStyle(polygon, getLabelLineStatesModels(itemModel), { | |
| // Default use item visual color | |
| stroke: visualColor | |
| }); | |
| } | |
| } | |
| class FunnelView extends ChartView { | |
| static type = 'funnel' as const; | |
| type = FunnelView.type; | |
| private _data: SeriesData; | |
| ignoreLabelLineUpdate = true; | |
| render(seriesModel: FunnelSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) { | |
| const data = seriesModel.getData(); | |
| const oldData = this._data; | |
| const group = this.group; | |
| data.diff(oldData) | |
| .add(function (idx) { | |
| const funnelPiece = new FunnelPiece(data, idx); | |
| data.setItemGraphicEl(idx, funnelPiece); | |
| group.add(funnelPiece); | |
| }) | |
| .update(function (newIdx, oldIdx) { | |
| const piece = oldData.getItemGraphicEl(oldIdx) as FunnelPiece; | |
| piece.updateData(data, newIdx); | |
| group.add(piece); | |
| data.setItemGraphicEl(newIdx, piece); | |
| }) | |
| .remove(function (idx) { | |
| const piece = oldData.getItemGraphicEl(idx); | |
| graphic.removeElementWithFadeOut(piece, seriesModel, idx); | |
| }) | |
| .execute(); | |
| this._data = data; | |
| } | |
| remove() { | |
| this.group.removeAll(); | |
| this._data = null; | |
| } | |
| dispose() {} | |
| } | |
| export default FunnelView; | |