@cdc/chart 4.23.6 → 4.23.8
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 +29981 -29995
- package/examples/feature/__data__/area-chart-date-apple.json +5122 -0
- package/examples/feature/__data__/city-temperature.json +2198 -0
- package/examples/feature/__data__/planet-example-data.json +1 -1
- package/examples/feature/area/area-chart-category.json +45 -45
- package/examples/feature/area/area-chart-date-apple.json +10376 -0
- package/examples/feature/area/area-chart-date-city-temperature.json +4528 -0
- package/examples/feature/area/area-chart-date.json +111 -3
- package/examples/feature/combo/right-issues.json +1 -1
- package/examples/feature/forecasting/combo-forecasting.json +72 -46
- package/examples/feature/forecasting/effective_reproduction.json +57 -8
- package/examples/feature/forecasting/forecasting.json +12 -3
- package/examples/feature/forest-plot/broken.json +700 -0
- package/examples/feature/forest-plot/data.csv +24 -0
- package/examples/feature/forest-plot/forest-plot.json +717 -0
- package/examples/feature/line/line-chart.json +11 -11
- package/examples/feature/pie/planet-pie-example-config.json +1 -1
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +167 -20
- package/examples/private/confidence_interval_test.json +248 -0
- package/examples/private/tooltip-issue.json +45275 -0
- package/index.html +13 -11
- package/package.json +4 -3
- package/src/CdcChart.jsx +78 -27
- package/src/components/AreaChart.jsx +65 -151
- package/src/components/BarChart.Horizontal.jsx +251 -0
- package/src/components/BarChart.StackedHorizontal.jsx +118 -0
- package/src/components/BarChart.StackedVertical.jsx +93 -0
- package/src/components/BarChart.Vertical.jsx +204 -0
- package/src/components/BarChart.jsx +17 -667
- package/src/components/BarChartType.jsx +15 -0
- package/src/components/BrushHandle.jsx +17 -0
- package/src/components/DataTable.jsx +67 -22
- package/src/components/EditorPanel.jsx +426 -358
- package/src/components/Forecasting.jsx +23 -86
- package/src/components/ForestPlot.jsx +191 -0
- package/src/components/ForestPlotSettings.jsx +508 -0
- package/src/components/Legend.jsx +10 -8
- package/src/components/LineChart.jsx +31 -6
- package/src/components/LinearChart.jsx +317 -230
- package/src/components/Series.jsx +40 -4
- package/src/data/initial-state.js +50 -3
- package/src/hooks/useBarChart.js +186 -0
- package/src/hooks/useEditorPermissions.js +218 -0
- package/src/hooks/useMinMax.js +18 -5
- package/src/hooks/useRightAxis.js +2 -1
- package/src/hooks/useScales.js +45 -2
- package/src/hooks/useTooltip.jsx +407 -0
- package/src/scss/main.scss +11 -17
|
@@ -248,7 +248,7 @@ const SeriesDropdownConfidenceInterval = props => {
|
|
|
248
248
|
|
|
249
249
|
return (
|
|
250
250
|
<div className='edit-block'>
|
|
251
|
-
<
|
|
251
|
+
<span className='edit-label column-heading'>Confidence Interval Groups</span>
|
|
252
252
|
<fieldset>
|
|
253
253
|
<Accordion allowZeroExpanded>
|
|
254
254
|
{series?.confidenceIntervals?.map((ciGroup, ciIndex) => {
|
|
@@ -290,7 +290,7 @@ const SeriesDropdownConfidenceInterval = props => {
|
|
|
290
290
|
</>
|
|
291
291
|
</AccordionItemHeading>
|
|
292
292
|
<AccordionItemPanel>
|
|
293
|
-
<div className='input-group'>
|
|
293
|
+
{/* <div className='input-group'>
|
|
294
294
|
<label htmlFor='showInTooltip'>Show In Tooltip</label>
|
|
295
295
|
<div className={'cove-input__checkbox--small'} onClick={e => updateShowInTooltip(e, index, ciIndex)}>
|
|
296
296
|
<div className={`cove-input__checkbox-box${'blue' ? ' custom-color' : ''}`} style={{ backgroundColor: '' }}>
|
|
@@ -298,7 +298,7 @@ const SeriesDropdownConfidenceInterval = props => {
|
|
|
298
298
|
</div>
|
|
299
299
|
<input className='cove-input--hidden' type='checkbox' name={'showInTooltip'} checked={showInTooltip ? showInTooltip : false} readOnly />
|
|
300
300
|
</div>
|
|
301
|
-
</div>
|
|
301
|
+
</div> */}
|
|
302
302
|
|
|
303
303
|
<InputSelect
|
|
304
304
|
initial='Select an option'
|
|
@@ -400,6 +400,38 @@ const SeriesInputName = props => {
|
|
|
400
400
|
)
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
+
const SeriesDisplayInTooltip = props => {
|
|
404
|
+
const { series, index } = props
|
|
405
|
+
const { config, updateConfig } = useContext(ConfigContext)
|
|
406
|
+
|
|
407
|
+
const toggleTooltip = seriesIndex => {
|
|
408
|
+
let copiedSeries = [...config.series]
|
|
409
|
+
|
|
410
|
+
const showInTooltip = copiedSeries[seriesIndex].tooltip ? copiedSeries[seriesIndex].tooltip : false
|
|
411
|
+
|
|
412
|
+
copiedSeries[seriesIndex].tooltip = !copiedSeries[seriesIndex].tooltip
|
|
413
|
+
|
|
414
|
+
updateConfig({
|
|
415
|
+
...config,
|
|
416
|
+
series: copiedSeries
|
|
417
|
+
})
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return (
|
|
421
|
+
<>
|
|
422
|
+
<div className='input-group'>
|
|
423
|
+
<label htmlFor={`series-tooltip--${index}`}>Show In Tooltip</label>
|
|
424
|
+
<div className={'cove-input__checkbox--small'} onClick={e => toggleTooltip(index)}>
|
|
425
|
+
<div className={`cove-input__checkbox-box${'blue' ? ' custom-color' : ''}`} style={{ backgroundColor: '' }}>
|
|
426
|
+
{series.tooltip && <Check className='' style={{ fill: '#025eaa' }} />}
|
|
427
|
+
</div>
|
|
428
|
+
<input className='cove-input--hidden' type='checkbox' name={`series-tooltip--${index}`} checked={series.tooltip ? series.tooltip : false} readOnly />
|
|
429
|
+
</div>
|
|
430
|
+
</div>
|
|
431
|
+
</>
|
|
432
|
+
)
|
|
433
|
+
}
|
|
434
|
+
|
|
403
435
|
const SeriesButtonRemove = props => {
|
|
404
436
|
const { config, updateConfig } = useContext(ConfigContext)
|
|
405
437
|
const { series, index } = props
|
|
@@ -474,9 +506,10 @@ const SeriesItem = props => {
|
|
|
474
506
|
<Series.Dropdown.SeriesType series={series} index={i} />
|
|
475
507
|
<Series.Dropdown.AxisPosition series={series} index={i} />
|
|
476
508
|
<Series.Dropdown.LineType series={series} index={i} />
|
|
477
|
-
<Series.Dropdown.ForecastingStage series={series} index={i} />
|
|
509
|
+
{/* <Series.Dropdown.ForecastingStage series={series} index={i} /> */}
|
|
478
510
|
<Series.Dropdown.ForecastingColor series={series} index={i} />
|
|
479
511
|
<Series.Dropdown.ConfidenceInterval series={series} index={i} />
|
|
512
|
+
<Series.Checkbox.DisplayInTooltip series={series} index={i} />
|
|
480
513
|
</AccordionItemPanel>
|
|
481
514
|
)}
|
|
482
515
|
</AccordionItem>
|
|
@@ -508,6 +541,9 @@ const Series = {
|
|
|
508
541
|
Input: {
|
|
509
542
|
Name: SeriesInputName
|
|
510
543
|
},
|
|
544
|
+
Checkbox: {
|
|
545
|
+
DisplayInTooltip: SeriesDisplayInTooltip
|
|
546
|
+
},
|
|
511
547
|
Button: {
|
|
512
548
|
Remove: SeriesButtonRemove
|
|
513
549
|
},
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
type: 'chart',
|
|
3
|
+
debugSvg: false,
|
|
3
4
|
title: '',
|
|
4
5
|
showTitle: true,
|
|
5
6
|
showDownloadMediaButton: false,
|
|
7
|
+
showChartBrush: false,
|
|
6
8
|
theme: 'theme-blue',
|
|
7
9
|
animate: false,
|
|
8
10
|
fontSize: 'medium',
|
|
@@ -15,6 +17,7 @@ export default {
|
|
|
15
17
|
barStyle: '',
|
|
16
18
|
roundingStyle: 'standard',
|
|
17
19
|
tipRounding: 'top',
|
|
20
|
+
isResponsiveTicks: false,
|
|
18
21
|
general: {
|
|
19
22
|
showDownloadButton: false
|
|
20
23
|
},
|
|
@@ -36,7 +39,7 @@ export default {
|
|
|
36
39
|
tickLabelColor: '#333',
|
|
37
40
|
tickColor: '#333',
|
|
38
41
|
rightHideAxis: true,
|
|
39
|
-
rightAxisSize:
|
|
42
|
+
rightAxisSize: 0,
|
|
40
43
|
rightLabel: '',
|
|
41
44
|
rightLabelOffsetSize: 0,
|
|
42
45
|
rightAxisLabelColor: '#333',
|
|
@@ -107,7 +110,7 @@ export default {
|
|
|
107
110
|
labelOffset: 65,
|
|
108
111
|
axisPadding: 0,
|
|
109
112
|
target: 0,
|
|
110
|
-
|
|
113
|
+
maxTickRotation: 0
|
|
111
114
|
},
|
|
112
115
|
table: {
|
|
113
116
|
label: 'Data Table',
|
|
@@ -169,5 +172,49 @@ export default {
|
|
|
169
172
|
useLogScale: false,
|
|
170
173
|
filterBehavior: 'Filter Change',
|
|
171
174
|
highlightedBarValues: [],
|
|
172
|
-
series: []
|
|
175
|
+
series: [],
|
|
176
|
+
tooltips: {
|
|
177
|
+
opacity: 90
|
|
178
|
+
},
|
|
179
|
+
forestPlot: {
|
|
180
|
+
startAt: 0,
|
|
181
|
+
width: 'auto',
|
|
182
|
+
colors: {
|
|
183
|
+
line: '',
|
|
184
|
+
shape: ''
|
|
185
|
+
},
|
|
186
|
+
estimateField: '',
|
|
187
|
+
estimateRadius: '',
|
|
188
|
+
lowerCiField: '',
|
|
189
|
+
upperCiField: '',
|
|
190
|
+
shape: '',
|
|
191
|
+
rowHeight: 20,
|
|
192
|
+
showZeroLine: false,
|
|
193
|
+
description: {
|
|
194
|
+
show: true,
|
|
195
|
+
text: 'description',
|
|
196
|
+
location: 0
|
|
197
|
+
},
|
|
198
|
+
result: {
|
|
199
|
+
show: true,
|
|
200
|
+
text: 'result',
|
|
201
|
+
location: 100
|
|
202
|
+
},
|
|
203
|
+
radius: {
|
|
204
|
+
min: 1,
|
|
205
|
+
max: 8,
|
|
206
|
+
scalingColumn: ''
|
|
207
|
+
},
|
|
208
|
+
regression: {
|
|
209
|
+
lower: 0,
|
|
210
|
+
upper: 0,
|
|
211
|
+
estimateField: 0
|
|
212
|
+
},
|
|
213
|
+
leftWidthOffset: 0,
|
|
214
|
+
rightWidthOffset: 0
|
|
215
|
+
},
|
|
216
|
+
brush: {
|
|
217
|
+
pattern_id: 'brush_pattern',
|
|
218
|
+
accent_color: '#ddd'
|
|
219
|
+
}
|
|
173
220
|
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import React, { useContext, useEffect } from 'react'
|
|
2
|
+
import ConfigContext from '../ConfigContext'
|
|
3
|
+
|
|
4
|
+
export const useBarChart = () => {
|
|
5
|
+
const { config, colorPalettes, tableData, updateConfig, parseDate, formatDate } = useContext(ConfigContext)
|
|
6
|
+
const { orientation } = config
|
|
7
|
+
|
|
8
|
+
const isHorizontal = orientation === 'horizontal'
|
|
9
|
+
const barBorderWidth = 1
|
|
10
|
+
const lollipopBarWidth = config.lollipopSize === 'large' ? 7 : config.lollipopSize === 'medium' ? 6 : 5
|
|
11
|
+
const lollipopShapeSize = config.lollipopSize === 'large' ? 14 : config.lollipopSize === 'medium' ? 12 : 10
|
|
12
|
+
const isLabelBelowBar = config.yAxis.labelPlacement === 'Below Bar'
|
|
13
|
+
const displayNumbersOnBar = config.yAxis.displayNumbersOnBar
|
|
14
|
+
const section = config.orientation === 'horizontal' ? 'yAxis' : 'xAxis'
|
|
15
|
+
|
|
16
|
+
const isRounded = config.barStyle === 'rounded'
|
|
17
|
+
const isStacked = config.visualizationSubType === 'stacked'
|
|
18
|
+
const tipRounding = config.tipRounding
|
|
19
|
+
const radius = config.roundingStyle === 'standard' ? '8px' : config.roundingStyle === 'shallow' ? '5px' : config.roundingStyle === 'finger' ? '15px' : '0px'
|
|
20
|
+
const stackCount = config.runtime.seriesKeys.length
|
|
21
|
+
const fontSize = { small: 16, medium: 18, large: 20 }
|
|
22
|
+
const hasMultipleSeries = Object.keys(config.runtime.seriesLabels).length > 1
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (orientation === 'horizontal' && !config.yAxis.labelPlacement) {
|
|
26
|
+
updateConfig({
|
|
27
|
+
...config,
|
|
28
|
+
yAxis: {
|
|
29
|
+
...config,
|
|
30
|
+
labelPlacement: 'Below Bar'
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
}, [config, updateConfig]) // eslint-disable-line
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (config.isLollipopChart === false && config.barHeight < 25) {
|
|
38
|
+
updateConfig({ ...config, barHeight: 25 })
|
|
39
|
+
}
|
|
40
|
+
}, [config.isLollipopChart]) // eslint-disable-line
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (config.visualizationSubType === 'horizontal') {
|
|
44
|
+
updateConfig({
|
|
45
|
+
...config,
|
|
46
|
+
orientation: 'horizontal'
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
}, []) // eslint-disable-line
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (config.barStyle === 'lollipop' && !config.isLollipopChart) {
|
|
53
|
+
updateConfig({ ...config, isLollipopChart: true })
|
|
54
|
+
}
|
|
55
|
+
if (isRounded || config.barStyle === 'flat') {
|
|
56
|
+
updateConfig({ ...config, isLollipopChart: false })
|
|
57
|
+
}
|
|
58
|
+
}, [config.barStyle]) // eslint-disable-line
|
|
59
|
+
|
|
60
|
+
const applyRadius = index => {
|
|
61
|
+
if (index === undefined || index === null || !isRounded) return {}
|
|
62
|
+
let style = {}
|
|
63
|
+
|
|
64
|
+
if ((isStacked && index + 1 === stackCount) || !isStacked) {
|
|
65
|
+
style = isHorizontal ? { borderRadius: `0 ${radius} ${radius} 0` } : { borderRadius: `${radius} ${radius} 0 0` }
|
|
66
|
+
}
|
|
67
|
+
if (!isStacked && index === -1) {
|
|
68
|
+
style = isHorizontal ? { borderRadius: `${radius} 0 0 ${radius} ` } : { borderRadius: ` 0 0 ${radius} ${radius}` }
|
|
69
|
+
}
|
|
70
|
+
if (tipRounding === 'full' && isStacked && index === 0 && stackCount > 1) {
|
|
71
|
+
style = isHorizontal ? { borderRadius: `${radius} 0 0 ${radius}` } : { borderRadius: `0 0 ${radius} ${radius}` }
|
|
72
|
+
}
|
|
73
|
+
if (tipRounding === 'full' && ((isStacked && index === 0 && stackCount === 1) || !isStacked)) {
|
|
74
|
+
style = { borderRadius: radius }
|
|
75
|
+
}
|
|
76
|
+
return style
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const assignColorsToValues = (barsCount, barIndex, currentBarColor) => {
|
|
80
|
+
if (!config.legend.colorCode && config.series.length > 1) {
|
|
81
|
+
return currentBarColor
|
|
82
|
+
}
|
|
83
|
+
const palettesArr = colorPalettes[config.palette]
|
|
84
|
+
const values = tableData.map(d => {
|
|
85
|
+
return d[config.legend.colorCode]
|
|
86
|
+
})
|
|
87
|
+
// Map to hold unique values and their colors
|
|
88
|
+
let colorMap = new Map()
|
|
89
|
+
// Resultant array to hold colors to the values
|
|
90
|
+
let palette = []
|
|
91
|
+
|
|
92
|
+
for (let i = 0; i < values.length; i++) {
|
|
93
|
+
// If value not in map, add it and assign a color
|
|
94
|
+
if (!colorMap.has(values[i])) {
|
|
95
|
+
colorMap.set(values[i], palettesArr[colorMap.size % palettesArr.length])
|
|
96
|
+
}
|
|
97
|
+
// push the color to the result array
|
|
98
|
+
palette.push(colorMap.get(values[i]))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// loop throghy existing colors and extend if needed
|
|
102
|
+
while (palette.length < barsCount) {
|
|
103
|
+
palette = palette.concat(palette)
|
|
104
|
+
}
|
|
105
|
+
const barColor = palette[barIndex]
|
|
106
|
+
return barColor
|
|
107
|
+
}
|
|
108
|
+
const updateBars = defaultBars => {
|
|
109
|
+
// function updates stacked && regular && lollipop horizontal bars
|
|
110
|
+
if (config.visualizationType !== 'Bar' && !isHorizontal) return defaultBars
|
|
111
|
+
|
|
112
|
+
const barsArr = [...defaultBars]
|
|
113
|
+
let barHeight
|
|
114
|
+
|
|
115
|
+
const heights = {
|
|
116
|
+
stacked: config.barHeight,
|
|
117
|
+
lollipop: lollipopBarWidth
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!isStacked) {
|
|
121
|
+
barHeight = heights[config.isLollipopChart ? 'lollipop' : 'stacked'] * stackCount
|
|
122
|
+
} else {
|
|
123
|
+
barHeight = heights.stacked
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const labelHeight = isLabelBelowBar ? fontSize[config.fontSize] * 1.2 : 0
|
|
127
|
+
let barSpace = Number(config.barSpace)
|
|
128
|
+
|
|
129
|
+
// calculate height of container based height, space and fontSize of labels
|
|
130
|
+
let totalHeight = barsArr.length * (barHeight + labelHeight + barSpace)
|
|
131
|
+
|
|
132
|
+
if (isHorizontal) {
|
|
133
|
+
config.heights.horizontal = totalHeight
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// return new updated bars/groupes
|
|
137
|
+
return barsArr.map((bar, i) => {
|
|
138
|
+
// set bars Y dynamically to handle space between bars
|
|
139
|
+
let y = 0
|
|
140
|
+
bar.index !== 0 && (y = (barHeight + barSpace + labelHeight) * i)
|
|
141
|
+
|
|
142
|
+
return { ...bar, y: y, height: barHeight }
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const getHighlightedBarColorByValue = value => {
|
|
147
|
+
const match = config?.highlightedBarValues.filter(item => {
|
|
148
|
+
if (!item.value) return
|
|
149
|
+
return config.xAxis.type === 'date' ? formatDate(parseDate(item.value)) === value : item.value === value
|
|
150
|
+
})[0]
|
|
151
|
+
|
|
152
|
+
if (!match?.color) return `rgba(255, 102, 1)`
|
|
153
|
+
return match.color
|
|
154
|
+
}
|
|
155
|
+
const getHighlightedBarByValue = value => {
|
|
156
|
+
const match = config?.highlightedBarValues.filter(item => {
|
|
157
|
+
if (!item.value) return
|
|
158
|
+
return config.xAxis.type === 'date' ? formatDate(parseDate(item.value)) === value : item.value === value
|
|
159
|
+
})[0]
|
|
160
|
+
|
|
161
|
+
if (!match?.color) return false
|
|
162
|
+
return match
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
isHorizontal,
|
|
167
|
+
barBorderWidth,
|
|
168
|
+
lollipopBarWidth,
|
|
169
|
+
lollipopShapeSize,
|
|
170
|
+
isLabelBelowBar,
|
|
171
|
+
displayNumbersOnBar,
|
|
172
|
+
section,
|
|
173
|
+
isRounded,
|
|
174
|
+
isStacked,
|
|
175
|
+
tipRounding,
|
|
176
|
+
radius,
|
|
177
|
+
stackCount,
|
|
178
|
+
fontSize,
|
|
179
|
+
hasMultipleSeries,
|
|
180
|
+
applyRadius,
|
|
181
|
+
updateBars,
|
|
182
|
+
assignColorsToValues,
|
|
183
|
+
getHighlightedBarColorByValue,
|
|
184
|
+
getHighlightedBarByValue
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import React, { useContext } from 'react'
|
|
2
|
+
import ConfigContext from '../ConfigContext'
|
|
3
|
+
|
|
4
|
+
export const useEditorPermissions = () => {
|
|
5
|
+
const { config } = useContext(ConfigContext)
|
|
6
|
+
const { visualizationType, series, orientation } = config
|
|
7
|
+
|
|
8
|
+
// Overall support for the chart types
|
|
9
|
+
// prettier-ignore
|
|
10
|
+
const enabledChartTypes = [
|
|
11
|
+
'Area Chart',
|
|
12
|
+
'Bar',
|
|
13
|
+
'Box Plot',
|
|
14
|
+
'Combo',
|
|
15
|
+
'Deviation Bar',
|
|
16
|
+
'Forecasting',
|
|
17
|
+
// 'Forest Plot',
|
|
18
|
+
'Line',
|
|
19
|
+
'Paired Bar',
|
|
20
|
+
'Pie',
|
|
21
|
+
'Scatter Plot',
|
|
22
|
+
'Spark Line'
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
const visHasLabelOnData = () => {
|
|
26
|
+
const disabledCharts = ['Area Chart', 'Box Plot', 'Pie', 'Scatter Plot', 'Forest Plot']
|
|
27
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
28
|
+
return true
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const visCanAnimate = () => {
|
|
32
|
+
const disabledCharts = ['Area Chart', 'Scatter Plot', 'Box Plot', 'Forest Plot']
|
|
33
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
34
|
+
return true
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const visHasLegend = () => {
|
|
38
|
+
switch (visualizationType) {
|
|
39
|
+
case 'Box Plot':
|
|
40
|
+
return false
|
|
41
|
+
case 'Forest Plot':
|
|
42
|
+
return false
|
|
43
|
+
default:
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const visHasNumbersOnBars = () => {
|
|
49
|
+
if (visualizationType === 'Forest Plot') return false
|
|
50
|
+
if (config.orientation === 'horizontal' && (config.yAxis.labelPlacement === 'Below Bar' || config.yAxis.labelPlacement === 'On Date/Category Axis' || config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar')) return true
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const visHasAnchors = () => {
|
|
55
|
+
switch (visualizationType) {
|
|
56
|
+
case 'Area Chart':
|
|
57
|
+
return true
|
|
58
|
+
case 'Combo':
|
|
59
|
+
return true
|
|
60
|
+
case 'Line':
|
|
61
|
+
return true
|
|
62
|
+
case 'Bar':
|
|
63
|
+
return true
|
|
64
|
+
case 'Scatter Plot':
|
|
65
|
+
return true
|
|
66
|
+
default:
|
|
67
|
+
return false
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const visHasBarBorders = () => {
|
|
72
|
+
const disabledCharts = ['Box Plot', 'Scatter Plot', 'Pie']
|
|
73
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
74
|
+
return series?.some(series => series.type === 'Bar' || series.type === 'Paired Bar' || series.type === 'Deviation Bar')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const visHasDataCutoff = () => {
|
|
78
|
+
switch (visualizationType) {
|
|
79
|
+
case 'Forest Plot':
|
|
80
|
+
return false
|
|
81
|
+
case 'Box Plot':
|
|
82
|
+
return false
|
|
83
|
+
case 'Pie':
|
|
84
|
+
return false
|
|
85
|
+
default:
|
|
86
|
+
return true
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const visSupportsTooltipLines = () => {
|
|
91
|
+
const enabledCharts = ['Combo', 'Forecasting', 'Area Chart', 'Line', 'Bar']
|
|
92
|
+
if (enabledCharts.includes(visualizationType)) return true
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const visSupportsSequentialPallete = () => {
|
|
97
|
+
const disabledCharts = ['Paired Bar', 'Deviation Bar', 'Forest Plot']
|
|
98
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
99
|
+
return true
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const visSupportsNonSequentialPallete = () => {
|
|
103
|
+
const disabledCharts = ['Paired Bar', 'Deviation Bar', 'Forest Plot']
|
|
104
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
105
|
+
return true
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const visSupportsReverseColorPalette = () => {
|
|
109
|
+
const disabledCharts = ['Forest Plot', 'Paired Bar', 'Deviation Bar']
|
|
110
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
111
|
+
return true
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const visSupportsDateCategoryAxisLabel = () => {
|
|
115
|
+
const disabledCharts = ['Forest Plot']
|
|
116
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
117
|
+
return true
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const visSupportsDateCategoryAxisLine = () => {
|
|
121
|
+
const disabledCharts = ['Forest Plot']
|
|
122
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
123
|
+
return true
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const visSupportsDateCategoryAxisTicks = () => {
|
|
127
|
+
const disabledCharts = ['Forest Plot']
|
|
128
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
129
|
+
return true
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const visSupportsDateCategoryTickRotation = () => {
|
|
133
|
+
const disabledCharts = ['Forest Plot']
|
|
134
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
135
|
+
return true
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const visSupportsDateCategoryNumTicks = () => {
|
|
139
|
+
const disabledCharts = ['Forest Plot']
|
|
140
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
141
|
+
return true
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const visSupportsRegions = () => {
|
|
145
|
+
const disabledCharts = ['Forest Plot', 'Pie', 'Paired Bar']
|
|
146
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
147
|
+
return true
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const visSupportsFilters = () => {
|
|
151
|
+
const disabledCharts = ['Forest Plot']
|
|
152
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
153
|
+
return true
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const visSupportsValueAxisGridLines = () => {
|
|
157
|
+
const disabledCharts = ['Forest Plot']
|
|
158
|
+
if (orientation === 'horizontal') return false
|
|
159
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
160
|
+
return true
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// implement later
|
|
164
|
+
const visSupportsValueAxisTicks = () => {
|
|
165
|
+
return true
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// implement later
|
|
169
|
+
const visSupportsValueAxisLine = () => {
|
|
170
|
+
return true
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// implement later
|
|
174
|
+
const visSupportsValueAxisLabels = () => {
|
|
175
|
+
return true
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const visSupportsBarSpace = () => {
|
|
179
|
+
const disabledCharts = ['Forest Plot']
|
|
180
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
181
|
+
if (orientation === 'horizontal' || visualizationType === 'Paired Bar') return true
|
|
182
|
+
return false
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const visSupportsBarThickness = () => {
|
|
186
|
+
const disabledCharts = ['Forest Plot']
|
|
187
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
188
|
+
return true
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
enabledChartTypes,
|
|
193
|
+
visHasLabelOnData,
|
|
194
|
+
visHasNumbersOnBars,
|
|
195
|
+
visHasAnchors,
|
|
196
|
+
visHasBarBorders,
|
|
197
|
+
visHasDataCutoff,
|
|
198
|
+
visCanAnimate,
|
|
199
|
+
visHasLegend,
|
|
200
|
+
visSupportsTooltipLines,
|
|
201
|
+
visSupportsNonSequentialPallete,
|
|
202
|
+
visSupportsSequentialPallete,
|
|
203
|
+
visSupportsReverseColorPalette,
|
|
204
|
+
visSupportsDateCategoryAxisLabel,
|
|
205
|
+
visSupportsDateCategoryAxisLine,
|
|
206
|
+
visSupportsDateCategoryAxisTicks,
|
|
207
|
+
visSupportsDateCategoryTickRotation,
|
|
208
|
+
visSupportsDateCategoryNumTicks,
|
|
209
|
+
visSupportsRegions,
|
|
210
|
+
visSupportsFilters,
|
|
211
|
+
visSupportsValueAxisGridLines,
|
|
212
|
+
visSupportsValueAxisTicks,
|
|
213
|
+
visSupportsValueAxisLine,
|
|
214
|
+
visSupportsValueAxisLabels,
|
|
215
|
+
visSupportsBarSpace,
|
|
216
|
+
visSupportsBarThickness
|
|
217
|
+
}
|
|
218
|
+
}
|
package/src/hooks/useMinMax.js
CHANGED
|
@@ -7,7 +7,8 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
const { max: enteredMaxValue, min: enteredMinValue } = config.runtime.yAxis
|
|
10
|
-
|
|
10
|
+
const minRequiredCIPadding = 1.15 // regardless of Editor if CI data, there must be 10% padding added
|
|
11
|
+
|
|
11
12
|
// do validation bafore applying t0 charts
|
|
12
13
|
const isMaxValid = existPositiveValue ? enteredMaxValue >= maxValue : enteredMaxValue >= 0
|
|
13
14
|
const isMinValid = config.useLogScale ? enteredMinValue >= 0 : (enteredMinValue <= 0 && minValue >= 0) || (enteredMinValue <= minValue && minValue < 0)
|
|
@@ -15,6 +16,7 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
|
|
|
15
16
|
min = enteredMinValue && isMinValid ? enteredMinValue : minValue
|
|
16
17
|
max = enteredMaxValue && isMaxValid ? enteredMaxValue : Number.MIN_VALUE
|
|
17
18
|
|
|
19
|
+
let ciYMin = 0
|
|
18
20
|
if (config.visualizationType === 'Bar' || config.visualizationType === 'Combo' || config.visualizationType === 'Deviation Bar') {
|
|
19
21
|
let ciYMax = 0
|
|
20
22
|
if (config.hasOwnProperty('confidenceKeys')) {
|
|
@@ -22,7 +24,15 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
|
|
|
22
24
|
return d[config.confidenceKeys.upper]
|
|
23
25
|
})
|
|
24
26
|
ciYMax = Math.max.apply(Math, upperCIValues)
|
|
25
|
-
if (ciYMax > max) max = ciYMax // bump up the max
|
|
27
|
+
if (ciYMax > max) max = ciYMax * minRequiredCIPadding // bump up the max plus some padding always
|
|
28
|
+
|
|
29
|
+
// check the min if lower confidence
|
|
30
|
+
let lowerCIValues = data.map(function (d) {
|
|
31
|
+
// if no lower CI then we need lowerCIValues to have nothing in it
|
|
32
|
+
return d[config.confidenceKeys.lower] !== undefined ? d[config.confidenceKeys.lower] : ''
|
|
33
|
+
})
|
|
34
|
+
ciYMin = Math.min.apply(Math, lowerCIValues)
|
|
35
|
+
if (ciYMin < min) min = ciYMin * minRequiredCIPadding // adjust the min + 10% padding for negative numbers to separate from axis
|
|
26
36
|
}
|
|
27
37
|
}
|
|
28
38
|
|
|
@@ -47,11 +57,12 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
|
|
|
47
57
|
const highCIGroup = Math.max.apply(
|
|
48
58
|
null,
|
|
49
59
|
result.map(item => item[0])
|
|
50
|
-
)
|
|
60
|
+
)
|
|
61
|
+
|
|
51
62
|
const lowCIGroup = Math.min.apply(
|
|
52
63
|
null,
|
|
53
64
|
result.map(item => item[1])
|
|
54
|
-
)
|
|
65
|
+
)
|
|
55
66
|
|
|
56
67
|
if (highCIGroup > max) {
|
|
57
68
|
max = highCIGroup
|
|
@@ -62,9 +73,11 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
|
|
|
62
73
|
}
|
|
63
74
|
}
|
|
64
75
|
|
|
65
|
-
|
|
76
|
+
// this should not apply to bar charts if there is negative CI data
|
|
77
|
+
if (((config.visualizationType === 'Bar' && ciYMin >= 0) || (config.visualizationType === 'Combo' && !isAllLine)) && min > 0) {
|
|
66
78
|
min = 0
|
|
67
79
|
}
|
|
80
|
+
|
|
68
81
|
if (config.visualizationType === 'Combo' && isAllLine) {
|
|
69
82
|
if ((enteredMinValue === undefined || enteredMinValue === null || enteredMinValue === '') && min > 0) {
|
|
70
83
|
min = 0
|
|
@@ -19,8 +19,9 @@ export default function useRightAxis({ config, yMax = 0, data = [], updateConfig
|
|
|
19
19
|
|
|
20
20
|
// if there is a bar series & the right axis doesn't include a negative number, default to zero
|
|
21
21
|
const hasBarSeries = config.runtime?.barSeriesKeys?.length > 0
|
|
22
|
+
const hasLineSeries = config.runtime?.lineSeriesKeys?.length > 0
|
|
22
23
|
|
|
23
|
-
if (hasBarSeries && minValue > 0) {
|
|
24
|
+
if ((hasBarSeries || hasLineSeries) && minValue > 0) {
|
|
24
25
|
minValue = 0
|
|
25
26
|
}
|
|
26
27
|
|