/*
|
* 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 { retrieveVisualColorForTooltipMarker } from '../../component/tooltip/tooltipMarkup';
|
|
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;
|
|
|
// 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;
|