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

chore(labels): add option to prevent overlapping labels #1428

Open
wants to merge 4 commits into
base: main
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/charts/PieChart/PieChart.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,23 @@ export function Labels() {
return root;
}

export function OverlappingLabels() {
const root = document.createElement('div');

new PieChart(
root,
{
labels: ['Big Slice', 11231231, 'Test the string', new Date(), 124124124],
series: [96, 1, 1, 1, 1]
},
{
preventOverlappingLabelOffset: 12
}
);

return root;
}

export function LabelInterpolation() {
const root = document.createElement('div');
const data = {
Expand Down
32 changes: 30 additions & 2 deletions src/charts/PieChart/PieChart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ const defaultOptions = {
// Label direction can be 'neutral', 'explode' or 'implode'. The labels anchor will be positioned based on those settings as well as the fact if the labels are on the right or left side of the center of the chart. Usually explode is useful when labels are positioned far away from the center.
labelDirection: 'neutral',
// If true empty values will be ignored to avoid drawing unnecessary slices and labels
ignoreEmptyValues: false
ignoreEmptyValues: false,
// If Nonzero check if a label has overlapping text then move it the number of pixels up and left (Should be half of label font size + 1 but you can tweak it as you prefer)
preventOverlappingLabelOffset: 0
};

/**
Expand Down Expand Up @@ -199,6 +201,7 @@ export class PieChart extends BaseChart<PieChartEventsTypes> {
const normalizedData = normalizeData(data);
const seriesGroups: Svg[] = [];
let labelsGroup: Svg;
const labelPositions: any[] = [];
let labelRadius: number;
let startAngle = options.startAngle;

Expand Down Expand Up @@ -387,7 +390,7 @@ export class PieChart extends BaseChart<PieChartEventsTypes> {

// If we need to show labels we need to add the label for this slice now
if (options.showLabel) {
let labelPosition;
let labelPosition: any;

if (data.series.length === 1) {
// If we have only 1 series, we can position the label in the center of the pie
Expand Down Expand Up @@ -421,6 +424,31 @@ export class PieChart extends BaseChart<PieChartEventsTypes> {
);

if (interpolatedValue || interpolatedValue === 0) {
if (options.preventOverlappingLabelOffset) {
const textSize = options.preventOverlappingLabelOffset;

const labelMover = (lp: any, item: any) => {
const length = // Tested with all three data types string, number, and date.
((normalizedData.labels[index] + '') as string)?.length ?? 1; // Default to 1 character length

if (
lp.y > item.y - textSize &&
lp.y < item.y + textSize &&
lp.x > item.x - length * textSize &&
lp.x < item.x + length * textSize
) {
lp.y -= textSize;
lp.x -= textSize;
labelMover(lp, item);
}
};

labelPositions.forEach(item => {
labelMover(labelPosition, item);
});
labelPositions.push(labelPosition);
}

const labelElement = labelsGroup
.elem(
'text',
Expand Down
7 changes: 6 additions & 1 deletion src/charts/PieChart/PieChart.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ export interface PieChartOptions extends Omit<Options, 'axisX' | 'axisY'> {
* If true empty values will be ignored to avoid drawing unnecessary slices and labels
*/
ignoreEmptyValues?: boolean;
/**
* If nonzero labels will not overlap.
*/
preventOverlappingLabelOffset?: number;
}

export type PieChartOptionsWithDefaults = RequiredKeys<
Expand All @@ -93,7 +97,8 @@ export type PieChartOptionsWithDefaults = RequiredKeys<
| 'labelOffset'
| 'labelPosition'
| 'labelInterpolationFnc'
| 'labelDirection',
| 'labelDirection'
| 'preventOverlappingLabelOffset',
'classNames'
>;

Expand Down