Skip to content

Commit

Permalink
fix: multi-axis tooltip/cursor formatting, proper extent for multi-ax…
Browse files Browse the repository at this point in the history
…is (#281)
  • Loading branch information
jtribe32 authored Mar 22, 2022
1 parent 9feb503 commit fc2f80f
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 64 deletions.
6 changes: 3 additions & 3 deletions src/components/Cursors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ function Cursor<TDatum>(props: {
const [focusedDatum] = focusedDatumState
const latestFocusedDatum = useLatestWhen(focusedDatum, !!focusedDatum)

const secondaryAxis = secondaryAxes.find(
d => d.id === props.options.axisId || latestFocusedDatum?.secondaryAxisId
)!
const secondaryAxis =
secondaryAxes.find(d => d.id === latestFocusedDatum?.secondaryAxisId) ??
secondaryAxes[0]

const axis = props.primary ? primaryAxis : secondaryAxis

Expand Down
24 changes: 17 additions & 7 deletions src/components/TooltipRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ function TooltipRenderer<TDatum>(props: TooltipRendererProps<TDatum>) {
return null
}

const { primaryAxis, secondaryAxis, getDatumStyle, focusedDatum } = props
const {
primaryAxis,
secondaryAxis,
getDatumStyle,
focusedDatum,
secondaryAxes,
} = props

const { tooltip, dark } = props.getOptions()

Expand Down Expand Up @@ -239,6 +245,10 @@ function TooltipRenderer<TDatum>(props: TooltipRendererProps<TDatum>) {
{visibleSortedGroupDatums.map((sortedDatum, i) => {
const active = sortedDatum === focusedDatum

const datumSecondaryAxis = secondaryAxes.find(
d => d.id === sortedDatum.secondaryAxisId
)

return (
<tr
key={i}
Expand Down Expand Up @@ -280,9 +290,9 @@ function TooltipRenderer<TDatum>(props: TooltipRendererProps<TDatum>) {
textAlign: 'right',
}}
>
{(secondaryAxis as AxisTime<any>).formatters.tooltip(
sortedDatum.secondaryValue
)}
{(
datumSecondaryAxis as AxisTime<any>
).formatters.tooltip(sortedDatum.secondaryValue)}
</td>
</React.Fragment>
) : tooltip.groupingMode === 'secondary' ? (
Expand All @@ -306,9 +316,9 @@ function TooltipRenderer<TDatum>(props: TooltipRendererProps<TDatum>) {
textAlign: 'right',
}}
>
{(secondaryAxis as AxisTime<any>).formatters.tooltip(
sortedDatum.secondaryValue
)}
{(
datumSecondaryAxis as AxisTime<any>
).formatters.tooltip(sortedDatum.secondaryValue)}
</td>
</React.Fragment>
)}
Expand Down
21 changes: 10 additions & 11 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ export type ChartOptions<TDatum> = {
primaryAxis: AxisOptions<TDatum>
secondaryAxes: AxisOptions<TDatum>[]
padding?:
| number
| {
left?: number
right?: number
top?: number
bottom?: number
}
| number
| {
left?: number
right?: number
top?: number
bottom?: number
}
getSeriesStyle?: (
series: Series<TDatum>,
status: SeriesFocusStatus
Expand Down Expand Up @@ -53,9 +53,9 @@ export type ChartOptions<TDatum> = {
tooltip?: boolean | TooltipOptions<TDatum>
useIntersectionObserver?: boolean
intersectionObserverRootMargin?:
| `${number}px`
| `${number}px ${number}px`
| `${number}px ${number}px ${number}px ${number}px`
| `${number}px`
| `${number}px ${number}px`
| `${number}px ${number}px ${number}px ${number}px`
}

export type RequiredChartOptions<TDatum> = TSTB.Object.Required<
Expand Down Expand Up @@ -493,7 +493,6 @@ export type CursorOptions = {
show?: boolean
showLine?: boolean
showLabel?: boolean
axisId?: string
onChange?: (value: any) => void
}

Expand Down
92 changes: 49 additions & 43 deletions src/utils/buildAxis.linear.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,16 @@ export default function buildAxisLinear<TDatum>(
// Give the scale a home
return options.scaleType === 'time' || options.scaleType === 'localTime'
? buildTimeAxis(
isPrimary,
options,
series,
allDatums,
isVertical,
range,
outerRange
)
isPrimary,
options,
series,
allDatums,
isVertical,
range,
outerRange
)
: options.scaleType === 'linear' || options.scaleType === 'log'
? buildLinearAxis(
? buildLinearAxis(
isPrimary,
options,
series,
Expand All @@ -91,11 +91,11 @@ export default function buildAxisLinear<TDatum>(
range,
outerRange
)
: options.scaleType === 'band'
? buildBandAxis(isPrimary, options, series, isVertical, range, outerRange)
: (() => {
throw new Error('Invalid scale type')
})()
: options.scaleType === 'band'
? buildBandAxis(isPrimary, options, series, isVertical, range, outerRange)
: (() => {
throw new Error('Invalid scale type')
})()
}

function buildTimeAxis<TDatum>(
Expand All @@ -111,6 +111,11 @@ function buildTimeAxis<TDatum>(

let isInvalid = false

series = isPrimary ? series : series
.filter(s => s.secondaryAxisId === options.id)

allDatums = isPrimary ? allDatums : allDatums.filter(d => d.secondaryAxisId === options.id)

// Now set the range
const scale = scaleFn(range)

Expand Down Expand Up @@ -144,7 +149,7 @@ function buildTimeAxis<TDatum>(
}

if (minValue === undefined || maxValue === undefined) {
console.info('Invalid scale min/max was detect for a chart:', {
console.info('Invalid scale min/max', {
options,
series,
range,
Expand Down Expand Up @@ -242,28 +247,32 @@ function buildLinearAxis<TDatum>(

let isInvalid = false

series = isPrimary ? series : series
.filter(s => s.secondaryAxisId === options.id)

allDatums = isPrimary ? allDatums : allDatums.filter(d => d.secondaryAxisId === options.id)

if (options.stacked) {
stackSeries(series, options)
}

let [minValue, maxValue] = options.stacked
? extent(
series
.map(s =>
s.datums.map(datum => {
const value = options.getValue(datum.originalDatum)
datum[isPrimary ? 'primaryValue' : 'secondaryValue'] = value

return datum.stackData ?? []
})
)
.flat(2) as unknown as number[]
)
series
.map(s =>
s.datums.map(datum => {
const value = options.getValue(datum.originalDatum)
datum[isPrimary ? 'primaryValue' : 'secondaryValue'] = value
return datum.stackData ?? []
})
)
.flat(2) as unknown as number[]
)
: extent(allDatums, datum => {
const value = options.getValue(datum.originalDatum)
datum[isPrimary ? 'primaryValue' : 'secondaryValue'] = value
return value
})
const value = options.getValue(datum.originalDatum)
datum[isPrimary ? 'primaryValue' : 'secondaryValue'] = value
return value
})

let shouldNice = options.shouldNice

Expand Down Expand Up @@ -310,7 +319,7 @@ function buildLinearAxis<TDatum>(
})
minValue = minValue ?? 0
maxValue = maxValue ?? 0
// throw new Error('Invalid scale min/max')
// throw new Error('Invalid scale min/max'
}

// Set the domain
Expand Down Expand Up @@ -465,13 +474,12 @@ function stackSeries<TDatum>(
series: Series<TDatum>[],
axisOptions: AxisOptions<TDatum>
) {
const axisSeries = series.filter(s => s.secondaryAxisId === axisOptions.id)
const seriesIndices = Object.keys(axisSeries)
const seriesIndices = Object.keys(series)
const stacker = stack()
.keys(seriesIndices)
.value((_, seriesIndex, index) => {
const originalDatum =
axisSeries[Number(seriesIndex)]?.datums[index]?.originalDatum
series[Number(seriesIndex)]?.datums[index]?.originalDatum

const val =
typeof originalDatum !== 'undefined'
Expand All @@ -488,7 +496,7 @@ function stackSeries<TDatum>(

const stacked = stacker(
Array.from({
length: axisSeries.sort((a, b) => b.datums.length - a.datums.length)[0]
length: series.sort((a, b) => b.datums.length - a.datums.length)[0]
.datums.length,
})
)
Expand All @@ -499,11 +507,11 @@ function stackSeries<TDatum>(
for (let i = 0; i < s.length; i++) {
const datum = s[i]

if (axisSeries[sIndex].datums[i]) {
if (series[sIndex].datums[i]) {
// @ts-ignore
datum.data = axisSeries[sIndex].datums[i]
datum.data = series[sIndex].datums[i]

axisSeries[sIndex].datums[i].stackData =
series[sIndex].datums[i].stackData =
datum as unknown as StackDatum<TDatum>
}
}
Expand Down Expand Up @@ -561,9 +569,7 @@ function buildSeriesBandScale<TDatum>(
primaryBandScale: ScaleBand<number>,
series: Series<TDatum>[]
) {
const bandDomain = d3Range(
series.filter(d => d.secondaryAxisId === options.id).length
)
const bandDomain = d3Range(series.length)

const seriesBandScale = scaleBand(bandDomain, [
0,
Expand All @@ -572,11 +578,11 @@ function buildSeriesBandScale<TDatum>(
.round(false)
.paddingOuter(
options.outerSeriesBandPadding ??
(options.outerBandPadding ? options.outerBandPadding / 2 : 0)
(options.outerBandPadding ? options.outerBandPadding / 2 : 0)
)
.paddingInner(
options.innerSeriesBandPadding ??
(options.innerBandPadding ? options.innerBandPadding / 2 : 0)
(options.innerBandPadding ? options.innerBandPadding / 2 : 0)
)

const scale = (seriesIndex: number) =>
Expand Down

0 comments on commit fc2f80f

Please sign in to comment.