Skip to content

Commit 498d9cb

Browse files
Merge pull request #269 from CSSLab/codex/fix-analysis-chart-updates
Fix analysis Stockfish ordering and moves-by-rating transitions
2 parents ba0b19e + 337f09a commit 498d9cb

2 files changed

Lines changed: 54 additions & 29 deletions

File tree

src/components/Analysis/AnalysisSidebar.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ export const AnalysisSidebar: React.FC<Props> = ({
141141
const movesByRatingProps = {
142142
moves: analysisEnabled ? controller.movesByRating : undefined,
143143
colorSanMapping: analysisEnabled ? controller.colorSanMapping : {},
144+
positionKey: analysisEnabled ? controller.currentNode?.fen : undefined,
144145
}
145146

146147
const renderHeader = (

src/components/Analysis/MovesByRating.tsx

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,53 @@ import {
88
CartesianGrid,
99
ResponsiveContainer,
1010
} from 'recharts'
11-
import { useContext } from 'react'
11+
import { useContext, useEffect, useMemo, useRef, useState } from 'react'
1212
import { ColorSanMapping } from 'src/types'
1313
import { WindowSizeContext } from 'src/contexts'
1414

1515
interface Props {
1616
moves: { [key: string]: number }[] | undefined
1717
colorSanMapping: ColorSanMapping
1818
isHomePage?: boolean
19+
positionKey?: string
1920
}
2021

2122
export const MovesByRating: React.FC<Props> = ({
2223
moves,
2324
colorSanMapping,
2425
isHomePage = false,
26+
positionKey,
2527
}: Props) => {
2628
const { isMobile } = useContext(WindowSizeContext)
29+
const [displayedMoves, setDisplayedMoves] = useState(moves)
30+
const [displayedColorSanMapping, setDisplayedColorSanMapping] =
31+
useState(colorSanMapping)
32+
const [displayedPositionKey, setDisplayedPositionKey] = useState(positionKey)
33+
const lastRenderedPositionKeyRef = useRef<string | undefined>(positionKey)
34+
const shouldAnimateSeries =
35+
!!displayedPositionKey &&
36+
displayedPositionKey !== lastRenderedPositionKeyRef.current
2737

28-
const maxValue = moves
38+
useEffect(() => {
39+
if (!moves?.length || !positionKey) return
40+
setDisplayedMoves(moves)
41+
setDisplayedColorSanMapping(colorSanMapping)
42+
setDisplayedPositionKey(positionKey)
43+
}, [moves, colorSanMapping, positionKey])
44+
45+
useEffect(() => {
46+
if (!displayedPositionKey) return
47+
lastRenderedPositionKeyRef.current = displayedPositionKey
48+
}, [displayedPositionKey])
49+
50+
const moveKeys = useMemo(() => {
51+
if (!displayedMoves?.length) return []
52+
return Object.keys(displayedMoves[0]).filter((move) => move !== 'rating')
53+
}, [displayedMoves])
54+
55+
const maxValue = displayedMoves
2956
? Math.max(
30-
...moves.flatMap((move) =>
57+
...displayedMoves.flatMap((move) =>
3158
Object.entries(move)
3259
.filter(([key]) => key !== 'rating')
3360
.map(([, value]) => value as number),
@@ -48,7 +75,7 @@ export const MovesByRating: React.FC<Props> = ({
4875
</h2>
4976
<ResponsiveContainer width="100%" height="90%">
5077
<AreaChart
51-
data={moves}
78+
data={displayedMoves}
5279
margin={{
5380
left: 0,
5481
right: isMobile ? 40 : 50,
@@ -99,11 +126,8 @@ export const MovesByRating: React.FC<Props> = ({
99126
tickFormatter={(value) => `${value}%`}
100127
/>
101128
<defs>
102-
{moves &&
103-
Object.keys(moves[0]).map((move, i) => {
104-
if (move === 'rating') {
105-
return null
106-
}
129+
{displayedMoves &&
130+
moveKeys.map((move) => {
107131
return (
108132
<linearGradient
109133
key={`color${move}`}
@@ -115,22 +139,26 @@ export const MovesByRating: React.FC<Props> = ({
115139
>
116140
<stop
117141
offset="5%"
118-
stopColor={colorSanMapping[move]?.color ?? '#fff'}
142+
stopColor={
143+
displayedColorSanMapping[move]?.color ?? '#fff'
144+
}
119145
stopOpacity={0.5}
120146
/>
121147
<stop
122148
offset="95%"
123-
stopColor={colorSanMapping[move]?.color ?? '#fff'}
149+
stopColor={
150+
displayedColorSanMapping[move]?.color ?? '#fff'
151+
}
124152
stopOpacity={0}
125153
/>
126154
</linearGradient>
127155
)
128156
})}
129157
</defs>
130-
{moves &&
158+
{displayedMoves &&
131159
// First, collect all the end points and sort them by y-position
132160
(() => {
133-
const lastIndex = moves.length - 1
161+
const lastIndex = displayedMoves.length - 1
134162

135163
// Define the type for end points
136164
interface EndPoint {
@@ -142,42 +170,38 @@ export const MovesByRating: React.FC<Props> = ({
142170
adjustment?: number
143171
}
144172

145-
const endPoints = Object.keys(moves[0])
146-
.filter((move) => move !== 'rating')
173+
const endPoints = moveKeys
147174
.map((move) => {
148-
const value = moves[lastIndex][move] as number
175+
const value = displayedMoves[lastIndex][move] as number
149176
return {
150177
move,
151178
value,
152-
san: colorSanMapping[move]?.san || move,
153-
color: colorSanMapping[move]?.color ?? '#fff',
179+
san: displayedColorSanMapping[move]?.san || move,
180+
color: displayedColorSanMapping[move]?.color ?? '#fff',
154181
} as EndPoint
155182
})
156183
.sort((a, b) => a.value - b.value) // Sort by value (y-position)
157184

158185
// Return the original map function with adjusted positions
159-
return Object.keys(moves[0]).map((move, i) => {
160-
if (move === 'rating') {
161-
return null
162-
}
163-
186+
return moveKeys.map((move, index) => {
164187
const endPoint = endPoints.find((ep) => ep.move === move)
165188
const san = endPoint?.san || move
166189

167190
return (
168191
<Area
169-
key={i}
192+
key={index}
170193
yAxisId="left"
171194
dataKey={move}
172195
dot={{
173196
r: isMobile ? 2 : 3,
174-
stroke: colorSanMapping[move]?.color ?? '#fff',
197+
stroke: displayedColorSanMapping[move]?.color ?? '#fff',
175198
strokeWidth: isMobile ? 2 : 3,
176199
}}
177-
stroke={colorSanMapping[move]?.color ?? '#fff'}
200+
stroke={displayedColorSanMapping[move]?.color ?? '#fff'}
178201
fill={`url(#color${move})`}
179202
strokeWidth={isMobile ? 2 : 3}
180203
animationDuration={300}
204+
isAnimationActive={shouldAnimateSeries}
181205
name={san}
182206
label={(props: {
183207
x: number
@@ -231,7 +255,7 @@ export const MovesByRating: React.FC<Props> = ({
231255
dy={isMobile ? 3 : 4}
232256
fontSize={11}
233257
fontWeight={600}
234-
fill={colorSanMapping[move]?.color ?? '#fff'}
258+
fill={displayedColorSanMapping[move]?.color ?? '#fff'}
235259
textAnchor="start"
236260
>
237261
{san}
@@ -298,8 +322,8 @@ export const MovesByRating: React.FC<Props> = ({
298322
fontSize: 14,
299323
}}
300324
iconSize={0}
301-
formatter={(value) => {
302-
return colorSanMapping[value as string]?.san ?? value
325+
formatter={(value: string) => {
326+
return displayedColorSanMapping[value as string]?.san ?? value
303327
}}
304328
/>
305329
</AreaChart>

0 commit comments

Comments
 (0)