@cdc/map 4.25.5-1 → 4.25.6-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import { useCallback, useContext } from 'react'
2
2
  import ConfigContext from '../context'
3
3
  import {
4
+ addUIDs,
4
5
  applyColorToLegend,
5
6
  getGeoFillColor,
6
7
  hashObj,
@@ -53,11 +54,15 @@ export const generateRuntimeLegend = (
53
54
  const newLegendMemo = new Map() // Reset memoization
54
55
  const newLegendSpecialClassLastMemo = new Map() // Reset bin memoization
55
56
  const countryKeys = Object.keys(supportedCountries)
56
- const { data, legend, columns, general } = configObj
57
+ const { legend, columns, general } = configObj
57
58
  const primaryColName = columns.primary.name
58
59
  const isBubble = general.type === 'bubble'
59
60
  const categoricalCol = columns.categorical ? columns.categorical.name : undefined
60
61
 
62
+ // filter out rows without a geo column
63
+ addUIDs(configObj, configObj.columns.geo.name)
64
+ const data = configObj.data.filter(row => row.uid) // Filter out rows without UIDs
65
+
61
66
  const result = {
62
67
  fromHash: null,
63
68
  runtimeDataHash: null,
@@ -81,69 +86,44 @@ export const generateRuntimeLegend = (
81
86
  let specialClasses = 0
82
87
  let specialClassesHash = {}
83
88
 
89
+ // Special classes
84
90
  if (legend.specialClasses.length) {
85
91
  if (typeof legend.specialClasses[0] === 'object') {
86
92
  legend.specialClasses.forEach(specialClass => {
87
- const val = String(specialClass.value)
88
- if (undefined === specialClassesHash[val]) {
89
- specialClassesHash[val] = true
90
- result.items.push({
91
- special: true,
92
- value: val,
93
- label: specialClass.label
94
- })
95
- result.items[result.items.length - 1].color = applyColorToLegend(
96
- result.items.length - 1,
97
- configObj,
98
- result.items
99
- )
100
- specialClasses += 1
101
- }
102
- // Optionally, still map any rows that match this special class
103
- dataSet.forEach(row => {
104
- const rowVal = String(row[specialClass.key])
105
- if (rowVal === val) {
106
- let specialColor = result.items.findIndex(p => p.value === val)
107
- newLegendMemo.set(hashObj(row), specialColor)
108
- }
109
- })
110
- })
111
- } else {
112
- dataSet = dataSet.filter(row => {
113
- const val = row[primaryColName]
114
-
115
- if (legend.specialClasses.includes(val)) {
116
- // apply the special color to the legend
117
- if (undefined === specialClassesHash[val]) {
118
- specialClassesHash[val] = true
119
-
120
- result.items.push({
121
- special: true,
122
- value: val
123
- })
124
-
125
- result.items[result.items.length - 1].color = applyColorToLegend(
126
- result.items.length - 1,
127
- configObj,
128
- result.items
129
- )
130
-
131
- specialClasses += 1
132
- }
93
+ dataSet = dataSet.filter(row => {
94
+ const val = String(row[specialClass.key])
95
+
96
+ if (specialClass.value === val) {
97
+ if (undefined === specialClassesHash[val]) {
98
+ specialClassesHash[val] = true
99
+
100
+ result.items.push({
101
+ special: true,
102
+ value: val,
103
+ label: specialClass.label
104
+ })
133
105
 
134
- let specialColor = 0
106
+ result.items[result.items.length - 1].color = applyColorToLegend(
107
+ result.items.length - 1,
108
+ configObj,
109
+ result.items
110
+ )
135
111
 
136
- // color the configObj if val is in row
137
- if (Object.values(row).includes(val)) {
112
+ specialClasses += 1
113
+ }
114
+
115
+ let specialColor: number
116
+
117
+ // color the configObj if val is in row
138
118
  specialColor = result.items.findIndex(p => p.value === val)
139
- }
140
119
 
141
- newLegendMemo.set(hashObj(row), specialColor)
120
+ newLegendMemo.set(hashObj(row), specialColor)
142
121
 
143
- return false
144
- }
122
+ return false
123
+ }
145
124
 
146
- return true
125
+ return true
126
+ })
147
127
  })
148
128
  }
149
129
  }
@@ -403,6 +383,12 @@ export const generateRuntimeLegend = (
403
383
  min = 1
404
384
  }
405
385
 
386
+ // For non-first ranges, add small increment to prevent overlap
387
+ if (index > 0 && !legend.separateZero) {
388
+ const decimalPlace = Number(configObj?.columns?.primary?.roundToPlace) || 1
389
+ min = Number(cachedBreaks[index]) + Math.pow(10, -decimalPlace)
390
+ }
391
+
406
392
  return min
407
393
  }
408
394
 
@@ -411,14 +397,14 @@ export const generateRuntimeLegend = (
411
397
  }
412
398
 
413
399
  const setMax = index => {
414
- let max = Number(breaks[index + 1]) - getDecimalPlace(Number(configObj?.columns?.primary?.roundToPlace))
400
+ let max = Number(breaks[index + 1])
415
401
 
416
402
  if (index === 0 && legend.separateZero) {
417
403
  max = 0
418
404
  }
419
405
 
420
406
  if (index + 1 === breaks.length) {
421
- max = domainNums[domainNums.length - 1]
407
+ max = Number(domainNums[domainNums.length - 1])
422
408
  }
423
409
 
424
410
  return max
@@ -443,11 +429,54 @@ export const generateRuntimeLegend = (
443
429
 
444
430
  if (result.items?.[updated]?.min === undefined || result.items?.[updated]?.max === undefined) return
445
431
 
446
- if (number >= result?.items?.[updated].min && number <= result?.items?.[updated].max) {
447
- newLegendMemo.set(hashObj(row), updated)
432
+ // Check if this row hasn't been assigned yet to prevent double assignment
433
+ if (!newLegendMemo.has(hashObj(row))) {
434
+ if (number >= result.items[updated].min && number <= result.items[updated].max) {
435
+ newLegendMemo.set(hashObj(row), updated)
436
+ }
448
437
  }
449
438
  })
450
439
  })
440
+
441
+ // Final pass: handle any unassigned rows
442
+ dataSet.forEach(row => {
443
+ if (!newLegendMemo.has(hashObj(row))) {
444
+ let number = row[columns.primary.name]
445
+ let assigned = false
446
+
447
+ // Find the correct range for this value - check both boundaries
448
+ for (let itemIndex = 0; itemIndex < result.items.length; itemIndex++) {
449
+ const item = result.items[itemIndex]
450
+
451
+ if (item.min === undefined || item.max === undefined) continue
452
+
453
+ // Check if value falls within range (inclusive of both min and max)
454
+ if (number >= item.min && number <= item.max) {
455
+ newLegendMemo.set(hashObj(row), itemIndex)
456
+ assigned = true
457
+ break
458
+ }
459
+ }
460
+
461
+ // Fallback: if still not assigned, assign to closest range
462
+ if (!assigned) {
463
+ console.warn('Value not assigned to any range:', number, 'assigning to closest range')
464
+ let closestIndex = 0
465
+ let minDistance = Math.abs(number - ((result.items[0].min + result.items[0].max) / 2))
466
+
467
+ for (let i = 1; i < result.items.length; i++) {
468
+ const midpoint = (result.items[i].min + result.items[i].max) / 2
469
+ const distance = Math.abs(number - midpoint)
470
+ if (distance < minDistance) {
471
+ minDistance = distance
472
+ closestIndex = i
473
+ }
474
+ }
475
+
476
+ newLegendMemo.set(hashObj(row), closestIndex)
477
+ }
478
+ }
479
+ })
451
480
  }
452
481
  }
453
482
 
@@ -0,0 +1,8 @@
1
+ import { getFilterControllingStatePicked } from '../components/UsaMap/helpers/map'
2
+ import { supportedStatesFipsCodes } from '../data/supported-geos'
3
+
4
+ export const getStatePicked = (config, runtimeData) => {
5
+ const stateName = getFilterControllingStatePicked(config, runtimeData)
6
+ const fipsCode = Object.keys(supportedStatesFipsCodes).find(key => supportedStatesFipsCodes[key] === stateName)
7
+ return { stateName, fipsCode }
8
+ }