@cdc/chart 4.26.5 → 4.26.7
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.
- package/CONFIG.md +20 -14
- package/dist/{cdcchart-DQ00cQCm.es.js → cdcchart-BWVIUcAF.es.js} +5 -55
- package/dist/cdcchart.js +36554 -34320
- package/examples/feature/heatmap/average-age-categorical.json +1 -1
- package/examples/feature/heatmap/calendar-heatmap.json +1 -1
- package/examples/feature/heatmap/sparse-aggregation.json +1 -1
- package/examples/private/bad-y-axis.json +543 -0
- package/examples/private/bar-chart-negative-value.json +455 -0
- package/examples/private/flueview.json +22051 -0
- package/package.json +3 -11
- package/src/CdcChart.tsx +7 -6
- package/src/CdcChartComponent.tsx +71 -18
- package/src/_stories/Chart.PieLabels.stories.tsx +47 -0
- package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +183 -0
- package/src/_stories/Chart.YAxisAutoMaxStrategy.stories.tsx +52 -0
- package/src/_stories/Chart.YAxisFilterDomain.stories.tsx +90 -0
- package/src/_stories/Chart.smoke.stories.tsx +14 -1
- package/src/_stories/ChartAnnotation.smoke.stories.tsx +10 -0
- package/src/_stories/ChartPrefixSuffix.smoke.stories.tsx +28 -1
- package/src/_stories/_mock/annotation_event-line_mock.json +1064 -0
- package/src/_stories/_mock/heatmap-average-age-categorical.json +1 -1
- package/src/_stories/_mock/heatmap.json +1 -1
- package/src/components/Annotations/components/AnnotationDraggable.styles.css +22 -1
- package/src/components/Annotations/components/AnnotationDraggable.tsx +219 -119
- package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +198 -0
- package/src/components/Axis/LeftAxis.tsx +3 -0
- package/src/components/Axis/LeftAxisGridlines.tsx +8 -1
- package/src/components/Axis/RightAxis.tsx +3 -0
- package/src/components/Axis/tests/AxisTickValues.test.tsx +86 -0
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +1 -2
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +1 -1
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +1 -1
- package/src/components/BarChart/components/BarChart.Vertical.tsx +1 -2
- package/src/components/BarChart/helpers/getBarData.ts +28 -28
- package/src/components/BarChart/helpers/getBarHeights.ts +2 -2
- package/src/components/BarChart/helpers/tests/useBarChart.test.tsx +98 -0
- package/src/components/BarChart/helpers/useBarChart.ts +4 -5
- package/src/components/BoxPlot/BoxPlot.Horizontal.tsx +7 -6
- package/src/components/BoxPlot/BoxPlot.Vertical.tsx +9 -7
- package/src/components/BoxPlot/helpers/index.ts +4 -3
- package/src/components/Brush/BrushSelector.tsx +1 -1
- package/src/components/EditorPanel/EditorPanel.tsx +457 -165
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +101 -52
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +16 -7
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +3 -3
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +19 -4
- package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.test.tsx +98 -0
- package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +10 -0
- package/src/components/EditorPanel/components/Panels/Panel.Visual.test.tsx +484 -0
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +3 -0
- package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +262 -0
- package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +32 -0
- package/src/components/EditorPanel/components/panels.scss +10 -0
- package/src/components/EditorPanel/editor-panel.scss +47 -0
- package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +6 -2
- package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +20 -2
- package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +3 -3
- package/src/components/EditorPanel/useEditorPermissions.test.tsx +288 -11
- package/src/components/EditorPanel/useEditorPermissions.ts +46 -6
- package/src/components/Forecasting/Forecasting.tsx +1 -1
- package/src/components/HeatMap/components/HeatMap.tsx +22 -17
- package/src/components/HeatMap/components/HeatMapGradientLegend.tsx +29 -15
- package/src/components/HeatMap/heatmap.css +15 -1
- package/src/components/HeatMap/tests/HeatMap.test.tsx +39 -7
- package/src/components/Legend/Legend.Component.tsx +56 -61
- package/src/components/Legend/Legend.Suppression.tsx +3 -3
- package/src/components/Legend/LegendGroup/LegendGroup.tsx +0 -1
- package/src/components/Legend/helpers/createFormatLabels.test.ts +88 -0
- package/src/components/Legend/helpers/createFormatLabels.tsx +6 -1
- package/src/components/LineChart/helpers.test.ts +230 -1
- package/src/components/LineChart/helpers.ts +25 -14
- package/src/components/LineChart/index.tsx +23 -7
- package/src/components/LinearChart/tests/LinearChart.test.tsx +30 -0
- package/src/components/LinearChart.tsx +51 -15
- package/src/components/PieChart/PieChart.tsx +117 -10
- package/src/components/PieChart/helpers/labelPlacement.test.ts +88 -0
- package/src/components/PieChart/helpers/labelPlacement.ts +95 -0
- package/src/components/ScatterPlot/ScatterPlot.jsx +5 -13
- package/src/components/SmallMultiples/SmallMultipleTile.tsx +3 -0
- package/src/components/SmallMultiples/SmallMultiples.tsx +38 -9
- package/src/components/SmallMultiples/tests/SmallMultiples.test.tsx +170 -0
- package/src/data/initial-state.js +3 -0
- package/src/helpers/calculateLeftYAxisWidth.ts +9 -3
- package/src/helpers/categoryOrder.ts +60 -0
- package/src/helpers/colorAssignmentHelpers.ts +102 -0
- package/src/helpers/dataHelpers.ts +11 -1
- package/src/helpers/getAxisMaxOverride.ts +16 -0
- package/src/helpers/getBoxPlotConfig.ts +19 -12
- package/src/helpers/getCleanTopTickMax.ts +64 -0
- package/src/helpers/getColorScale.ts +18 -9
- package/src/helpers/getComboChartConfig.ts +0 -1
- package/src/helpers/getExcludedData.ts +0 -1
- package/src/helpers/getHasBoundarySuppression.ts +27 -0
- package/src/helpers/getMinMax.ts +25 -22
- package/src/helpers/getNewRuntime.ts +0 -2
- package/src/helpers/getPiePercent.ts +3 -3
- package/src/helpers/getYAxisDomainData.ts +38 -0
- package/src/helpers/getYAxisFinalizationEligibility.ts +40 -0
- package/src/helpers/hasSpacedInlineLabel.ts +10 -0
- package/src/helpers/isConvertLineToBarGraph.ts +2 -2
- package/src/helpers/seriesColumnSettings.ts +26 -7
- package/src/helpers/sizeHelpers.ts +0 -2
- package/src/helpers/smallMultiplesHelpers.ts +5 -0
- package/src/helpers/tests/calculateLeftYAxisWidth.test.ts +38 -0
- package/src/helpers/tests/categoryOrder.test.ts +57 -0
- package/src/helpers/tests/dataHelpers.test.ts +135 -0
- package/src/helpers/tests/getAxisMaxOverride.test.ts +36 -0
- package/src/helpers/tests/getCleanTopTickMax.test.ts +165 -0
- package/src/helpers/tests/getColorScale.test.ts +197 -0
- package/src/helpers/tests/getMinMax.test.ts +211 -0
- package/src/helpers/tests/getYAxisDomainData.test.ts +119 -0
- package/src/helpers/tests/getYAxisFinalizationEligibility.test.ts +185 -0
- package/src/helpers/tests/{getYAxisAutoPaddingMode.test.ts → hasSpacedInlineLabel.test.ts} +17 -32
- package/src/helpers/tests/seriesColumnSettings.test.ts +76 -2
- package/src/helpers/tests/smallMultiplesHelpers.test.ts +99 -0
- package/src/hooks/tests/useRightAxis.test.tsx +268 -0
- package/src/hooks/tests/useScales.test.tsx +302 -27
- package/src/hooks/tests/useTooltip.test.tsx +132 -0
- package/src/hooks/useRightAxis.ts +35 -25
- package/src/hooks/useScales.ts +45 -28
- package/src/hooks/useTooltip.tsx +17 -11
- package/src/store/chart.reducer.ts +0 -1
- package/src/test/CdcChart.dataTable.test.tsx +216 -0
- package/src/types/ChartConfig.ts +6 -1
- package/src/types/ChartContext.ts +3 -0
- package/src/helpers/getYAxisAutoPadding.ts +0 -55
- package/src/helpers/getYAxisAutoPaddingMode.ts +0 -17
- package/src/helpers/tests/getYAxisAutoPadding.test.ts +0 -37
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef } from 'react'
|
|
2
|
+
import cloneConfig from '@cdc/core/helpers/cloneConfig'
|
|
3
|
+
import { Select } from '@cdc/core/components/EditorPanel/Inputs'
|
|
4
|
+
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
5
|
+
import Icon from '@cdc/core/components/ui/Icon'
|
|
6
|
+
import { DataColorSelector } from '@cdc/core/components/DataColorSelector'
|
|
7
|
+
import { getColorPaletteVersion } from '@cdc/core/helpers/getColorPaletteVersion'
|
|
8
|
+
import { getCurrentPaletteName, migratePaletteWithMap } from '@cdc/core/helpers/palettes/utils'
|
|
9
|
+
import { paletteMigrationMap } from '@cdc/core/helpers/palettes/migratePaletteName'
|
|
10
|
+
import { getColorScale } from '../../../../helpers/getColorScale'
|
|
11
|
+
import { ChartConfig } from '../../../../types/ChartConfig'
|
|
12
|
+
import {
|
|
13
|
+
getSeriesColorAssignmentItems,
|
|
14
|
+
getSeriesColorAssignments,
|
|
15
|
+
isSeriesColorAssignmentModeByValue,
|
|
16
|
+
supportsSeriesColorAssignments,
|
|
17
|
+
type SeriesColorAssignment,
|
|
18
|
+
type SeriesColorAssignmentItem
|
|
19
|
+
} from '../../../../helpers/colorAssignmentHelpers'
|
|
20
|
+
|
|
21
|
+
type SeriesColorAssignmentsProps = {
|
|
22
|
+
config: ChartConfig
|
|
23
|
+
updateConfig: (config: ChartConfig) => void
|
|
24
|
+
colorPalettes: Record<string, any>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const SeriesColorAssignments = ({ config, updateConfig, colorPalettes }: SeriesColorAssignmentsProps) => {
|
|
28
|
+
const seriesColorAssignmentItems = useMemo(() => getSeriesColorAssignmentItems(config), [config])
|
|
29
|
+
const seriesColorAssignments = getSeriesColorAssignments(config)
|
|
30
|
+
const seriesColorAssignmentMap = useMemo(
|
|
31
|
+
() => new Map(seriesColorAssignments.map(assignment => [assignment.key, assignment.color])),
|
|
32
|
+
[seriesColorAssignments]
|
|
33
|
+
)
|
|
34
|
+
const seriesColorAssignmentItemsFingerprint = seriesColorAssignmentItems
|
|
35
|
+
.map(({ key, label }) => `${key}:${label}`)
|
|
36
|
+
.join('|')
|
|
37
|
+
const seriesColorAssignmentsFingerprint = seriesColorAssignments.map(({ key, color }) => `${key}:${color}`).join('|')
|
|
38
|
+
const seriesColorAssignmentSupported = supportsSeriesColorAssignments(config)
|
|
39
|
+
const seriesColorAssignmentMode = config.general?.palette?.colorAssignmentMode || 'ordered'
|
|
40
|
+
const isSeriesColorAssignmentByValue = isSeriesColorAssignmentModeByValue(config)
|
|
41
|
+
const currentPaletteName = getCurrentPaletteName(config)
|
|
42
|
+
const customColors = config.general?.palette?.customColorsOrdered || config.general?.palette?.customColors
|
|
43
|
+
const hasCustomColors = Array.isArray(customColors) && customColors.length > 0
|
|
44
|
+
|
|
45
|
+
const getOrderedColorScaleConfig = () => ({
|
|
46
|
+
...config,
|
|
47
|
+
general: {
|
|
48
|
+
...config.general,
|
|
49
|
+
palette: {
|
|
50
|
+
...config.general?.palette,
|
|
51
|
+
colorAssignmentMode: 'ordered' as const
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const orderedColorScaleConfig = useMemo(getOrderedColorScaleConfig, [config])
|
|
57
|
+
const orderedColorScale = useMemo(() => getColorScale(orderedColorScaleConfig), [orderedColorScaleConfig])
|
|
58
|
+
const distributedPaletteColorOptions = useMemo(() => {
|
|
59
|
+
const colors = (orderedColorScale as any)?.range?.() || []
|
|
60
|
+
return Array.from(new Set(colors.filter(Boolean)))
|
|
61
|
+
}, [orderedColorScale])
|
|
62
|
+
const paletteColorOptions = useMemo(() => {
|
|
63
|
+
if (hasCustomColors) {
|
|
64
|
+
return Array.from(new Set(customColors.filter(Boolean)))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const version = getColorPaletteVersion(config)
|
|
68
|
+
const versionedPalettes = colorPalettes?.[`v${version}`] || colorPalettes?.v2 || colorPalettes || {}
|
|
69
|
+
const paletteName = migratePaletteWithMap(currentPaletteName, paletteMigrationMap, false)
|
|
70
|
+
const colors =
|
|
71
|
+
versionedPalettes[paletteName] || versionedPalettes[currentPaletteName] || distributedPaletteColorOptions
|
|
72
|
+
|
|
73
|
+
return Array.from(new Set(colors.filter(Boolean)))
|
|
74
|
+
}, [colorPalettes, config, customColors, hasCustomColors, currentPaletteName, distributedPaletteColorOptions])
|
|
75
|
+
const paletteSourceFingerprint = hasCustomColors
|
|
76
|
+
? 'custom-colors'
|
|
77
|
+
: `${currentPaletteName}|${paletteColorOptions.join('|')}`
|
|
78
|
+
const previousPaletteSource = useRef<{ hasCustomColors: boolean; fingerprint: string } | null>(null)
|
|
79
|
+
|
|
80
|
+
const getColorForAssignmentItem = ({ label }: SeriesColorAssignmentItem, index: number): string => {
|
|
81
|
+
const orderedColor = orderedColorScale(label)
|
|
82
|
+
return paletteColorOptions.includes(orderedColor)
|
|
83
|
+
? orderedColor
|
|
84
|
+
: distributedPaletteColorOptions[index % distributedPaletteColorOptions.length] ||
|
|
85
|
+
paletteColorOptions[index % paletteColorOptions.length] ||
|
|
86
|
+
'#000000'
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const getAssignmentsFromCurrentColors = (): SeriesColorAssignment[] =>
|
|
90
|
+
seriesColorAssignmentItems.map((item, index) => ({
|
|
91
|
+
key: item.key,
|
|
92
|
+
color: getColorForAssignmentItem(item, index)
|
|
93
|
+
}))
|
|
94
|
+
|
|
95
|
+
const getAssignmentsWithMissingCurrentColors = (): SeriesColorAssignment[] | null => {
|
|
96
|
+
const assignments = [...seriesColorAssignments]
|
|
97
|
+
let hasMissingAssignment = false
|
|
98
|
+
|
|
99
|
+
seriesColorAssignmentItems.forEach((item, index) => {
|
|
100
|
+
const existingIndex = assignments.findIndex(assignment => assignment.key === item.key)
|
|
101
|
+
const nextAssignment = { key: item.key, color: getColorForAssignmentItem(item, index) }
|
|
102
|
+
|
|
103
|
+
if (existingIndex === -1) {
|
|
104
|
+
assignments.push(nextAssignment)
|
|
105
|
+
hasMissingAssignment = true
|
|
106
|
+
} else if (!assignments[existingIndex]?.color) {
|
|
107
|
+
assignments[existingIndex] = nextAssignment
|
|
108
|
+
hasMissingAssignment = true
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
return hasMissingAssignment ? assignments : null
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const updateSeriesColorAssignmentMode = (mode: 'ordered' | 'by-value') => {
|
|
116
|
+
const _state = cloneConfig(config)
|
|
117
|
+
if (!_state.general.palette) {
|
|
118
|
+
_state.general.palette = {}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
_state.general.palette.colorAssignmentMode = mode
|
|
122
|
+
if (mode === 'by-value') {
|
|
123
|
+
_state.general.palette.colorAssignments = getAssignmentsFromCurrentColors()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
updateConfig(_state)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const resetSeriesColorAssignmentsToCurrentColors = () => {
|
|
130
|
+
const _state = cloneConfig(config)
|
|
131
|
+
if (!_state.general.palette) {
|
|
132
|
+
_state.general.palette = {}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
_state.general.palette.colorAssignmentMode = 'by-value'
|
|
136
|
+
_state.general.palette.colorAssignments = getAssignmentsFromCurrentColors()
|
|
137
|
+
updateConfig(_state)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const updateSeriesColorAssignment = (key: string, color: string) => {
|
|
141
|
+
const _state = cloneConfig(config)
|
|
142
|
+
if (!_state.general.palette) {
|
|
143
|
+
_state.general.palette = {}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const currentSeriesKeys = new Set(seriesColorAssignmentItems.map(({ key }) => key))
|
|
147
|
+
const assignments = seriesColorAssignments.filter(assignment => currentSeriesKeys.has(assignment.key))
|
|
148
|
+
const existingIndex = assignments.findIndex(assignment => assignment.key === key)
|
|
149
|
+
if (existingIndex === -1) {
|
|
150
|
+
assignments.push({ key, color })
|
|
151
|
+
} else {
|
|
152
|
+
assignments[existingIndex] = { key, color }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
_state.general.palette.colorAssignmentMode = 'by-value'
|
|
156
|
+
_state.general.palette.colorAssignments = assignments
|
|
157
|
+
updateConfig(_state)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
const currentSource = { hasCustomColors, fingerprint: paletteSourceFingerprint }
|
|
162
|
+
|
|
163
|
+
if (!seriesColorAssignmentSupported || !isSeriesColorAssignmentByValue) {
|
|
164
|
+
previousPaletteSource.current = currentSource
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const shouldResetFromPalette =
|
|
169
|
+
previousPaletteSource.current !== null &&
|
|
170
|
+
!hasCustomColors &&
|
|
171
|
+
paletteColorOptions.length > 0 &&
|
|
172
|
+
(previousPaletteSource.current.hasCustomColors ||
|
|
173
|
+
previousPaletteSource.current.fingerprint !== paletteSourceFingerprint)
|
|
174
|
+
|
|
175
|
+
previousPaletteSource.current = currentSource
|
|
176
|
+
|
|
177
|
+
if (shouldResetFromPalette) {
|
|
178
|
+
resetSeriesColorAssignmentsToCurrentColors()
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const assignmentsWithMissingCurrentColors = getAssignmentsWithMissingCurrentColors()
|
|
183
|
+
if (assignmentsWithMissingCurrentColors) {
|
|
184
|
+
const _state = cloneConfig(config)
|
|
185
|
+
if (!_state.general.palette) {
|
|
186
|
+
_state.general.palette = {}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
_state.general.palette.colorAssignmentMode = 'by-value'
|
|
190
|
+
_state.general.palette.colorAssignments = assignmentsWithMissingCurrentColors
|
|
191
|
+
updateConfig(_state)
|
|
192
|
+
}
|
|
193
|
+
}, [
|
|
194
|
+
hasCustomColors,
|
|
195
|
+
isSeriesColorAssignmentByValue,
|
|
196
|
+
paletteSourceFingerprint,
|
|
197
|
+
seriesColorAssignmentItemsFingerprint,
|
|
198
|
+
seriesColorAssignmentsFingerprint,
|
|
199
|
+
seriesColorAssignmentSupported
|
|
200
|
+
])
|
|
201
|
+
|
|
202
|
+
if (!seriesColorAssignmentSupported) return null
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<fieldset className='series-color-assignments'>
|
|
206
|
+
<Select
|
|
207
|
+
value={seriesColorAssignmentMode}
|
|
208
|
+
label='Color Assignment Mode'
|
|
209
|
+
tooltip={
|
|
210
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
211
|
+
<Tooltip.Target>
|
|
212
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
213
|
+
</Tooltip.Target>
|
|
214
|
+
<Tooltip.Content>
|
|
215
|
+
<p>
|
|
216
|
+
Toggling this determines how colors in the palette are assigned. Colors can be assigned in order or can
|
|
217
|
+
be associated with specific series.
|
|
218
|
+
</p>
|
|
219
|
+
</Tooltip.Content>
|
|
220
|
+
</Tooltip>
|
|
221
|
+
}
|
|
222
|
+
fieldName='colorAssignmentMode'
|
|
223
|
+
section='general'
|
|
224
|
+
subsection='palette'
|
|
225
|
+
updateField={(_section, _subsection, _fieldName, value) => {
|
|
226
|
+
updateSeriesColorAssignmentMode(value as 'ordered' | 'by-value')
|
|
227
|
+
}}
|
|
228
|
+
options={[
|
|
229
|
+
{ label: 'Use palette order', value: 'ordered' },
|
|
230
|
+
{ label: 'Assign colors to series', value: 'by-value' }
|
|
231
|
+
]}
|
|
232
|
+
/>
|
|
233
|
+
{isSeriesColorAssignmentByValue && (
|
|
234
|
+
<div className='series-color-assignments__rows'>
|
|
235
|
+
{seriesColorAssignmentItems.map(({ key, label }) => {
|
|
236
|
+
const assignedColor = seriesColorAssignmentMap.get(key)
|
|
237
|
+
const color = assignedColor || orderedColorScale(label) || paletteColorOptions[0] || '#000000'
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
<div className='series-color-assignments__row' key={key}>
|
|
241
|
+
<label className='series-color-assignments__label' title={`Series key: ${key}`}>
|
|
242
|
+
{label}
|
|
243
|
+
</label>
|
|
244
|
+
<DataColorSelector
|
|
245
|
+
aria-label={`Color for ${label}`}
|
|
246
|
+
value={color}
|
|
247
|
+
colors={paletteColorOptions}
|
|
248
|
+
allowNone={false}
|
|
249
|
+
allowCustom={false}
|
|
250
|
+
showCustomValue={false}
|
|
251
|
+
onChange={nextColor => updateSeriesColorAssignment(key, nextColor)}
|
|
252
|
+
/>
|
|
253
|
+
</div>
|
|
254
|
+
)
|
|
255
|
+
})}
|
|
256
|
+
</div>
|
|
257
|
+
)}
|
|
258
|
+
</fieldset>
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export default SeriesColorAssignments
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
.series-color-assignments {
|
|
2
|
+
border: 1px solid #d6d7d9;
|
|
3
|
+
border-radius: 4px;
|
|
4
|
+
margin-top: 1rem;
|
|
5
|
+
padding: 0.875rem;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.series-color-assignments__rows {
|
|
9
|
+
display: grid;
|
|
10
|
+
gap: 0.5rem;
|
|
11
|
+
margin-top: 0.75rem;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.series-color-assignments__row {
|
|
15
|
+
align-items: center;
|
|
16
|
+
display: grid;
|
|
17
|
+
gap: 0.5rem;
|
|
18
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.series-color-assignments__label {
|
|
22
|
+
color: #222;
|
|
23
|
+
display: block;
|
|
24
|
+
font-size: 0.875rem;
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
text-overflow: ellipsis;
|
|
27
|
+
white-space: nowrap;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.series-color-assignments__row .data-color-selector__trigger {
|
|
31
|
+
justify-self: end;
|
|
32
|
+
}
|
|
@@ -83,3 +83,13 @@
|
|
|
83
83
|
.annotation-group {
|
|
84
84
|
border: 1px solid black;
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
.small-multiples-color-assignment-warning {
|
|
88
|
+
background: #fff7e6;
|
|
89
|
+
border-left: 3px solid #a65f00;
|
|
90
|
+
color: #3d2a00;
|
|
91
|
+
font-size: 0.875rem;
|
|
92
|
+
line-height: 1.4;
|
|
93
|
+
margin: 0.75rem 0 1rem;
|
|
94
|
+
padding: 0.5rem 0.75rem;
|
|
95
|
+
}
|
|
@@ -1,4 +1,51 @@
|
|
|
1
1
|
.cove-visualization.type-chart {
|
|
2
|
+
.axis-domain-group {
|
|
3
|
+
border: 1px solid var(--lightGray);
|
|
4
|
+
border-radius: 4px;
|
|
5
|
+
margin-top: 1em;
|
|
6
|
+
padding: 0.75em;
|
|
7
|
+
|
|
8
|
+
> label,
|
|
9
|
+
> .checkbox {
|
|
10
|
+
margin-top: 0.9em;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.axis-domain-group__title {
|
|
15
|
+
display: block;
|
|
16
|
+
font-size: 0.85em;
|
|
17
|
+
font-weight: 700;
|
|
18
|
+
margin-bottom: 0.75em;
|
|
19
|
+
text-transform: uppercase;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.axis-domain-group__row {
|
|
23
|
+
display: flex;
|
|
24
|
+
gap: 0.75em;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.axis-domain-group__field {
|
|
28
|
+
flex: 1 1 0;
|
|
29
|
+
min-width: 0;
|
|
30
|
+
|
|
31
|
+
> label {
|
|
32
|
+
margin-top: 0 !important;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.axis-domain-number {
|
|
37
|
+
max-width: 96px;
|
|
38
|
+
min-width: auto;
|
|
39
|
+
width: 100%;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.axis-domain-warning {
|
|
43
|
+
color: red;
|
|
44
|
+
display: block;
|
|
45
|
+
font-size: 0.85em;
|
|
46
|
+
margin-top: 0.25em;
|
|
47
|
+
}
|
|
48
|
+
|
|
2
49
|
.viewport-overrides {
|
|
3
50
|
button {
|
|
4
51
|
width: 100%;
|
|
@@ -22,7 +22,11 @@ export const getVisualizationTypeConfigUpdate = (
|
|
|
22
22
|
return {
|
|
23
23
|
...config,
|
|
24
24
|
visualizationType,
|
|
25
|
-
series: []
|
|
25
|
+
series: (config.series || []).map(series => ({
|
|
26
|
+
...series,
|
|
27
|
+
type: 'HeatMap',
|
|
28
|
+
axis: 'Left'
|
|
29
|
+
})),
|
|
26
30
|
yAxis: {
|
|
27
31
|
...config.yAxis,
|
|
28
32
|
type: 'categorical',
|
|
@@ -40,7 +44,7 @@ export const getVisualizationTypeConfigUpdate = (
|
|
|
40
44
|
...config.legend,
|
|
41
45
|
position: 'top',
|
|
42
46
|
style: 'gradient',
|
|
43
|
-
subStyle: '
|
|
47
|
+
subStyle: 'linear blocks'
|
|
44
48
|
},
|
|
45
49
|
general: {
|
|
46
50
|
...config.general,
|
|
@@ -40,17 +40,35 @@ describe('getVisualizationTypeConfigUpdate', () => {
|
|
|
40
40
|
const updatedConfig = getVisualizationTypeConfigUpdate(buildConfig(), 'HeatMap')
|
|
41
41
|
|
|
42
42
|
expect(updatedConfig?.visualizationType).toBe('HeatMap')
|
|
43
|
-
expect(updatedConfig?.series).toEqual([])
|
|
43
|
+
expect(updatedConfig?.series).toEqual([{ dataKey: 'Value', type: 'HeatMap', axis: 'Left' }])
|
|
44
44
|
expect(updatedConfig?.yAxis.type).toBe('categorical')
|
|
45
45
|
expect(updatedConfig?.yAxis.titlePlacement).toBe('side')
|
|
46
46
|
expect(updatedConfig?.heatmap).toEqual(HEATMAP_CONFIG_DEFAULTS)
|
|
47
47
|
expect(updatedConfig?.legend.position).toBe('top')
|
|
48
48
|
expect(updatedConfig?.legend.style).toBe('gradient')
|
|
49
|
-
expect(updatedConfig?.legend.subStyle).toBe('
|
|
49
|
+
expect(updatedConfig?.legend.subStyle).toBe('linear blocks')
|
|
50
50
|
expect(updatedConfig?.general.palette).toEqual({
|
|
51
51
|
isReversed: false,
|
|
52
52
|
version: '2.0',
|
|
53
53
|
name: 'sequential_blue'
|
|
54
54
|
})
|
|
55
55
|
})
|
|
56
|
+
|
|
57
|
+
it('preserves selected rows when switching back to HeatMap from another chart type', () => {
|
|
58
|
+
const updatedConfig = getVisualizationTypeConfigUpdate(
|
|
59
|
+
buildConfig({
|
|
60
|
+
visualizationType: 'Bar',
|
|
61
|
+
series: [
|
|
62
|
+
{ dataKey: 'North', name: 'North', type: 'Bar', axis: 'Left', tooltip: true },
|
|
63
|
+
{ dataKey: 'South', name: 'South', type: 'Bar', axis: 'Left', tooltip: true }
|
|
64
|
+
]
|
|
65
|
+
}),
|
|
66
|
+
'HeatMap'
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
expect(updatedConfig?.series).toEqual([
|
|
70
|
+
{ dataKey: 'North', name: 'North', type: 'HeatMap', axis: 'Left', tooltip: true },
|
|
71
|
+
{ dataKey: 'South', name: 'South', type: 'HeatMap', axis: 'Left', tooltip: true }
|
|
72
|
+
])
|
|
73
|
+
})
|
|
56
74
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import DataTransform from '@cdc/core/helpers/DataTransform'
|
|
2
2
|
import { ChartConfig } from '../../../types/ChartConfig'
|
|
3
3
|
import cloneConfig from '@cdc/core/helpers/cloneConfig'
|
|
4
|
-
import
|
|
4
|
+
import get from 'lodash/get'
|
|
5
5
|
|
|
6
6
|
const transform = new DataTransform()
|
|
7
7
|
|
|
@@ -31,8 +31,8 @@ export const updateFieldRankByValue = (
|
|
|
31
31
|
newConfig.rankByValue = newValue
|
|
32
32
|
|
|
33
33
|
if (config.rankByValue && !newValue) {
|
|
34
|
-
const CIkeys: string[] = Object.values(
|
|
35
|
-
const seriesKeys: string[] =
|
|
34
|
+
const CIkeys: string[] = Object.values(get(config, 'confidenceKeys', {})) as string[]
|
|
35
|
+
const seriesKeys: string[] = get(config, 'series', []).map((s: any) => s.dataKey)
|
|
36
36
|
const keysToClean: string[] = [...(seriesKeys ?? []), ...(CIkeys ?? [])]
|
|
37
37
|
|
|
38
38
|
const cleanData = config?.xAxis?.dataKey
|