@cdc/chart 4.24.1 → 4.24.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.
Files changed (82) hide show
  1. package/dist/cdcchart.js +48948 -37923
  2. package/examples/{private/combo.json → chart-regression-1.json} +40 -31
  3. package/examples/chart-regression-2.json +2360 -0
  4. package/examples/feature/filters/url-filter.json +1076 -0
  5. package/examples/feature/line/line-chart-preliminary.json +84 -37
  6. package/examples/feature/line/line-chart.json +2 -1
  7. package/examples/feature/regions/index.json +55 -5
  8. package/examples/feature/sankey/sankey-example-data.json +1364 -0
  9. package/examples/feature/sankey/sankey_chart_data.csv +20 -0
  10. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +306 -19
  11. package/examples/sparkline.json +868 -0
  12. package/index.html +128 -121
  13. package/package.json +4 -2
  14. package/src/CdcChart.tsx +73 -38
  15. package/src/_stories/ChartEditor.stories.tsx +15 -4
  16. package/src/_stories/_mock/pie_config.json +4 -3
  17. package/src/_stories/_mock/url_filter.json +1076 -0
  18. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +2 -1
  19. package/src/components/AreaChart/components/AreaChart.jsx +2 -25
  20. package/src/components/BarChart/components/BarChart.Horizontal.tsx +39 -49
  21. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +36 -56
  22. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +36 -41
  23. package/src/components/BarChart/components/BarChart.Vertical.tsx +48 -64
  24. package/src/components/BoxPlot/BoxPlot.jsx +11 -9
  25. package/src/components/DeviationBar.jsx +3 -3
  26. package/src/components/EditorPanel/EditorPanel.tsx +1717 -1961
  27. package/src/components/EditorPanel/EditorPanelContext.ts +40 -0
  28. package/src/components/EditorPanel/components/Panels/Panel.BoxPlot.tsx +148 -0
  29. package/src/components/EditorPanel/components/{Panel.ForestPlotSettings.tsx → Panels/Panel.ForestPlotSettings.tsx} +16 -7
  30. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +160 -0
  31. package/src/components/EditorPanel/components/{Panel.Regions.tsx → Panels/Panel.Regions.tsx} +6 -6
  32. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +108 -0
  33. package/src/components/EditorPanel/components/{Panel.Series.tsx → Panels/Panel.Series.tsx} +50 -6
  34. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +338 -0
  35. package/src/components/EditorPanel/components/Panels/index.tsx +19 -0
  36. package/src/components/EditorPanel/components/panels.scss +11 -0
  37. package/src/components/EditorPanel/editor-panel.scss +1 -13
  38. package/src/components/EditorPanel/useEditorPermissions.js +44 -13
  39. package/src/components/Legend/Legend.Component.tsx +207 -0
  40. package/src/components/Legend/Legend.tsx +8 -327
  41. package/src/components/Legend/helpers/createFormatLabels.tsx +140 -0
  42. package/src/components/LineChart/LineChartProps.ts +2 -1
  43. package/src/components/LineChart/components/LineChart.Circle.tsx +85 -52
  44. package/src/components/LineChart/helpers.ts +3 -3
  45. package/src/components/LineChart/index.tsx +99 -23
  46. package/src/components/LinearChart.jsx +12 -33
  47. package/src/components/PairedBarChart.jsx +10 -12
  48. package/src/components/PieChart/PieChart.tsx +80 -27
  49. package/src/components/Regions/components/Regions.tsx +120 -69
  50. package/src/components/Sankey/index.tsx +434 -0
  51. package/src/components/Sankey/sankey.scss +153 -0
  52. package/src/components/Sankey/types/index.ts +16 -0
  53. package/src/components/ScatterPlot/ScatterPlot.jsx +1 -0
  54. package/src/components/Sparkline/{SparkLine.jsx → components/SparkLine.tsx} +14 -30
  55. package/src/components/Sparkline/index.scss +3 -0
  56. package/src/components/Sparkline/index.tsx +1 -1
  57. package/src/components/ZoomBrush.tsx +2 -1
  58. package/src/data/initial-state.js +51 -4
  59. package/src/helpers/computeMarginBottom.ts +4 -3
  60. package/src/helpers/tests/computeMarginBottom.test.ts +2 -1
  61. package/src/hooks/useBarChart.js +5 -2
  62. package/src/hooks/useHighlightedBars.js +1 -1
  63. package/src/hooks/useMinMax.ts +3 -3
  64. package/src/hooks/useScales.ts +28 -18
  65. package/src/hooks/useTooltip.tsx +19 -14
  66. package/src/scss/main.scss +8 -96
  67. package/src/types/ChartConfig.ts +47 -20
  68. package/src/types/ChartContext.ts +17 -4
  69. package/src/types/Label.ts +7 -0
  70. package/examples/private/chart-t.json +0 -3740
  71. package/examples/private/epi-data.csv +0 -13
  72. package/examples/private/epi-data.json +0 -62
  73. package/examples/private/epi.json +0 -403
  74. package/examples/private/occupancy.json +0 -109283
  75. package/examples/private/prod-line-config.json +0 -401
  76. package/examples/private/region-data.json +0 -822
  77. package/examples/private/region-testing.json +0 -312
  78. package/examples/private/scaling.json +0 -45325
  79. package/examples/private/testing-data.json +0 -1739
  80. package/examples/private/testing.json +0 -816
  81. package/src/components/EditorPanel/components/Panel.DateHighlighting.tsx +0 -109
  82. package/src/components/EditorPanel/components/Panels.tsx +0 -13
