From f665bc3afb6224accbd0486bf01abdf3c4672482 Mon Sep 17 00:00:00 2001 From: Neil Kistner Date: Tue, 6 Jul 2021 10:17:50 -0500 Subject: [PATCH] fix(bar): fix animations when swapping keys (#1656) --- packages/bar/src/Bar.tsx | 84 +++++++++++++++++++++++++++------- packages/bar/src/BarCanvas.tsx | 14 ++++-- packages/bar/src/BarItem.tsx | 27 +++++++---- packages/bar/src/types.ts | 20 ++++---- 4 files changed, 107 insertions(+), 38 deletions(-) diff --git a/packages/bar/src/Bar.tsx b/packages/bar/src/Bar.tsx index 3fb8ab48a1..c6cdaee3a7 100644 --- a/packages/bar/src/Bar.tsx +++ b/packages/bar/src/Bar.tsx @@ -5,7 +5,6 @@ import { BarLayer, BarLayerId, BarSvgProps, - ComputedBarDatum, ComputedBarDatumWithValue, LegendData, } from './types' @@ -118,11 +117,17 @@ const InnerBar = ({ ) const formatValue = useValueFormatter(valueFormat) - const getBorderColor = useInheritedColor>(borderColor, theme) + const getBorderColor = useInheritedColor>( + borderColor, + theme + ) const getColor = useOrdinalColorScale(colors, colorBy) const getIndex = usePropertyAccessor(indexBy) const getLabel = usePropertyAccessor(label) - const getLabelColor = useInheritedColor>(labelTextColor, theme) + const getLabelColor = useInheritedColor>( + labelTextColor, + theme + ) const getTooltipLabel = usePropertyAccessor(tooltipLabel) const generateBars = groupMode === 'grouped' ? generateGroupedBars : generateStackedBars @@ -164,23 +169,70 @@ const InnerBar = ({ [result.bars] ) - const transition = useTransition(barsWithValue, { - keys: bar => bar.key, - enter: bar => ({ - x: bar.width / 2, - y: bar.height / 2, + const transition = useTransition< + ComputedBarDatumWithValue, + { + borderColor: string + color: string + height: number + labelColor: string + labelOpacity: number + labelX: number + labelY: number + opacity: number + transform: string + width: number + } + >(barsWithValue, { + keys: bar => `${bar.key}.${layout}.${reverse}.${groupMode}`, + from: bar => ({ + borderColor: getBorderColor(bar) as string, + color: bar.color, + height: 0, + labelColor: getLabelColor(bar) as string, + labelOpacity: 0, + labelX: bar.width / 2, + labelY: bar.height / 2, + transform: `translate(${bar.x}, ${bar.y + bar.height})`, width: bar.width, - height: bar.height, + ...(layout === 'vertical' + ? {} + : { + height: bar.height, + transform: `translate(${bar.x}, ${bar.y})`, + width: 0, + }), + }), + enter: bar => ({ + borderColor: getBorderColor(bar) as string, color: bar.color, + height: bar.height, + labelColor: getLabelColor(bar) as string, + labelOpacity: 1, + labelX: bar.width / 2, + labelY: bar.height / 2, transform: `translate(${bar.x}, ${bar.y})`, - }), - update: bar => ({ - x: bar.width / 2, - y: bar.height / 2, width: bar.width, - height: bar.height, + }), + leave: bar => ({ + borderColor: getBorderColor(bar) as string, color: bar.color, - transform: `translate(${bar.x}, ${bar.y})`, + height: 0, + labelColor: getLabelColor(bar) as string, + labelOpacity: 0, + labelX: bar.width / 2, + labelY: 0, + transform: `translate(${bar.x}, ${bar.y + bar.height})`, + width: bar.width, + ...(layout === 'vertical' + ? {} + : { + labelX: 0, + labelY: bar.height / 2, + height: bar.height, + transform: `translate(${bar.x}, ${bar.y})`, + width: 0, + }), }), config: springConfig, immediate: !animate, @@ -271,8 +323,6 @@ const InnerBar = ({ style, shouldRenderLabel: shouldRenderLabel(bar), label: getLabel(bar.data), - labelColor: getLabelColor(bar), - borderColor: getBorderColor(bar), }) )} diff --git a/packages/bar/src/BarCanvas.tsx b/packages/bar/src/BarCanvas.tsx index 671cc428a4..adb44cb654 100644 --- a/packages/bar/src/BarCanvas.tsx +++ b/packages/bar/src/BarCanvas.tsx @@ -189,11 +189,17 @@ const InnerBarCanvas = ({ const { showTooltipFromEvent, hideTooltip } = useTooltip() const formatValue = useValueFormatter(valueFormat) - const getBorderColor = useInheritedColor>(borderColor, theme) + const getBorderColor = useInheritedColor>( + borderColor, + theme + ) const getColor = useOrdinalColorScale(colors, colorBy) const getIndex = usePropertyAccessor(indexBy) const getLabel = usePropertyAccessor(label) - const getLabelColor = useInheritedColor>(labelTextColor, theme) + const getLabelColor = useInheritedColor>( + labelTextColor, + theme + ) const getTooltipLabel = usePropertyAccessor(tooltipLabel) const options = { @@ -362,11 +368,11 @@ const InnerBarCanvas = ({ barsWithValue.forEach(bar => { renderBar(ctx, { bar, - borderColor: getBorderColor(bar), + borderColor: getBorderColor(bar) as string, borderRadius, borderWidth, label: getLabel(bar.data), - labelColor: getLabelColor(bar), + labelColor: getLabelColor(bar) as string, shouldRenderLabel: shouldRenderLabel(bar), }) }) diff --git a/packages/bar/src/BarItem.tsx b/packages/bar/src/BarItem.tsx index 214e73f34f..6c4221c396 100644 --- a/packages/bar/src/BarItem.tsx +++ b/packages/bar/src/BarItem.tsx @@ -1,5 +1,5 @@ import { BarDatum, BarItemProps } from './types' -import { animated } from '@react-spring/web' +import { animated, to } from '@react-spring/web' import { createElement, useCallback } from 'react' import { useTheme } from '@nivo/core' import { useTooltip } from '@nivo/tooltip' @@ -7,15 +7,23 @@ import { useTooltip } from '@nivo/tooltip' export const BarItem = ({ bar: { data, ...bar }, - style: { height, transform, width, x, y, ...style }, + style: { + borderColor, + color, + height, + labelColor, + labelOpacity, + labelX, + labelY, + transform, + width, + }, borderRadius, borderWidth, - borderColor, label, shouldRenderLabel, - labelColor, isInteractive, onClick, @@ -56,11 +64,11 @@ export const BarItem = ({ return ( Math.max(value, 0))} + height={to(height, value => Math.max(value, 0))} rx={borderRadius} ry={borderRadius} - fill={data.fill ?? style.color} + fill={data.fill ?? color} strokeWidth={borderWidth} stroke={borderColor} onMouseEnter={isInteractive ? handleMouseEnter : undefined} @@ -70,10 +78,11 @@ export const BarItem = ({ /> {shouldRenderLabel && ( } } - borderColor: string - style: SpringValues<{ + borderColor: string color: string height: number + labelColor: string + labelOpacity: number + labelX: number + labelY: number + opacity: number transform: string width: number - x: number - y: number }> label: string - labelColor: string shouldRenderLabel: boolean } export type RenderBarProps = Omit< BarItemProps, 'isInteractive' | 'style' | 'tooltip' -> +> & { + borderColor: string + labelColor: string +} export interface BarTooltipProps extends ComputedDatum { color: string @@ -198,7 +202,7 @@ export type BarCommonProps = { enableGridY: boolean gridYValues?: GridValues - borderColor: InheritedColorConfig> + borderColor: InheritedColorConfig> borderRadius: number borderWidth: number @@ -207,7 +211,7 @@ export type BarCommonProps = { labelFormat: string | LabelFormatter labelSkipWidth: number labelSkipHeight: number - labelTextColor: InheritedColorConfig> + labelTextColor: InheritedColorConfig> isInteractive: boolean