@cdc/chart 4.25.8 → 4.25.11
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/.claude/settings.local.json +9 -0
- package/dist/{cdcchart-1a1724a1.es.js → cdcchart-dgT_1dIT.es.js} +136 -151
- package/dist/cdcchart.js +44236 -40355
- package/examples/feature/__data__/planet-example-data.json +0 -30
- package/examples/feature/boxplot/valid-boxplot.csv +38 -17
- package/examples/grouped-bar-test.json +400 -0
- package/examples/private/DEV-11825.json +573 -0
- package/examples/private/d.json +382 -0
- package/examples/private/example-2.json +49784 -0
- package/examples/private/f2.json +1 -0
- package/examples/private/f4.json +1577 -0
- package/examples/private/forecast.json +1180 -0
- package/examples/private/lollipop.json +468 -0
- package/examples/private/na.json +913 -0
- package/examples/private/new.json +48756 -0
- package/examples/private/pie-chart-legend.json +904 -0
- package/examples/private/test-data.csv +28 -0
- package/examples/suppressed_tooltip.json +480 -0
- package/index.html +2 -133
- package/package.json +25 -7
- package/src/CdcChart.tsx +9 -13
- package/src/CdcChartComponent.tsx +403 -92
- package/src/_stories/Chart.Anchors.stories.tsx +2 -2
- package/src/_stories/Chart.BoxPlot.stories.tsx +1 -1
- package/src/_stories/Chart.CI.stories.tsx +1 -1
- package/src/_stories/Chart.Combo.stories.tsx +18 -0
- package/src/_stories/Chart.CustomColors.stories.tsx +1 -1
- package/src/_stories/Chart.DynamicSeries.stories.tsx +2 -2
- package/src/_stories/Chart.Filters.stories.tsx +2 -2
- package/src/_stories/Chart.Forecast.stories.tsx +36 -0
- package/src/_stories/Chart.HTMLInDataTable.stories.tsx +520 -0
- package/src/_stories/Chart.Legend.Gradient.stories.tsx +2 -2
- package/src/_stories/Chart.Patterns.stories.tsx +20 -0
- package/src/_stories/Chart.PreserveDecimals.stories.tsx +220 -0
- package/src/_stories/Chart.ScatterPlot.stories.tsx +1 -1
- package/src/_stories/Chart.SmallMultiples.stories.tsx +47 -0
- package/src/_stories/Chart.stories.tsx +8 -5
- package/src/_stories/Chart.tooltip.stories.tsx +1 -1
- package/src/_stories/ChartAnnotation.stories.tsx +7 -4
- package/src/_stories/ChartAxisLabels.stories.tsx +2 -2
- package/src/_stories/ChartAxisTitles.stories.tsx +2 -2
- package/src/_stories/ChartBar.Editor.stories.tsx +3580 -0
- package/src/_stories/ChartEditor.Editor.stories.tsx +658 -0
- package/src/_stories/ChartEditor.stories.tsx +59 -60
- package/src/_stories/ChartLine.Suppression.stories.tsx +1 -1
- package/src/_stories/ChartLine.Symbols.stories.tsx +1 -1
- package/src/_stories/ChartPrefixSuffix.stories.tsx +2 -2
- package/src/_stories/_mock/combo.json +451 -0
- package/src/_stories/_mock/editor-test-configs.json +376 -0
- package/src/_stories/_mock/editor-test-datasets.json +477 -0
- package/src/_stories/_mock/editor-tests/bar-chart-editor-test.json +255 -0
- package/src/_stories/_mock/editor-tests/bar-chart-general-test.json +267 -0
- package/src/_stories/_mock/editor-tests/bar-chart-test.json +237 -0
- package/src/_stories/_mock/forecast_combo_with_gaps.json +913 -0
- package/src/_stories/_mock/pie_config.json +257 -62
- package/src/_stories/_mock/small_multiples/small_multiples_bars.json +1944 -0
- package/src/_stories/_mock/small_multiples/small_multiples_big_data_bars.json +1114 -0
- package/src/_stories/_mock/small_multiples/small_multiples_lines.json +2646 -0
- package/src/_stories/_mock/small_multiples/small_multiples_lines_colors.json +1305 -0
- package/src/_stories/_mock/small_multiples/small_multiples_stacked_bars.json +1936 -0
- package/src/_stories/_mock/stacked-pattern-test.json +520 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +1 -0
- package/src/components/Annotations/components/AnnotationDropdown.tsx +1 -1
- package/src/components/Annotations/components/findNearestDatum.ts +6 -41
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +10 -6
- package/src/components/AreaChart/index.tsx +1 -2
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +161 -22
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +138 -5
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +215 -73
- package/src/components/BarChart/components/BarChart.Vertical.tsx +155 -22
- package/src/components/BarChart/helpers/index.ts +43 -4
- package/src/components/BarChart/helpers/lollipopColors.ts +27 -0
- package/src/components/BarChart/helpers/useBarChart.ts +25 -3
- package/src/components/BoxPlot/BoxPlot.Vertical.tsx +2 -1
- package/src/components/BoxPlot/helpers/index.ts +3 -3
- package/src/components/Brush/BrushChart.tsx +1 -1
- package/src/components/DeviationBar.jsx +9 -6
- package/src/components/EditorPanel/EditorPanel.tsx +563 -229
- package/src/components/EditorPanel/EditorPanelContext.ts +3 -0
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +96 -111
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +19 -1
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +461 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +80 -67
- package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +422 -0
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +188 -139
- package/src/components/EditorPanel/components/Panels/index.tsx +5 -1
- package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +0 -8
- package/src/components/EditorPanel/editor-panel.scss +0 -20
- package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +49 -48
- package/src/components/EditorPanel/useEditorPermissions.ts +7 -15
- package/src/components/Forecasting/Forecasting.tsx +175 -27
- package/src/components/ForestPlot/ForestPlot.tsx +11 -7
- package/src/components/ForestPlot/ForestPlotProps.ts +1 -1
- package/src/components/Legend/Legend.Component.tsx +114 -14
- package/src/components/Legend/helpers/createFormatLabels.tsx +230 -171
- package/src/components/Legend/helpers/getLegendClasses.ts +0 -1
- package/src/components/LegendWrapper.tsx +1 -1
- package/src/components/LineChart/LineChartProps.ts +0 -3
- package/src/components/LineChart/components/LineChart.Circle.tsx +2 -2
- package/src/components/LineChart/helpers.ts +1 -1
- package/src/components/LineChart/index.tsx +38 -15
- package/src/components/LinearChart.tsx +96 -84
- package/src/components/PairedBarChart.jsx +6 -4
- package/src/components/PieChart/PieChart.tsx +170 -54
- package/src/components/Regions/components/Regions.tsx +3 -24
- package/src/components/Sankey/components/Sankey.tsx +7 -1
- package/src/components/Sankey/types/index.ts +1 -1
- package/src/components/ScatterPlot/ScatterPlot.jsx +32 -4
- package/src/components/SmallMultiples/SmallMultipleTile.tsx +198 -0
- package/src/components/SmallMultiples/SmallMultiples.css +32 -0
- package/src/components/SmallMultiples/SmallMultiples.tsx +271 -0
- package/src/components/SmallMultiples/index.ts +2 -0
- package/src/data/initial-state.js +327 -293
- package/src/helpers/buildForecastPaletteMappings.ts +112 -0
- package/src/helpers/buildForecastPaletteOptions.ts +71 -0
- package/src/helpers/getColorScale.ts +82 -8
- package/src/{hooks/useMinMax.ts → helpers/getMinMax.ts} +14 -7
- package/src/helpers/getNewRuntime.ts +1 -1
- package/src/helpers/getTransformedData.ts +1 -1
- package/src/helpers/getYAxisAutoPadding.ts +53 -0
- package/src/helpers/smallMultiplesHelpers.ts +529 -0
- package/src/hooks/useChartHoverAnalytics.tsx +44 -0
- package/src/hooks/useProgrammaticTooltip.ts +96 -0
- package/src/hooks/useReduceData.ts +105 -70
- package/src/hooks/useScales.ts +88 -34
- package/src/hooks/useSmallMultipleSynchronization.ts +59 -0
- package/src/hooks/useTooltip.tsx +116 -29
- package/src/index.jsx +0 -2
- package/src/scss/main.scss +13 -80
- package/src/store/chart.actions.ts +2 -0
- package/src/store/chart.reducer.ts +5 -1
- package/src/test/CdcChart.test.jsx +8 -3
- package/src/types/ChartConfig.ts +53 -11
- package/src/types/ChartContext.ts +4 -0
- package/vite.config.js +1 -1
- package/vitest.config.ts +16 -0
- package/src/_stories/_mock/pie_data.json +0 -218
- package/src/components/AreaChart/components/AreaChart.jsx +0 -109
- package/src/coreStyles_chart.scss +0 -3
- package/src/helpers/configHelpers.ts +0 -28
- package/src/helpers/generateColorsArray.ts +0 -8
- package/src/helpers/sort.ts +0 -7
- package/src/hooks/useActiveElement.js +0 -19
- package/src/hooks/useChartClasses.js +0 -41
- package/src/hooks/useColorPalette.js +0 -76
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { useContext, FC } from 'react'
|
|
1
|
+
import { useContext, FC, useMemo } from 'react'
|
|
2
|
+
import _ from 'lodash'
|
|
3
|
+
import cloneConfig from '@cdc/core/helpers/cloneConfig'
|
|
2
4
|
|
|
3
5
|
// external libraries
|
|
4
6
|
import {
|
|
@@ -15,7 +17,10 @@ import Icon from '@cdc/core/components/ui/Icon'
|
|
|
15
17
|
import InputToggle from '@cdc/core/components/inputs/InputToggle'
|
|
16
18
|
|
|
17
19
|
// contexts
|
|
18
|
-
import { useColorPalette } from '
|
|
20
|
+
import { useColorPalette } from '@cdc/core/hooks/useColorPalette'
|
|
21
|
+
import { getCurrentPaletteName } from '@cdc/core/helpers/palettes/utils'
|
|
22
|
+
import { getColorPaletteVersion } from '@cdc/core/helpers/getColorPaletteVersion'
|
|
23
|
+
import { isCoveDeveloperMode } from '@cdc/core/helpers/queryStringUtils'
|
|
19
24
|
import { ChartContext } from './../../../../types/ChartContext.js'
|
|
20
25
|
|
|
21
26
|
import { useEditorPermissions } from '../../useEditorPermissions.js'
|
|
@@ -23,17 +28,23 @@ import { useEditorPanelContext } from '../../EditorPanelContext.js'
|
|
|
23
28
|
import ConfigContext from '../../../../ConfigContext.js'
|
|
24
29
|
import { PanelProps } from '../PanelProps'
|
|
25
30
|
import { LineChartConfig } from '../../../../types/ChartConfig'
|
|
31
|
+
import { PaletteSelector, DeveloperPaletteRollback } from '@cdc/core/components/PaletteSelector'
|
|
32
|
+
import { HeaderThemeSelector } from '@cdc/core/components/HeaderThemeSelector'
|
|
33
|
+
import { CustomColorsEditor } from '@cdc/core/components/CustomColorsEditor'
|
|
34
|
+
import { getColorScale } from '../../../../helpers/getColorScale'
|
|
35
|
+
import '@cdc/core/styles/v2/components/editor.scss'
|
|
26
36
|
import './panelVisual.styles.css'
|
|
27
37
|
|
|
28
38
|
const PanelVisual: FC<PanelProps> = props => {
|
|
29
39
|
const { config, updateConfig, colorPalettes, twoColorPalette } = useContext<ChartContext>(ConfigContext)
|
|
30
40
|
const { visual } = config
|
|
31
|
-
|
|
41
|
+
|
|
42
|
+
const { setLollipopShape, updateField, handlePaletteSelection, handleTwoColorPaletteSelection } =
|
|
43
|
+
useEditorPanelContext()
|
|
32
44
|
const {
|
|
33
45
|
visHasBarBorders,
|
|
34
46
|
visCanAnimate,
|
|
35
47
|
visSupportsNonSequentialPallete,
|
|
36
|
-
headerColors,
|
|
37
48
|
visSupportsTooltipOpacity,
|
|
38
49
|
visSupportsTooltipLines,
|
|
39
50
|
visSupportsBarSpace,
|
|
@@ -45,6 +56,14 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
45
56
|
} = useEditorPermissions()
|
|
46
57
|
const { twoColorPalettes, sequential, nonSequential, accessibleColors } = useColorPalette(config, updateConfig)
|
|
47
58
|
|
|
59
|
+
const currentPaletteName = getCurrentPaletteName(config)
|
|
60
|
+
|
|
61
|
+
const versionedTwoColorPalette = useMemo(() => {
|
|
62
|
+
const version = getColorPaletteVersion(config)
|
|
63
|
+
const versionKey = `v${version}`
|
|
64
|
+
return twoColorPalette[versionKey] || twoColorPalette.v2
|
|
65
|
+
}, [config, twoColorPalette])
|
|
66
|
+
|
|
48
67
|
const updateColor = (property, _value) => {
|
|
49
68
|
console.error('value', _value)
|
|
50
69
|
if (property === 'storyNodeFontColor') {
|
|
@@ -71,7 +90,7 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
71
90
|
}
|
|
72
91
|
|
|
73
92
|
return (
|
|
74
|
-
<AccordionItem>
|
|
93
|
+
<AccordionItem className='panel-visual'>
|
|
75
94
|
<AccordionItemHeading>
|
|
76
95
|
<AccordionItemButton>Visual</AccordionItemButton>
|
|
77
96
|
</AccordionItemHeading>
|
|
@@ -232,140 +251,152 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
232
251
|
/>
|
|
233
252
|
</>
|
|
234
253
|
)}
|
|
235
|
-
{
|
|
236
|
-
<label className='header'>
|
|
237
|
-
<span className='edit-label'>Header Theme</span>
|
|
238
|
-
<ul className='color-palette'>
|
|
239
|
-
{headerColors.map(palette => (
|
|
240
|
-
<button
|
|
241
|
-
title={palette}
|
|
242
|
-
key={palette}
|
|
243
|
-
onClick={e => {
|
|
244
|
-
e.preventDefault()
|
|
245
|
-
updateConfig({ ...config, theme: palette })
|
|
246
|
-
}}
|
|
247
|
-
className={config.theme === palette ? 'selected ' + palette : palette}
|
|
248
|
-
></button>
|
|
249
|
-
))}
|
|
250
|
-
</ul>
|
|
251
|
-
</label>
|
|
252
|
-
{/* eslint-enable */}
|
|
254
|
+
<HeaderThemeSelector selectedTheme={config.theme} onThemeSelect={theme => updateConfig({ ...config, theme })} />
|
|
253
255
|
{(visSupportsNonSequentialPallete() || visSupportsNonSequentialPallete()) && (
|
|
254
256
|
<>
|
|
255
257
|
<label>
|
|
256
258
|
<span className='edit-label'>Chart Color Palette</span>
|
|
257
259
|
</label>
|
|
260
|
+
<div className='mb-2'>
|
|
261
|
+
<small className='text-muted'>
|
|
262
|
+
Review color contrasts{' '}
|
|
263
|
+
<a href='https://webaim.org/resources/contrastchecker/' target='_blank' rel='noopener noreferrer'>
|
|
264
|
+
here
|
|
265
|
+
</a>
|
|
266
|
+
</small>
|
|
267
|
+
</div>
|
|
268
|
+
<DeveloperPaletteRollback config={config} updateConfig={updateConfig} />
|
|
258
269
|
{visSupportsReverseColorPalette() && (
|
|
259
270
|
<InputToggle
|
|
260
|
-
|
|
271
|
+
section='general'
|
|
272
|
+
subsection='palette'
|
|
273
|
+
fieldName='isReversed'
|
|
261
274
|
size='small'
|
|
262
275
|
label='Use selected palette in reverse order'
|
|
263
276
|
updateField={updateField}
|
|
264
|
-
|
|
277
|
+
onClick={() => {
|
|
278
|
+
const _state = cloneConfig(config)
|
|
279
|
+
const currentPaletteName = getCurrentPaletteName(config)
|
|
280
|
+
_state.general.palette.isReversed = !_state.general.palette.isReversed
|
|
281
|
+
let paletteName = ''
|
|
282
|
+
if (_state.general.palette.isReversed && !currentPaletteName.endsWith('reverse')) {
|
|
283
|
+
paletteName = currentPaletteName + 'reverse'
|
|
284
|
+
}
|
|
285
|
+
if (!_state.general.palette.isReversed && currentPaletteName.endsWith('reverse')) {
|
|
286
|
+
paletteName = currentPaletteName.slice(0, -7)
|
|
287
|
+
}
|
|
288
|
+
if (paletteName) {
|
|
289
|
+
_state.general.palette.name = paletteName
|
|
290
|
+
}
|
|
291
|
+
updateConfig(_state)
|
|
292
|
+
}}
|
|
293
|
+
value={config.general?.palette?.isReversed}
|
|
265
294
|
/>
|
|
266
295
|
)}
|
|
267
296
|
{visSupportsSequentialPallete() && (
|
|
268
297
|
<>
|
|
269
298
|
<span>Sequential</span>
|
|
270
|
-
<
|
|
271
|
-
{sequential
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const colorThree = {
|
|
281
|
-
backgroundColor: colorPalettes[palette][5]
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
return (
|
|
285
|
-
<button
|
|
286
|
-
title={palette}
|
|
287
|
-
key={palette}
|
|
288
|
-
onClick={e => {
|
|
289
|
-
e.preventDefault()
|
|
290
|
-
updateConfig({ ...config, palette })
|
|
291
|
-
}}
|
|
292
|
-
className={config.palette === palette ? 'selected' : ''}
|
|
293
|
-
>
|
|
294
|
-
<span style={colorOne}></span>
|
|
295
|
-
<span style={colorTwo}></span>
|
|
296
|
-
<span style={colorThree}></span>
|
|
297
|
-
</button>
|
|
298
|
-
)
|
|
299
|
-
})}
|
|
300
|
-
</ul>
|
|
299
|
+
<PaletteSelector
|
|
300
|
+
palettes={sequential}
|
|
301
|
+
colorPalettes={colorPalettes}
|
|
302
|
+
config={config}
|
|
303
|
+
onPaletteSelect={handlePaletteSelection}
|
|
304
|
+
selectedPalette={currentPaletteName}
|
|
305
|
+
colorIndices={[2, 3, 5]}
|
|
306
|
+
className='color-palette'
|
|
307
|
+
/>
|
|
301
308
|
</>
|
|
302
309
|
)}
|
|
303
310
|
{visSupportsNonSequentialPallete() && (
|
|
304
311
|
<>
|
|
305
312
|
<span>Non-Sequential</span>
|
|
306
|
-
<
|
|
307
|
-
{nonSequential
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const colorThree = {
|
|
317
|
-
backgroundColor: colorPalettes[palette][6]
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
return (
|
|
321
|
-
<button
|
|
322
|
-
title={palette}
|
|
323
|
-
key={palette}
|
|
324
|
-
onClick={e => {
|
|
325
|
-
e.preventDefault()
|
|
326
|
-
updateConfig({ ...config, palette })
|
|
327
|
-
}}
|
|
328
|
-
className={config.palette === palette ? 'selected' : ''}
|
|
329
|
-
>
|
|
330
|
-
<span style={colorOne}></span>
|
|
331
|
-
<span style={colorTwo}></span>
|
|
332
|
-
<span style={colorThree}></span>
|
|
333
|
-
</button>
|
|
334
|
-
)
|
|
335
|
-
})}
|
|
336
|
-
</ul>
|
|
313
|
+
<PaletteSelector
|
|
314
|
+
palettes={nonSequential}
|
|
315
|
+
colorPalettes={colorPalettes}
|
|
316
|
+
config={config}
|
|
317
|
+
onPaletteSelect={handlePaletteSelection}
|
|
318
|
+
selectedPalette={getCurrentPaletteName(config)}
|
|
319
|
+
colorIndices={[2, 4, 6]}
|
|
320
|
+
className='color-palette'
|
|
321
|
+
/>
|
|
337
322
|
<span>Colorblind Safe</span>
|
|
338
|
-
<
|
|
339
|
-
{accessibleColors
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
323
|
+
<PaletteSelector
|
|
324
|
+
palettes={accessibleColors}
|
|
325
|
+
colorPalettes={colorPalettes}
|
|
326
|
+
config={config}
|
|
327
|
+
onPaletteSelect={handlePaletteSelection}
|
|
328
|
+
selectedPalette={getCurrentPaletteName(config)}
|
|
329
|
+
colorIndices={[2, 3, 5]}
|
|
330
|
+
className='color-palette'
|
|
331
|
+
/>
|
|
332
|
+
</>
|
|
333
|
+
)}
|
|
347
334
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
335
|
+
{isCoveDeveloperMode() && (visSupportsSequentialPallete() || visSupportsNonSequentialPallete()) && (
|
|
336
|
+
<>
|
|
337
|
+
<div className='mt-3'>
|
|
338
|
+
<label className='checkbox'>
|
|
339
|
+
<input
|
|
340
|
+
type='checkbox'
|
|
341
|
+
checked={
|
|
342
|
+
!!(config.general?.palette?.customColorsOrdered || config.general?.palette?.customColors)
|
|
343
|
+
}
|
|
344
|
+
onChange={e => {
|
|
345
|
+
const _state = cloneConfig(config)
|
|
346
|
+
// Ensure palette object exists
|
|
347
|
+
if (!_state.general.palette) {
|
|
348
|
+
_state.general.palette = {}
|
|
349
|
+
}
|
|
350
|
+
if (e.target.checked) {
|
|
351
|
+
// Extract colors from current color scale if runtime data available
|
|
352
|
+
if (config.runtime?.seriesLabelsAll && config.runtime.seriesLabelsAll.length > 0) {
|
|
353
|
+
const colorScale = getColorScale(config)
|
|
354
|
+
const extractedColors = config.runtime.seriesLabelsAll.map((label: string) =>
|
|
355
|
+
colorScale(label)
|
|
356
|
+
)
|
|
357
|
+
_state.general.palette.customColorsOrdered =
|
|
358
|
+
extractedColors.length > 0
|
|
359
|
+
? extractedColors
|
|
360
|
+
: ['#3366cc', '#5588dd', '#77aaee', '#99ccff']
|
|
361
|
+
} else {
|
|
362
|
+
// Fallback to default colors if runtime not available
|
|
363
|
+
_state.general.palette.customColorsOrdered = ['#3366cc', '#5588dd', '#77aaee', '#99ccff']
|
|
364
|
+
}
|
|
365
|
+
} else {
|
|
366
|
+
// Remove custom colors and revert to default palette
|
|
367
|
+
delete _state.general.palette.customColorsOrdered
|
|
368
|
+
delete _state.general.palette.customColors
|
|
369
|
+
// Set default palette if none exists
|
|
370
|
+
if (!_state.general.palette.name) {
|
|
371
|
+
_state.general.palette.name = 'qualitative_standard'
|
|
372
|
+
_state.general.palette.version = '2.0'
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
updateConfig(_state)
|
|
376
|
+
}}
|
|
377
|
+
/>
|
|
378
|
+
Use Custom Colors
|
|
379
|
+
</label>
|
|
380
|
+
</div>
|
|
351
381
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
382
|
+
{(config.general?.palette?.customColorsOrdered || config.general?.palette?.customColors) && (
|
|
383
|
+
<div className='mt-2'>
|
|
384
|
+
<CustomColorsEditor
|
|
385
|
+
colors={config.general.palette.customColorsOrdered || config.general.palette.customColors}
|
|
386
|
+
onChange={newColors => {
|
|
387
|
+
const _state = cloneConfig(config)
|
|
388
|
+
if (!_state.general.palette) {
|
|
389
|
+
_state.general.palette = {}
|
|
390
|
+
}
|
|
391
|
+
_state.general.palette.customColorsOrdered = newColors
|
|
392
|
+
updateConfig(_state)
|
|
393
|
+
}}
|
|
394
|
+
label='Custom Color Order'
|
|
395
|
+
minColors={1}
|
|
396
|
+
maxColors={20}
|
|
397
|
+
/>
|
|
398
|
+
</div>
|
|
399
|
+
)}
|
|
369
400
|
</>
|
|
370
401
|
)}
|
|
371
402
|
</>
|
|
@@ -406,6 +437,7 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
406
437
|
)}
|
|
407
438
|
{(config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') && (
|
|
408
439
|
<>
|
|
440
|
+
<DeveloperPaletteRollback config={config} updateConfig={updateConfig} className='mt-3' />
|
|
409
441
|
<InputToggle
|
|
410
442
|
section='twoColor'
|
|
411
443
|
fieldName='isPaletteReversed'
|
|
@@ -415,30 +447,48 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
415
447
|
value={config.twoColor.isPaletteReversed}
|
|
416
448
|
/>
|
|
417
449
|
<ul className='color-palette'>
|
|
418
|
-
{twoColorPalettes
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
450
|
+
{twoColorPalettes
|
|
451
|
+
.map(palette => {
|
|
452
|
+
const paletteColors = versionedTwoColorPalette[palette]
|
|
422
453
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
454
|
+
if (!paletteColors || paletteColors.length < 2) {
|
|
455
|
+
console.warn(
|
|
456
|
+
`Two-color palette "${palette}" not found or incomplete in version ${getColorPaletteVersion(
|
|
457
|
+
config
|
|
458
|
+
)}`
|
|
459
|
+
)
|
|
460
|
+
return null
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const colorOne = {
|
|
464
|
+
backgroundColor: paletteColors[0]
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const colorTwo = {
|
|
468
|
+
backgroundColor: paletteColors[1]
|
|
469
|
+
}
|
|
426
470
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
471
|
+
return (
|
|
472
|
+
<button
|
|
473
|
+
title={palette}
|
|
474
|
+
key={palette}
|
|
475
|
+
onClick={e => {
|
|
476
|
+
e.preventDefault()
|
|
477
|
+
if (handleTwoColorPaletteSelection) {
|
|
478
|
+
handleTwoColorPaletteSelection(palette)
|
|
479
|
+
} else {
|
|
480
|
+
// Fallback to direct update if handler not available
|
|
481
|
+
updateConfig({ ...config, twoColor: { ...config.twoColor, palette } })
|
|
482
|
+
}
|
|
483
|
+
}}
|
|
484
|
+
className={config.twoColor.palette === palette ? 'selected' : ''}
|
|
485
|
+
>
|
|
486
|
+
<span className='two-color' style={colorOne}></span>
|
|
487
|
+
<span className='two-color' style={colorTwo}></span>
|
|
488
|
+
</button>
|
|
489
|
+
)
|
|
490
|
+
})
|
|
491
|
+
.filter(Boolean)}
|
|
442
492
|
</ul>
|
|
443
493
|
</>
|
|
444
494
|
)}
|
|
@@ -448,7 +498,6 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
448
498
|
value={config.dataCutoff}
|
|
449
499
|
type='number'
|
|
450
500
|
fieldName='dataCutoff'
|
|
451
|
-
className='number-narrow'
|
|
452
501
|
label='Data Cutoff'
|
|
453
502
|
updateField={updateField}
|
|
454
503
|
tooltip={
|
|
@@ -6,6 +6,8 @@ import BoxPlot from './Panel.BoxPlot'
|
|
|
6
6
|
import Visual from './Panel.Visual'
|
|
7
7
|
import Sankey from './Panel.Sankey'
|
|
8
8
|
import Annotate from './Panel.Annotate'
|
|
9
|
+
import PatternSettings from './Panel.PatternSettings'
|
|
10
|
+
import SmallMultiples from './Panel.SmallMultiples'
|
|
9
11
|
|
|
10
12
|
const Panels = {
|
|
11
13
|
ForestPlot: ForestPlotSettings,
|
|
@@ -15,7 +17,9 @@ const Panels = {
|
|
|
15
17
|
BoxPlot,
|
|
16
18
|
Visual,
|
|
17
19
|
Sankey,
|
|
18
|
-
Annotate
|
|
20
|
+
Annotate,
|
|
21
|
+
PatternSettings,
|
|
22
|
+
SmallMultiples
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
export default Panels
|
|
@@ -7,26 +7,6 @@
|
|
|
7
7
|
text-align: left;
|
|
8
8
|
|
|
9
9
|
span {
|
|
10
|
-
display: inline-block;
|
|
11
|
-
float: right;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.edit-block {
|
|
16
|
-
margin-top: 0;
|
|
17
|
-
padding: 1em;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.viewport-overrides {
|
|
22
|
-
button {
|
|
23
|
-
width: 100%;
|
|
24
|
-
padding: 1em;
|
|
25
|
-
margin-top: 1em;
|
|
26
|
-
text-align: left;
|
|
27
|
-
|
|
28
|
-
span {
|
|
29
|
-
display: inline-block;
|
|
30
10
|
float: right;
|
|
31
11
|
}
|
|
32
12
|
}
|
|
@@ -1,48 +1,49 @@
|
|
|
1
|
-
import DataTransform from '@cdc/core/helpers/DataTransform'
|
|
2
|
-
import { ChartConfig } from '../../../types/ChartConfig'
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
let
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
newConfig
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
1
|
+
import DataTransform from '@cdc/core/helpers/DataTransform'
|
|
2
|
+
import { ChartConfig } from '../../../types/ChartConfig'
|
|
3
|
+
import cloneConfig from '@cdc/core/helpers/cloneConfig'
|
|
4
|
+
import _ from 'lodash'
|
|
5
|
+
|
|
6
|
+
const transform = new DataTransform()
|
|
7
|
+
|
|
8
|
+
const indexOfObj = (data, obj) => {
|
|
9
|
+
for (let i = 0; i < data.length; i++) {
|
|
10
|
+
let keys = Object.keys(data[i])
|
|
11
|
+
let equal = true
|
|
12
|
+
for (let j = 0; j < keys.length; j++) {
|
|
13
|
+
if (data[i][keys[j]] !== obj[keys[j]]) {
|
|
14
|
+
equal = false
|
|
15
|
+
break
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (equal) {
|
|
19
|
+
return i
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return -1
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const updateFieldRankByValue = (
|
|
26
|
+
config: ChartConfig,
|
|
27
|
+
newValue: 'asc' | 'desc' | undefined,
|
|
28
|
+
preTransformedData: Object[]
|
|
29
|
+
): [ChartConfig, Object[]?] => {
|
|
30
|
+
const newConfig = cloneConfig(config)
|
|
31
|
+
newConfig.rankByValue = newValue
|
|
32
|
+
|
|
33
|
+
if (config.rankByValue && !newValue) {
|
|
34
|
+
const CIkeys: string[] = Object.values(_.get(config, 'confidenceKeys', {})) as string[]
|
|
35
|
+
const seriesKeys: string[] = _.get(config, 'series', []).map((s: any) => s.dataKey)
|
|
36
|
+
const keysToClean: string[] = [...(seriesKeys ?? []), ...(CIkeys ?? [])]
|
|
37
|
+
|
|
38
|
+
const cleanData = config?.xAxis?.dataKey
|
|
39
|
+
? transform.cleanData(config.data, config.xAxis.dataKey, keysToClean)
|
|
40
|
+
: config.data
|
|
41
|
+
const newData = preTransformedData.sort((a, b) => {
|
|
42
|
+
const aIndex = indexOfObj(cleanData, a)
|
|
43
|
+
const bIndex = indexOfObj(cleanData, b)
|
|
44
|
+
return aIndex - bIndex
|
|
45
|
+
})
|
|
46
|
+
return [newConfig, newData]
|
|
47
|
+
}
|
|
48
|
+
return [newConfig]
|
|
49
|
+
}
|
|
@@ -22,20 +22,6 @@ export const useEditorPermissions = () => {
|
|
|
22
22
|
'Scatter Plot',
|
|
23
23
|
'Spark Line',
|
|
24
24
|
'Sankey'
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
const headerColors = [
|
|
28
|
-
'theme-blue',
|
|
29
|
-
'theme-purple',
|
|
30
|
-
'theme-brown',
|
|
31
|
-
'theme-teal',
|
|
32
|
-
'theme-pink',
|
|
33
|
-
'theme-orange',
|
|
34
|
-
'theme-slate',
|
|
35
|
-
'theme-indigo',
|
|
36
|
-
'theme-cyan',
|
|
37
|
-
'theme-green',
|
|
38
|
-
'theme-amber'
|
|
39
25
|
]
|
|
40
26
|
|
|
41
27
|
const visSupportsDateCategoryAxis = () => {
|
|
@@ -383,6 +369,12 @@ export const useEditorPermissions = () => {
|
|
|
383
369
|
)
|
|
384
370
|
}
|
|
385
371
|
|
|
372
|
+
const visSupportsSmallMultiples = () => {
|
|
373
|
+
const enabledCharts = ['Line', 'Bar', 'Area Chart', 'Combo', 'Box Plot', 'Scatter Plot']
|
|
374
|
+
if (enabledCharts.includes(visualizationType)) return true
|
|
375
|
+
return false
|
|
376
|
+
}
|
|
377
|
+
|
|
386
378
|
const visSupportsYPadding = () => {
|
|
387
379
|
return !config.yAxis.inlineLabel || !config.yAxis.inlineLabel?.includes(' ')
|
|
388
380
|
}
|
|
@@ -411,7 +403,6 @@ export const useEditorPermissions = () => {
|
|
|
411
403
|
|
|
412
404
|
return {
|
|
413
405
|
enabledChartTypes,
|
|
414
|
-
headerColors,
|
|
415
406
|
visCanAnimate,
|
|
416
407
|
visHasAnchors,
|
|
417
408
|
visHasBarBorders,
|
|
@@ -460,6 +451,7 @@ export const useEditorPermissions = () => {
|
|
|
460
451
|
visSupportsValueAxisMax,
|
|
461
452
|
visSupportsValueAxisMin,
|
|
462
453
|
visSupportsDynamicSeries,
|
|
454
|
+
visSupportsSmallMultiples,
|
|
463
455
|
visSupportsYPadding,
|
|
464
456
|
visHasSingleSeriesTooltip,
|
|
465
457
|
visHasCategoricalAxis
|