@@ -0,0 +1,40 @@
1
+ import { createContext, useContext } from 'react'
2
+
3
+ export type EditorPanelContext = {
4
+ addNewExclusion?: Function
5
+ updateField?: Function
6
+ // warning messages updated within EditorPanel
7
+ warningMsg?: { maxMsg?: string; minMsg?: string; rightMaxMessage?: string; minMsgRight?: string }
8
+ // current enabled chart types in useEditorPermissions file
9
+ enabledChartTypes?: string[]
10
+ showBarStyleOptions?: boolean
11
+ getDataValueOptions?: Function
12
+ data?: object[]
13
+ // function used on inputs, selects, etc. to update config values.
14
+ getColumns?: Function
15
+ getDataValues?: Function
16
+ handleAddNewHighlightedBar?: Function
17
+ handleHighlightedBarLegendLabel?: Function
18
+ handleUpdateHighlightedBar?: Function
19
+ handleUpdateHighlightedBarColor?: Function
20
+ handleUpdateHighlightedBorderWidth?: Function
21
+ highlightedBarValues?: Function
22
+ highlightedSeriesValues?: Function
23
+ isPaletteReversed?: boolean
24
+ handleRemoveHighlightedBar?: Function
25
+ setLollipopShape?: Function
26
+ }
27
+
28
+ const EditorPanelContext = createContext<EditorPanelContext>(null)
29
+
30
+ export const useEditorPanelContext = () => {
31
+ const editorPanelCtx = useContext(EditorPanelContext)
32
+
33
+ if (editorPanelCtx === null) {
34
+ throw new Error('COVE: editor panel context is null.')
35
+ }
36
+
37
+ return editorPanelCtx
38
+ }
39
+
40
+ export default EditorPanelContext
@@ -0,0 +1,148 @@
1
+ import { useContext, FC } from 'react'
2
+ import { AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
3
+ import { TextField } from '@cdc/core/components/EditorPanel/Inputs'
4
+ import Tooltip from '@cdc/core/components/ui/Tooltip'
5
+ import Icon from '@cdc/core/components/ui/Icon'
6
+ import ConfigContext from '../../../../ConfigContext'
7
+ import { useEditorPanelContext } from '../../EditorPanelContext'
8
+
9
+ // types
10
+ import { type PanelProps } from './../PanelProps'
11
+
12
+ const PanelBoxPlot: FC<PanelProps> = props => {
13
+ const { config } = useContext(ConfigContext)
14
+ const { boxplot } = config
15
+ if (config.visualizationType !== 'Box Plot') return
16
+ const { updateField } = useEditorPanelContext()
17
+
18
+ return (
19
+ <AccordionItem>
20
+ <AccordionItemHeading>
21
+ <AccordionItemButton>{props.name}</AccordionItemButton>
22
+ </AccordionItemHeading>
23
+ <AccordionItemPanel>
24
+ <h4 style={{ fontSize: '18px' }}>Labels for 5-Number Summary</h4>
25
+
26
+ {/* max */}
27
+ <TextField
28
+ type='text'
29
+ value={boxplot.labels.maximum}
30
+ fieldName='maximum'
31
+ section='boxplot'
32
+ subsection='labels'
33
+ label='Maximum'
34
+ updateField={updateField}
35
+ tooltip={
36
+ <Tooltip style={{ textTransform: 'none' }}>
37
+ <Tooltip.Target>
38
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
39
+ </Tooltip.Target>
40
+ <Tooltip.Content>
41
+ <p>Highest value, excluding outliers</p>
42
+ </Tooltip.Content>
43
+ </Tooltip>
44
+ }
45
+ />
46
+
47
+ {/* Q3 */}
48
+ <TextField
49
+ type='text'
50
+ value={boxplot.labels.q3}
51
+ fieldName='q3'
52
+ section='boxplot'
53
+ subsection='labels'
54
+ label='Upper Quartile'
55
+ updateField={updateField}
56
+ tooltip={
57
+ <Tooltip style={{ textTransform: 'none' }}>
58
+ <Tooltip.Target>
59
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
60
+ </Tooltip.Target>
61
+ <Tooltip.Content>
62
+ <p>Represented by top line of box. 25% of data are higher.</p>
63
+ </Tooltip.Content>
64
+ </Tooltip>
65
+ }
66
+ />
67
+
68
+ {/* median */}
69
+ <TextField
70
+ type='text'
71
+ value={boxplot.labels.median}
72
+ fieldName='median'
73
+ section='boxplot'
74
+ subsection='labels'
75
+ label='Median'
76
+ updateField={updateField}
77
+ tooltip={
78
+ <Tooltip style={{ textTransform: 'none' }}>
79
+ <Tooltip.Target>
80
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
81
+ </Tooltip.Target>
82
+ <Tooltip.Content>
83
+ <p>Middle data point. Half of data are higher value.</p>
84
+ </Tooltip.Content>
85
+ </Tooltip>
86
+ }
87
+ />
88
+
89
+ {/* q1 */}
90
+ <TextField
91
+ type='text'
92
+ value={boxplot.labels.q1}
93
+ fieldName='q1'
94
+ section='boxplot'
95
+ subsection='labels'
96
+ label='Lower Quartile'
97
+ updateField={updateField}
98
+ tooltip={
99
+ <Tooltip style={{ textTransform: 'none' }}>
100
+ <Tooltip.Target>
101
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
102
+ </Tooltip.Target>
103
+ <Tooltip.Content>
104
+ <p>Represented by bottom line of box. 25% of data are lower.</p>
105
+ </Tooltip.Content>
106
+ </Tooltip>
107
+ }
108
+ />
109
+
110
+ {/* minimum */}
111
+ <TextField
112
+ type='text'
113
+ value={boxplot.labels.minimum}
114
+ fieldName='minimum'
115
+ section='boxplot'
116
+ subsection='labels'
117
+ label='Minimum'
118
+ updateField={updateField}
119
+ tooltip={
120
+ <Tooltip style={{ textTransform: 'none' }}>
121
+ <Tooltip.Target>
122
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
123
+ </Tooltip.Target>
124
+ <Tooltip.Content>
125
+ <p>Lowest value, excluding outliers</p>
126
+ </Tooltip.Content>
127
+ </Tooltip>
128
+ }
129
+ />
130
+ <br />
131
+ <h4 style={{ fontSize: '18px' }}>Labels for Additional Measures</h4>
132
+
133
+ {/* iqr */}
134
+ <TextField type='text' value={boxplot.labels.iqr} fieldName='iqr' section='boxplot' subsection='labels' label='Interquartile Range' updateField={updateField} />
135
+ {/* count */}
136
+ <TextField type='text' value={boxplot.labels.total} fieldName='total' section='boxplot' subsection='labels' label='Total' updateField={updateField} />
137
+ {/* mean */}
138
+ <TextField type='text' value={boxplot.labels.mean} fieldName='mean' section='boxplot' subsection='labels' label='Mean' updateField={updateField} />
139
+ {/* outliers */}
140
+ <TextField type='text' value={boxplot.labels.outliers} fieldName='outliers' section='boxplot' subsection='labels' label='Outliers' updateField={updateField} />
141
+ {/* values */}
142
+ <TextField type='text' value={boxplot.labels.values} fieldName='values' section='boxplot' subsection='labels' label='Values' updateField={updateField} />
143
+ </AccordionItemPanel>
144
+ </AccordionItem>
145
+ )
146
+ }
147
+
148
+ export default PanelBoxPlot
@@ -1,18 +1,25 @@
1
- import React, { useContext, memo, useState, useEffect } from 'react'
2
- import ConfigContext from '../../../ConfigContext'
3
- import { useDebounce } from 'use-debounce'
4
- import WarningImage from '../../../images/warning.svg'
1
+ import { useContext, FC } from 'react'
2
+
3
+ // cdc
5
4
  import Tooltip from '@cdc/core/components/ui/Tooltip'
6
5
  import Icon from '@cdc/core/components/ui/Icon'
7
- import { type ChartContext } from '../../../types/ChartContext'
8
6
  import { Select, CheckBox, TextField } from '@cdc/core/components/EditorPanel/Inputs'
9
- import { type PanelProps } from './PanelProps'
7
+ import WarningImage from '../../../../images/warning.svg'
8
+
9
+ // contexts
10
+ import ConfigContext from '../../../../ConfigContext'
11
+
12
+ // types
13
+ import { type ChartContext } from '../../../../types/ChartContext'
14
+ import { type PanelProps } from '../PanelProps'
10
15
 
11
16
  import { AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
12
17
 
13
- const ForestPlotSettings = ({ name }: PanelProps) => {
18
+ const ForestPlotSettings: FC<PanelProps> = ({ name }) => {
14
19
  const { config, rawData: unfilteredData, updateConfig } = useContext<ChartContext>(ConfigContext)
20
+ if (config.visualizationType !== 'Forest Plot') return
15
21
 
22
+ // todo: get from editor context?
16
23
  const enforceRestrictions = updatedConfig => {
17
24
  if (updatedConfig.orientation === 'horizontal') {
18
25
  updatedConfig.labels = false
@@ -26,6 +33,7 @@ const ForestPlotSettings = ({ name }: PanelProps) => {
26
33
  }
27
34
  }
28
35
 
36
+ // todo: get from editor context?
29
37
  const getColumns = (filter = true) => {
30
38
  let columns = {}
31
39
  unfilteredData.forEach(row => {
@@ -50,6 +58,7 @@ const ForestPlotSettings = ({ name }: PanelProps) => {
50
58
  return Object.keys(columns)
51
59
  }
52
60
 
61
+ // todo: editor context?
53
62
  const updateField = (section, subsection, fieldName, newValue) => {
54
63
  if (section === 'boxplot' && subsection === 'legend') {
55
64
  updateConfig({
@@ -0,0 +1,160 @@
1
+ import { useContext, FC } from 'react'
2
+
3
+ // external libraries
4
+ import { AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
5
+ import { approvedCurveTypes } from '@cdc/core/helpers/lineChartHelpers'
6
+
7
+ // core
8
+ import { TextField, Select, CheckBox } from '@cdc/core/components/EditorPanel/Inputs'
9
+ import Tooltip from '@cdc/core/components/ui/Tooltip'
10
+ import Icon from '@cdc/core/components/ui/Icon'
11
+
12
+ // contexts
13
+ import { useEditorPermissions } from '../../useEditorPermissions.js'
14
+ import { useEditorPanelContext } from '../../EditorPanelContext.js'
15
+ import ConfigContext from '../../../../ConfigContext.js'
16
+ import { PanelProps } from '../PanelProps'
17
+
18
+ const PanelGeneral: FC<PanelProps> = props => {
19
+ const { config } = useContext(ConfigContext)
20
+ const { updateField } = useEditorPanelContext()
21
+ const { enabledChartTypes, visHasNumbersOnBars, visHasLabelOnData, visSupportsChartHeight, visSupportsSuperTitle, visSupportsFootnotes } = useEditorPermissions()
22
+ const { visualizationType, visualizationSubType, barStyle } = config
23
+
24
+ const showBarStyleOptions = () => {
25
+ if ((visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && visualizationSubType !== 'stacked' && (config.orientation === 'horizontal' || config.orientation === 'vertical')) {
26
+ return ['flat', 'rounded', 'lollipop']
27
+ } else {
28
+ return ['flat', 'rounded']
29
+ }
30
+ }
31
+
32
+ return (
33
+ <AccordionItem>
34
+ {' '}
35
+ {/* General */}
36
+ <AccordionItemHeading>
37
+ <AccordionItemButton>General</AccordionItemButton>
38
+ </AccordionItemHeading>
39
+ <AccordionItemPanel>
40
+ <Select value={visualizationType} fieldName='visualizationType' label='Chart Type' updateField={updateField} options={enabledChartTypes} />
41
+ {(visualizationType === 'Bar' || visualizationType === 'Combo' || visualizationType === 'Area Chart') && <Select value={visualizationSubType || 'Regular'} fieldName='visualizationSubType' label='Chart Subtype' updateField={updateField} options={['regular', 'stacked']} />}
42
+ {visualizationType === 'Area Chart' && visualizationSubType === 'stacked' && <Select value={config.stackedAreaChartLineType || 'Linear'} fieldName='stackedAreaChartLineType' label='Stacked Area Chart Line Type' updateField={updateField} options={Object.keys(approvedCurveTypes)} />}
43
+ {visualizationType === 'Bar' && <Select value={config.orientation || 'vertical'} fieldName='orientation' label='Orientation' updateField={updateField} options={['vertical', 'horizontal']} />}
44
+ {visualizationType === 'Deviation Bar' && <Select label='Orientation' options={['horizontal']} />}
45
+ {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && <Select value={config.isLollipopChart ? 'lollipop' : barStyle || 'flat'} fieldName='barStyle' label='bar style' updateField={updateField} options={showBarStyleOptions()} />}
46
+ {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && barStyle === 'rounded' && <Select value={config.tipRounding || 'top'} fieldName='tipRounding' label='tip rounding' updateField={updateField} options={['top', 'full']} />}
47
+ {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && barStyle === 'rounded' && <Select value={config.roundingStyle || 'standard'} fieldName='roundingStyle' label='rounding style' updateField={updateField} options={['standard', 'shallow', 'finger']} />}
48
+ {visualizationType === 'Bar' && config.orientation === 'horizontal' && <Select value={config.yAxis.labelPlacement || 'Below Bar'} section='yAxis' fieldName='labelPlacement' label='Label Placement' updateField={updateField} options={['Below Bar', 'On Date/Category Axis']} />}
49
+ {visHasNumbersOnBars() ? (
50
+ <CheckBox value={config.yAxis.displayNumbersOnBar} section='yAxis' fieldName='displayNumbersOnBar' label={config.isLollipopChart ? 'Display Numbers after Bar' : 'Display Numbers on Bar'} updateField={updateField} />
51
+ ) : (
52
+ visHasLabelOnData() && <CheckBox value={config.labels} fieldName='labels' label='Display label on data' updateField={updateField} />
53
+ )}
54
+ {visualizationType === 'Pie' && <Select fieldName='pieType' label='Pie Chart Type' updateField={updateField} options={['Regular', 'Donut']} />}
55
+
56
+ <TextField
57
+ value={config.title || 'Chart Title'}
58
+ fieldName='title'
59
+ id='title'
60
+ label='Title'
61
+ placeholder='Chart Title'
62
+ //defaultValue='Chart Title'
63
+ updateField={updateField}
64
+ //onChange={handleTitleChange}
65
+ tooltip={
66
+ <Tooltip style={{ textTransform: 'none' }}>
67
+ <Tooltip.Target>
68
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
69
+ </Tooltip.Target>
70
+ <Tooltip.Content>
71
+ <p>Title is required to set the name of the download file but can be hidden using the option below.</p>
72
+ </Tooltip.Content>
73
+ </Tooltip>
74
+ }
75
+ />
76
+ <CheckBox value={config.showTitle} fieldName='showTitle' label='Show Title' updateField={updateField} />
77
+
78
+ {visSupportsSuperTitle() && (
79
+ <TextField
80
+ value={config.superTitle}
81
+ updateField={updateField}
82
+ fieldName='superTitle'
83
+ label='Super Title'
84
+ placeholder='Super Title'
85
+ tooltip={
86
+ <Tooltip style={{ textTransform: 'none' }}>
87
+ <Tooltip.Target>
88
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
89
+ </Tooltip.Target>
90
+ <Tooltip.Content>
91
+ <p>Super Title</p>
92
+ </Tooltip.Content>
93
+ </Tooltip>
94
+ }
95
+ />
96
+ )}
97
+
98
+ <TextField
99
+ type='textarea'
100
+ value={config.introText}
101
+ updateField={updateField}
102
+ fieldName='introText'
103
+ label='Message'
104
+ tooltip={
105
+ <Tooltip style={{ textTransform: 'none' }}>
106
+ <Tooltip.Target>
107
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
108
+ </Tooltip.Target>
109
+ <Tooltip.Content>
110
+ <p>Intro Text</p>
111
+ </Tooltip.Content>
112
+ </Tooltip>
113
+ }
114
+ />
115
+
116
+ <TextField
117
+ type='textarea'
118
+ value={config.description}
119
+ fieldName='description'
120
+ label='Subtext/Citation'
121
+ updateField={updateField}
122
+ tooltip={
123
+ <Tooltip style={{ textTransform: 'none' }}>
124
+ <Tooltip.Target>
125
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
126
+ </Tooltip.Target>
127
+ <Tooltip.Content>
128
+ <p>Enter supporting text to display below the data visualization, if applicable. The following HTML tags are supported: strong, em, sup, and sub.</p>
129
+ </Tooltip.Content>
130
+ </Tooltip>
131
+ }
132
+ />
133
+
134
+ {visSupportsFootnotes() && (
135
+ <TextField
136
+ type='textarea'
137
+ value={config.footnotes}
138
+ updateField={updateField}
139
+ fieldName='footnotes'
140
+ label='Footnotes'
141
+ tooltip={
142
+ <Tooltip style={{ textTransform: 'none' }}>
143
+ <Tooltip.Target>
144
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
145
+ </Tooltip.Target>
146
+ <Tooltip.Content>
147
+ <p>Footnotes</p>
148
+ </Tooltip.Content>
149
+ </Tooltip>
150
+ }
151
+ />
152
+ )}
153
+
154
+ {visSupportsChartHeight() && config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
155
+ </AccordionItemPanel>
156
+ </AccordionItem>
157
+ )
158
+ }
159
+
160
+ export default PanelGeneral
@@ -1,13 +1,13 @@
1
1
  import { memo, useContext } from 'react'
2
- import { useEditorPermissions } from './../useEditorPermissions.js'
2
+ import { useEditorPermissions } from '../../useEditorPermissions.js'
3
3
  import { AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
4
- import { type ChartConfig } from './../../../types/ChartConfig.js'
4
+ import { type ChartConfig } from '../../../../types/ChartConfig.js'
5
5
  import { TextField, Select } from '@cdc/core/components/EditorPanel/Inputs'
6
6
  import Tooltip from '@cdc/core/components/ui/Tooltip'
7
7
  import Icon from '@cdc/core/components/ui/Icon'
8
- import { type ChartContext } from '../../../types/ChartContext'
9
- import { type PanelProps } from './PanelProps'
10
- import ConfigContext from '../../../ConfigContext'
8
+ import { type ChartContext } from '../../../../types/ChartContext.js'
9
+ import { type PanelProps } from '../PanelProps.js'
10
+ import ConfigContext from '../../../../ConfigContext.js'
11
11
 
12
12
  const RegionSettings = memo(({ config, updateConfig }: { config: ChartConfig; updateConfig: Function }) => {
13
13
  let regionUpdate = (fieldName, value, i) => {
@@ -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>The date needs to be in the original format of the data. Not the displayed format of the data.</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,108 @@
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
+ console.log('story nodes', storyNodes[i])
25
+ updateConfig({
26
+ ...config,
27
+ sankey: {
28
+ ...config.sankey,
29
+ data: {
30
+ ...config.sankey.data,
31
+ storyNodeText: storyNodes
32
+ }
33
+ }
34
+ })
35
+ }
36
+
37
+ const addStoryNode = () => {
38
+ const newData = data
39
+
40
+ newData.storyNodeText.push({
41
+ StoryNode: '',
42
+ segmentTextBefore: '',
43
+ segmentTextAfter: ''
44
+ })
45
+
46
+ updateConfig({
47
+ ...config,
48
+ sankey: {
49
+ ...config.sankey,
50
+ data: [{ ...newData }]
51
+ }
52
+ })
53
+ }
54
+
55
+ const removeStoryNode = index => {
56
+ const newData = data
57
+ newData.storyNodeText.splice(index, 1)
58
+
59
+ updateConfig({ ...config, sankey: { ...config.sankey, data: { ...newData } } })
60
+ }
61
+
62
+ return (
63
+ <AccordionItem>
64
+ <AccordionItemHeading>
65
+ <AccordionItemButton>Sankey Settings</AccordionItemButton>
66
+ </AccordionItemHeading>
67
+ <AccordionItemPanel>
68
+ {data?.storyNodeText &&
69
+ data?.storyNodeText.map(({ StoryNode, segmentTextBefore, segmentTextAfter }, i) => (
70
+ <div key={i} style={{ border: '1px solid black', margin: '15px auto', padding: '15px', borderRadius: '10px' }}>
71
+ <label>
72
+ Story Node Text
73
+ <input type='text' value={StoryNode} fieldName='StoryNode' label='StoryNode' onChange={e => updateStoryNode('StoryNode', e.target.value, i)} />
74
+ </label>
75
+ <label>
76
+ Story Text Before
77
+ <input type='text' value={segmentTextBefore} fieldName='segmentTextBefore' label='Segment Text Before' onChange={e => updateStoryNode('segmentTextBefore', e.target.value, i)} />
78
+ </label>
79
+ <label>
80
+ Story Text After
81
+ <input type='text' value={segmentTextAfter} fieldName='segmentTextAfter' label='Segment Text After' onChange={e => updateStoryNode('segmentTextAfter', e.target.value, i)} />
82
+ </label>
83
+ <Button onClick={e => removeStoryNode(i)} className='btn' style={{ background: 'tomato' }}>
84
+ Remove Story Node
85
+ </Button>
86
+ </div>
87
+ ))}
88
+ {`Total Story Nodes: ${data?.storyNodeText?.length}`}
89
+ {data?.storyNodeText?.length < 3 && (
90
+ <button
91
+ type='button'
92
+ className='btn full-width'
93
+ onClick={e => {
94
+ e.preventDefault()
95
+ addStoryNode()
96
+ }}
97
+ >
98
+ Add StoryNode
99
+ </button>
100
+ )}
101
+
102
+ <CheckBox value={config.enableTooltips} fieldName='enableTooltips' label='Enable Tooltips' updateField={updateField} />
103
+ </AccordionItemPanel>
104
+ </AccordionItem>
105
+ )
106
+ }
107
+
108
+ export default SankeySettings
@@ -1,5 +1,5 @@
1
1
  import React, { useContext } from 'react'
2
- import ConfigContext from '../../../ConfigContext'
2
+ import ConfigContext from '../../../../ConfigContext'
3
3
 
4
4
  // Core
5
5
  import InputSelect from '@cdc/core/components/inputs/InputSelect'
@@ -424,16 +424,56 @@ const SeriesDropdownConfidenceInterval = props => {
424
424
  )
425
425
  }
426
426
 
427
- const SeriesInputName = props => {
427
+ const SeriesInputWeight = props => {
428
428
  const { series, index: i } = props
429
429
  const { config, updateConfig } = useContext(ConfigContext)
430
- const adjustableNameSeriesTypes = ['Bar', 'Line', 'Area Chart', 'dashed-sm', 'dashed-md', 'dashed-lg']
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
+ }
431
451
 
432
- if (config.visualizationType === 'Combo') return
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
+
469
+ const SeriesInputName = props => {
470
+ const { series, index: i } = props
471
+ const { config, updateConfig } = useContext(ConfigContext)
472
+ const adjustableNameSeriesTypes = ['Bar', 'Line', 'Area Chart', 'Combo', 'Deviation Bar', 'Paired Bar', 'Scatter Plot', 'dashed-sm', 'dashed-md', 'dashed-lg']
433
473
 
434
474
  if (!adjustableNameSeriesTypes.includes(series.type)) return
435
475
 
436
- let changeSeriesName = (i, value) => {
476
+ const changeSeriesName = (i, value) => {
437
477
  let series = [...config.series]
438
478
  let seriesLabelsCopy = { ...config.runtime.seriesLabels }
439
479
  series[i].name = value
@@ -470,6 +510,8 @@ const SeriesDisplayInTooltip = props => {
470
510
  const { series, index } = props
471
511
  const { config, updateConfig } = useContext(ConfigContext)
472
512
 
513
+ if (['Paired Bar', 'Scatter Plot', 'Deviation Bar'].includes(config.visualizationType)) return
514
+
473
515
  const toggleTooltip = seriesIndex => {
474
516
  let copiedSeries = [...config.series]
475
517
 
@@ -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