Skip to content

Commit

Permalink
Revert "refactor(pie-label): 饼图label的调整,移动至layout中处理(需要将labelItem传递至l…
Browse files Browse the repository at this point in the history
…ayoutFn)"

This reverts commit 0d22912.
  • Loading branch information
simaQ committed Mar 9, 2020
1 parent 3f30741 commit 33703ec
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 197 deletions.
4 changes: 1 addition & 3 deletions src/component/labels.ts
Expand Up @@ -149,14 +149,12 @@ export default class Labels {
}

private renderLabel(cfg: LabelItem, container: IGroup) {
const { id, data, mappingData, coordinate, animate, content, offset } = cfg;
const { id, data, mappingData, coordinate, animate, content } = cfg;
const shapeAppendCfg = {
id,
data,
origin: mappingData,
coordinate,
/** 把 labelItem 传递下去 */
labelItem: cfg,
};
const labelGroup = container.addGroup({
name: 'label',
Expand Down
192 changes: 0 additions & 192 deletions src/geometry/label/layout/distribute.ts

This file was deleted.

151 changes: 151 additions & 0 deletions src/geometry/label/pie.ts
Expand Up @@ -14,6 +14,95 @@ function getEndPoint(center, angle, r) {
};
}

function antiCollision(labels, lineHeight, plotRange, center, isRight) {
// adjust y position of labels to avoid overlapping
let overlapping = true;
const start = plotRange.start;
const end = plotRange.end;
const startY = Math.min(start.y, end.y);
let totalHeight = Math.abs(start.y - end.y);
let i;

let maxY = 0;
let minY = Number.MIN_VALUE;
const boxes = labels.map((label) => {
if (label.y > maxY) {
maxY = label.y;
}
if (label.y < minY) {
minY = label.y;
}
return {
size: lineHeight,
targets: [label.y - startY],
};
});
minY -= startY;
if (maxY - startY > totalHeight) {
totalHeight = maxY - startY;
}

while (overlapping) {
/* eslint no-loop-func: 0 */
boxes.forEach((box) => {
const target = (Math.min.apply(minY, box.targets) + Math.max.apply(minY, box.targets)) / 2;
box.pos = Math.min(Math.max(minY, target - box.size / 2), totalHeight - box.size);
// box.pos = Math.max(0, target - box.size / 2);
});

// detect overlapping and join boxes
overlapping = false;
i = boxes.length;
while (i--) {
if (i > 0) {
const previousBox = boxes[i - 1];
const box = boxes[i];
if (previousBox.pos + previousBox.size > box.pos) {
// overlapping
previousBox.size += box.size;
previousBox.targets = previousBox.targets.concat(box.targets);

// overflow, shift up
if (previousBox.pos + previousBox.size > totalHeight) {
previousBox.pos = totalHeight - previousBox.size;
}
boxes.splice(i, 1); // removing box
overlapping = true;
}
}
}
}

i = 0;
// step 4: normalize y and adjust x
boxes.forEach((b) => {
let posInCompositeBox = startY + lineHeight / 2; // middle of the label
b.targets.forEach(() => {
labels[i].y = b.pos + posInCompositeBox;
posInCompositeBox += lineHeight;
i++;
});
});

// (x - cx)^2 + (y - cy)^2 = totalR^2
labels.forEach((label) => {
const rPow2 = label.r * label.r;
const dyPow2 = Math.pow(Math.abs(label.y - center.y), 2);
if (rPow2 < dyPow2) {
label.x = center.x;
} else {
const dx = Math.sqrt(rPow2 - dyPow2);
if (!isRight) {
// left
label.x = center.x - dx;
} else {
// right
label.x = center.x + dx;
}
}
});
}

/**
* 饼图 label
*/
Expand All @@ -26,6 +115,14 @@ export default class PieLabel extends PolarLabel {
return offset || 0;
}

protected adjustItems(items: LabelItem[]) {
const offset = items[0] ? items[0].offset : 0;
if (offset > 0) {
items = this.distribute(items, offset);
}
return super.adjustItems(items);
}

// 连接线
protected lineToLabel(label: LabelItem) {
const coordinate = this.coordinate;
Expand Down Expand Up @@ -123,4 +220,58 @@ export default class PieLabel extends PolarLabel {
r,
};
}

// distribute labels
private distribute(labels, offset) {
const coordinate = this.coordinate;
// @ts-ignore
const radius = coordinate.getRadius();
const lineHeight = get(this.geometry.theme, ['pieLabels', 'labelHeight'], 14);
const center = coordinate.getCenter();
const totalR = radius + offset;
const totalHeight = totalR * 2 + lineHeight * 2;
const plotRange = {
start: coordinate.start,
end: coordinate.end,
};

// step 1: separate labels
const halves = [
[], // left
[], // right
];
labels.forEach((label) => {
if (!label) {
return;
}
if (label.textAlign === 'right') {
// left
halves[0].push(label);
} else {
// right or center will be put on the right side
halves[1].push(label);
}
});

halves.forEach((half, index) => {
// step 2: reduce labels
const maxLabelsCountForOneSide = totalHeight / lineHeight;
if (half.length > maxLabelsCountForOneSide) {
half.sort((a, b) => {
// sort by percentage DESC
return b['..percent'] - a['..percent'];
});
half.splice(maxLabelsCountForOneSide, half.length - maxLabelsCountForOneSide);
}

// step 3: distribute position (x and y)
half.sort((a, b) => {
// sort by y ASC
return a.y - b.y;
});
antiCollision(half, lineHeight, plotRange, center, index);
});

return halves[0].concat(halves[1]);
}
}
2 changes: 0 additions & 2 deletions src/index.ts
Expand Up @@ -76,7 +76,6 @@ registerGeometryLabel('polar', PolarLabel);

// 注册 Geometry label 内置的布局函数
import { registerGeometryLabelLayout } from './core';
import { distribute } from './geometry/label/layout/distribute';
import { limitInCanvas } from './geometry/label/layout/limit-in-canvas';
import { limitInShape } from './geometry/label/layout/limit-in-shape';
import { fixedOverlap, overlap } from './geometry/label/layout/overlap';
Expand All @@ -85,7 +84,6 @@ registerGeometryLabelLayout('overlap', overlap);
registerGeometryLabelLayout('fixed-overlap', fixedOverlap);
registerGeometryLabelLayout('limit-in-shape', limitInShape);
registerGeometryLabelLayout('limit-in-canvas', limitInCanvas);
registerGeometryLabelLayout('distribute', distribute);

// 注册需要的动画执行函数
import { fadeIn, fadeOut } from './animate/animation/fade';
Expand Down

0 comments on commit 33703ec

Please sign in to comment.