Skip to content

Commit

Permalink
Component | Donut: Automatic label placement
Browse files Browse the repository at this point in the history
  • Loading branch information
curran committed Dec 12, 2024
1 parent 44c5a25 commit c2ae7f7
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export const component = (): JSX.Element => {
duration={0}
arcWidth={80}
angleRange={currentAngleRange}
centralLabel="Central Label"
centralSubLabel="Sub-label"
/>
</VisSingleContainer>
)
Expand Down
33 changes: 31 additions & 2 deletions packages/ts/src/components/donut/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export class Donut<Datum> extends ComponentCore<Datum[], DonutConfigInterface<Da
)
const isVerticalHalfDonut = isHalfDonutTop || isHalfDonutBottom
const isHorizontalHalfDonut = isHalfDonutRight || isHalfDonutLeft
const isHalfDonut = isVerticalHalfDonut || isHorizontalHalfDonut

// Compute the bounding box of the donut,
// considering it may be a half-donut
Expand Down Expand Up @@ -162,17 +163,45 @@ export class Donut<Datum> extends ComponentCore<Datum[], DonutConfigInterface<Da

// Label
this.centralLabel
.attr('transform', translate)
.attr('dy', config.centralSubLabel ? '-0.55em' : null)
.text(config.centralLabel ?? null)

this.centralSubLabel
.attr('transform', translate)
.attr('dy', config.centralLabel ? '0.55em' : null)
.text(config.centralSubLabel ?? null)

if (config.centralSubLabelWrap) wrapSVGText(this.centralSubLabel, innerRadius * 1.9)

// Default to position labels at the center
let labelTranslate = translate

// Special case label placement for half donut
if (isHalfDonut) {
// Measure the text
const centralLabelSize = this.centralLabel.node().getBoundingClientRect()
const centralSubLabelSize = this.centralSubLabel.node().getBoundingClientRect()

// Offset labels to align with half donut edges
const halfDonutLabelOffsetX = Math.max(centralLabelSize.width, centralSubLabelSize.width) / 2
const labelTranslateX = isHalfDonutLeft
? -halfDonutLabelOffsetX
: isHalfDonutRight
? halfDonutLabelOffsetX
: 0

const labelTranslateY = isHalfDonutTop
? -centralSubLabelSize.height
: isHalfDonutBottom
? centralLabelSize.height
: 0

labelTranslate = `translate(${translateX + labelTranslateX},${translateY + labelTranslateY})`
}

// Apply label placement
this.centralLabel.attr('transform', labelTranslate)
this.centralSubLabel.attr('transform', labelTranslate)

// Background
this.arcBackground.attr('class', s.background)
.attr('visibility', config.showBackground ? null : 'hidden')
Expand Down

0 comments on commit c2ae7f7

Please sign in to comment.