@cdc/chart 4.24.2 → 4.24.4
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/dist/cdcchart.js +47933 -36918
- package/examples/chart-regression-1.json +378 -0
- package/examples/chart-regression-2.json +2360 -0
- package/examples/feature/filters/url-filter.json +1076 -0
- package/examples/feature/line/line-chart.json +362 -37
- package/examples/feature/regions/index.json +50 -4
- package/examples/feature/sankey/sankey-example-data.json +1364 -0
- package/examples/feature/sankey/sankey_chart_data.csv +20 -0
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +306 -19
- package/examples/region-issue.json +2065 -0
- package/examples/sparkline.json +868 -0
- package/examples/test.json +5409 -0
- package/index.html +130 -123
- package/package.json +4 -2
- package/src/CdcChart.tsx +178 -94
- package/src/_stories/ChartEditor.stories.tsx +14 -3
- package/src/_stories/_mock/url_filter.json +1076 -0
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +2 -1
- package/src/components/AreaChart/components/AreaChart.jsx +2 -1
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +46 -63
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +36 -56
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +32 -39
- package/src/components/BarChart/components/BarChart.Vertical.tsx +44 -59
- package/src/components/BoxPlot/BoxPlot.jsx +2 -1
- package/src/components/DeviationBar.jsx +3 -3
- package/src/components/EditorPanel/EditorPanel.tsx +1684 -1564
- package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +1 -1
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +107 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +48 -4
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +41 -0
- package/src/components/EditorPanel/components/Panels/index.tsx +9 -7
- package/src/components/EditorPanel/components/panels.scss +11 -0
- package/src/components/EditorPanel/editor-panel.scss +0 -724
- package/src/components/EditorPanel/useEditorPermissions.js +40 -14
- package/src/components/Legend/Legend.Component.tsx +43 -63
- package/src/components/Legend/Legend.tsx +8 -4
- package/src/components/LineChart/LineChartProps.ts +1 -0
- package/src/components/LineChart/helpers.ts +2 -2
- package/src/components/LineChart/index.tsx +7 -7
- package/src/components/LinearChart.jsx +11 -31
- package/src/components/PairedBarChart.jsx +6 -10
- package/src/components/PieChart/PieChart.tsx +3 -3
- package/src/components/Regions/components/Regions.tsx +120 -78
- package/src/components/Sankey/index.tsx +434 -0
- package/src/components/Sankey/sankey.scss +153 -0
- package/src/components/Sankey/types/index.ts +16 -0
- package/src/components/ScatterPlot/ScatterPlot.jsx +1 -0
- package/src/components/Sparkline/{SparkLine.jsx → components/SparkLine.tsx} +14 -30
- package/src/components/Sparkline/index.scss +3 -0
- package/src/components/Sparkline/index.tsx +1 -1
- package/src/components/ZoomBrush.tsx +2 -1
- package/src/data/initial-state.js +46 -2
- package/src/helpers/computeMarginBottom.ts +2 -1
- package/src/helpers/tests/computeMarginBottom.test.ts +2 -1
- package/src/hooks/useBarChart.js +5 -2
- package/src/hooks/useScales.ts +47 -18
- package/src/hooks/useTooltip.tsx +9 -8
- package/src/scss/main.scss +33 -29
- package/src/types/ChartConfig.ts +32 -14
- package/src/types/ChartContext.ts +7 -0
|
@@ -104,7 +104,7 @@ const RegionSettings = memo(({ config, updateConfig }: { config: ChartConfig; up
|
|
|
104
104
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
105
105
|
</Tooltip.Target>
|
|
106
106
|
<Tooltip.Content>
|
|
107
|
-
<p>
|
|
107
|
+
<p>When using categorical (linear scale) match the data set value. When using date (linear / date time scale) match the x-axis value.</p>
|
|
108
108
|
</Tooltip.Content>
|
|
109
109
|
</Tooltip>
|
|
110
110
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { useContext } from 'react'
|
|
2
|
+
import ConfigContext from '../../../../ConfigContext'
|
|
3
|
+
import { CheckBox, TextField } from '@cdc/core/components/EditorPanel/Inputs'
|
|
4
|
+
import Button from '@cdc/core/components/elements/Button'
|
|
5
|
+
|
|
6
|
+
import { AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
|
|
7
|
+
import EditorPanelContext, { type EditorPanelContext as EPContext } from '../../EditorPanelContext'
|
|
8
|
+
|
|
9
|
+
const SankeySettings = () => {
|
|
10
|
+
const { config, updateConfig } = useContext(ConfigContext)
|
|
11
|
+
const data = config.data?.[0]
|
|
12
|
+
const { updateField } = useContext<EPContext>(EditorPanelContext)
|
|
13
|
+
|
|
14
|
+
if (config.visualizationType !== 'Sankey') return
|
|
15
|
+
|
|
16
|
+
const updateStoryNode = (fieldName, value, i) => {
|
|
17
|
+
let storyNodes = []
|
|
18
|
+
|
|
19
|
+
if (data?.storyNodeText) {
|
|
20
|
+
storyNodes = [...data?.storyNodeText]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
storyNodes[i][fieldName] = value
|
|
24
|
+
updateConfig({
|
|
25
|
+
...config,
|
|
26
|
+
sankey: {
|
|
27
|
+
...config.sankey,
|
|
28
|
+
data: {
|
|
29
|
+
...config.sankey.data,
|
|
30
|
+
storyNodeText: storyNodes
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const addStoryNode = () => {
|
|
37
|
+
const newData = data
|
|
38
|
+
|
|
39
|
+
newData.storyNodeText.push({
|
|
40
|
+
StoryNode: '',
|
|
41
|
+
segmentTextBefore: '',
|
|
42
|
+
segmentTextAfter: ''
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
updateConfig({
|
|
46
|
+
...config,
|
|
47
|
+
sankey: {
|
|
48
|
+
...config.sankey,
|
|
49
|
+
data: [{ ...newData }]
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const removeStoryNode = index => {
|
|
55
|
+
const newData = data
|
|
56
|
+
newData.storyNodeText.splice(index, 1)
|
|
57
|
+
|
|
58
|
+
updateConfig({ ...config, sankey: { ...config.sankey, data: { ...newData } } })
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<AccordionItem>
|
|
63
|
+
<AccordionItemHeading>
|
|
64
|
+
<AccordionItemButton>Sankey Settings</AccordionItemButton>
|
|
65
|
+
</AccordionItemHeading>
|
|
66
|
+
<AccordionItemPanel>
|
|
67
|
+
{data?.storyNodeText &&
|
|
68
|
+
data?.storyNodeText.map(({ StoryNode, segmentTextBefore, segmentTextAfter }, i) => (
|
|
69
|
+
<div key={i} style={{ border: '1px solid black', margin: '15px auto', padding: '15px', borderRadius: '10px' }}>
|
|
70
|
+
<label>
|
|
71
|
+
Story Node Text
|
|
72
|
+
<input type='text' value={StoryNode} fieldName='StoryNode' label='StoryNode' onChange={e => updateStoryNode('StoryNode', e.target.value, i)} />
|
|
73
|
+
</label>
|
|
74
|
+
<label>
|
|
75
|
+
Story Text Before
|
|
76
|
+
<input type='text' value={segmentTextBefore} fieldName='segmentTextBefore' label='Segment Text Before' onChange={e => updateStoryNode('segmentTextBefore', e.target.value, i)} />
|
|
77
|
+
</label>
|
|
78
|
+
<label>
|
|
79
|
+
Story Text After
|
|
80
|
+
<input type='text' value={segmentTextAfter} fieldName='segmentTextAfter' label='Segment Text After' onChange={e => updateStoryNode('segmentTextAfter', e.target.value, i)} />
|
|
81
|
+
</label>
|
|
82
|
+
<Button onClick={e => removeStoryNode(i)} className='btn' style={{ background: 'tomato' }}>
|
|
83
|
+
Remove Story Node
|
|
84
|
+
</Button>
|
|
85
|
+
</div>
|
|
86
|
+
))}
|
|
87
|
+
{`Total Story Nodes: ${data?.storyNodeText?.length}`}
|
|
88
|
+
{data?.storyNodeText?.length < 3 && (
|
|
89
|
+
<button
|
|
90
|
+
type='button'
|
|
91
|
+
className='btn full-width'
|
|
92
|
+
onClick={e => {
|
|
93
|
+
e.preventDefault()
|
|
94
|
+
addStoryNode()
|
|
95
|
+
}}
|
|
96
|
+
>
|
|
97
|
+
Add StoryNode
|
|
98
|
+
</button>
|
|
99
|
+
)}
|
|
100
|
+
|
|
101
|
+
<CheckBox value={config.enableTooltips} fieldName='enableTooltips' label='Enable Tooltips' updateField={updateField} />
|
|
102
|
+
</AccordionItemPanel>
|
|
103
|
+
</AccordionItem>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export default SankeySettings
|
|
@@ -424,14 +424,56 @@ const SeriesDropdownConfidenceInterval = props => {
|
|
|
424
424
|
)
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
+
const SeriesInputWeight = props => {
|
|
428
|
+
const { series, index: i } = props
|
|
429
|
+
const { config, updateConfig } = useContext(ConfigContext)
|
|
430
|
+
const adjustableWeightSeriesTypes = ['Line', 'Combo', 'dashed-sm', 'dashed-md', 'dashed-lg']
|
|
431
|
+
|
|
432
|
+
if (!adjustableWeightSeriesTypes.includes(series.type)) return
|
|
433
|
+
|
|
434
|
+
const changeSeriesWeight = (i, value, min, max) => {
|
|
435
|
+
let series = [...config.series]
|
|
436
|
+
let seriesLabelsCopy = { ...config.runtime.seriesLabels }
|
|
437
|
+
series[i].weight = !value ? value : Math.max(Number(min), Math.min(Number(max), Number(value)))
|
|
438
|
+
seriesLabelsCopy[series[i].dataKey] = series[i].weight ? series[i].weight : series[i].dataKey
|
|
439
|
+
|
|
440
|
+
const newConfig = {
|
|
441
|
+
...config,
|
|
442
|
+
series,
|
|
443
|
+
runtime: {
|
|
444
|
+
...config.runtime,
|
|
445
|
+
seriesLabels: seriesLabelsCopy
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
updateConfig(newConfig)
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return (
|
|
453
|
+
<>
|
|
454
|
+
<label htmlFor='series-weight'>Line Weight</label>
|
|
455
|
+
<input
|
|
456
|
+
type='number'
|
|
457
|
+
key={`series-weight-${i}`}
|
|
458
|
+
value={series.weight ? series.weight : ''}
|
|
459
|
+
min="1"
|
|
460
|
+
max="9"
|
|
461
|
+
onChange={event => {
|
|
462
|
+
changeSeriesWeight(i, event.target.value, event.target.min, event.target.max)
|
|
463
|
+
}}
|
|
464
|
+
/>
|
|
465
|
+
</>
|
|
466
|
+
)
|
|
467
|
+
}
|
|
468
|
+
|
|
427
469
|
const SeriesInputName = props => {
|
|
428
470
|
const { series, index: i } = props
|
|
429
471
|
const { config, updateConfig } = useContext(ConfigContext)
|
|
430
|
-
const adjustableNameSeriesTypes = ['Bar', 'Line', 'Area Chart', 'Combo', 'Deviation', 'Paired', 'Scatter', 'dashed-sm', 'dashed-md', 'dashed-lg']
|
|
472
|
+
const adjustableNameSeriesTypes = ['Bar', 'Line', 'Area Chart', 'Combo', 'Deviation Bar', 'Paired Bar', 'Scatter Plot', 'dashed-sm', 'dashed-md', 'dashed-lg']
|
|
431
473
|
|
|
432
474
|
if (!adjustableNameSeriesTypes.includes(series.type)) return
|
|
433
475
|
|
|
434
|
-
|
|
476
|
+
const changeSeriesName = (i, value) => {
|
|
435
477
|
let series = [...config.series]
|
|
436
478
|
let seriesLabelsCopy = { ...config.runtime.seriesLabels }
|
|
437
479
|
series[i].name = value
|
|
@@ -468,7 +510,7 @@ const SeriesDisplayInTooltip = props => {
|
|
|
468
510
|
const { series, index } = props
|
|
469
511
|
const { config, updateConfig } = useContext(ConfigContext)
|
|
470
512
|
|
|
471
|
-
if(['Paired Bar', 'Scatter Plot', 'Deviation Bar'].includes(config.visualizationType)) return
|
|
513
|
+
if (['Paired Bar', 'Scatter Plot', 'Deviation Bar'].includes(config.visualizationType)) return
|
|
472
514
|
|
|
473
515
|
const toggleTooltip = seriesIndex => {
|
|
474
516
|
let copiedSeries = [...config.series]
|
|
@@ -569,6 +611,7 @@ const SeriesItem = props => {
|
|
|
569
611
|
{chartsWithOptions.includes(config.visualizationType) && (
|
|
570
612
|
<AccordionItemPanel>
|
|
571
613
|
<Series.Input.Name series={series} index={i} />
|
|
614
|
+
<Series.Input.Weight series={series} index={i} />
|
|
572
615
|
<Series.Dropdown.SeriesType series={series} index={i} />
|
|
573
616
|
<Series.Dropdown.AxisPosition series={series} index={i} />
|
|
574
617
|
<Series.Dropdown.LineType series={series} index={i} />
|
|
@@ -604,7 +647,8 @@ const Series = {
|
|
|
604
647
|
ForecastingColor: SeriesDropdownForecastColor
|
|
605
648
|
},
|
|
606
649
|
Input: {
|
|
607
|
-
Name: SeriesInputName
|
|
650
|
+
Name: SeriesInputName,
|
|
651
|
+
Weight: SeriesInputWeight
|
|
608
652
|
},
|
|
609
653
|
Checkbox: {
|
|
610
654
|
DisplayInTooltip: SeriesDisplayInTooltip
|
|
@@ -25,6 +25,31 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
25
25
|
const { visHasBarBorders, visCanAnimate, visSupportsNonSequentialPallete, headerColors, visSupportsTooltipOpacity, visSupportsTooltipLines, visSupportsBarSpace, visSupportsBarThickness, visHasDataCutoff, visSupportsSequentialPallete, visSupportsReverseColorPalette } = useEditorPermissions()
|
|
26
26
|
const { twoColorPalettes, sequential, nonSequential } = useColorPalette(config, updateConfig)
|
|
27
27
|
|
|
28
|
+
const updateColor = (property, _value) => {
|
|
29
|
+
console.log('value', _value)
|
|
30
|
+
if (property === 'storyNodeFontColor') {
|
|
31
|
+
updateConfig({
|
|
32
|
+
...config,
|
|
33
|
+
sankey: {
|
|
34
|
+
...config.sankey,
|
|
35
|
+
storyNodeFontColor: _value
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
return
|
|
39
|
+
} else {
|
|
40
|
+
updateConfig({
|
|
41
|
+
...config,
|
|
42
|
+
sankey: {
|
|
43
|
+
...config.sankey,
|
|
44
|
+
[property]: {
|
|
45
|
+
...config.sankey[property],
|
|
46
|
+
default: _value
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
28
53
|
return (
|
|
29
54
|
<AccordionItem>
|
|
30
55
|
<AccordionItemHeading>
|
|
@@ -175,6 +200,22 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
175
200
|
)}
|
|
176
201
|
</>
|
|
177
202
|
)}
|
|
203
|
+
{config.visualizationType === 'Sankey' && (
|
|
204
|
+
<>
|
|
205
|
+
<span className='sankey__color-input'>
|
|
206
|
+
<input type='color' value={config.sankey.nodeColor.default} id='storyNodeColor' name='storyNodeColor' onChange={e => updateColor('nodeColor', e.target.value)} />
|
|
207
|
+
<label htmlFor='storyNodeColor'>Story Node Color</label>
|
|
208
|
+
</span>
|
|
209
|
+
<span className='sankey__color-input'>
|
|
210
|
+
<input type='color' value={config.sankey.storyNodeFontColor || 'red'} id='storyNodeFontColor' name='storyNodeFontColor' onChange={e => updateColor('storyNodeFontColor', e.target.value)} />
|
|
211
|
+
<label htmlFor='storyNodeFontColor'>Story Node Font Color</label>
|
|
212
|
+
</span>
|
|
213
|
+
<span className='sankey__color-input'>
|
|
214
|
+
<input type='color' value={config.sankey.linkColor.default} id='linkColor' name='linkColor' onChange={e => updateColor('linkColor', e.target.value)} />
|
|
215
|
+
<label htmlFor='linkColor'>Link Color</label>
|
|
216
|
+
</span>
|
|
217
|
+
</>
|
|
218
|
+
)}
|
|
178
219
|
{(config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') && (
|
|
179
220
|
<>
|
|
180
221
|
<InputToggle section='twoColor' fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={config.twoColor.isPaletteReversed} />
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import ForestPlotSettings from './Panel.ForestPlotSettings
|
|
2
|
-
import Series from './Panel.Series
|
|
3
|
-
import Regions from './Panel.Regions
|
|
4
|
-
import General from './Panel.General
|
|
5
|
-
import BoxPlot from './Panel.BoxPlot
|
|
6
|
-
import Visual from './Panel.Visual
|
|
1
|
+
import ForestPlotSettings from './Panel.ForestPlotSettings'
|
|
2
|
+
import Series from './Panel.Series'
|
|
3
|
+
import Regions from './Panel.Regions'
|
|
4
|
+
import General from './Panel.General'
|
|
5
|
+
import BoxPlot from './Panel.BoxPlot'
|
|
6
|
+
import Visual from './Panel.Visual'
|
|
7
|
+
import Sankey from './Panel.Sankey'
|
|
7
8
|
|
|
8
9
|
const Panels = {
|
|
9
10
|
ForestPlot: ForestPlotSettings,
|
|
@@ -11,7 +12,8 @@ const Panels = {
|
|
|
11
12
|
Regions,
|
|
12
13
|
General,
|
|
13
14
|
BoxPlot,
|
|
14
|
-
Visual
|
|
15
|
+
Visual,
|
|
16
|
+
Sankey
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
export default Panels
|