Skip to content

fix: prevent stroke gap on single-slice pie/donut charts (Closes #5084) - #5267

Open
waterWang wants to merge 4 commits into
apexcharts:mainfrom
waterWang:fix/pie-stroke-single-slice-5084
Open

fix: prevent stroke gap on single-slice pie/donut charts (Closes #5084)#5267
waterWang wants to merge 4 commits into
apexcharts:mainfrom
waterWang:fix/pie-stroke-single-slice-5084

Conversation

@waterWang

Copy link
Copy Markdown
Contributor

Description

Fixes #5084 — when a pie or donut chart has only one data point, the slice occupies the full 360 degrees. With stroke enabled, the stroke at the start/end junction creates a visible gap from the center to the edge of the circle.

Fix

In src/charts/Pie.js, set strokeWidth to 0 when there is only one slice (sectorAngleArr.length === 1), so no stroke is applied to the single full-circle path. Multi-slice charts are unaffected and keep their configured stroke.

Tests

Added regression coverage in tests/unit/pie-chart.spec.js:

  • Single-slice pie chart renders with stroke-width: 0
  • Multi-slice pie chart keeps the configured stroke-width

All 39 tests in pie-chart.spec.js pass.

Acceptance Criteria

  • Single-slice pie/donut chart with stroke shows no gap
  • Multi-slice charts keep their stroke
  • Regression tests added and passing

…charts#5084)

When a pie or donut chart has only one data point, the slice occupies the
full 360 degrees. The stroke at the start/end junction creates a visible
gap from the center to the edge of the circle.

Fix: set strokeWidth to 0 when there is only one slice, so no stroke is
applied to the single full-circle path.
@junedchhipa

Copy link
Copy Markdown
Contributor

Thanks for digging into #5084. The diagnosis is right, but I'd like some changes before this can land: the fix is both incomplete and over-broad, and the PR carries an unrelated axis-scale regression.

I checked all of the points below by running the PR branch locally.


1. Blocker: unrelated breaking change in src/modules/Scales.js

-        w.config.xaxis.max === undefined ? w.config.xaxis.stepSize : undefined,
+        w.config.xaxis.stepSize,

Nothing in the description mentions this hunk. It reverts a guard added deliberately in ba757dba5 (bubble chart data parsing), and it breaks xaxis.max. With xaxis: { min: 0, max: 7, stepSize: 5, tickAmount: 6 }, gl.xAxisScale.result becomes:

branch result
main [0, 1.17, 2.34, 3.51, 4.68, 5.85, 7.02]
this PR [0, 5, 10, 15, 20, 25, 30]

The user-set max: 7 is discarded and the axis runs to 30. No unit test covers it (the unit suite is green on both branches), so this would ship unnoticed. Please drop this hunk from the PR.

2. The fix misses the actual reported case

sectorAngleArr.length === 1 keys off the series count, not the slice angle. A slice reaches 360 degrees whenever its siblings are zero. On this branch, series: [44, 0, 0] with stroke: { show: true, width: 4 } renders:

[{"stroke-width":"4","angle":"360"},{"stroke-width":"4","angle":"0"},{"stroke-width":"4","angle":"0"}]

Full-circle slice, stroke still 4, so the seam from #5084 is still visible. That is a common data shape (filtered data, or a single non-zero category).

3. The fix regresses a case that was never broken

The same condition fires for single-series semicircle pies, which are not full circles and legitimately want an outline. With plotOptions.pie: { startAngle: -90, endAngle: 90 } and series: [44]:

[{"stroke-width":"0","angle":"180"}]

The half-disc silently loses its configured 4px border. Single-slice donuts ([{"stroke-width":"0","angle":"360"}]) also lose the inner hollow border, which is a deliberate design element for a lot of users rather than an artifact.

Related: Pie.js:61 still subtracts stroke.width from w.globals.radialSize, so a single-slice pie now draws smaller than it should for a stroke that no longer exists.

4. Suggested direction: fix the geometry, not the stroke

The root cause is in getPiePath. The "prevent overlap" clamp pulls endDeg back by 0.01 degrees:

if (Math.ceil(endDeg) >= this.fullAngle + (...)) {
  endDeg = this.fullAngle + (...) - 0.01
}

and the pie branch then appends L centerX centerY L x1 y1. For a 360 degree span those two nearly coincident radial lines to the center are exactly what the stroke paints as a line from center to edge.

The targeted fix is a special case in getPiePath when the span covers the whole angle (spanDeg >= fullAngle && fullAngle >= 360):

  • pie / polarArea: emit a closed circle (two 180 degree arcs plus z), with no radial lines to the center
  • donut: emit the outer circle plus a reverse-sweep inner circle as one closed path (an annulus)

That keeps the configured stroke rendering correctly as a clean ring outline, fixes the [44, 0, 0] and legend-collapsed cases for free, and leaves semicircles untouched.

5. Tests

  • tests/unit/pie-stroke-repro.spec.js looks like a leftover scratch repro. It duplicates the two tests already added to pie-chart.spec.js, imports beforeEach without using it, and has no trailing newline. Please delete it.
  • In pie-chart.spec.js, the new describe('stroke') block is inserted after the }) that closes describe('Pie chart'), so it ends up as a top-level block with 2-space indentation, wedged between the pie section and the DONUT CHART TESTS banner comment. It runs, but it is in the wrong place and mis-indented.
  • Missing coverage for the cases that break it: [44, 0, 0], a single-slice semicircle, and a single-slice donut.

To move forward

  1. Drop the Scales.js hunk.
  2. Rework the fix in getPiePath to emit a true circle / annulus for full-angle slices instead of zeroing the stroke.
  3. Delete the duplicate spec file and re-nest the new tests inside describe('Pie chart').
  4. Add cases for zero-valued siblings, semicircles, and donuts.

Happy to review again once those are in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stroke with one series in pie chart

2 participants