@cdc/chart 4.23.2 → 4.23.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/dist/cdcchart.js +41198 -39447
- package/examples/area-chart.json +187 -0
- package/examples/big-small-test-bar.json +328 -0
- package/examples/big-small-test-line.json +328 -0
- package/examples/big-small-test-negative.json +328 -0
- package/examples/box-plot.json +0 -1
- package/examples/example-bar-chart.json +4 -1
- package/examples/example-sparkline.json +76 -0
- package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart.json +31 -172
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-confidence.json +1 -0
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-with-confidence.json +96 -14
- package/examples/gallery/line/line.json +1 -0
- package/examples/horizontal-chart-max-increase.json +38 -0
- package/examples/line-chart-max-increase.json +32 -0
- package/examples/line-chart-nonnumeric.json +5 -5
- package/examples/line-chart.json +6 -6
- package/examples/planet-deviation-config.json +168 -0
- package/examples/planet-deviation-data.json +38 -0
- package/examples/planet-example-config.json +139 -20
- package/examples/planet-example-data-max-increase.json +56 -0
- package/examples/planet-example-data.json +10 -10
- package/examples/scatterplot-continuous.csv +3 -3
- package/examples/scatterplot.json +2 -2
- package/examples/sparkline-chart-nonnumeric.json +3 -3
- package/index.html +26 -9
- package/package.json +6 -3
- package/src/CdcChart.jsx +146 -92
- package/src/components/AreaChart.jsx +198 -0
- package/src/components/BarChart.jsx +58 -34
- package/src/components/BoxPlot.jsx +28 -15
- package/src/components/DataTable.jsx +21 -17
- package/src/components/DeviationBar.jsx +191 -0
- package/src/components/EditorPanel.jsx +473 -168
- package/src/components/Filters.jsx +3 -2
- package/src/components/Legend.jsx +59 -46
- package/src/components/LineChart.jsx +3 -21
- package/src/components/LinearChart.jsx +158 -55
- package/src/components/PairedBarChart.jsx +0 -1
- package/src/components/PieChart.jsx +11 -14
- package/src/components/ScatterPlot.jsx +19 -16
- package/src/components/SparkLine.jsx +87 -85
- package/src/components/useIntersectionObserver.jsx +1 -1
- package/src/data/initial-state.js +20 -4
- package/src/hooks/useColorPalette.js +58 -48
- package/src/hooks/useReduceData.js +3 -4
- package/src/index.jsx +1 -1
- package/src/scss/editor-panel.scss +5 -0
- package/src/test/CdcChart.test.jsx +6 -0
|
@@ -3,39 +3,42 @@ import ConfigContext from '../ConfigContext'
|
|
|
3
3
|
import { Group } from '@visx/group'
|
|
4
4
|
|
|
5
5
|
const CoveScatterPlot = ({ xScale, yScale, getXAxisData, getYAxisData }) => {
|
|
6
|
-
const { colorScale, transformedData: data, config } = useContext(ConfigContext)
|
|
6
|
+
const { colorScale, transformedData: data, config, formatNumber, seriesHighlight, colorPalettes } = useContext(ConfigContext)
|
|
7
7
|
|
|
8
|
-
// copied from line chart
|
|
9
|
-
// should probably be a constant somewhere.
|
|
8
|
+
// TODO: copied from line chart should probably be a constant somewhere.
|
|
10
9
|
let circleRadii = 4.5
|
|
11
|
-
|
|
12
|
-
let pointStyles = {
|
|
13
|
-
filter: 'unset',
|
|
14
|
-
opacity: 1,
|
|
15
|
-
stroke: 'black'
|
|
16
|
-
}
|
|
10
|
+
const hasMultipleSeries = Object.keys(config.runtime.seriesLabels).length > 1
|
|
17
11
|
|
|
18
12
|
const handleTooltip = (item, s) => `<div>
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
${config.legend.showLegendValuesTooltip && config.runtime.seriesLabels && hasMultipleSeries ? `${config.runtime.seriesLabels[s] || ''}<br/>` : ''}
|
|
14
|
+
${config.xAxis.label}: ${formatNumber(item[config.xAxis.dataKey], 'bottom')} <br/>
|
|
15
|
+
${config.yAxis.label}: ${formatNumber(item[s], 'left')}
|
|
21
16
|
</div>`
|
|
22
17
|
|
|
23
18
|
return (
|
|
24
19
|
<Group className='scatter-plot' left={config.yAxis.size}>
|
|
25
20
|
{data.map((item, dataIndex) => {
|
|
26
21
|
// prettier-ignore
|
|
27
|
-
return config.runtime.seriesKeys.map(s => {
|
|
22
|
+
return config.runtime.seriesKeys.map((s, index) => {
|
|
23
|
+
const transparentArea = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(s) === -1
|
|
24
|
+
const displayArea = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(s) !== -1
|
|
25
|
+
const seriesColor = config.palette ? colorPalettes[config.palette][index] : '#000'
|
|
26
|
+
|
|
27
|
+
let pointStyles = {
|
|
28
|
+
filter: 'unset',
|
|
29
|
+
opacity: 1,
|
|
30
|
+
stroke: displayArea ? 'black' : ''
|
|
31
|
+
}
|
|
28
32
|
|
|
29
33
|
return (
|
|
30
34
|
<circle
|
|
31
|
-
key={`${dataIndex}`}
|
|
35
|
+
key={`${dataIndex}-${index}`}
|
|
32
36
|
r={circleRadii}
|
|
33
37
|
cx={xScale(item[config.xAxis.dataKey])}
|
|
34
38
|
cy={yScale(item[s])}
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
fill={displayArea ? seriesColor : 'transparent'}
|
|
40
|
+
fillOpacity={transparentArea ? .25 : 1}
|
|
37
41
|
style={pointStyles}
|
|
38
|
-
fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[s] : s) : '#000'}
|
|
39
42
|
data-tooltip-html={handleTooltip(item, s)}
|
|
40
43
|
data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
|
|
41
44
|
/>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useContext
|
|
1
|
+
import React, { useContext } from 'react'
|
|
2
2
|
|
|
3
3
|
import * as allCurves from '@visx/curve'
|
|
4
4
|
import { Group } from '@visx/group'
|
|
@@ -15,7 +15,7 @@ import useReduceData from '../hooks/useReduceData'
|
|
|
15
15
|
import ConfigContext from '../ConfigContext'
|
|
16
16
|
|
|
17
17
|
export default function SparkLine({ width: parentWidth, height: parentHeight }) {
|
|
18
|
-
const { transformedData: data,
|
|
18
|
+
const { transformedData: data, config, parseDate, formatDate, seriesHighlight, formatNumber, colorScale, handleChartAriaLabels } = useContext(ConfigContext)
|
|
19
19
|
let width = parentWidth
|
|
20
20
|
const { minValue, maxValue } = useReduceData(config, data, ConfigContext)
|
|
21
21
|
|
|
@@ -35,13 +35,12 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
|
|
|
35
35
|
const isMaxValid = Number(enteredMaxValue) >= Number(maxValue)
|
|
36
36
|
const isMinValid = Number(enteredMinValue) <= Number(minValue)
|
|
37
37
|
|
|
38
|
-
|
|
39
38
|
// REMOVE bad data points from the data set
|
|
40
39
|
// Examples: NA, N/A, "1,234", "anystring"
|
|
41
40
|
// - if you dont call this on data into LineGroup below, for example
|
|
42
41
|
// then entire data series are removed because of the defined statement
|
|
43
42
|
// i.e. if a series has any bad data points the entire series wont plot
|
|
44
|
-
|
|
43
|
+
const cleanData = (data, testing = false) => {
|
|
45
44
|
let cleanedup = []
|
|
46
45
|
if (testing) console.log('## Data to clean=', data)
|
|
47
46
|
data.forEach(function (d, i) {
|
|
@@ -52,8 +51,8 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
|
|
|
52
51
|
cleanedSeries[key] = d[key]
|
|
53
52
|
} else {
|
|
54
53
|
// remove comma and dollar signs
|
|
55
|
-
let tmp = d[key]
|
|
56
|
-
if (testing) console.log(
|
|
54
|
+
let tmp = d[key] !== null && d[key] !== '' ? d[key].replace(/[,$]/g, '') : ''
|
|
55
|
+
if (testing) console.log('tmp no comma or $', tmp)
|
|
57
56
|
if ((tmp !== '' && tmp !== null && !isNaN(tmp)) || (tmp !== '' && tmp !== null && /\d+\.?\d*/.test(tmp))) {
|
|
58
57
|
cleanedSeries[key] = tmp
|
|
59
58
|
} else {
|
|
@@ -66,11 +65,11 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
|
|
|
66
65
|
})
|
|
67
66
|
if (testing) console.log('## cleanedData =', cleanedup)
|
|
68
67
|
return cleanedup
|
|
69
|
-
|
|
68
|
+
}
|
|
70
69
|
|
|
71
70
|
// Just do this once up front otherwise we end up
|
|
72
71
|
// calling clean several times on same set of data (TT)
|
|
73
|
-
const cleanedData = cleanData(data, config.xAxis.dataKey)
|
|
72
|
+
const cleanedData = cleanData(data, config.xAxis.dataKey)
|
|
74
73
|
|
|
75
74
|
if (cleanedData) {
|
|
76
75
|
let min = enteredMinValue && isMinValid ? enteredMinValue : minValue
|
|
@@ -116,6 +115,7 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
|
|
|
116
115
|
range: [margin.left, width - margin.right]
|
|
117
116
|
})
|
|
118
117
|
|
|
118
|
+
// eslint-disable-next-line
|
|
119
119
|
seriesScale = scalePoint({
|
|
120
120
|
domain: config.runtime.barSeriesKeys || config.runtime.seriesKeys,
|
|
121
121
|
range: [0, xMax]
|
|
@@ -128,88 +128,90 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
|
|
|
128
128
|
return (
|
|
129
129
|
<ErrorBoundary component='SparkLine'>
|
|
130
130
|
<svg role='img' aria-label={handleChartAriaLabels(config)} width={width} height={height} className={'sparkline'} tabIndex={0}>
|
|
131
|
-
{
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
131
|
+
{config.runtime.lineSeriesKeys.length > 0
|
|
132
|
+
? config.runtime.lineSeriesKeys
|
|
133
|
+
: config.runtime.seriesKeys.map((seriesKey, index) => (
|
|
134
|
+
<>
|
|
135
|
+
<Group
|
|
136
|
+
className='sparkline-group'
|
|
137
|
+
height={parentHeight}
|
|
138
|
+
style={{ height: parentHeight }}
|
|
139
|
+
top={margin.top}
|
|
140
|
+
key={`series-${seriesKey}`}
|
|
141
|
+
opacity={config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(seriesKey) === -1 ? 0.5 : 1}
|
|
142
|
+
display={config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(seriesKey) !== -1 ? 'block' : 'none'}
|
|
143
|
+
>
|
|
144
|
+
{cleanedData.map((d, dataIndex) => {
|
|
145
|
+
let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${formatNumber(getYAxisData(d, seriesKey))}` : formatNumber(getYAxisData(d, seriesKey))
|
|
146
|
+
let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${d[config.runtime.xAxis.dataKey]}` : d[config.runtime.xAxis.dataKey]
|
|
147
|
+
|
|
148
|
+
const tooltip = `<div>
|
|
147
149
|
${yAxisTooltip}<br />
|
|
148
150
|
${xAxisTooltip}<br />
|
|
149
151
|
${config.seriesLabel ? `${config.seriesLabel}: ${seriesKey}` : ''}
|
|
150
152
|
</div>`
|
|
151
153
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
154
|
+
let circleRadii = 4.5
|
|
155
|
+
return (
|
|
156
|
+
<Group key={`series-${seriesKey}-point-${dataIndex}`}>
|
|
157
|
+
<Text display={config.labels ? 'block' : 'none'} x={xScale(getXAxisData(d))} y={yScale(getYAxisData(d, seriesKey))} fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'} textAnchor='middle'>
|
|
158
|
+
{formatNumber(d[seriesKey])}
|
|
159
|
+
</Text>
|
|
160
|
+
|
|
161
|
+
{dataIndex + 1 !== data.length && (config.lineDatapointStyle === 'always show' || config.lineDatapointStyle === 'hover') && (
|
|
162
|
+
<circle
|
|
163
|
+
key={`${seriesKey}-${dataIndex}`}
|
|
164
|
+
r={circleRadii}
|
|
165
|
+
cx={xScale(getXAxisData(d))}
|
|
166
|
+
cy={yScale(getYAxisData(d, seriesKey))}
|
|
167
|
+
fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
|
|
168
|
+
style={{ fill: colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000' }}
|
|
169
|
+
data-tooltip-html={tooltip}
|
|
170
|
+
data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
|
|
171
|
+
/>
|
|
172
|
+
)}
|
|
173
|
+
</Group>
|
|
174
|
+
)
|
|
175
|
+
})}
|
|
176
|
+
<LinePath
|
|
177
|
+
curve={allCurves.curveLinear}
|
|
178
|
+
data={cleanedData}
|
|
179
|
+
x={d => xScale(getXAxisData(d))}
|
|
180
|
+
y={d => yScale(getYAxisData(d, seriesKey))}
|
|
181
|
+
stroke={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
|
|
182
|
+
strokeWidth={2}
|
|
183
|
+
strokeOpacity={1}
|
|
184
|
+
shapeRendering='geometricPrecision'
|
|
185
|
+
markerEnd={`url(#${'arrow'}--${index})`}
|
|
186
|
+
/>
|
|
187
|
+
<MarkerArrow
|
|
188
|
+
id={`arrow--${index}`}
|
|
189
|
+
refX={2}
|
|
190
|
+
size={6}
|
|
191
|
+
markerEnd={`url(#${'arrow'}--${index})`}
|
|
192
|
+
strokeOpacity={1}
|
|
193
|
+
fillOpacity={1}
|
|
194
|
+
// stroke={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
|
|
195
|
+
fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
|
|
196
|
+
/>
|
|
197
|
+
</Group>
|
|
198
|
+
<AxisBottom
|
|
199
|
+
top={yMax + margin.top}
|
|
200
|
+
hideAxisLine
|
|
201
|
+
hideTicks
|
|
202
|
+
scale={xScale}
|
|
203
|
+
tickValues={handleSparkLineTicks}
|
|
204
|
+
tickFormat={formatDate}
|
|
205
|
+
stroke={'black'}
|
|
206
|
+
tickStroke={'black'}
|
|
207
|
+
tickLabelProps={() => ({
|
|
208
|
+
fill: 'black',
|
|
209
|
+
fontSize: 11,
|
|
210
|
+
textAnchor: 'middle'
|
|
211
|
+
})}
|
|
212
|
+
/>
|
|
213
|
+
</>
|
|
214
|
+
))}
|
|
213
215
|
</svg>
|
|
214
216
|
</ErrorBoundary>
|
|
215
217
|
)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
type: 'chart',
|
|
3
3
|
title: '',
|
|
4
|
+
showTitle: true,
|
|
4
5
|
theme: 'theme-blue',
|
|
5
6
|
animate: false,
|
|
6
7
|
fontSize: 'medium',
|
|
@@ -24,6 +25,7 @@ export default {
|
|
|
24
25
|
hideTicks: false,
|
|
25
26
|
size: 50,
|
|
26
27
|
gridLines: false,
|
|
28
|
+
enablePadding: false,
|
|
27
29
|
min: '',
|
|
28
30
|
max: '',
|
|
29
31
|
labelColor: '#333',
|
|
@@ -63,7 +65,7 @@ export default {
|
|
|
63
65
|
median: 'Median',
|
|
64
66
|
sd: 'Standard Deviation',
|
|
65
67
|
iqr: 'Interquartile Range',
|
|
66
|
-
|
|
68
|
+
total: 'Total',
|
|
67
69
|
outliers: 'Outliers',
|
|
68
70
|
values: 'Values'
|
|
69
71
|
}
|
|
@@ -81,6 +83,8 @@ export default {
|
|
|
81
83
|
},
|
|
82
84
|
xAxis: {
|
|
83
85
|
type: 'categorical',
|
|
86
|
+
showTargetLabel: true,
|
|
87
|
+
targetLabel: 'Target',
|
|
84
88
|
hideAxis: false,
|
|
85
89
|
hideLabel: false,
|
|
86
90
|
hideTicks: false,
|
|
@@ -93,7 +97,8 @@ export default {
|
|
|
93
97
|
tickColor: '#333',
|
|
94
98
|
numTicks: '',
|
|
95
99
|
labelOffset: 65,
|
|
96
|
-
axisPadding: 0
|
|
100
|
+
axisPadding: 0,
|
|
101
|
+
target: 0
|
|
97
102
|
},
|
|
98
103
|
table: {
|
|
99
104
|
label: 'Data Table',
|
|
@@ -106,7 +111,6 @@ export default {
|
|
|
106
111
|
orientation: 'vertical',
|
|
107
112
|
legend: {
|
|
108
113
|
behavior: 'isolate',
|
|
109
|
-
position: 'right',
|
|
110
114
|
singleRow: false,
|
|
111
115
|
colorCode: '',
|
|
112
116
|
reverseLabelOrder: false,
|
|
@@ -123,8 +127,20 @@ export default {
|
|
|
123
127
|
},
|
|
124
128
|
palette: 'qualitative-bold',
|
|
125
129
|
isPaletteReversed: false,
|
|
130
|
+
twoColor: {
|
|
131
|
+
palette: 'monochrome-1',
|
|
132
|
+
isPaletteReversed: false
|
|
133
|
+
},
|
|
126
134
|
labels: false,
|
|
127
|
-
dataFormat: {
|
|
135
|
+
dataFormat: {
|
|
136
|
+
commas: false,
|
|
137
|
+
prefix: '',
|
|
138
|
+
suffix: '',
|
|
139
|
+
abbreviated: false,
|
|
140
|
+
bottomSuffix: '',
|
|
141
|
+
bottomPrefix: '',
|
|
142
|
+
bottomAbbreviated: false
|
|
143
|
+
},
|
|
128
144
|
confidenceKeys: {},
|
|
129
145
|
visual: {
|
|
130
146
|
border: true,
|
|
@@ -1,58 +1,68 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
// constants
|
|
4
|
-
const SEQUENTIAL = 'SEQUENTIAL'
|
|
5
|
-
const SEQUENTIAL_REVERSE = 'SEQUENTIAL_REVERSE'
|
|
6
|
-
export const GET_PALETTE = 'GET_PALETTE'
|
|
7
|
-
|
|
8
|
-
// create initial state
|
|
9
|
-
const initialState = {
|
|
10
|
-
filteredPallets: [],
|
|
11
|
-
isPaletteReversed: false,
|
|
12
|
-
filteredQualitative: [],
|
|
13
|
-
paletteName: undefined
|
|
14
|
-
}
|
|
1
|
+
import { colorPalettesChart, twoColorPalette } from '@cdc/core/data/colorPalettes'
|
|
2
|
+
import { useEffect } from 'react'
|
|
15
3
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
let
|
|
19
|
-
|
|
20
|
-
case GET_PALETTE:
|
|
21
|
-
return { ...state, paletteName: action.paletteName }
|
|
22
|
-
case SEQUENTIAL:
|
|
23
|
-
paletteName = state.paletteName && state.paletteName.endsWith('reverse') ? String(state.paletteName).substring(0, state.paletteName.length - 7) : String(state.paletteName)
|
|
24
|
-
const qualitative = palletNamesArr.filter((name) => String(name).startsWith('qualitative') && !String(name).endsWith('reverse'))
|
|
25
|
-
const sequential = palletNamesArr.filter((name) => String(name).startsWith('sequential') && !String(name).endsWith('reverse'))
|
|
26
|
-
return { ...state, filteredPallets: sequential, filteredQualitative: qualitative, paletteName: paletteName, isPaletteReversed: false }
|
|
27
|
-
|
|
28
|
-
case SEQUENTIAL_REVERSE:
|
|
29
|
-
paletteName = palletNamesArr.find((name) => name === String(state.paletteName).concat('reverse') || name === String(state.paletteName).concat('-reverse'))
|
|
30
|
-
const qualitativeReverse = palletNamesArr.filter((name) => String(name).startsWith('qualitative') && String(name).endsWith('reverse'))
|
|
31
|
-
const sequentialReverse = palletNamesArr.filter((name) => String(name).startsWith('sequential') && String(name).endsWith('reverse'))
|
|
32
|
-
return { ...state, filteredQualitative: qualitativeReverse, filteredPallets: sequentialReverse, paletteName: paletteName, isPaletteReversed: true }
|
|
33
|
-
default:
|
|
34
|
-
return state
|
|
35
|
-
}
|
|
36
|
-
}
|
|
4
|
+
export const useColorPalette = (config, updateConfig) => {
|
|
5
|
+
let twoColorPalettes = []
|
|
6
|
+
let sequential = []
|
|
7
|
+
let nonSequential = []
|
|
37
8
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
9
|
+
// Get two color palettes if visualization type is Paired Bar
|
|
10
|
+
if (config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') {
|
|
11
|
+
const isReversed = config.twoColor.isPaletteReversed
|
|
12
|
+
twoColorPalettes = Object.keys(twoColorPalette).filter(name => (isReversed ? name.endsWith('reverse') : !name.endsWith('reverse')))
|
|
13
|
+
} else {
|
|
14
|
+
// Get sequential and non-sequential palettes for other visualization types
|
|
15
|
+
const seqPalettes = []
|
|
16
|
+
const nonSeqPalettes = []
|
|
17
|
+
|
|
18
|
+
for (const paletteName in colorPalettesChart) {
|
|
19
|
+
const isSequential = paletteName.startsWith('sequential')
|
|
20
|
+
const isQualitative = paletteName.startsWith('qualitative')
|
|
21
|
+
const isReversed = paletteName.endsWith('reverse')
|
|
41
22
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
23
|
+
if (isSequential && ((!config.isPaletteReversed && !isReversed) || (config.isPaletteReversed && isReversed))) {
|
|
24
|
+
seqPalettes.push(paletteName)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (isQualitative && ((!config.isPaletteReversed && !isReversed) || (config.isPaletteReversed && isReversed))) {
|
|
28
|
+
nonSeqPalettes.push(paletteName)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
sequential = seqPalettes
|
|
33
|
+
nonSequential = nonSeqPalettes
|
|
34
|
+
}
|
|
45
35
|
|
|
36
|
+
// Update pairedBar.palette based on isPaletteReversed
|
|
46
37
|
useEffect(() => {
|
|
47
|
-
|
|
48
|
-
}, [])
|
|
38
|
+
let palette = ''
|
|
49
39
|
|
|
40
|
+
if (config.twoColor.isPaletteReversed && !config.twoColor.palette.endsWith('reverse')) {
|
|
41
|
+
palette = config.twoColor.palette + 'reverse'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!config.twoColor.isPaletteReversed && config.twoColor.palette.endsWith('reverse')) {
|
|
45
|
+
palette = config.twoColor.palette.slice(0, -7)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
updateConfig({ ...config, twoColor: { ...config.twoColor, palette: palette } })
|
|
49
|
+
}, [config.twoColor.isPaletteReversed])
|
|
50
|
+
|
|
51
|
+
// Update palette based on isPaletteReversed
|
|
50
52
|
useEffect(() => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
let palette = ''
|
|
54
|
+
|
|
55
|
+
if (config.isPaletteReversed && !config.palette.endsWith('reverse')) {
|
|
56
|
+
palette = config.palette + 'reverse'
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!config.isPaletteReversed && config.palette.endsWith('reverse')) {
|
|
60
|
+
palette = config.palette.slice(0, -7)
|
|
54
61
|
}
|
|
55
|
-
}, [configState.isPaletteReversed, dispatch, colorPalettes])
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
updateConfig({ ...config, palette: palette })
|
|
64
|
+
}, [config.isPaletteReversed])
|
|
65
|
+
|
|
66
|
+
// Return all palettes
|
|
67
|
+
return { twoColorPalettes, sequential, nonSequential }
|
|
58
68
|
}
|
|
@@ -9,7 +9,7 @@ function useReduceData(config, data) {
|
|
|
9
9
|
// remove comma and $ signs
|
|
10
10
|
let tmp
|
|
11
11
|
if (typeof value === 'string') {
|
|
12
|
-
tmp = value !== null && value !== '' ? value.replace(/[
|
|
12
|
+
tmp = value !== null && value !== '' ? value.replace(/[,$]/g, '') : ''
|
|
13
13
|
} else {
|
|
14
14
|
tmp = value !== null && value !== '' ? value : ''
|
|
15
15
|
}
|
|
@@ -18,7 +18,6 @@ function useReduceData(config, data) {
|
|
|
18
18
|
const getMaxValueFromData = () => {
|
|
19
19
|
let max // will hold max number from data.
|
|
20
20
|
if ((config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && isBar)) && config.visualizationSubType === 'stacked') {
|
|
21
|
-
|
|
22
21
|
const yTotals = data.reduce((allTotals, xValue) => {
|
|
23
22
|
const totalYValues = config.runtime.seriesKeys.reduce((yTotal, k) => {
|
|
24
23
|
yTotal += Number(xValue[k])
|
|
@@ -33,7 +32,7 @@ function useReduceData(config, data) {
|
|
|
33
32
|
}, [])
|
|
34
33
|
|
|
35
34
|
max = Math.max(...yTotals)
|
|
36
|
-
} else if (config.visualizationType === 'Bar' && config.series && config.series.dataKey) {
|
|
35
|
+
} else if ((config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.series && config.series.dataKey) {
|
|
37
36
|
max = Math.max(...data.map(d => (isNumber(d[config.series.dataKey]) ? Number(cleanChars(d[config.series.dataKey])) : 0)))
|
|
38
37
|
//max = Math.max(...data.map(d => Number(d[config.series.dataKey])))
|
|
39
38
|
} else if (config.visualizationType === 'Combo' && config.visualizationSubType === 'stacked' && !isBar) {
|
|
@@ -46,7 +45,7 @@ function useReduceData(config, data) {
|
|
|
46
45
|
yTotal += Number(d[k])
|
|
47
46
|
return yTotal
|
|
48
47
|
}, 0)
|
|
49
|
-
total.push(totalYValues)
|
|
48
|
+
return total.push(totalYValues)
|
|
50
49
|
})
|
|
51
50
|
// get lineSeries largest values
|
|
52
51
|
const lineMax = Math.max(...data.map(d => Math.max(...config.runtime.lineSeriesKeys.map(key => Number(cleanChars(d[key]))))))
|
package/src/index.jsx
CHANGED
|
@@ -12,5 +12,5 @@ let domContainer = document.getElementsByClassName('react-container')[0]
|
|
|
12
12
|
ReactDOM.createRoot(domContainer).render(
|
|
13
13
|
<React.StrictMode>
|
|
14
14
|
<CdcChart configUrl={domContainer.attributes['data-config'].value} isEditor={isEditor} />
|
|
15
|
-
</React.StrictMode
|
|
15
|
+
</React.StrictMode>
|
|
16
16
|
)
|