@cdc/chart 4.26.2 → 4.26.3
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/LICENSE +201 -0
- package/dist/cdcchart.js +35674 -32430
- package/examples/data/data-with-metadata.json +10 -0
- package/examples/feature/pie/planet-pie-example-config.json +2 -1
- package/examples/metadata-variables.json +58 -0
- package/package.json +3 -3
- package/src/CdcChart.tsx +8 -4
- package/src/CdcChartComponent.tsx +321 -288
- package/src/_stories/Chart.CustomColors.stories.tsx +74 -0
- package/src/_stories/Chart.Defaults.stories.tsx +95 -0
- package/src/_stories/Chart.SmallestLeftAxisMax.stories.tsx +64 -0
- package/src/_stories/Chart.stories.tsx +36 -2
- package/src/_stories/ChartBar.Editor.stories.tsx +97 -38
- package/src/_stories/ChartBrush.Editor.stories.tsx +11 -25
- package/src/_stories/ChartEditor.Editor.stories.tsx +1 -1
- package/src/_stories/_mock/paired-bar-abbr.json +421 -0
- package/src/_stories/_mock/pie_custom_colors.json +268 -0
- package/src/_stories/_mock/smallest_left_axis_max.json +104 -0
- package/src/components/Annotations/components/AnnotationDraggable.styles.css +10 -10
- package/src/components/Annotations/components/AnnotationDropdown.styles.css +1 -1
- package/src/components/Annotations/components/AnnotationList.styles.css +11 -11
- package/src/components/Axis/BottomAxis.tsx +10 -3
- package/src/components/Axis/PairedBarAxis.tsx +10 -4
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +12 -28
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +12 -30
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +12 -31
- package/src/components/BarChart/components/BarChart.Vertical.tsx +12 -28
- package/src/components/BarChart/helpers/getPatternUrl.ts +94 -0
- package/src/components/BarChart/helpers/tests/getPatternUrl.test.ts +134 -0
- package/src/components/BarChart/helpers/useBarChart.ts +3 -0
- package/src/components/Brush/BrushSelector.tsx +2 -1
- package/src/components/Brush/MiniChartPreview.tsx +21 -26
- package/src/components/EditorPanel/EditorPanel.tsx +56 -43
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +9 -9
- package/src/components/EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx +0 -78
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +39 -1
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +24 -42
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +83 -2
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +45 -42
- package/src/components/EditorPanel/editor-panel.scss +1 -1
- package/src/components/ForestPlot/ForestPlot.tsx +26 -22
- package/src/components/Legend/LegendGroup/LegendGroup.styles.css +4 -4
- package/src/components/Legend/helpers/createFormatLabels.tsx +3 -2
- package/src/components/LinearChart/tests/LinearChart.test.tsx +77 -0
- package/src/components/LinearChart/tests/mockConfigContext.ts +2 -0
- package/src/components/LinearChart.tsx +26 -6
- package/src/components/PieChart/PieChart.tsx +19 -4
- package/src/components/RadarChart/RadarChart.tsx +1 -1
- package/src/components/Regions/components/Regions.tsx +6 -6
- package/src/components/Sankey/components/Sankey.tsx +3 -3
- package/src/components/Sankey/sankey.scss +1 -1
- package/src/components/SmallMultiples/SmallMultiples.css +5 -5
- package/src/components/Sparkline/index.scss +4 -2
- package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +8 -8
- package/src/data/initial-state.js +23 -14
- package/src/data/legacy-defaults.ts +18 -0
- package/src/helpers/abbreviateNumber.ts +24 -17
- package/src/helpers/getChartPatternId.ts +17 -0
- package/src/helpers/getMinMax.ts +16 -2
- package/src/helpers/seriesColumnSettings.ts +114 -0
- package/src/helpers/tests/countNumOfTicks.test.ts +77 -0
- package/src/helpers/tests/seriesColumnSettings.test.ts +84 -0
- package/src/hooks/useRightAxis.ts +14 -0
- package/src/hooks/useScales.ts +92 -56
- package/src/hooks/useTooltip.tsx +20 -3
- package/src/scss/main.scss +152 -79
- package/src/test/CdcChart.test.jsx +2 -2
- package/src/types/ChartConfig.ts +4 -0
- package/tests/fixtures/chart-config-with-metadata.json +29 -0
- package/tests/fixtures/data-with-metadata.json +10 -0
|
@@ -6,7 +6,7 @@ import { useEditorPermissions } from '../../useEditorPermissions'
|
|
|
6
6
|
import Accordion from '@cdc/core/components/ui/Accordion'
|
|
7
7
|
import Button from '@cdc/core/components/elements/Button'
|
|
8
8
|
import { CheckBox, Select } from '@cdc/core/components/EditorPanel/Inputs'
|
|
9
|
-
import
|
|
9
|
+
import cloneDeep from 'lodash/cloneDeep'
|
|
10
10
|
|
|
11
11
|
// types
|
|
12
12
|
import { type PanelProps } from './../PanelProps'
|
|
@@ -161,7 +161,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
161
161
|
subsection={null}
|
|
162
162
|
fieldName='anchorMode'
|
|
163
163
|
updateField={(section, subsection, fieldName, value) => {
|
|
164
|
-
const updatedAnnotations =
|
|
164
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
165
165
|
updatedAnnotations[index].anchorMode = value
|
|
166
166
|
|
|
167
167
|
// When switching to data mode, ensure seriesKey and dataX are initialized
|
|
@@ -191,7 +191,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
191
191
|
subsection={null}
|
|
192
192
|
fieldName='seriesKey'
|
|
193
193
|
updateField={(section, subsection, fieldName, value) => {
|
|
194
|
-
const updatedAnnotations =
|
|
194
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
195
195
|
updatedAnnotations[index].seriesKey = value || config.series?.[0]?.dataKey
|
|
196
196
|
updateConfig({
|
|
197
197
|
...config,
|
|
@@ -207,7 +207,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
207
207
|
<input
|
|
208
208
|
type='range'
|
|
209
209
|
onChange={e => {
|
|
210
|
-
const updatedAnnotations =
|
|
210
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
211
211
|
updatedAnnotations[index].opacity = e.target.value
|
|
212
212
|
updateConfig({
|
|
213
213
|
...config,
|
|
@@ -225,7 +225,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
225
225
|
fieldName={`${index}.edit.subject`}
|
|
226
226
|
label='Edit Subject'
|
|
227
227
|
updateField={(section, subsection, fieldName, value) => {
|
|
228
|
-
const updatedAnnotations =
|
|
228
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
229
229
|
updatedAnnotations[index].edit.subject = value
|
|
230
230
|
updateConfig({
|
|
231
231
|
...config,
|
|
@@ -240,7 +240,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
240
240
|
fieldName={`${index}.edit.label`}
|
|
241
241
|
label='Edit Label'
|
|
242
242
|
updateField={(section, subsection, fieldName, value) => {
|
|
243
|
-
const updatedAnnotations =
|
|
243
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
244
244
|
updatedAnnotations[index].edit.label = value
|
|
245
245
|
updateConfig({
|
|
246
246
|
...config,
|
|
@@ -257,7 +257,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
257
257
|
subsection={null}
|
|
258
258
|
fieldName='connectionType'
|
|
259
259
|
updateField={(section, subsection, fieldName, value) => {
|
|
260
|
-
const updatedAnnotations =
|
|
260
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
261
261
|
updatedAnnotations[index].connectionType = value
|
|
262
262
|
updateConfig({
|
|
263
263
|
...config,
|
|
@@ -277,7 +277,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
277
277
|
max='20'
|
|
278
278
|
value={config?.annotations[index]?.bezier || 0}
|
|
279
279
|
onChange={e => {
|
|
280
|
-
const updatedAnnotations =
|
|
280
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
281
281
|
updatedAnnotations[index].bezier = e.target.value
|
|
282
282
|
updateConfig({
|
|
283
283
|
...config,
|
|
@@ -297,7 +297,7 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
|
|
|
297
297
|
subsection={null}
|
|
298
298
|
fieldName='marker'
|
|
299
299
|
updateField={(section, subsection, fieldName, value) => {
|
|
300
|
-
const updatedAnnotations =
|
|
300
|
+
const updatedAnnotations = cloneDeep(config?.annotations)
|
|
301
301
|
updatedAnnotations[index].marker = value
|
|
302
302
|
updateConfig({
|
|
303
303
|
...config,
|
|
@@ -320,84 +320,6 @@ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
|
|
|
320
320
|
<br />
|
|
321
321
|
<hr />
|
|
322
322
|
<br />
|
|
323
|
-
<h4>Width Settings</h4>
|
|
324
|
-
|
|
325
|
-
<label>
|
|
326
|
-
<span className='edit-label column-heading'>Chart Offset Left (%)</span>
|
|
327
|
-
<input
|
|
328
|
-
type='number'
|
|
329
|
-
min={0}
|
|
330
|
-
max={100}
|
|
331
|
-
value={config.forestPlot.leftWidthOffset || 0}
|
|
332
|
-
onChange={e => {
|
|
333
|
-
updateConfig({
|
|
334
|
-
...config,
|
|
335
|
-
forestPlot: {
|
|
336
|
-
...config.forestPlot,
|
|
337
|
-
leftWidthOffset: e.target.value
|
|
338
|
-
}
|
|
339
|
-
})
|
|
340
|
-
}}
|
|
341
|
-
/>
|
|
342
|
-
</label>
|
|
343
|
-
|
|
344
|
-
<label>
|
|
345
|
-
<span className='edit-label column-heading'>Chart Offset Left Mobile(%)</span>
|
|
346
|
-
<input
|
|
347
|
-
type='number'
|
|
348
|
-
min={0}
|
|
349
|
-
max={100}
|
|
350
|
-
value={config.forestPlot.leftWidthOffsetMobile || 0}
|
|
351
|
-
onChange={e => {
|
|
352
|
-
updateConfig({
|
|
353
|
-
...config,
|
|
354
|
-
forestPlot: {
|
|
355
|
-
...config.forestPlot,
|
|
356
|
-
leftWidthOffsetMobile: e.target.value
|
|
357
|
-
}
|
|
358
|
-
})
|
|
359
|
-
}}
|
|
360
|
-
/>
|
|
361
|
-
</label>
|
|
362
|
-
|
|
363
|
-
<label>
|
|
364
|
-
<span className='edit-label column-heading'>Chart Offset Right (%)</span>
|
|
365
|
-
<input
|
|
366
|
-
type='number'
|
|
367
|
-
min={0}
|
|
368
|
-
max={100}
|
|
369
|
-
value={config.forestPlot.rightWidthOffset || 0}
|
|
370
|
-
onChange={e => {
|
|
371
|
-
updateConfig({
|
|
372
|
-
...config,
|
|
373
|
-
forestPlot: {
|
|
374
|
-
...config.forestPlot,
|
|
375
|
-
rightWidthOffset: e.target.value
|
|
376
|
-
}
|
|
377
|
-
})
|
|
378
|
-
}}
|
|
379
|
-
/>
|
|
380
|
-
</label>
|
|
381
|
-
|
|
382
|
-
<label>
|
|
383
|
-
<span className='edit-label column-heading'>Chart Offset Right Mobile(%)</span>
|
|
384
|
-
<input
|
|
385
|
-
type='number'
|
|
386
|
-
min={0}
|
|
387
|
-
max={100}
|
|
388
|
-
value={config.forestPlot.rightWidthOffsetMobile || 0}
|
|
389
|
-
onChange={e => {
|
|
390
|
-
updateConfig({
|
|
391
|
-
...config,
|
|
392
|
-
forestPlot: {
|
|
393
|
-
...config.forestPlot,
|
|
394
|
-
rightWidthOffsetMobile: e.target.value
|
|
395
|
-
}
|
|
396
|
-
})
|
|
397
|
-
}}
|
|
398
|
-
/>
|
|
399
|
-
</label>
|
|
400
|
-
|
|
401
323
|
<TextField
|
|
402
324
|
type='number'
|
|
403
325
|
min={20}
|
|
@@ -47,6 +47,22 @@ const PanelGeneral: FC<PanelProps> = props => {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
const handleTitleStyleChange = (newTitleStyle: string) => {
|
|
51
|
+
updateConfig({
|
|
52
|
+
...config,
|
|
53
|
+
titleStyle: newTitleStyle,
|
|
54
|
+
visual:
|
|
55
|
+
newTitleStyle === 'legacy'
|
|
56
|
+
? config.visual
|
|
57
|
+
: {
|
|
58
|
+
...config.visual,
|
|
59
|
+
border: undefined,
|
|
60
|
+
borderColorTheme: undefined,
|
|
61
|
+
accent: undefined
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
50
66
|
return (
|
|
51
67
|
<AccordionItem>
|
|
52
68
|
{' '}
|
|
@@ -475,12 +491,12 @@ const PanelGeneral: FC<PanelProps> = props => {
|
|
|
475
491
|
value={config.titleStyle}
|
|
476
492
|
fieldName='titleStyle'
|
|
477
493
|
label='Title Style'
|
|
478
|
-
updateField={updateField}
|
|
479
494
|
options={[
|
|
480
495
|
{ value: 'small', label: 'Small (h3)' },
|
|
481
496
|
{ value: 'large', label: 'Large (h2)' },
|
|
482
497
|
{ value: 'legacy', label: 'Legacy' }
|
|
483
498
|
]}
|
|
499
|
+
onChange={event => handleTitleStyleChange(event.target.value)}
|
|
484
500
|
tooltip={
|
|
485
501
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
486
502
|
<Tooltip.Target>
|
|
@@ -579,6 +595,28 @@ const PanelGeneral: FC<PanelProps> = props => {
|
|
|
579
595
|
}
|
|
580
596
|
/>
|
|
581
597
|
)}
|
|
598
|
+
<Select
|
|
599
|
+
value={config.locale}
|
|
600
|
+
fieldName='locale'
|
|
601
|
+
label='Language for dates and numbers'
|
|
602
|
+
updateField={updateField}
|
|
603
|
+
options={[
|
|
604
|
+
{ value: 'en-US', label: 'English (en-US)' },
|
|
605
|
+
{ value: 'es-MX', label: 'Spanish (es-MX)' }
|
|
606
|
+
]}
|
|
607
|
+
tooltip={
|
|
608
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
609
|
+
<Tooltip.Target>
|
|
610
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
611
|
+
</Tooltip.Target>
|
|
612
|
+
<Tooltip.Content>
|
|
613
|
+
<p>
|
|
614
|
+
Change the language (locale) for this visualization to alter the way dates and numbers are formatted.
|
|
615
|
+
</p>
|
|
616
|
+
</Tooltip.Content>
|
|
617
|
+
</Tooltip>
|
|
618
|
+
}
|
|
619
|
+
/>
|
|
582
620
|
</AccordionItemPanel>
|
|
583
621
|
</AccordionItem>
|
|
584
622
|
)
|
|
@@ -16,7 +16,7 @@ import { ChartContext } from '../../../../types/ChartContext'
|
|
|
16
16
|
import { PanelProps } from '../PanelProps'
|
|
17
17
|
import { checkColorContrast, getColorContrast } from '@cdc/core/helpers/cove/accessibility'
|
|
18
18
|
import { getColorScale } from '../../../../helpers/getColorScale'
|
|
19
|
-
import
|
|
19
|
+
import { sanitizeToSvgId } from '@cdc/core/helpers/cove/string'
|
|
20
20
|
|
|
21
21
|
const PanelPatternSettings: FC<PanelProps> = props => {
|
|
22
22
|
const { config, updateConfig, transformedData } = useContext<ChartContext>(ConfigContext)
|
|
@@ -69,19 +69,6 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
// Get unique values from a specific data field for dropdown options
|
|
73
|
-
const getDataValueOptions = (dataKey: string) => {
|
|
74
|
-
if (!dataKey || !Array.isArray(transformedData) || transformedData.length === 0) {
|
|
75
|
-
return []
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const uniqueValues = Array.from(new Set(transformedData.map(row => row[dataKey])))
|
|
79
|
-
.filter(val => val !== undefined && val !== null && val !== '')
|
|
80
|
-
.sort()
|
|
81
|
-
|
|
82
|
-
return uniqueValues.map(value => ({ value: String(value), label: String(value) }))
|
|
83
|
-
}
|
|
84
|
-
|
|
85
72
|
const getFieldOptions = () => {
|
|
86
73
|
if (!Array.isArray(transformedData) || transformedData.length === 0) return []
|
|
87
74
|
|
|
@@ -282,11 +269,6 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
282
269
|
[field]: value
|
|
283
270
|
}
|
|
284
271
|
|
|
285
|
-
// Clear dataValue if dataKey is being cleared or set to 'Select'
|
|
286
|
-
if (field === 'dataKey' && (value === 'Select' || value === '')) {
|
|
287
|
-
updatedPattern.dataValue = ''
|
|
288
|
-
}
|
|
289
|
-
|
|
290
272
|
const newPatterns = {
|
|
291
273
|
...(legendCfg.patterns || {}),
|
|
292
274
|
[patternKey]: updatedPattern
|
|
@@ -333,14 +315,18 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
333
315
|
{/* Individual Pattern Configurations */}
|
|
334
316
|
{Object.entries(currentPatterns).map(([patternKey, pattern], index) => {
|
|
335
317
|
const p: LegendPattern = pattern || {}
|
|
336
|
-
const
|
|
318
|
+
const domPatternKey = `${sanitizeToSvgId(patternKey)}-${index}`
|
|
337
319
|
|
|
338
320
|
return (
|
|
339
321
|
<Accordion allowZeroExpanded key={`pattern-accordion-${index}`}>
|
|
340
322
|
<AccordionItem>
|
|
341
323
|
<AccordionItemHeading>
|
|
342
324
|
<AccordionItemButton>
|
|
343
|
-
{p.dataKey && p.dataValue
|
|
325
|
+
{p.dataKey && p.dataValue
|
|
326
|
+
? `${p.dataKey}: ${p.dataValue}`
|
|
327
|
+
: p.dataValue
|
|
328
|
+
? `All Series: ${p.dataValue}`
|
|
329
|
+
: `Pattern ${index + 1}`}
|
|
344
330
|
</AccordionItemButton>
|
|
345
331
|
</AccordionItemHeading>
|
|
346
332
|
<AccordionItemPanel>
|
|
@@ -359,32 +345,28 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
359
345
|
value={p.dataKey || ''}
|
|
360
346
|
options={fieldOptions}
|
|
361
347
|
initial='Select Data Key'
|
|
362
|
-
fieldName={`pattern-datakey-${
|
|
348
|
+
fieldName={`pattern-datakey-${domPatternKey}`}
|
|
363
349
|
updateField={(section, subsection, fieldName, value) =>
|
|
364
350
|
handlePatternUpdate(patternKey, 'dataKey', value)
|
|
365
351
|
}
|
|
366
352
|
/>
|
|
367
353
|
|
|
368
|
-
{
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
/>
|
|
379
|
-
</label>
|
|
380
|
-
</>
|
|
381
|
-
)}
|
|
354
|
+
<label htmlFor={`pattern-datavalue-${domPatternKey}`}>
|
|
355
|
+
Data Value:
|
|
356
|
+
<input
|
|
357
|
+
type='text'
|
|
358
|
+
id={`pattern-datavalue-${domPatternKey}`}
|
|
359
|
+
value={p.dataValue || ''}
|
|
360
|
+
onChange={e => handlePatternUpdate(patternKey, 'dataValue', e.target.value)}
|
|
361
|
+
placeholder='Enter data value'
|
|
362
|
+
/>
|
|
363
|
+
</label>
|
|
382
364
|
|
|
383
|
-
<label htmlFor={`pattern-label-${
|
|
365
|
+
<label htmlFor={`pattern-label-${domPatternKey}`}>
|
|
384
366
|
Label (optional):
|
|
385
367
|
<input
|
|
386
368
|
type='text'
|
|
387
|
-
id={`pattern-label-${
|
|
369
|
+
id={`pattern-label-${domPatternKey}`}
|
|
388
370
|
value={p.label || ''}
|
|
389
371
|
onChange={e => handlePatternUpdate(patternKey, 'label', e.target.value)}
|
|
390
372
|
/>
|
|
@@ -394,7 +376,7 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
394
376
|
label='Pattern Type:'
|
|
395
377
|
value={p.shape || 'circles'}
|
|
396
378
|
options={patternTypes}
|
|
397
|
-
fieldName={`pattern-type-${
|
|
379
|
+
fieldName={`pattern-type-${domPatternKey}`}
|
|
398
380
|
updateField={(section, subsection, fieldName, value) =>
|
|
399
381
|
handlePatternUpdate(patternKey, 'shape', value)
|
|
400
382
|
}
|
|
@@ -404,14 +386,14 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
404
386
|
label='Pattern Size:'
|
|
405
387
|
value={getPatternSizeText(p.patternSize || 8)}
|
|
406
388
|
options={patternSizes}
|
|
407
|
-
fieldName={`pattern-size-${
|
|
389
|
+
fieldName={`pattern-size-${domPatternKey}`}
|
|
408
390
|
updateField={(section, subsection, fieldName, value) =>
|
|
409
391
|
handlePatternUpdate(patternKey, 'patternSize', getPatternSizeNumeric(value))
|
|
410
392
|
}
|
|
411
393
|
/>
|
|
412
394
|
|
|
413
395
|
<div className='mt-3'>
|
|
414
|
-
<label htmlFor={`pattern-color-${
|
|
396
|
+
<label htmlFor={`pattern-color-${domPatternKey}`}>
|
|
415
397
|
Pattern Color
|
|
416
398
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
417
399
|
<Tooltip.Target>
|
|
@@ -430,7 +412,7 @@ const PanelPatternSettings: FC<PanelProps> = props => {
|
|
|
430
412
|
<input
|
|
431
413
|
type='text'
|
|
432
414
|
value={p.color || ''}
|
|
433
|
-
id={`pattern-color-${
|
|
415
|
+
id={`pattern-color-${domPatternKey}`}
|
|
434
416
|
onChange={e => handlePatternUpdate(patternKey, 'color', e.target.value)}
|
|
435
417
|
placeholder='#666666'
|
|
436
418
|
/>
|
|
@@ -8,8 +8,9 @@ import { colorPalettesChartV1, colorPalettesChartV2, sequentialPalettes } from '
|
|
|
8
8
|
import { updatePaletteNames } from '@cdc/core/helpers/updatePaletteNames'
|
|
9
9
|
import { getColorPaletteVersion } from '@cdc/core/helpers/getColorPaletteVersion'
|
|
10
10
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
11
|
-
import { Select } from '@cdc/core/components/EditorPanel/Inputs'
|
|
11
|
+
import { CheckBox, Select, TextField } from '@cdc/core/components/EditorPanel/Inputs'
|
|
12
12
|
import { buildForecastPaletteOptions } from '../../../../helpers/buildForecastPaletteOptions'
|
|
13
|
+
import { getSeriesColumnConfig, upsertSeriesColumnConfig } from '../../../../helpers/seriesColumnSettings'
|
|
13
14
|
|
|
14
15
|
// Third Party
|
|
15
16
|
import {
|
|
@@ -538,6 +539,84 @@ const SeriesDisplayInTooltip = props => {
|
|
|
538
539
|
)
|
|
539
540
|
}
|
|
540
541
|
|
|
542
|
+
const SeriesColumnSettings = props => {
|
|
543
|
+
const { series } = props
|
|
544
|
+
const { config, updateConfig } = useContext(ConfigContext)
|
|
545
|
+
const { columnConfig } = getSeriesColumnConfig(config.columns || {}, series.dataKey)
|
|
546
|
+
|
|
547
|
+
const updateSeriesColumn = (fieldName, value) => {
|
|
548
|
+
const columns = upsertSeriesColumnConfig(config.columns || {}, series.dataKey, {
|
|
549
|
+
[fieldName]: value
|
|
550
|
+
})
|
|
551
|
+
|
|
552
|
+
updateConfig({
|
|
553
|
+
...config,
|
|
554
|
+
columns
|
|
555
|
+
})
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return (
|
|
559
|
+
<>
|
|
560
|
+
<span className='divider-heading'>Series Column Settings</span>
|
|
561
|
+
<TextField
|
|
562
|
+
value={columnConfig.label || ''}
|
|
563
|
+
section='seriesColumn'
|
|
564
|
+
subsection={series.dataKey}
|
|
565
|
+
fieldName='label'
|
|
566
|
+
label='Label'
|
|
567
|
+
updateField={(_section, _subsection, _fieldName, value) => updateSeriesColumn('label', value)}
|
|
568
|
+
/>
|
|
569
|
+
<div className='three-col'>
|
|
570
|
+
<TextField
|
|
571
|
+
value={columnConfig.prefix || ''}
|
|
572
|
+
section='seriesColumn'
|
|
573
|
+
subsection={series.dataKey}
|
|
574
|
+
fieldName='prefix'
|
|
575
|
+
label='Prefix'
|
|
576
|
+
updateField={(_section, _subsection, _fieldName, value) => updateSeriesColumn('prefix', value)}
|
|
577
|
+
/>
|
|
578
|
+
<TextField
|
|
579
|
+
value={columnConfig.suffix || ''}
|
|
580
|
+
section='seriesColumn'
|
|
581
|
+
subsection={series.dataKey}
|
|
582
|
+
fieldName='suffix'
|
|
583
|
+
label='Suffix'
|
|
584
|
+
updateField={(_section, _subsection, _fieldName, value) => updateSeriesColumn('suffix', value)}
|
|
585
|
+
/>
|
|
586
|
+
<TextField
|
|
587
|
+
type='number'
|
|
588
|
+
value={columnConfig.roundToPlace ?? 0}
|
|
589
|
+
section='seriesColumn'
|
|
590
|
+
subsection={series.dataKey}
|
|
591
|
+
fieldName='roundToPlace'
|
|
592
|
+
label='Round'
|
|
593
|
+
updateField={(_section, _subsection, _fieldName, value) =>
|
|
594
|
+
updateSeriesColumn('roundToPlace', Number(value) || 0)
|
|
595
|
+
}
|
|
596
|
+
/>
|
|
597
|
+
</div>
|
|
598
|
+
<CheckBox
|
|
599
|
+
value={columnConfig.commas || false}
|
|
600
|
+
section='seriesColumn'
|
|
601
|
+
subsection={series.dataKey}
|
|
602
|
+
fieldName='commas'
|
|
603
|
+
label='Add Commas to Numbers'
|
|
604
|
+
updateField={(_section, _subsection, _fieldName, value) => updateSeriesColumn('commas', value)}
|
|
605
|
+
/>
|
|
606
|
+
{config.table.showVertical && (
|
|
607
|
+
<CheckBox
|
|
608
|
+
value={columnConfig.dataTable ?? true}
|
|
609
|
+
section='seriesColumn'
|
|
610
|
+
subsection={series.dataKey}
|
|
611
|
+
fieldName='dataTable'
|
|
612
|
+
label='Show in Data Table'
|
|
613
|
+
updateField={(_section, _subsection, _fieldName, value) => updateSeriesColumn('dataTable', value)}
|
|
614
|
+
/>
|
|
615
|
+
)}
|
|
616
|
+
</>
|
|
617
|
+
)
|
|
618
|
+
}
|
|
619
|
+
|
|
541
620
|
const SeriesButtonRemove = props => {
|
|
542
621
|
const { config, updateConfig } = useContext(ConfigContext)
|
|
543
622
|
const { series, index } = props
|
|
@@ -637,6 +716,7 @@ const SeriesItem = props => {
|
|
|
637
716
|
{chartsWithOptions.includes(config.visualizationType) && (
|
|
638
717
|
<AccordionItemPanel>
|
|
639
718
|
<Series.Input.Name series={series} index={i} />
|
|
719
|
+
<Series.Input.ColumnSettings series={series} index={i} />
|
|
640
720
|
{showDynamicCategory && (
|
|
641
721
|
<>
|
|
642
722
|
<Select
|
|
@@ -722,7 +802,8 @@ const Series = {
|
|
|
722
802
|
},
|
|
723
803
|
Input: {
|
|
724
804
|
Name: SeriesInputName,
|
|
725
|
-
Weight: SeriesInputWeight
|
|
805
|
+
Weight: SeriesInputWeight,
|
|
806
|
+
ColumnSettings: SeriesColumnSettings
|
|
726
807
|
},
|
|
727
808
|
Checkbox: {
|
|
728
809
|
DisplayInTooltip: SeriesDisplayInTooltip
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useContext, FC, useMemo } from 'react'
|
|
2
|
-
import _ from 'lodash'
|
|
3
2
|
import cloneConfig from '@cdc/core/helpers/cloneConfig'
|
|
4
3
|
|
|
5
4
|
// external libraries
|
|
@@ -31,13 +30,16 @@ import { LineChartConfig } from '../../../../types/ChartConfig'
|
|
|
31
30
|
import { PaletteSelector, DeveloperPaletteRollback } from '@cdc/core/components/PaletteSelector'
|
|
32
31
|
import { HeaderThemeSelector } from '@cdc/core/components/HeaderThemeSelector'
|
|
33
32
|
import { CustomColorsEditor } from '@cdc/core/components/CustomColorsEditor'
|
|
33
|
+
import StyleTreatmentSection from '@cdc/core/components/EditorPanel/sections/StyleTreatmentSection'
|
|
34
34
|
import { getColorScale } from '../../../../helpers/getColorScale'
|
|
35
|
-
import '@cdc/core/
|
|
35
|
+
import { ENABLE_CHART_MAP_TP5_TREATMENT_SELECTION, ENABLE_CHART_VISUAL_SETTINGS } from '@cdc/core/helpers/constants'
|
|
36
|
+
import '@cdc/core/components/EditorPanel/editor.scss'
|
|
36
37
|
import './panelVisual.styles.css'
|
|
37
38
|
|
|
38
39
|
const PanelVisual: FC<PanelProps> = props => {
|
|
39
40
|
const { config, updateConfig, colorPalettes, twoColorPalette } = useContext<ChartContext>(ConfigContext)
|
|
40
41
|
const { visual } = config
|
|
42
|
+
const styleTreatment = config.titleStyle === 'legacy' && !visual?.tp5Treatment ? 'legacy' : 'tp5'
|
|
41
43
|
|
|
42
44
|
const { setLollipopShape, updateField, handlePaletteSelection, handleTwoColorPaletteSelection } =
|
|
43
45
|
useEditorPanelContext()
|
|
@@ -89,12 +91,44 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
89
91
|
}
|
|
90
92
|
}
|
|
91
93
|
|
|
94
|
+
const handleStyleTreatmentChange = (value: string) => {
|
|
95
|
+
const useTp5Treatment = value === 'tp5'
|
|
96
|
+
|
|
97
|
+
updateConfig({
|
|
98
|
+
...config,
|
|
99
|
+
titleStyle: useTp5Treatment ? 'small' : 'legacy',
|
|
100
|
+
visual: {
|
|
101
|
+
...config.visual,
|
|
102
|
+
tp5Treatment: useTp5Treatment,
|
|
103
|
+
border: useTp5Treatment ? false : config.visual?.border,
|
|
104
|
+
borderColorTheme: useTp5Treatment ? false : config.visual?.borderColorTheme,
|
|
105
|
+
accent: useTp5Treatment ? false : config.visual?.accent
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
92
110
|
return (
|
|
93
111
|
<AccordionItem className='panel-visual'>
|
|
94
112
|
<AccordionItemHeading>
|
|
95
113
|
<AccordionItemButton>Visual</AccordionItemButton>
|
|
96
114
|
</AccordionItemHeading>
|
|
97
115
|
<AccordionItemPanel>
|
|
116
|
+
<HeaderThemeSelector selectedTheme={config.theme} onThemeSelect={theme => updateConfig({ ...config, theme })} />
|
|
117
|
+
{ENABLE_CHART_VISUAL_SETTINGS && (
|
|
118
|
+
<StyleTreatmentSection
|
|
119
|
+
styleTreatment={styleTreatment}
|
|
120
|
+
onStyleTreatmentChange={handleStyleTreatmentChange}
|
|
121
|
+
showStyleTreatment={ENABLE_CHART_MAP_TP5_TREATMENT_SELECTION}
|
|
122
|
+
border={visual?.border}
|
|
123
|
+
borderColorTheme={visual?.borderColorTheme}
|
|
124
|
+
accent={visual?.accent}
|
|
125
|
+
background={visual?.background}
|
|
126
|
+
hideBackgroundColor={visual?.hideBackgroundColor}
|
|
127
|
+
showBackground={config.visualizationType === 'Spark Line'}
|
|
128
|
+
showHideBackgroundColor={config.visualizationType === 'Spark Line'}
|
|
129
|
+
updateField={updateField}
|
|
130
|
+
/>
|
|
131
|
+
)}
|
|
98
132
|
{(config.barStyle === 'lollipop' || config.isLollipopChart) && (
|
|
99
133
|
<>
|
|
100
134
|
<fieldset className='header'>
|
|
@@ -272,7 +306,6 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
272
306
|
/>
|
|
273
307
|
</>
|
|
274
308
|
)}
|
|
275
|
-
<HeaderThemeSelector selectedTheme={config.theme} onThemeSelect={theme => updateConfig({ ...config, theme })} />
|
|
276
309
|
{(visSupportsNonSequentialPallete() || visSupportsNonSequentialPallete()) && (
|
|
277
310
|
<>
|
|
278
311
|
<label>
|
|
@@ -573,45 +606,6 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
573
606
|
updateField={updateField}
|
|
574
607
|
/>
|
|
575
608
|
)}
|
|
576
|
-
{config.visualizationType === 'Spark Line' && (
|
|
577
|
-
<div className='cove-accordion__panel-section checkbox-group'>
|
|
578
|
-
<CheckBox
|
|
579
|
-
value={visual?.border}
|
|
580
|
-
section='visual'
|
|
581
|
-
fieldName='border'
|
|
582
|
-
label='Show Border'
|
|
583
|
-
updateField={updateField}
|
|
584
|
-
/>
|
|
585
|
-
<CheckBox
|
|
586
|
-
value={visual?.borderColorTheme}
|
|
587
|
-
section='visual'
|
|
588
|
-
fieldName='borderColorTheme'
|
|
589
|
-
label='Use Border Color Theme'
|
|
590
|
-
updateField={updateField}
|
|
591
|
-
/>
|
|
592
|
-
<CheckBox
|
|
593
|
-
value={visual?.accent}
|
|
594
|
-
section='visual'
|
|
595
|
-
fieldName='accent'
|
|
596
|
-
label='Use Accent Style'
|
|
597
|
-
updateField={updateField}
|
|
598
|
-
/>
|
|
599
|
-
<CheckBox
|
|
600
|
-
value={visual?.background}
|
|
601
|
-
section='visual'
|
|
602
|
-
fieldName='background'
|
|
603
|
-
label='Use Theme Background Color'
|
|
604
|
-
updateField={updateField}
|
|
605
|
-
/>
|
|
606
|
-
<CheckBox
|
|
607
|
-
value={visual?.hideBackgroundColor}
|
|
608
|
-
section='visual'
|
|
609
|
-
fieldName='hideBackgroundColor'
|
|
610
|
-
label='Hide Background Color'
|
|
611
|
-
updateField={updateField}
|
|
612
|
-
/>
|
|
613
|
-
</div>
|
|
614
|
-
)}
|
|
615
609
|
{(config.visualizationType === 'Line' || config.visualizationType === 'Combo') && (
|
|
616
610
|
<CheckBox
|
|
617
611
|
value={config.showLineSeriesLabels}
|
|
@@ -690,6 +684,15 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
690
684
|
}
|
|
691
685
|
/>
|
|
692
686
|
</label>
|
|
687
|
+
{isCoveDeveloperMode() && (
|
|
688
|
+
<CheckBox
|
|
689
|
+
value={visual?.highlightWrappers}
|
|
690
|
+
section='visual'
|
|
691
|
+
fieldName='highlightWrappers'
|
|
692
|
+
label='Highlight Layout Wrappers'
|
|
693
|
+
updateField={updateField}
|
|
694
|
+
/>
|
|
695
|
+
)}
|
|
693
696
|
</AccordionItemPanel>
|
|
694
697
|
</AccordionItem>
|
|
695
698
|
)
|