From d8ab7e1f6a1955c0b2dfbfc7819151e8caa27e90 Mon Sep 17 00:00:00 2001 From: Jacob Parker Date: Wed, 3 Jul 2024 16:32:27 +0100 Subject: [PATCH] AG-12034 Corner radius fixes for sectors --- .../src/chart/series/polar/pieSeries.ts | 11 +++--- .../src/scene/shape/sector.ts | 38 ++++++++++--------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/packages/ag-charts-community/src/chart/series/polar/pieSeries.ts b/packages/ag-charts-community/src/chart/series/polar/pieSeries.ts index 350d87019b1..67d9b11d68d 100644 --- a/packages/ag-charts-community/src/chart/series/polar/pieSeries.ts +++ b/packages/ag-charts-community/src/chart/series/polar/pieSeries.ts @@ -677,12 +677,11 @@ export class PieSeries extends PolarSeries= 0 || inset > 0 ? 'miter' : 'round'; + const insetStrokeWidth = format.stroke != null ? format.strokeWidth : 0; + const radialEdgeInset = Math.max((this.properties.sectorSpacing + insetStrokeWidth) / 2, 0); + sector.radialEdgeInset = radialEdgeInset; + sector.concentricEdgeInset = Math.max(insetStrokeWidth / 2, 0); + sector.lineJoin = this.properties.sectorSpacing >= 0 || radialEdgeInset > 0 ? 'miter' : 'round'; }; this.itemSelection.each((node, datum, index) => updateSectorFn(node, datum, index, false)); diff --git a/packages/ag-charts-community/src/scene/shape/sector.ts b/packages/ag-charts-community/src/scene/shape/sector.ts index fba697748d6..4ef7d8b6d28 100644 --- a/packages/ag-charts-community/src/scene/shape/sector.ts +++ b/packages/ag-charts-community/src/scene/shape/sector.ts @@ -163,7 +163,9 @@ export class Sector extends Path { const innerAngleOffset = this.getAngleOffset(innerRadius); const outerAngleOffset = this.getAngleOffset(outerRadius); - const angleOffset = inner ? this.getAngleOffset(innerRadius + r) : this.getAngleOffset(outerRadius - r); + const angleOffset = inner + ? this.getAngleOffset(Math.sqrt((innerRadius + r) ** 2 - r ** 2)) + : this.getAngleOffset(Math.sqrt((outerRadius - r) ** 2 - r ** 2)); const angle = start ? startAngle + angleOffset + angleSweep : endAngle - angleOffset - angleSweep; const radius = inner ? innerRadius + r : outerRadius - r; @@ -301,7 +303,7 @@ export class Sector extends Path { // radiiScalingFactor doesn't find outer radii factors when the corners are larger than the sector radius // First, scale everything down so every corner radius individually fits within the sector's radial range - const radialLength = outerRadius - innerRadius; + const radialLength = this.outerRadius - this.innerRadius; const maxRadialLength = Math.max( startOuterCornerRadius, startInnerCornerRadius, @@ -352,6 +354,11 @@ export class Sector extends Path { startInnerCornerRadius *= edgesScalingFactor; endInnerCornerRadius *= edgesScalingFactor; + startOuterCornerRadius = Math.max(startOuterCornerRadius - concentricEdgeInset, 0); + endOuterCornerRadius = Math.max(endOuterCornerRadius - concentricEdgeInset, 0); + startInnerCornerRadius = Math.max(startInnerCornerRadius - concentricEdgeInset, 0); + endInnerCornerRadius = Math.max(endInnerCornerRadius - concentricEdgeInset, 0); + let startOuterCornerRadiusAngleSweep = 0; let endOuterCornerRadiusAngleSweep = 0; const startOuterCornerRadiusSweep = startOuterCornerRadius / (outerRadius - startOuterCornerRadius); @@ -359,14 +366,15 @@ export class Sector extends Path { if (startOuterCornerRadiusSweep >= 0 && startOuterCornerRadiusSweep < 1 - delta) { startOuterCornerRadiusAngleSweep = Math.asin(startOuterCornerRadiusSweep); } else { - startOuterCornerRadiusAngleSweep = sweepAngle / 2; + startOuterCornerRadiusAngleSweep = + sweepAngle / 2 - this.getAngleOffset(this.outerRadius + this.innerRadius); const maxStartOuterCornerRadius = outerRadius / (1 / Math.sin(startOuterCornerRadiusAngleSweep) + 1); startOuterCornerRadius = Math.min(maxStartOuterCornerRadius, startOuterCornerRadius); } if (endOuterCornerRadiusSweep >= 0 && endOuterCornerRadiusSweep < 1 - delta) { endOuterCornerRadiusAngleSweep = Math.asin(endOuterCornerRadiusSweep); } else { - endOuterCornerRadiusAngleSweep = sweepAngle / 2; + endOuterCornerRadiusAngleSweep = sweepAngle / 2 - this.getAngleOffset(this.outerRadius + this.innerRadius); const maxEndOuterCornerRadius = outerRadius / (1 / Math.sin(endOuterCornerRadiusAngleSweep) + 1); endOuterCornerRadius = Math.min(maxEndOuterCornerRadius, endOuterCornerRadius); } @@ -439,7 +447,11 @@ export class Sector extends Path { true ); - if (innerAngleExceeded) { + if (!innerAngleExceeded && (startInnerArc?.isValid() === true || innerArc?.isValid() === true)) { + // The first point of the path will be the first point on an arc + // We don't need to call moveTo here - it's implicit + // Not having a moveTo also fixes some issues Chrome has about mitering + } else { // Draw a wedge on a cartesian co-ordinate with radius `sweep` // Inset from bottom - i.e. y = innerRadius // Inset the top - i.e. y = (x - x0) * tan(sweep) @@ -457,22 +469,14 @@ export class Sector extends Path { if (x > 0 && x < outerRadius) { // Even within the formula limits, floating point precision isn't always enough, // so ensure we never go less than the inner radius - r = Math.max(Math.hypot(radialEdgeInset, x), innerRadius); + r = Math.hypot(radialEdgeInset, x); } else { - // Formula limits exceeded - just use the inner radius - r = innerRadius; + // Formula limits exceeded + r = radialEdgeInset; } + r = Math.max(r, innerRadius); const midAngle = startAngle + sweepAngle * 0.5; path.moveTo(centerX + r * Math.cos(midAngle), centerY + r * Math.sin(midAngle)); - } else if (startInnerArc?.isValid() === true || innerArc?.isValid() === true) { - // The first point of the path will be the first point on an arc - // We don't need to call moveTo here - it's implicit - // Not having a moveTo also fixes some issues Chrome has about mitering - } else { - const midAngle = startAngle + sweepAngle / 2; - const cx = innerRadius * Math.cos(midAngle); - const cy = innerRadius * Math.sin(midAngle); - path.moveTo(centerX + cx, centerY + cy); } if (startOuterArc?.isValid() === true) {