@@ -3,7 +3,7 @@ import { getImageUrl } from './util';
3
3
import { BoardDetails } from '@/app/lib/types' ;
4
4
import { HoldHeatmapData } from '@/app/lib/db/queries/holds-heatmap' ;
5
5
import { LitUpHoldsMap } from './types' ;
6
- import { scaleLinear } from 'd3-scale' ;
6
+ import { scaleLinear , scaleLog } from 'd3-scale' ;
7
7
import useHeatmapData from '../search-drawer/use-heatmap' ;
8
8
import { usePathname , useSearchParams } from 'next/navigation' ;
9
9
import { useUISearchParams } from '@/app/components/queue-control/ui-searchparams-provider' ;
@@ -104,50 +104,27 @@ const BoardHeatmap: React.FC<BoardHeatmapProps> = ({
104
104
} ;
105
105
}
106
106
107
- // Create breakpoints at different percentiles for more even distribution
108
- const percentileValues = {
109
- min : values [ 0 ] ,
110
- p20 : getPercentileValue ( values , 20 ) ,
111
- p40 : getPercentileValue ( values , 40 ) ,
112
- p60 : getPercentileValue ( values , 60 ) ,
113
- p80 : getPercentileValue ( values , 80 ) ,
114
- p95 : getPercentileValue ( values , 95 ) ,
115
- max : values [ values . length - 1 ]
116
- } ;
107
+ const min = Math . max ( 1 , values [ 0 ] ) ;
108
+ const max = values [ values . length - 1 ] ;
109
+
110
+ // Use log scale for better distribution of values
111
+ const logScale = scaleLog ( )
112
+ . domain ( [ min , max ] )
113
+ . range ( [ 0 , HEATMAP_COLORS . length - 1 ] )
114
+ . clamp ( true ) ;
117
115
118
116
const getColorScale = ( ) => {
119
117
return ( value : number ) => {
120
- if ( ! value || value === 0 ) return 'transparent' ;
121
-
122
- // Map the value to color index based on which percentile bucket it falls into
123
- let normalizedIndex ;
124
- if ( value <= percentileValues . p20 ) {
125
- normalizedIndex = ( value - percentileValues . min ) / ( percentileValues . p20 - percentileValues . min ) ;
126
- } else if ( value <= percentileValues . p40 ) {
127
- normalizedIndex = 2 + ( value - percentileValues . p20 ) / ( percentileValues . p40 - percentileValues . p20 ) ;
128
- } else if ( value <= percentileValues . p60 ) {
129
- normalizedIndex = 4 + ( value - percentileValues . p40 ) / ( percentileValues . p60 - percentileValues . p40 ) ;
130
- } else if ( value <= percentileValues . p80 ) {
131
- normalizedIndex = 6 + ( value - percentileValues . p60 ) / ( percentileValues . p80 - percentileValues . p60 ) ;
132
- } else {
133
- normalizedIndex = 8 + ( value - percentileValues . p80 ) / ( percentileValues . p95 - percentileValues . p80 ) ;
134
- }
135
-
136
- const index = Math . floor ( normalizedIndex ) ;
137
- return HEATMAP_COLORS [ Math . max ( 0 , Math . min ( index , HEATMAP_COLORS . length - 1 ) ) ] ;
118
+ if ( ! value || value < threshold ) return 'transparent' ;
119
+ const index = Math . floor ( logScale ( value ) ) ;
120
+ return HEATMAP_COLORS [ index ] ;
138
121
} ;
139
122
} ;
140
123
141
124
const getOpacityScale = ( ) => {
142
125
return ( value : number ) => {
143
- if ( ! value || value === 0 ) return 0 ;
144
- // Use percentile values for opacity scaling
145
- return Math . max ( 0.2 , Math . min ( 0.8 ,
146
- scaleLinear ( )
147
- . domain ( [ percentileValues . min , percentileValues . p95 ] )
148
- . range ( [ 0.2 , 0.8 ] )
149
- . clamp ( true ) ( value )
150
- ) ) ;
126
+ if ( ! value || value < threshold ) return 0 ;
127
+ return Math . max ( 0.3 , Math . min ( 0.8 , logScale ( value ) / HEATMAP_COLORS . length ) ) ;
151
128
} ;
152
129
} ;
153
130
0 commit comments