| /* |
| * 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, enableHoverEmphasis } from '../../util/states'; |
| import ChartView from '../../view/Chart'; |
| import FunnelSeriesModel, {FunnelDataItemOption} from './FunnelSeries'; |
| import GlobalModel from '../../model/Global'; |
| import ExtensionAPI from '../../core/ExtensionAPI'; |
| import List from '../../data/List'; |
| import { ColorString } from '../../util/types'; |
| import { setLabelLineStyle, getLabelLineStatesModels } from '../../label/labelGuideHelper'; |
| import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle'; |
| import { saveOldStyle } from '../../animation/basicTrasition'; |
| |
| const opacityAccessPath = ['itemStyle', 'opacity'] as const; |
| |
| /** |
| * Piece of pie including Sector, Label, LabelLine |
| */ |
| class FunnelPiece extends graphic.Polygon { |
| |
| constructor(data: List, 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: List, 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); |
| |
| enableHoverEmphasis(this, emphasisModel.get('focus'), emphasisModel.get('blurScope')); |
| } |
| |
| _updateLabel(data: List, 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: List; |
| |
| 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; |