@cdc/chart 4.26.5 → 4.26.6
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 +12 -8
- package/dist/{cdcchart-DQ00cQCm.es.js → cdcchart-BWVIUcAF.es.js} +5 -55
- package/dist/cdcchart.js +34093 -32767
- 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/package.json +3 -3
- package/src/CdcChart.tsx +5 -4
- package/src/CdcChartComponent.tsx +32 -9
- 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/ChartAnnotation.smoke.stories.tsx +10 -0
- 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/EditorPanel/EditorPanel.tsx +367 -136
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +101 -52
- 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/useEditorPermissions.test.tsx +256 -11
- package/src/components/EditorPanel/useEditorPermissions.ts +41 -5
- 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 +2 -2
- 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 +26 -13
- package/src/components/LineChart/index.tsx +21 -4
- package/src/components/LinearChart/tests/LinearChart.test.tsx +30 -0
- package/src/components/LinearChart.tsx +50 -15
- package/src/components/ScatterPlot/ScatterPlot.jsx +3 -3
- 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 +1 -0
- package/src/helpers/calculateLeftYAxisWidth.ts +9 -3
- package/src/helpers/colorAssignmentHelpers.ts +102 -0
- package/src/helpers/dataHelpers.ts +11 -1
- package/src/helpers/getAxisMaxOverride.ts +16 -0
- package/src/helpers/getCleanTopTickMax.ts +64 -0
- package/src/helpers/getColorScale.ts +18 -9
- package/src/helpers/getHasBoundarySuppression.ts +26 -0
- package/src/helpers/getMinMax.ts +24 -22
- package/src/helpers/getYAxisDomainData.ts +38 -0
- package/src/helpers/getYAxisFinalizationEligibility.ts +40 -0
- package/src/helpers/hasSpacedInlineLabel.ts +10 -0
- package/src/helpers/seriesColumnSettings.ts +5 -4
- package/src/helpers/smallMultiplesHelpers.ts +5 -0
- package/src/helpers/tests/calculateLeftYAxisWidth.test.ts +38 -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 +16 -2
- package/src/helpers/tests/smallMultiplesHelpers.test.ts +99 -0
- package/src/hooks/tests/useRightAxis.test.tsx +127 -0
- package/src/hooks/tests/useScales.test.tsx +307 -29
- package/src/hooks/useRightAxis.ts +30 -13
- package/src/hooks/useScales.ts +45 -28
- package/src/hooks/useTooltip.tsx +3 -1
- package/src/test/CdcChart.dataTable.test.tsx +122 -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
|
@@ -2,6 +2,7 @@ import React, { useContext } from 'react'
|
|
|
2
2
|
import { Draggable } from '@hello-pangea/dnd'
|
|
3
3
|
import ConfigContext from '../../../../ConfigContext.js'
|
|
4
4
|
import { useEditorPermissions } from '../../useEditorPermissions'
|
|
5
|
+
import { EVENT_LINE_LABEL_OFFSET } from '../../../Annotations/components/AnnotationDraggable'
|
|
5
6
|
|
|
6
7
|
// CDC Core
|
|
7
8
|
import Accordion from '@cdc/core/components/ui/Accordion'
|
|
@@ -63,6 +64,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
63
64
|
const handleAddAnnotation = () => {
|
|
64
65
|
const newAnnotation = {
|
|
65
66
|
text: 'New annotation',
|
|
67
|
+
style: 'callout',
|
|
66
68
|
anchorMode: 'fixed',
|
|
67
69
|
fontSize: 16,
|
|
68
70
|
bezier: 10,
|
|
@@ -213,7 +215,48 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
213
215
|
/>
|
|
214
216
|
</label>
|
|
215
217
|
|
|
216
|
-
|
|
218
|
+
<Select
|
|
219
|
+
label='Annotation Style:'
|
|
220
|
+
value={annotation.style || 'callout'}
|
|
221
|
+
options={[
|
|
222
|
+
{ value: 'callout', label: 'Callout' },
|
|
223
|
+
{
|
|
224
|
+
value: 'event-line',
|
|
225
|
+
label: visSupportsDataAnnotations()
|
|
226
|
+
? 'Event Line'
|
|
227
|
+
: 'Event Line (requires Line/Bar/Combo/Area/Forecasting, vertical)'
|
|
228
|
+
}
|
|
229
|
+
]}
|
|
230
|
+
section='annotations'
|
|
231
|
+
subsection={null}
|
|
232
|
+
fieldName='style'
|
|
233
|
+
updateField={(section, subsection, fieldName, value) => {
|
|
234
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
235
|
+
const target = updatedAnnotations[index]
|
|
236
|
+
target.style = value
|
|
237
|
+
|
|
238
|
+
if (value === 'event-line') {
|
|
239
|
+
target.anchorMode = 'data'
|
|
240
|
+
if (!target.dataX) {
|
|
241
|
+
target.dataX = transformedData?.[0]?.[config.xAxis.dataKey] || ''
|
|
242
|
+
}
|
|
243
|
+
target.seriesKey = ''
|
|
244
|
+
target.edit = { subject: false, label: true }
|
|
245
|
+
target.dx =
|
|
246
|
+
typeof target.dx === 'number' && target.dx < 0
|
|
247
|
+
? -EVENT_LINE_LABEL_OFFSET
|
|
248
|
+
: EVENT_LINE_LABEL_OFFSET
|
|
249
|
+
if (target.dy === undefined || target.dy === null) target.dy = -120
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
updateConfig({
|
|
253
|
+
...config,
|
|
254
|
+
annotations: updatedAnnotations
|
|
255
|
+
})
|
|
256
|
+
}}
|
|
257
|
+
/>
|
|
258
|
+
|
|
259
|
+
{visSupportsDataAnnotations() && annotation.style !== 'event-line' && (
|
|
217
260
|
<Select
|
|
218
261
|
label='Position Mode:'
|
|
219
262
|
value={annotation.anchorMode || 'fixed'}
|
|
@@ -246,24 +289,26 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
246
289
|
/>
|
|
247
290
|
)}
|
|
248
291
|
|
|
249
|
-
{visSupportsDataAnnotations() &&
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
292
|
+
{visSupportsDataAnnotations() &&
|
|
293
|
+
annotation.style !== 'event-line' &&
|
|
294
|
+
annotation.anchorMode === 'data' && (
|
|
295
|
+
<Select
|
|
296
|
+
label='Series:'
|
|
297
|
+
value={annotation.seriesKey || config.series?.[0]?.dataKey || ''}
|
|
298
|
+
options={config.series.map(s => s.dataKey)}
|
|
299
|
+
section='annotations'
|
|
300
|
+
subsection={null}
|
|
301
|
+
fieldName='seriesKey'
|
|
302
|
+
updateField={(section, subsection, fieldName, value) => {
|
|
303
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
304
|
+
updatedAnnotations[index].seriesKey = value || config.series?.[0]?.dataKey
|
|
305
|
+
updateConfig({
|
|
306
|
+
...config,
|
|
307
|
+
annotations: updatedAnnotations
|
|
308
|
+
})
|
|
309
|
+
}}
|
|
310
|
+
/>
|
|
311
|
+
)}
|
|
267
312
|
|
|
268
313
|
<label>
|
|
269
314
|
Opacity
|
|
@@ -313,24 +358,26 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
313
358
|
}}
|
|
314
359
|
/>
|
|
315
360
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
361
|
+
{annotation.style !== 'event-line' && (
|
|
362
|
+
<Select
|
|
363
|
+
label='Connection Type:'
|
|
364
|
+
value={config?.annotations[index]?.connectionType}
|
|
365
|
+
options={['Select', 'curve', 'line', 'elbow', 'none']}
|
|
366
|
+
section='annotations'
|
|
367
|
+
subsection={null}
|
|
368
|
+
fieldName='connectionType'
|
|
369
|
+
updateField={(section, subsection, fieldName, value) => {
|
|
370
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
371
|
+
updatedAnnotations[index].connectionType = value
|
|
372
|
+
updateConfig({
|
|
373
|
+
...config,
|
|
374
|
+
annotations: updatedAnnotations
|
|
375
|
+
})
|
|
376
|
+
}}
|
|
377
|
+
/>
|
|
378
|
+
)}
|
|
332
379
|
|
|
333
|
-
{annotation.connectionType === 'curve' && (
|
|
380
|
+
{annotation.style !== 'event-line' && annotation.connectionType === 'curve' && (
|
|
334
381
|
<>
|
|
335
382
|
<label>
|
|
336
383
|
Curve Control
|
|
@@ -353,22 +400,24 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
353
400
|
</>
|
|
354
401
|
)}
|
|
355
402
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
403
|
+
{annotation.style !== 'event-line' && (
|
|
404
|
+
<Select
|
|
405
|
+
label='Marker'
|
|
406
|
+
value={annotation.marker}
|
|
407
|
+
options={['arrow', 'circle']}
|
|
408
|
+
section='annotations'
|
|
409
|
+
subsection={null}
|
|
410
|
+
fieldName='marker'
|
|
411
|
+
updateField={(section, subsection, fieldName, value) => {
|
|
412
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
413
|
+
updatedAnnotations[index].marker = value
|
|
414
|
+
updateConfig({
|
|
415
|
+
...config,
|
|
416
|
+
annotations: updatedAnnotations
|
|
417
|
+
})
|
|
418
|
+
}}
|
|
419
|
+
/>
|
|
420
|
+
)}
|
|
372
421
|
</AccordionItemPanel>
|
|
373
422
|
</AccordionItem>
|
|
374
423
|
</AccessibleAccordion>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Accordion } from 'react-accessible-accordion'
|
|
3
|
+
import { render, screen, fireEvent } from '@testing-library/react'
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
5
|
+
import ConfigContext from '../../../../ConfigContext'
|
|
6
|
+
import EditorPanelContext from '../../EditorPanelContext'
|
|
7
|
+
import PanelSmallMultiples from './Panel.SmallMultiples'
|
|
8
|
+
import { createMockChartContext, createMockConfig } from '../../../LinearChart/tests/mockConfigContext'
|
|
9
|
+
|
|
10
|
+
vi.mock('@cdc/core/components/ui/Icon', () => ({
|
|
11
|
+
default: () => <span data-testid='icon' />
|
|
12
|
+
}))
|
|
13
|
+
|
|
14
|
+
const renderPanel = config => {
|
|
15
|
+
const context = createMockChartContext(config, {
|
|
16
|
+
rawData: [{ Date: '2024-01-01', series_a: 1, series_b: 2 }]
|
|
17
|
+
} as any)
|
|
18
|
+
|
|
19
|
+
render(
|
|
20
|
+
<ConfigContext.Provider value={context}>
|
|
21
|
+
<EditorPanelContext.Provider value={{ updateField: vi.fn() }}>
|
|
22
|
+
<Accordion allowZeroExpanded>
|
|
23
|
+
<PanelSmallMultiples name='Small Multiples' />
|
|
24
|
+
</Accordion>
|
|
25
|
+
</EditorPanelContext.Provider>
|
|
26
|
+
</ConfigContext.Provider>
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
fireEvent.click(screen.getByRole('button', { name: 'Small Multiples' }))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe('PanelSmallMultiples color assignments warning', () => {
|
|
33
|
+
it('shows the by-series same-color override warning only when assignments are active', () => {
|
|
34
|
+
const config = createMockConfig({
|
|
35
|
+
visualizationType: 'Line',
|
|
36
|
+
general: {
|
|
37
|
+
palette: {
|
|
38
|
+
colorAssignmentMode: 'by-value',
|
|
39
|
+
colorAssignments: [{ key: 'series_a', color: '#123456' }]
|
|
40
|
+
}
|
|
41
|
+
} as any,
|
|
42
|
+
smallMultiples: {
|
|
43
|
+
mode: 'by-series',
|
|
44
|
+
colorMode: 'same'
|
|
45
|
+
},
|
|
46
|
+
series: [
|
|
47
|
+
{ dataKey: 'series_a', name: 'Alpha', type: 'Line' },
|
|
48
|
+
{ dataKey: 'series_b', name: 'Beta', type: 'Line' }
|
|
49
|
+
] as any
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
renderPanel(config)
|
|
53
|
+
|
|
54
|
+
expect(screen.queryByText(/Color assignments are enabled/)).toBeInTheDocument()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('does not show the override warning when assignment mode is ordered', () => {
|
|
58
|
+
const config = createMockConfig({
|
|
59
|
+
visualizationType: 'Line',
|
|
60
|
+
general: {
|
|
61
|
+
palette: {
|
|
62
|
+
colorAssignmentMode: 'ordered',
|
|
63
|
+
colorAssignments: [{ key: 'series_a', color: '#123456' }]
|
|
64
|
+
}
|
|
65
|
+
} as any,
|
|
66
|
+
smallMultiples: {
|
|
67
|
+
mode: 'by-series',
|
|
68
|
+
colorMode: 'same'
|
|
69
|
+
},
|
|
70
|
+
series: [{ dataKey: 'series_a', name: 'Alpha', type: 'Line' }] as any
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
renderPanel(config)
|
|
74
|
+
|
|
75
|
+
expect(screen.queryByText(/Color assignments are enabled/)).not.toBeInTheDocument()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('does not show the override warning when assignments only contain stale keys', () => {
|
|
79
|
+
const config = createMockConfig({
|
|
80
|
+
visualizationType: 'Line',
|
|
81
|
+
general: {
|
|
82
|
+
palette: {
|
|
83
|
+
colorAssignmentMode: 'by-value',
|
|
84
|
+
colorAssignments: [{ key: 'removed_series', color: '#123456' }]
|
|
85
|
+
}
|
|
86
|
+
} as any,
|
|
87
|
+
smallMultiples: {
|
|
88
|
+
mode: 'by-series',
|
|
89
|
+
colorMode: 'same'
|
|
90
|
+
},
|
|
91
|
+
series: [{ dataKey: 'series_a', name: 'Alpha', type: 'Line' }] as any
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
renderPanel(config)
|
|
95
|
+
|
|
96
|
+
expect(screen.queryByText(/Color assignments are enabled/)).not.toBeInTheDocument()
|
|
97
|
+
})
|
|
98
|
+
})
|
|
@@ -20,6 +20,7 @@ import { useEditorPanelContext } from '../../EditorPanelContext.js'
|
|
|
20
20
|
import ConfigContext from '../../../../ConfigContext.js'
|
|
21
21
|
import { PanelProps } from '../PanelProps'
|
|
22
22
|
import { getTileKeys } from '../../../../helpers/smallMultiplesHelpers'
|
|
23
|
+
import { hasSeriesColorAssignmentOverrides } from '../../../../helpers/colorAssignmentHelpers'
|
|
23
24
|
|
|
24
25
|
const PanelSmallMultiples: FC<PanelProps> = props => {
|
|
25
26
|
const { config, rawData, updateConfig } = useContext<ChartContext>(ConfigContext)
|
|
@@ -273,6 +274,15 @@ const PanelSmallMultiples: FC<PanelProps> = props => {
|
|
|
273
274
|
}
|
|
274
275
|
/>
|
|
275
276
|
|
|
277
|
+
{config.smallMultiples?.mode === 'by-series' &&
|
|
278
|
+
config.smallMultiples?.colorMode === 'same' &&
|
|
279
|
+
hasSeriesColorAssignmentOverrides(config) && (
|
|
280
|
+
<p className='small-multiples-color-assignment-warning mt-1'>
|
|
281
|
+
Color assignments are enabled in the Visual section, so tiles will use their assigned series
|
|
282
|
+
colors instead of the ‘Same Color’ setting.
|
|
283
|
+
</p>
|
|
284
|
+
)}
|
|
285
|
+
|
|
276
286
|
{/* Custom Tile Titles - only show for by-column mode */}
|
|
277
287
|
{config.smallMultiples?.mode === 'by-column' && (
|
|
278
288
|
<div>
|