Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pie): 'itemRadiusScale' function added for pie series #19435

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 25 additions & 1 deletion src/chart/pie/PieSeries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,18 @@ interface PieItemStyleOption<TCbParams = never> extends ItemStyleOption<TCbParam
// which means that innerCornerRadius is 20% of the innerRadius
// and outerCornerRadius is half of outerRadius.
borderRadius?: (number | string)[] | number | string

// The radius of each pie item can be adjusted depends on this value.
// Value (or returned value in case of function) should be a decimal between 0 and 1,
// where 0 means the minimum outer radius from the initially calculated radius of the element,
// and 1 means 100% of initial outer radius.
radiusPercent?: number | ((dataParams: PieCallbackDataParams) => number)
}

export interface PieCallbackDataParams extends CallbackDataParams {
percent: number
max?: number
sum?: number
}

export interface PieStateOption<TCbParams = never> {
Expand Down Expand Up @@ -131,6 +139,9 @@ export interface PieSeriesOption extends
showEmptyCircle?: boolean;
emptyCircleStyle?: PieItemStyleOption;

showBackground?: boolean
backgroundStyle?: PieItemStyleOption

data?: (OptionDataValueNumeric | OptionDataValueNumeric[] | PieDataItemOption)[]
}

Expand Down Expand Up @@ -179,12 +190,13 @@ class PieSeriesModel extends SeriesModel<PieSeriesOption> {
*/
getDataParams(dataIndex: number): PieCallbackDataParams {
const data = this.getData();
const valueDim = data.mapDimension('value');
// update seats when data is changed
const dataInner = innerData(data);
let seats = dataInner.seats;
if (!seats) {
const valueList: number[] = [];
data.each(data.mapDimension('value'), function (value: number) {
data.each(valueDim, function (value: number) {
valueList.push(value);
});
seats = dataInner.seats = getPercentSeats(valueList, data.hostModel.get('percentPrecision'));
Expand All @@ -193,6 +205,13 @@ class PieSeriesModel extends SeriesModel<PieSeriesOption> {
// seats may be empty when sum is 0
params.percent = seats[dataIndex] || 0;
params.$vars.push('percent');

const radiusPercent = data.hostModel.get(['itemStyle', 'radiusPercent']);
if (radiusPercent != null) {
// useful variables for custom percentage calculations in formatters etc.
params.max = data.getDataExtent(valueDim)[1];
params.sum = data.getSum(valueDim);
}
return params;
}

Expand Down Expand Up @@ -299,6 +318,11 @@ class PieSeriesModel extends SeriesModel<PieSeriesOption> {
opacity: 1
},

showBackground: false,
backgroundStyle: {
opacity: 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting opacity: 1 by default is confusing and unconvenient. How about make it 0.25 by default?

},

labelLayout: {
// Hide the overlapped label.
hideOverlap: true
Expand Down
55 changes: 54 additions & 1 deletion src/chart/pie/PieView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@
*/


import { extend, retrieve3 } from 'zrender/src/core/util';
import { extend, defaults, retrieve3 } from 'zrender/src/core/util';
import * as graphic from '../../util/graphic';
import { setStatesStylesFromModel, toggleHoverEmphasis } from '../../util/states';
import ChartView from '../../view/Chart';
import GlobalModel from '../../model/Global';
import ExtensionAPI from '../../core/ExtensionAPI';
import { Payload, ColorString } from '../../util/types';
import {SectorProps} from 'zrender/src/graphic/shape/Sector';
import SeriesData from '../../data/SeriesData';
import PieSeriesModel, {PieDataItemOption} from './PieSeries';
import labelLayout from './labelLayout';
Expand Down Expand Up @@ -236,6 +237,9 @@ class PieView extends ChartView {
private _data: SeriesData;
private _emptyCircleSector: graphic.Sector;

private _backgroundGroup: graphic.Group;
private _backgroundEls: graphic.Sector[] = [];

render(seriesModel: PieSeriesModel, ecModel: GlobalModel, api: ExtensionAPI, payload: Payload): void {
const data = seriesModel.getData();

Expand Down Expand Up @@ -268,12 +272,43 @@ class PieView extends ChartView {
group.add(sector);
}


const animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;
const drawBackground = seriesModel.get('showBackground', true);
const basicOuterRadius = getBasicPieLayout(seriesModel, api).r;
const bgStyle = seriesModel.getModel('backgroundStyle').getItemStyle();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If data.backgroundStyle is not supported, how should developers set each pie piece to be a different color other than the default colors? I would suggest supporting data.backgroundStyle but not data.showBackground (only series.showBackground is supported).


const bgEls: PieView['_backgroundEls'] = [];
const existBgEls = this._backgroundEls;

function createBackground(idx: number) {
const bgEl = new graphic.Sector({
shape: data.getItemLayout(idx),
silent: true,
z2: 0
});
bgEl.setShape('r', basicOuterRadius);

const style = data.getItemVisual(idx, 'style');
const visualColor = style && style.fill as ColorString;
bgEl.useStyle(extend(
// inherit item color if no background color specified
{fill: visualColor},
bgStyle
));
return bgEl;
}

data.diff(oldData)
.add(function (idx) {
const piePiece = new PiePiece(data, idx, startAngle);

data.setItemGraphicEl(idx, piePiece);

if (drawBackground) {
bgEls[idx] = createBackground(idx);
}

group.add(piePiece);
})
.update(function (newIdx, oldIdx) {
Expand All @@ -283,6 +318,15 @@ class PieView extends ChartView {

piePiece.off('click');

if (drawBackground) {
bgEls[newIdx] = existBgEls[oldIdx] || createBackground(newIdx);
const shape = defaults(
{r: basicOuterRadius},
data.getItemLayout(newIdx)
);
graphic.updateProps<SectorProps>(bgEls[newIdx], {shape}, animationModel, newIdx);
}

group.add(piePiece);
data.setItemGraphicEl(newIdx, piePiece);
})
Expand All @@ -292,6 +336,15 @@ class PieView extends ChartView {
})
.execute();

this._backgroundGroup ||= new graphic.Group();
this._backgroundGroup.removeAll();

for (const bgEl of bgEls) {
this._backgroundGroup.add(bgEl);
}
group.add(this._backgroundGroup);
this._backgroundEls = bgEls;

labelLayout(seriesModel);

// Always use initial animation.
Expand Down
24 changes: 21 additions & 3 deletions src/chart/pie/pieLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export default function pieLayout(
const clockwise = seriesModel.get('clockwise');

const roseType = seriesModel.get('roseType');
const radiusPercent = seriesModel.get(['itemStyle', 'radiusPercent']);
const stillShowZeroSum = seriesModel.get('stillShowZeroSum');

// [0...max]
Expand Down Expand Up @@ -188,6 +189,25 @@ export default function pieLayout(
actualEndAngle = endAngle - halfPadAngle;
}

let outerRadius = r;
if (radiusPercent != null) {
let scale = 0;
if (zrUtil.isFunction(radiusPercent)) {
// calculate the radius of the current pie item based on the scale from the user-defined function
scale = radiusPercent(seriesModel.getDataParams(idx)) || 0;
}
else if (zrUtil.isNumber(radiusPercent)) {
scale = radiusPercent;
}
// scale should always be between 0 and 1
scale = Math.max(0, Math.min(scale, 1));
// r0 is used here to scale radius properly in case of 'donut' style.
outerRadius = (r - r0) * scale + r0;
}
else if (roseType) {
outerRadius = linearMap(value, extent, [r0, r]);
}

data.setItemLayout(idx, {
angle: angle,
startAngle: actualStartAngle,
Expand All @@ -196,9 +216,7 @@ export default function pieLayout(
cx: cx,
cy: cy,
r0: r0,
r: roseType
? linearMap(value, extent, [r0, r])
: r
r: outerRadius
});

currentAngle = endAngle;
Expand Down