Skip to content

Commit

Permalink
Component | Axis: Tick label collision iterations and transitions
Browse files Browse the repository at this point in the history
  • Loading branch information
rokotyan committed Oct 30, 2024
1 parent de26885 commit 9a852f2
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 21 deletions.
45 changes: 25 additions & 20 deletions packages/ts/src/components/axis/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ export class Axis<Datum> extends XYComponentCore<Datum, AxisConfigInterface<Datu
const tickText = selection.selectAll<SVGTextElement, number | Date>('g.tick > text')
.filter(tickValue => tickValues.some((t: number | Date) => isEqual(tickValue, t))) // We use isEqual to compare Dates
.classed(s.tickLabel, true)
.classed(s.tickLabelHideable, Boolean(config.tickTextHideOverlapping))
.style('fill', config.tickTextColor) as Selection<SVGTextElement, number, SVGGElement, unknown> | Selection<SVGTextElement, Date, SVGGElement, unknown>


Expand Down Expand Up @@ -281,29 +282,33 @@ export class Axis<Datum> extends XYComponentCore<Datum, AxisConfigInterface<Datu
node._visible = true
})

// We do three iterations because not all overlapping labels can be resolved in the first iteration
const numIterations = 3
for (let i = 0; i < numIterations; i += 1) {
// Run collision detection and set labels visibility
selection.each((d, i, elements) => {
const label1 = elements[i] as SVGOverlappingTextElement
const isLabel1Visible = label1._visible
if (!isLabel1Visible) return

// Calculate bounding rect of point's label
const label1BoundingRect = label1.getBoundingClientRect()

for (let j = i + 1; j < elements.length; j += 1) {
if (i === j) continue
const label2 = elements[j] as SVGOverlappingTextElement
const isLabel2Visible = label2._visible
if (isLabel2Visible) {
const label2BoundingRect = label2.getBoundingClientRect()
const intersect = rectIntersect(label1BoundingRect, label2BoundingRect, -5)
if (intersect) {
label2._visible = false
break
selection.each((d, i, elements) => {
const label1 = elements[i] as SVGOverlappingTextElement
const isLabel1Visible = label1._visible
if (!isLabel1Visible) return

// Calculate bounding rect of point's label
const label1BoundingRect = label1.getBoundingClientRect()

for (let j = i + 1; j < elements.length; j += 1) {
if (i === j) continue
const label2 = elements[j] as SVGOverlappingTextElement
const isLabel2Visible = label2._visible
if (isLabel2Visible) {
const label2BoundingRect = label2.getBoundingClientRect()
const intersect = rectIntersect(label1BoundingRect, label2BoundingRect, -5)
if (intersect) {
label2._visible = false
break
}
}
}
}
})
})
}

// Hide the overlapping labels
selection.each((d, i, elements) => {
Expand Down
8 changes: 7 additions & 1 deletion packages/ts/src/components/axis/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const globalStyles = injectGlobal`
--vis-axis-tick-label-text-decoration: none;
--vis-axis-label-font-size: 14px;
--vis-axis-tick-line-width: 1px;
--vis-axis-tick-label-hide-transition: opacity 400ms ease-in-out;
--vis-axis-grid-line-width: 1px;
/* --vis-axis-domain-line-width: // Undefined by default to allow fallback to var(--vis-axis-grid-line-width) */
Expand Down Expand Up @@ -99,7 +100,6 @@ export const tick = css`
text-decoration: var(--vis-axis-tick-label-text-decoration);
stroke: none;
}
`

export const label = css`
Expand All @@ -113,3 +113,9 @@ export const label = css`
export const tickLabel = css`
label: tick-label;
`

export const tickLabelHideable = css`
label: tick-label-hideable;
opacity: 0;
transition: var(--vis-axis-tick-label-hide-transition);
`

0 comments on commit 9a852f2

Please sign in to comment.