Skip to content

Commit

Permalink
fix: mixed axis stacking voronoi
Browse files Browse the repository at this point in the history
  • Loading branch information
tannerlinsley committed Jul 20, 2021
1 parent ac8f167 commit d09fb93
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 55 deletions.
26 changes: 20 additions & 6 deletions src/components/Chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
materializeStyles,
getSeriesStatus,
getDatumStatus,
sortDatums,
sortDatumsBySecondaryPx,
} from '../utils/Utils'
import buildAxisLinear from '../utils/buildAxis.linear'
import { ChartContextProvider } from '../utils/chartContext'
Expand Down Expand Up @@ -70,7 +70,7 @@ function defaultChartOptions<TDatum>(
getSeriesOrder:
options.getSeriesOrder ?? ((series: Series<TDatum>[]) => series),
interactionMode: options.interactionMode ?? 'primary',
showVoronoi: options.showVoronoi ?? false,
showVoronoi: options.showVoronoi ?? true,
defaultColors: options.defaultColors ?? defaultColorScheme,
useIntersectionObserver: options.useIntersectionObserver ?? true,
intersectionObserverRootMargin:
Expand Down Expand Up @@ -269,7 +269,10 @@ function ChartInner<TDatum>({
optionsWithScaleType.stacked = true
}

return { position: !i ? 'left' : 'right', ...optionsWithScaleType }
return {
position: !i ? 'left' : 'right',
...optionsWithScaleType,
}
}
)
}, [options.data, options.secondaryAxes, primaryAxisOptions])
Expand Down Expand Up @@ -491,11 +494,17 @@ function ChartInner<TDatum>({
})

datumsByInteractionGroup.forEach((value, key) => {
datumsByInteractionGroup.set(key, sortDatums(value, secondaryAxes))
datumsByInteractionGroup.set(
key,
sortDatumsBySecondaryPx(value, secondaryAxes)
)
})

datumsByTooltipGroup.forEach((value, key) => {
datumsByTooltipGroup.set(key, sortDatums(value, secondaryAxes))
datumsByTooltipGroup.set(
key,
sortDatumsBySecondaryPx(value, secondaryAxes)
)
})

allDatums.forEach(datum => {
Expand All @@ -506,7 +515,12 @@ function ChartInner<TDatum>({
})

return [datumsByInteractionGroup, datumsByTooltipGroup]
}, [allDatums, options.interactionMode, tooltipOptions.groupingMode])
}, [
allDatums,
options.interactionMode,
secondaryAxes,
tooltipOptions.groupingMode,
])

const getSeriesStatusStyle = React.useCallback(
(series: Series<TDatum>, focusedDatum: Datum<TDatum> | null) => {
Expand Down
1 change: 1 addition & 0 deletions src/components/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ export default function Tooltip<TDatum>(): React.ReactPortal | null {
getOptions,
focusedDatum: latestFocusedDatum,
primaryAxis,
secondaryAxes,
secondaryAxis,
getDatumStyle: (datum: Datum<TDatum>) =>
getDatumStatusStyle(datum, focusedDatum),
Expand Down
88 changes: 50 additions & 38 deletions src/components/TooltipRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type TooltipRendererProps<TDatum> = {
focusedDatum: Datum<TDatum> | null
getOptions: () => ResolvedChartOptions<TDatum>
primaryAxis: Axis<TDatum>
secondaryAxes: Axis<TDatum>[]
secondaryAxis: Axis<TDatum>
getDatumStyle: (datum: Datum<TDatum>) => CSSProperties
anchor: ReturnType<typeof useAnchor>
Expand Down Expand Up @@ -325,47 +326,58 @@ function TooltipRenderer<TDatum>(props: TooltipRendererProps<TDatum>) {
<td />
</tr>
) : null}
{secondaryAxis.stacked &&
(focusedDatum.tooltipGroup ?? []).length > 1 ? (
<tr>
<td
style={{
paddingTop: '5px',
}}
>
<div
style={{
width: '12px',
height: '12px',
backgroundColor: dark
? 'rgba(0, 26, 39, 0.3)'
: 'rgba(255,255,255,.2)',
borderRadius: '50px',
}}
/>
</td>
<td
style={{
paddingTop: '5px',
}}
>
Total: &nbsp;
</td>
<td
style={{
paddingTop: '5px',
}}
>
{/* {secondaryAxis.format(
{(focusedDatum.tooltipGroup ?? []).length > 1
? props.secondaryAxes
.filter(d => d.stacked)
.map((secondaryAxis, i) => {
return (
<tr key={`${secondaryAxis.id}_${i}`}>
<td
style={{
paddingTop: '5px',
}}
>
<div
style={{
width: '12px',
height: '12px',
backgroundColor: dark
? 'rgba(0, 26, 39, 0.3)'
: 'rgba(255,255,255,.2)',
borderRadius: '50px',
}}
/>
</td>
<td
style={{
paddingTop: '5px',
}}
>
{props.secondaryAxes.length > 1
? secondaryAxis.id ?? `Axis ${i + 1} `
: ''}
Total: &nbsp;
</td>
<td
style={{
paddingTop: '5px',
}}
>
{/* {secondaryAxis.format(
[...focusedDatum.group].reverse()[0].totalValue,
-1
)} */}
{(secondaryAxis as AxisLinear<any>).formatters.scale(
sum(focusedDatum.tooltipGroup ?? [], d => d.secondaryValue)
)}
</td>
</tr>
) : null}
{(secondaryAxis as AxisLinear<any>).formatters.scale(
sum(
focusedDatum.tooltipGroup ?? [],
d => d.secondaryValue
)
)}
</td>
</tr>
)
})
: null}
</tbody>
</table>
</div>
Expand Down
38 changes: 29 additions & 9 deletions src/components/Voronoi.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import { Delaunay } from 'd3-delaunay'

