Skip to content

Commit 52ca054

Browse files
b84330808claude
andcommitted
fix(pie): clear stale leader lines when outside labels move back inside
A redraw without a recalc (for example a resize through relayout or react) reuses the calcdata points. The plot step set labelExtraX, labelExtraY and yLabelMid only for labels that were outside on the current draw. A label that moved back inside kept the values of the previous draw. scootLabels then treated the label as an outside label, and plotTextLines drew its old leader line and shifted the other labels. Reset this state for every slice at the start of each draw. Fixes #4979 and #5616. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 8c66898 commit 52ca054

3 files changed

Lines changed: 46 additions & 2 deletions

File tree

‎draftlogs/0000_fix.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Remove stale leader lines and label offsets of pie slices when the labels move back inside after a resize [[#0000](https://github.com/plotly/plotly.js/pull/0000)]

‎src/traces/pie/plot.js‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ function plot(gd, cdModule) {
5454
var hasOutsideText = false;
5555

5656
slices.each(function (pt, i) {
57+
// Clear the outside-label state of the previous draw.
58+
// Otherwise a label that moved back inside keeps its old leader line and offset.
59+
pt.yLabelMin = undefined;
60+
pt.yLabelMid = undefined;
61+
pt.yLabelMax = undefined;
62+
pt.labelExtraX = 0;
63+
pt.labelExtraY = 0;
64+
5765
if (pt.hidden) {
5866
d3.select(this).selectAll('path,g').remove();
5967
return;
@@ -219,8 +227,6 @@ function plot(gd, cdModule) {
219227
pt.yLabelMin = targetY - textBB.height / 2;
220228
pt.yLabelMid = targetY;
221229
pt.yLabelMax = targetY + textBB.height / 2;
222-
pt.labelExtraX = 0;
223-
pt.labelExtraY = 0;
224230
hasOutsideText = true;
225231
}
226232

‎test/jasmine/tests/pie_test.js‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,43 @@ describe('pie relayout', function() {
16711671
})
16721672
.then(done, done.fail);
16731673
});
1674+
1675+
it('removes leader lines and label offsets that a larger size no longer needs', (done) => {
1676+
const labels = [];
1677+
const values = [];
1678+
for (let i = 0; i < 8; i++) {
1679+
labels.push(`Label ${i}`);
1680+
values.push(i < 4 ? 20 : 3);
1681+
}
1682+
const data = [{ type: 'pie', labels, values, textposition: 'auto', textinfo: 'label' }];
1683+
const largeLayout = { width: 1000, height: 1000, showlegend: false };
1684+
const countTextLines = () => d3SelectAll('.pielayer path.textline').size();
1685+
const getTextTransforms = () => {
1686+
const transforms = [];
1687+
d3SelectAll(SLICES_TEXT_SELECTOR).each(function () {
1688+
transforms.push(this.getAttribute('transform'));
1689+
});
1690+
return transforms;
1691+
};
1692+
let textLinesAfterRelayout;
1693+
let transformsAfterRelayout;
1694+
1695+
Plotly.newPlot(gd, data, { width: 300, height: 300, showlegend: false })
1696+
.then(() => {
1697+
expect(countTextLines()).toBeGreaterThan(0, 'leader lines at the small size');
1698+
return Plotly.relayout(gd, { width: largeLayout.width, height: largeLayout.height });
1699+
})
1700+
.then(() => {
1701+
textLinesAfterRelayout = countTextLines();
1702+
transformsAfterRelayout = getTextTransforms();
1703+
return Plotly.newPlot(gd, data, largeLayout);
1704+
})
1705+
.then(() => {
1706+
expect(textLinesAfterRelayout).toBe(countTextLines(), 'leader lines after relayout');
1707+
expect(transformsAfterRelayout).toEqual(getTextTransforms());
1708+
})
1709+
.then(done, done.fail);
1710+
});
16741711
});
16751712

16761713
describe('Test pie interactions edge cases:', function() {

0 commit comments

Comments
 (0)