//
import { Datum } from '../types'
import { getPrimary, getX, getY, sortDatums, translate } from '../utils/Utils'
import {
getPrimary,
getX,
getY,
sortDatumsBySecondaryPx,
translate,
} from '../utils/Utils'
import useChartContext from '../utils/chartContext'
import { line } from 'd3-shape'

Expand Down Expand Up @@ -67,6 +73,8 @@ function PrimaryVoronoi<TDatum>({
datumsByInteractionGroup,
} = useChartContext<TDatum>()

const stackedVoronoi = secondaryAxes.length === 1 && secondaryAxes[0].stacked

return React.useMemo(() => {
const columns = series[0].datums
.filter(datum => {
Expand Down Expand Up @@ -115,7 +123,7 @@ function PrimaryVoronoi<TDatum>({
d => d.id === datum.secondaryAxisId
)

if (secondaryAxis?.stacked) {
if (stackedVoronoi) {
let range = secondaryAxis?.scale.range() ?? [0, 0]

let stackData = [datum.stackData?.[0], datum.stackData?.[1]]
Expand Down Expand Up @@ -144,7 +152,12 @@ function PrimaryVoronoi<TDatum>({
}
}

const value = secondaryAxis?.scale(datum.secondaryValue) ?? NaN
const value =
secondaryAxis?.scale(
secondaryAxis.stacked
? datum.stackData?.[1]
: datum.secondaryValue
) ?? NaN

let range = secondaryAxis?.scale.range() ?? [0, 0]

Expand All @@ -158,15 +171,21 @@ function PrimaryVoronoi<TDatum>({
const prevAxis = secondaryAxes.find(
d => d.id === prev?.secondaryAxisId
)
const prevValue = prevAxis?.scale(prev.secondaryValue) ?? NaN
const prevValue =
prevAxis?.scale(
prevAxis.stacked ? prev.stackData?.[1] : prev.secondaryValue
) ?? NaN
secondaryStart = value - (value - prevValue) / 2
}

if (next) {
const nextAxis = secondaryAxes.find(
d => d.id === next?.secondaryAxisId
)
const nextValue = nextAxis?.scale(next.secondaryValue) ?? NaN
const nextValue =
nextAxis?.scale(
nextAxis.stacked ? next.stackData?.[1] : next.secondaryValue
) ?? NaN
secondaryEnd = value + (nextValue - value) / 2
}

Expand Down Expand Up @@ -241,14 +260,15 @@ function PrimaryVoronoi<TDatum>({
</g>
)
}, [
getOptions,
series,
gridDimensions.left,
gridDimensions.top,
datumsByInteractionGroup,
handleFocus,
primaryAxis,
datumsByInteractionGroup,
secondaryAxes,
series,
stackedVoronoi,
handleFocus,
getOptions,
])
}

Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ export type AxisOptionsBase = {
show?: boolean
stacked?: boolean
stackOffset?: typeof stackOffsetNone
id?: string
id?: string | number
styles?: CSSProperties & {
line?: CSSProperties
tick?: CSSProperties
Expand Down
3 changes: 2 additions & 1 deletion src/utils/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ export function getTickPx<TDatum>(scale: Axis<TDatum>['scale'], value: any) {
return px
}

export function sortDatums<TDatum>(
export function sortDatumsBySecondaryPx<TDatum>(
datums: Datum<TDatum>[],
secondaryAxes: Axis<TDatum>[]
) {
Expand All @@ -277,6 +277,7 @@ export function sortDatums<TDatum>(

const aPx =
aAxis?.scale(aAxis.stacked ? a.stackData?.[1] : a.secondaryValue) ?? NaN

const bPx =
bAxis?.scale(bAxis.stacked ? b.stackData?.[1] : b.secondaryValue) ?? NaN

Expand Down

1 comment on commit d09fb93

@vercel
Copy link

@vercel vercel bot commented on d09fb93 Jul 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.