@cdc/chart 4.23.1 → 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 +56289 -702
- package/examples/Barchart_with_negative.json +34 -0
- 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 +1 -2
- package/examples/dynamic-legends.json +1 -1
- package/examples/example-bar-chart-nonnumeric.json +36 -0
- package/examples/example-bar-chart.json +36 -0
- package/examples/example-combo-bar-nonnumeric.json +105 -0
- 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-categorical.json +1 -1
- 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/bar-chart-vertical/vertical-bar-chart.json +2 -2
- package/examples/gallery/line/line.json +1 -0
- package/examples/gallery/paired-bar/paired-bar-chart.json +65 -13
- package/examples/horizontal-chart-max-increase.json +38 -0
- package/examples/line-chart-max-increase.json +32 -0
- package/examples/line-chart-nonnumeric.json +32 -0
- package/examples/line-chart.json +21 -63
- package/examples/newdata.json +1 -1
- package/examples/planet-combo-example-config.json +143 -20
- 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-nonnumeric.json +56 -0
- package/examples/planet-example-data.json +9 -9
- package/examples/planet-pie-example-config-nonnumeric.json +30 -0
- package/examples/scatterplot-continuous.csv +17 -0
- package/examples/scatterplot.json +136 -0
- package/examples/sparkline-chart-nonnumeric.json +76 -0
- package/examples/stacked-vertical-bar-example-negative.json +154 -0
- package/examples/stacked-vertical-bar-example-nonnumerics.json +154 -0
- package/index.html +91 -0
- package/package.json +33 -24
- package/src/{CdcChart.tsx → CdcChart.jsx} +196 -124
- package/src/components/AreaChart.jsx +198 -0
- package/src/components/{BarChart.tsx → BarChart.jsx} +154 -122
- package/src/components/BoxPlot.jsx +101 -0
- package/src/components/{DataTable.tsx → DataTable.jsx} +109 -28
- package/src/components/DeviationBar.jsx +191 -0
- package/src/components/{EditorPanel.js → EditorPanel.jsx} +676 -157
- package/src/components/{Filters.js → Filters.jsx} +6 -11
- package/src/components/Legend.jsx +316 -0
- package/src/components/{LineChart.tsx → LineChart.jsx} +22 -26
- package/src/components/{LinearChart.tsx → LinearChart.jsx} +214 -91
- package/src/components/{PairedBarChart.tsx → PairedBarChart.jsx} +44 -78
- package/src/components/{PieChart.tsx → PieChart.jsx} +26 -44
- package/src/components/ScatterPlot.jsx +51 -0
- package/src/components/SparkLine.jsx +218 -0
- package/src/components/{useIntersectionObserver.tsx → useIntersectionObserver.jsx} +2 -2
- package/src/data/initial-state.js +51 -5
- package/src/hooks/useColorPalette.js +68 -0
- package/src/hooks/{useReduceData.ts → useReduceData.js} +26 -16
- package/src/hooks/useRightAxis.js +3 -1
- package/src/index.jsx +16 -0
- package/src/scss/DataTable.scss +22 -0
- package/src/scss/editor-panel.scss +5 -0
- package/src/scss/main.scss +30 -10
- package/src/test/CdcChart.test.jsx +6 -0
- package/vite.config.js +4 -0
- package/dist/495.js +0 -3
- package/dist/703.js +0 -1
- package/src/components/BoxPlot.js +0 -92
- package/src/components/Legend.js +0 -291
- package/src/components/SparkLine.js +0 -185
- package/src/hooks/useColorPalette.ts +0 -76
- package/src/index.html +0 -67
- package/src/index.tsx +0 -18
- /package/src/{context.tsx → ConfigContext.jsx} +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React, { useState, useEffect, useCallback, memo, useContext } from 'react'
|
|
2
|
-
import { DragDropContext, Droppable, Draggable } from '
|
|
2
|
+
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
|
|
3
3
|
|
|
4
4
|
import { Accordion, AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
|
|
5
5
|
|
|
6
6
|
import { useDebounce } from 'use-debounce'
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import ConfigContext from '../ConfigContext'
|
|
9
9
|
import WarningImage from '../images/warning.svg'
|
|
10
10
|
import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
|
|
11
11
|
|
|
@@ -17,12 +17,9 @@ import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
|
17
17
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
18
18
|
import useReduceData from '../hooks/useReduceData'
|
|
19
19
|
import useRightAxis from '../hooks/useRightAxis'
|
|
20
|
-
|
|
21
|
-
// TODO: Remove unused imports
|
|
22
|
-
// TDOO: Move inline styles to a scss file
|
|
20
|
+
import * as allCurves from '@visx/curve'
|
|
23
21
|
|
|
24
22
|
/* eslint-disable react-hooks/rules-of-hooks */
|
|
25
|
-
|
|
26
23
|
const TextField = memo(({ label, tooltip, section = null, subsection = null, fieldName, updateField, value: stateValue, type = 'input', i = null, min = null, ...attributes }) => {
|
|
27
24
|
const [value, setValue] = useState(stateValue)
|
|
28
25
|
|
|
@@ -79,7 +76,7 @@ const CheckBox = memo(({ label, value, fieldName, section = null, subsection = n
|
|
|
79
76
|
type='checkbox'
|
|
80
77
|
name={fieldName}
|
|
81
78
|
checked={value}
|
|
82
|
-
onChange={
|
|
79
|
+
onChange={e => {
|
|
83
80
|
updateField(section, subsection, fieldName, !value)
|
|
84
81
|
}}
|
|
85
82
|
{...attributes}
|
|
@@ -209,17 +206,11 @@ const Regions = memo(({ config, updateConfig }) => {
|
|
|
209
206
|
const headerColors = ['theme-blue', 'theme-purple', 'theme-brown', 'theme-teal', 'theme-pink', 'theme-orange', 'theme-slate', 'theme-indigo', 'theme-cyan', 'theme-green', 'theme-amber']
|
|
210
207
|
|
|
211
208
|
const EditorPanel = () => {
|
|
212
|
-
const { config, updateConfig, transformedData: data, loading, colorPalettes, unfilteredData, excludedData, isDashboard, setParentConfig, missingRequiredSections } = useContext(
|
|
209
|
+
const { config, updateConfig, transformedData: data, loading, colorPalettes, twoColorPalette, unfilteredData, excludedData, isDashboard, setParentConfig, missingRequiredSections } = useContext(ConfigContext)
|
|
213
210
|
|
|
214
211
|
const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
|
|
215
|
-
const { paletteName, isPaletteReversed, filteredPallets, filteredQualitative, dispatch } = useColorPalette(colorPalettes, config)
|
|
216
|
-
useEffect(() => {
|
|
217
|
-
if (paletteName) updateConfig({ ...config, palette: paletteName })
|
|
218
|
-
}, [paletteName]) // eslint-disable-line
|
|
219
212
|
|
|
220
|
-
|
|
221
|
-
dispatch({ type: 'GET_PALETTE', payload: colorPalettes, paletteName: config.palette })
|
|
222
|
-
}, [dispatch, config.palette]) // eslint-disable-line
|
|
213
|
+
const { twoColorPalettes, sequential, nonSequential } = useColorPalette(config, updateConfig)
|
|
223
214
|
|
|
224
215
|
// when the visualization type changes we
|
|
225
216
|
// have to update the individual series type & axis details
|
|
@@ -243,6 +234,19 @@ const EditorPanel = () => {
|
|
|
243
234
|
})
|
|
244
235
|
}, [config.visualizationType]) // eslint-disable-line
|
|
245
236
|
|
|
237
|
+
// Scatter Plots default date/category axis is 'continuous'
|
|
238
|
+
useEffect(() => {
|
|
239
|
+
if (config.visualizationType === 'Scatter Plot') {
|
|
240
|
+
updateConfig({
|
|
241
|
+
...config,
|
|
242
|
+
xAxis: {
|
|
243
|
+
...config.xAxis,
|
|
244
|
+
type: 'continuous'
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
}
|
|
248
|
+
}, [])
|
|
249
|
+
|
|
246
250
|
const { hasRightAxis } = useRightAxis({ config: config, yMax: config.yAxis.size, data: config.data, updateConfig })
|
|
247
251
|
|
|
248
252
|
const filterOptions = [
|
|
@@ -287,15 +291,43 @@ const EditorPanel = () => {
|
|
|
287
291
|
if (updatedConfig.table.show === undefined) {
|
|
288
292
|
updatedConfig.table.show = !isDashboard
|
|
289
293
|
}
|
|
294
|
+
// DEV-3293 - Force combo to always be vertical
|
|
295
|
+
if (updatedConfig.visualizationType === 'Combo') {
|
|
296
|
+
updatedConfig.orientation = 'vertical'
|
|
297
|
+
}
|
|
290
298
|
}
|
|
291
299
|
|
|
292
300
|
const updateField = (section, subsection, fieldName, newValue) => {
|
|
293
|
-
|
|
301
|
+
if (section === 'boxplot' && subsection === 'legend') {
|
|
302
|
+
updateConfig({
|
|
303
|
+
...config,
|
|
304
|
+
[section]: {
|
|
305
|
+
...config[section],
|
|
306
|
+
[subsection]: {
|
|
307
|
+
...config.boxplot[subsection],
|
|
308
|
+
[fieldName]: newValue
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
})
|
|
312
|
+
return
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (section === 'boxplot' && subsection === 'labels') {
|
|
316
|
+
updateConfig({
|
|
317
|
+
...config,
|
|
318
|
+
[section]: {
|
|
319
|
+
...config[section],
|
|
320
|
+
[subsection]: {
|
|
321
|
+
...config.boxplot[subsection],
|
|
322
|
+
[fieldName]: newValue
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
})
|
|
326
|
+
return
|
|
327
|
+
}
|
|
294
328
|
if (null === section && null === subsection) {
|
|
295
329
|
let updatedConfig = { ...config, [fieldName]: newValue }
|
|
296
|
-
|
|
297
330
|
enforceRestrictions(updatedConfig)
|
|
298
|
-
|
|
299
331
|
updateConfig(updatedConfig)
|
|
300
332
|
return
|
|
301
333
|
}
|
|
@@ -328,6 +360,19 @@ const EditorPanel = () => {
|
|
|
328
360
|
return null
|
|
329
361
|
}
|
|
330
362
|
|
|
363
|
+
useEffect(() => {
|
|
364
|
+
if (!config.general?.boxplot) return
|
|
365
|
+
if (!config.general.boxplot.firstQuartilePercentage) {
|
|
366
|
+
updateConfig({
|
|
367
|
+
...config,
|
|
368
|
+
boxplot: {
|
|
369
|
+
...config.boxplot,
|
|
370
|
+
firstQuartilePercentage: 25
|
|
371
|
+
}
|
|
372
|
+
})
|
|
373
|
+
}
|
|
374
|
+
}, [config])
|
|
375
|
+
|
|
331
376
|
const setLollipopShape = shape => {
|
|
332
377
|
updateConfig({
|
|
333
378
|
...config,
|
|
@@ -361,7 +406,7 @@ const EditorPanel = () => {
|
|
|
361
406
|
|
|
362
407
|
const addNewSeries = seriesKey => {
|
|
363
408
|
let newSeries = config.series ? [...config.series] : []
|
|
364
|
-
newSeries.push({ dataKey: seriesKey, type:
|
|
409
|
+
newSeries.push({ dataKey: seriesKey, type: config.visualizationType })
|
|
365
410
|
updateConfig({ ...config, series: newSeries }) // left axis series keys
|
|
366
411
|
}
|
|
367
412
|
|
|
@@ -481,7 +526,7 @@ const EditorPanel = () => {
|
|
|
481
526
|
}
|
|
482
527
|
|
|
483
528
|
const showBarStyleOptions = () => {
|
|
484
|
-
if (config.visualizationType === 'Bar' && config.visualizationSubType !== 'stacked' && (config.orientation === 'horizontal' || config.orientation === 'vertical')) {
|
|
529
|
+
if ((config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.visualizationSubType !== 'stacked' && (config.orientation === 'horizontal' || config.orientation === 'vertical')) {
|
|
485
530
|
return ['flat', 'rounded', 'lollipop']
|
|
486
531
|
} else {
|
|
487
532
|
return ['flat', 'rounded']
|
|
@@ -565,6 +610,13 @@ const EditorPanel = () => {
|
|
|
565
610
|
}
|
|
566
611
|
}, [config.isLollipopChart, config.lollipopShape]) // eslint-disable-line
|
|
567
612
|
|
|
613
|
+
/// temporary force orientation untill we support Vartical deviaton bar
|
|
614
|
+
useEffect(() => {
|
|
615
|
+
if (config.visualizationType === 'Deviation Bar') {
|
|
616
|
+
updateConfig({ ...config, orientation: 'horizontal' })
|
|
617
|
+
}
|
|
618
|
+
}, [config.visualizationType])
|
|
619
|
+
|
|
568
620
|
const ExclusionsList = useCallback(() => {
|
|
569
621
|
const exclusions = [...config.exclusions.keys]
|
|
570
622
|
return (
|
|
@@ -602,6 +654,63 @@ const EditorPanel = () => {
|
|
|
602
654
|
updateConfig({ ...config, filters })
|
|
603
655
|
}
|
|
604
656
|
|
|
657
|
+
const visHasLegend = () => {
|
|
658
|
+
const { visualizationType } = config
|
|
659
|
+
|
|
660
|
+
switch (visualizationType) {
|
|
661
|
+
case 'Box Plot':
|
|
662
|
+
return false
|
|
663
|
+
default:
|
|
664
|
+
return true
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
const visCanAnimate = () => {
|
|
669
|
+
const { visualizationType } = config
|
|
670
|
+
switch (visualizationType) {
|
|
671
|
+
case 'Scatter Plot':
|
|
672
|
+
return false
|
|
673
|
+
case 'Box Plot':
|
|
674
|
+
return false
|
|
675
|
+
default:
|
|
676
|
+
return true
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
const visHasDataCutoff = () => {
|
|
681
|
+
const { visualizationType } = config
|
|
682
|
+
switch (visualizationType) {
|
|
683
|
+
case 'Box Plot':
|
|
684
|
+
return false
|
|
685
|
+
case 'Pie':
|
|
686
|
+
return false
|
|
687
|
+
default:
|
|
688
|
+
return true
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
const visHasLabelOnData = () => {
|
|
693
|
+
const { visualizationType } = config
|
|
694
|
+
switch (visualizationType) {
|
|
695
|
+
case 'Box Plot':
|
|
696
|
+
return false
|
|
697
|
+
case 'Pie':
|
|
698
|
+
return false
|
|
699
|
+
case 'Scatter Plot':
|
|
700
|
+
return false
|
|
701
|
+
default:
|
|
702
|
+
return true
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
const visHasBarBorders = () => {
|
|
707
|
+
const { series, visualizationType } = config
|
|
708
|
+
if (visualizationType === 'Box Plot') return false
|
|
709
|
+
if (visualizationType === 'Scatter Plot') return false
|
|
710
|
+
if (visualizationType === 'Pie') return false
|
|
711
|
+
return series?.some(series => series.type === 'Bar' || series.type === 'Paired Bar' || series.type === 'Deviation Bar')
|
|
712
|
+
}
|
|
713
|
+
|
|
605
714
|
const handleSeriesChange = (idx1, idx2) => {
|
|
606
715
|
let seriesOrder = config.series
|
|
607
716
|
let [movedItem] = seriesOrder.splice(idx1, 1)
|
|
@@ -651,7 +760,7 @@ const EditorPanel = () => {
|
|
|
651
760
|
case config.visualizationType === 'Combo' && isAllLine && enteredValue && parseFloat(enteredValue) > minVal:
|
|
652
761
|
message = 'Value must be less than ' + minValue
|
|
653
762
|
break
|
|
654
|
-
case (config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && !isAllLine)) && enteredValue && minVal > 0 && parseFloat(enteredValue) > 0:
|
|
763
|
+
case (config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar' || (config.visualizationType === 'Combo' && !isAllLine)) && enteredValue && minVal > 0 && parseFloat(enteredValue) > 0:
|
|
655
764
|
message = 'Value must be less than or equal to 0'
|
|
656
765
|
break
|
|
657
766
|
case enteredValue && minVal < 0 && parseFloat(enteredValue) > minVal:
|
|
@@ -669,6 +778,19 @@ const EditorPanel = () => {
|
|
|
669
778
|
validateMaxValue()
|
|
670
779
|
}, [minValue, maxValue, config]) // eslint-disable-line
|
|
671
780
|
|
|
781
|
+
const enabledChartTypes = [
|
|
782
|
+
'Pie',
|
|
783
|
+
'Line',
|
|
784
|
+
'Bar',
|
|
785
|
+
'Combo',
|
|
786
|
+
'Paired Bar',
|
|
787
|
+
'Spark Line',
|
|
788
|
+
// 'Area Chart',
|
|
789
|
+
'Scatter Plot',
|
|
790
|
+
'Box Plot',
|
|
791
|
+
'Deviation Bar'
|
|
792
|
+
]
|
|
793
|
+
|
|
672
794
|
return (
|
|
673
795
|
<ErrorBoundary component='EditorPanel'>
|
|
674
796
|
{config.newViz && <Confirm />}
|
|
@@ -688,21 +810,44 @@ const EditorPanel = () => {
|
|
|
688
810
|
<AccordionItemButton>General</AccordionItemButton>
|
|
689
811
|
</AccordionItemHeading>
|
|
690
812
|
<AccordionItemPanel>
|
|
691
|
-
<Select value={config.visualizationType} fieldName='visualizationType' label='Chart Type' updateField={updateField} options={
|
|
813
|
+
<Select value={config.visualizationType} fieldName='visualizationType' label='Chart Type' updateField={updateField} options={enabledChartTypes} />
|
|
692
814
|
{(config.visualizationType === 'Bar' || config.visualizationType === 'Combo') && <Select value={config.visualizationSubType || 'Regular'} fieldName='visualizationSubType' label='Chart Subtype' updateField={updateField} options={['regular', 'stacked']} />}
|
|
693
815
|
{config.visualizationType === 'Bar' && <Select value={config.orientation || 'vertical'} fieldName='orientation' label='Orientation' updateField={updateField} options={['vertical', 'horizontal']} />}
|
|
694
|
-
{config.visualizationType === 'Bar' && <Select
|
|
695
|
-
{config.visualizationType === 'Bar'
|
|
696
|
-
{config.visualizationType === 'Bar' && config.barStyle === 'rounded' && <Select value={config.
|
|
816
|
+
{config.visualizationType === 'Deviation Bar' && <Select label='Orientation' options={['horizontal']} />}
|
|
817
|
+
{(config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && <Select value={config.isLollipopChart ? 'lollipop' : config.barStyle || 'flat'} fieldName='barStyle' label='bar style' updateField={updateField} options={showBarStyleOptions()} />}
|
|
818
|
+
{(config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.barStyle === 'rounded' && <Select value={config.tipRounding || 'top'} fieldName='tipRounding' label='tip rounding' updateField={updateField} options={['top', 'full']} />}
|
|
819
|
+
{(config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.barStyle === 'rounded' && (
|
|
820
|
+
<Select value={config.roundingStyle || 'standard'} fieldName='roundingStyle' label='rounding style' updateField={updateField} options={['standard', 'shallow', 'finger']} />
|
|
821
|
+
)}
|
|
697
822
|
{config.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']} />}
|
|
698
|
-
{config.orientation === 'horizontal' && (config.yAxis.labelPlacement === 'Below Bar' || config.yAxis.labelPlacement === 'On Date/Category Axis' || config.visualizationType === 'Paired Bar') ? (
|
|
823
|
+
{config.orientation === 'horizontal' && (config.yAxis.labelPlacement === 'Below Bar' || config.yAxis.labelPlacement === 'On Date/Category Axis' || config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') ? (
|
|
699
824
|
<CheckBox value={config.yAxis.displayNumbersOnBar} section='yAxis' fieldName='displayNumbersOnBar' label={config.isLollipopChart ? 'Display Numbers after Bar' : 'Display Numbers on Bar'} updateField={updateField} />
|
|
700
825
|
) : (
|
|
701
|
-
|
|
826
|
+
visHasLabelOnData() && <CheckBox value={config.labels} fieldName='labels' label='Display label on data' updateField={updateField} />
|
|
702
827
|
)}
|
|
703
828
|
{config.visualizationType === 'Pie' && <Select fieldName='pieType' label='Pie Chart Type' updateField={updateField} options={['Regular', 'Donut']} />}
|
|
704
829
|
|
|
705
|
-
<TextField
|
|
830
|
+
<TextField
|
|
831
|
+
value={config.title || 'Chart Title'}
|
|
832
|
+
fieldName='title'
|
|
833
|
+
id='title'
|
|
834
|
+
label='Title'
|
|
835
|
+
placeholder='Chart Title'
|
|
836
|
+
//defaultValue='Chart Title'
|
|
837
|
+
updateField={updateField}
|
|
838
|
+
//onChange={handleTitleChange}
|
|
839
|
+
tooltip={
|
|
840
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
841
|
+
<Tooltip.Target>
|
|
842
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
843
|
+
</Tooltip.Target>
|
|
844
|
+
<Tooltip.Content>
|
|
845
|
+
<p>Title is required to set the name of the download file but can be hidden using the option below.</p>
|
|
846
|
+
</Tooltip.Content>
|
|
847
|
+
</Tooltip>
|
|
848
|
+
}
|
|
849
|
+
/>
|
|
850
|
+
<CheckBox value={config.showTitle} fieldName='showTitle' label='Show Title' updateField={updateField} />
|
|
706
851
|
<TextField
|
|
707
852
|
value={config.superTitle}
|
|
708
853
|
updateField={updateField}
|
|
@@ -806,7 +951,7 @@ const EditorPanel = () => {
|
|
|
806
951
|
{provided => (
|
|
807
952
|
<ul {...provided.droppableProps} className='series-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
|
|
808
953
|
{config.series.map((series, i) => {
|
|
809
|
-
if (config.visualizationType === 'Combo') {
|
|
954
|
+
if (config.visualizationType === 'Combo' || 'Area Chart') {
|
|
810
955
|
let changeType = (i, value) => {
|
|
811
956
|
let series = [...config.series]
|
|
812
957
|
series[i].type = value
|
|
@@ -816,6 +961,12 @@ const EditorPanel = () => {
|
|
|
816
961
|
updateConfig({ ...config, series })
|
|
817
962
|
}
|
|
818
963
|
|
|
964
|
+
let changeLineType = (i, value) => {
|
|
965
|
+
let series = [...config.series]
|
|
966
|
+
series[i].lineType = value
|
|
967
|
+
updateConfig({ ...config, series })
|
|
968
|
+
}
|
|
969
|
+
|
|
819
970
|
let typeDropdown = (
|
|
820
971
|
<select
|
|
821
972
|
value={series.type}
|
|
@@ -823,33 +974,69 @@ const EditorPanel = () => {
|
|
|
823
974
|
changeType(i, event.target.value)
|
|
824
975
|
}}
|
|
825
976
|
style={{ width: '100px', marginRight: '10px' }}
|
|
977
|
+
>
|
|
978
|
+
<option value='' default key='default'>
|
|
979
|
+
Select
|
|
980
|
+
</option>
|
|
981
|
+
{config.visualizationType === 'Combo' && <option value='Bar'>Bar</option>}
|
|
982
|
+
<option value='Line' key='Line'>
|
|
983
|
+
Solid Line
|
|
984
|
+
</option>
|
|
985
|
+
<option value='dashed-sm' key='dashed-sm'>
|
|
986
|
+
Small Dashed
|
|
987
|
+
</option>
|
|
988
|
+
<option value='dashed-md' key='dashed-md'>
|
|
989
|
+
Medium Dashed
|
|
990
|
+
</option>
|
|
991
|
+
<option value='dashed-lg' key='dashed-lg'>
|
|
992
|
+
Large Dashed
|
|
993
|
+
</option>
|
|
994
|
+
</select>
|
|
995
|
+
)
|
|
996
|
+
|
|
997
|
+
const lineType = (
|
|
998
|
+
<select
|
|
999
|
+
value={series.lineStyle}
|
|
1000
|
+
onChange={event => {
|
|
1001
|
+
changeLineType(i, event.target.value)
|
|
1002
|
+
}}
|
|
1003
|
+
style={{ width: '100px', marginRight: '10px' }}
|
|
1004
|
+
key='lineTypeSelection'
|
|
826
1005
|
>
|
|
827
1006
|
<option value='' default>
|
|
828
1007
|
Select
|
|
829
1008
|
</option>
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
1009
|
+
|
|
1010
|
+
{Object.keys(allCurves).map(curveName => (
|
|
1011
|
+
<option key={`curve-option-${curveName}`} value={curveName}>
|
|
1012
|
+
{curveName}
|
|
1013
|
+
</option>
|
|
1014
|
+
))}
|
|
835
1015
|
</select>
|
|
836
1016
|
)
|
|
837
1017
|
|
|
838
1018
|
return (
|
|
839
1019
|
<Draggable key={series.dataKey} draggableId={`draggableFilter-${series.dataKey}`} index={i}>
|
|
840
1020
|
{(provided, snapshot) => (
|
|
841
|
-
<li>
|
|
1021
|
+
<li key={i}>
|
|
842
1022
|
<div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
|
|
843
1023
|
<div className={`series-list__name${series.dataKey.length > 15 ? ' series-list__name--truncate' : ''}`} data-title={series.dataKey}>
|
|
844
1024
|
<div className='series-list__name-text'>{series.dataKey}</div>
|
|
845
1025
|
</div>
|
|
846
1026
|
<span>
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
1027
|
+
<>
|
|
1028
|
+
{(config.visualizationType === 'Combo' || config.visualizationType === 'Area Chart') && (
|
|
1029
|
+
<>
|
|
1030
|
+
<span className='series-list__dropdown'>{typeDropdown}</span>
|
|
1031
|
+
{config.visualizationType === 'Area Chart' && <span className='series-list__dropdown series-list__dropdown--lineType'>{lineType}</span>}
|
|
1032
|
+
</>
|
|
1033
|
+
)}
|
|
1034
|
+
{config.series && config.series.length > 1 && (
|
|
1035
|
+
<button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
|
|
1036
|
+
×
|
|
1037
|
+
</button>
|
|
1038
|
+
)}
|
|
1039
|
+
</>
|
|
853
1040
|
</span>
|
|
854
1041
|
</div>
|
|
855
1042
|
</li>
|
|
@@ -859,7 +1046,7 @@ const EditorPanel = () => {
|
|
|
859
1046
|
}
|
|
860
1047
|
|
|
861
1048
|
return (
|
|
862
|
-
<Draggable key={series.dataKey} draggableId={`draggableFilter-${series.dataKey}`} index={i}>
|
|
1049
|
+
<Draggable key={`series.dataKey--${i}`} draggableId={`draggableFilter-${series.dataKey}`} index={i}>
|
|
863
1050
|
{(provided, snapshot) => (
|
|
864
1051
|
<li
|
|
865
1052
|
key={series.dataKey}
|
|
@@ -904,6 +1091,7 @@ const EditorPanel = () => {
|
|
|
904
1091
|
}}
|
|
905
1092
|
options={getColumns()}
|
|
906
1093
|
/>
|
|
1094
|
+
|
|
907
1095
|
{config.series && config.series.length <= 1 && config.visualizationType === 'Bar' && (
|
|
908
1096
|
<>
|
|
909
1097
|
<span className='divider-heading'>Confidence Keys</span>
|
|
@@ -917,6 +1105,183 @@ const EditorPanel = () => {
|
|
|
917
1105
|
</AccordionItem>
|
|
918
1106
|
)}
|
|
919
1107
|
|
|
1108
|
+
{config.visualizationType === 'Box Plot' && (
|
|
1109
|
+
<AccordionItem>
|
|
1110
|
+
<AccordionItemHeading>
|
|
1111
|
+
<AccordionItemButton>Measures</AccordionItemButton>
|
|
1112
|
+
</AccordionItemHeading>
|
|
1113
|
+
<AccordionItemPanel>
|
|
1114
|
+
<h4 style={{ fontSize: '18px' }}>Labels for 5-Number Summary</h4>
|
|
1115
|
+
|
|
1116
|
+
{/* prettier-ignore */}
|
|
1117
|
+
{/* max */}
|
|
1118
|
+
<TextField
|
|
1119
|
+
type='text'
|
|
1120
|
+
value={config.boxplot.labels.maximum}
|
|
1121
|
+
fieldName='maximum'
|
|
1122
|
+
section='boxplot'
|
|
1123
|
+
subsection='labels'
|
|
1124
|
+
label='Maximum'
|
|
1125
|
+
updateField={updateField}
|
|
1126
|
+
tooltip={
|
|
1127
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1128
|
+
<Tooltip.Target>
|
|
1129
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1130
|
+
</Tooltip.Target>
|
|
1131
|
+
<Tooltip.Content>
|
|
1132
|
+
<p>Highest value, excluding outliers</p>
|
|
1133
|
+
</Tooltip.Content>
|
|
1134
|
+
</Tooltip>
|
|
1135
|
+
}
|
|
1136
|
+
/>
|
|
1137
|
+
|
|
1138
|
+
{/* prettier-ignore */}
|
|
1139
|
+
{/* Q3 */}
|
|
1140
|
+
<TextField
|
|
1141
|
+
type='text'
|
|
1142
|
+
value={config.boxplot.labels.q3}
|
|
1143
|
+
fieldName='q3'
|
|
1144
|
+
section='boxplot'
|
|
1145
|
+
subsection='labels'
|
|
1146
|
+
label='Upper Quartile'
|
|
1147
|
+
updateField={updateField}
|
|
1148
|
+
tooltip={
|
|
1149
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1150
|
+
<Tooltip.Target>
|
|
1151
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1152
|
+
</Tooltip.Target>
|
|
1153
|
+
<Tooltip.Content>
|
|
1154
|
+
<p>Represented by top line of box. 25% of data are higher.</p>
|
|
1155
|
+
</Tooltip.Content>
|
|
1156
|
+
</Tooltip>
|
|
1157
|
+
}
|
|
1158
|
+
/>
|
|
1159
|
+
|
|
1160
|
+
{/* prettier-ignore */}
|
|
1161
|
+
{/* median */}
|
|
1162
|
+
<TextField
|
|
1163
|
+
type='text'
|
|
1164
|
+
value={config.boxplot.labels.median}
|
|
1165
|
+
fieldName='median'
|
|
1166
|
+
section='boxplot'
|
|
1167
|
+
subsection='labels'
|
|
1168
|
+
label='Median'
|
|
1169
|
+
updateField={updateField}
|
|
1170
|
+
tooltip={
|
|
1171
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1172
|
+
<Tooltip.Target>
|
|
1173
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1174
|
+
</Tooltip.Target>
|
|
1175
|
+
<Tooltip.Content>
|
|
1176
|
+
<p>Middle data point. Half of data are higher value.</p>
|
|
1177
|
+
</Tooltip.Content>
|
|
1178
|
+
</Tooltip>
|
|
1179
|
+
}
|
|
1180
|
+
/>
|
|
1181
|
+
|
|
1182
|
+
{/* prettier-ignore */}
|
|
1183
|
+
{/* q1 */}
|
|
1184
|
+
<TextField
|
|
1185
|
+
type='text'
|
|
1186
|
+
value={config.boxplot.labels.q1}
|
|
1187
|
+
fieldName='q1'
|
|
1188
|
+
section='boxplot'
|
|
1189
|
+
subsection='labels'
|
|
1190
|
+
label='Lower Quartile'
|
|
1191
|
+
updateField={updateField}
|
|
1192
|
+
tooltip={
|
|
1193
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1194
|
+
<Tooltip.Target>
|
|
1195
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1196
|
+
</Tooltip.Target>
|
|
1197
|
+
<Tooltip.Content>
|
|
1198
|
+
<p>Represented by bottom line of box. 25% of data are lower.</p>
|
|
1199
|
+
</Tooltip.Content>
|
|
1200
|
+
</Tooltip>
|
|
1201
|
+
}
|
|
1202
|
+
/>
|
|
1203
|
+
|
|
1204
|
+
{/* prettier-ignore */}
|
|
1205
|
+
{/* minimum */}
|
|
1206
|
+
<TextField
|
|
1207
|
+
type='text'
|
|
1208
|
+
value={config.boxplot.labels.minimum}
|
|
1209
|
+
fieldName='minimum'
|
|
1210
|
+
section='boxplot'
|
|
1211
|
+
subsection='labels'
|
|
1212
|
+
label='Minimum'
|
|
1213
|
+
updateField={updateField}
|
|
1214
|
+
tooltip={
|
|
1215
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1216
|
+
<Tooltip.Target>
|
|
1217
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1218
|
+
</Tooltip.Target>
|
|
1219
|
+
<Tooltip.Content>
|
|
1220
|
+
<p>Lowest value, excluding outliers</p>
|
|
1221
|
+
</Tooltip.Content>
|
|
1222
|
+
</Tooltip>
|
|
1223
|
+
}
|
|
1224
|
+
/>
|
|
1225
|
+
<br />
|
|
1226
|
+
<h4 style={{ fontSize: '18px' }}>Labels for Additional Measures</h4>
|
|
1227
|
+
|
|
1228
|
+
{/* iqr */}
|
|
1229
|
+
<TextField type='text' value={config.boxplot.labels.iqr} fieldName='iqr' section='boxplot' subsection='labels' label='Interquartile Range' updateField={updateField} />
|
|
1230
|
+
|
|
1231
|
+
{/* count */}
|
|
1232
|
+
<TextField type='text' value={config.boxplot.labels.total} fieldName='total' section='boxplot' subsection='labels' label='Total' updateField={updateField} />
|
|
1233
|
+
|
|
1234
|
+
{/* mean */}
|
|
1235
|
+
<TextField type='text' value={config.boxplot.labels.mean} fieldName='mean' section='boxplot' subsection='labels' label='Mean' updateField={updateField} />
|
|
1236
|
+
{/* outliers */}
|
|
1237
|
+
<TextField type='text' value={config.boxplot.labels.outliers} fieldName='outliers' section='boxplot' subsection='labels' label='Outliers' updateField={updateField} />
|
|
1238
|
+
{/* values */}
|
|
1239
|
+
<TextField type='text' value={config.boxplot.labels.values} fieldName='values' section='boxplot' subsection='labels' label='Values' updateField={updateField} />
|
|
1240
|
+
<br />
|
|
1241
|
+
<h4 style={{ fontSize: '18px' }}>Percentages for Quartiles</h4>
|
|
1242
|
+
<TextField
|
|
1243
|
+
type='number'
|
|
1244
|
+
value={config.boxplot.firstQuartilePercentage ? config.boxplot.firstQuartilePercentage : 25}
|
|
1245
|
+
fieldName='firstQuartilePercentage'
|
|
1246
|
+
section='boxplot'
|
|
1247
|
+
label='Lower Quartile'
|
|
1248
|
+
max={100}
|
|
1249
|
+
updateField={updateField}
|
|
1250
|
+
tooltip={
|
|
1251
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1252
|
+
<Tooltip.Target>
|
|
1253
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1254
|
+
</Tooltip.Target>
|
|
1255
|
+
<Tooltip.Content>
|
|
1256
|
+
<p>Represented by bottom line of box. 25% of data are lower.</p>
|
|
1257
|
+
</Tooltip.Content>
|
|
1258
|
+
</Tooltip>
|
|
1259
|
+
}
|
|
1260
|
+
/>
|
|
1261
|
+
|
|
1262
|
+
<TextField
|
|
1263
|
+
type='number'
|
|
1264
|
+
value={config.boxplot.thirdQuartilePercentage ? config.boxplot.thirdQuartilePercentage : 75}
|
|
1265
|
+
fieldName='thirdQuartilePercentage'
|
|
1266
|
+
label='Upper Quartile'
|
|
1267
|
+
section='boxplot'
|
|
1268
|
+
max={100}
|
|
1269
|
+
updateField={updateField}
|
|
1270
|
+
tooltip={
|
|
1271
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1272
|
+
<Tooltip.Target>
|
|
1273
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1274
|
+
</Tooltip.Target>
|
|
1275
|
+
<Tooltip.Content>
|
|
1276
|
+
<p>Represented by top line of box. 25% of data are higher.</p>
|
|
1277
|
+
</Tooltip.Content>
|
|
1278
|
+
</Tooltip>
|
|
1279
|
+
}
|
|
1280
|
+
/>
|
|
1281
|
+
</AccordionItemPanel>
|
|
1282
|
+
</AccordionItem>
|
|
1283
|
+
)}
|
|
1284
|
+
|
|
920
1285
|
{hasRightAxis && config.series && config.visualizationType === 'Combo' && (
|
|
921
1286
|
<AccordionItem>
|
|
922
1287
|
<AccordionItemHeading>
|
|
@@ -956,10 +1321,12 @@ const EditorPanel = () => {
|
|
|
956
1321
|
}}
|
|
957
1322
|
style={{ width: '100px', marginRight: '10px' }}
|
|
958
1323
|
>
|
|
959
|
-
<option value='Left' default>
|
|
1324
|
+
<option value='Left' default key='left'>
|
|
960
1325
|
left
|
|
961
1326
|
</option>
|
|
962
|
-
<option value='Right'
|
|
1327
|
+
<option value='Right' key='right'>
|
|
1328
|
+
right
|
|
1329
|
+
</option>
|
|
963
1330
|
</select>
|
|
964
1331
|
)
|
|
965
1332
|
|
|
@@ -1014,8 +1381,9 @@ const EditorPanel = () => {
|
|
|
1014
1381
|
{config.visualizationType !== 'Pie' && (
|
|
1015
1382
|
<>
|
|
1016
1383
|
<TextField value={config.yAxis.label} section='yAxis' fieldName='label' label='Label' updateField={updateField} />
|
|
1017
|
-
{config.runtime.seriesKeys && config.runtime.seriesKeys.length === 1 && <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />}
|
|
1384
|
+
{config.runtime.seriesKeys && config.runtime.seriesKeys.length === 1 && config.visualizationType !== 'Box Plot' && <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />}
|
|
1018
1385
|
<TextField value={config.yAxis.numTicks} placeholder='Auto' type='number' section='yAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
|
|
1386
|
+
{config.visualizationType === 'Paired Bar' && <TextField value={config.yAxis.tickRotation || 0} type='number' min='0' section='yAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
|
|
1019
1387
|
<TextField
|
|
1020
1388
|
value={config.yAxis.size}
|
|
1021
1389
|
type='number'
|
|
@@ -1035,8 +1403,11 @@ const EditorPanel = () => {
|
|
|
1035
1403
|
</Tooltip>
|
|
1036
1404
|
}
|
|
1037
1405
|
/>
|
|
1406
|
+
{/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
|
|
1407
|
+
{/* <TextField value={config.yAxis.axisPadding} type='number' max={10} min={0} section='yAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
|
|
1038
1408
|
{config.orientation === 'horizontal' && <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />}
|
|
1039
1409
|
{config.orientation !== 'horizontal' && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Display Gridlines' updateField={updateField} />}
|
|
1410
|
+
<CheckBox value={config.yAxis.enablePadding} section='yAxis' fieldName='enablePadding' label='Add Padding to Value Axis Scale' updateField={updateField} />
|
|
1040
1411
|
</>
|
|
1041
1412
|
)}
|
|
1042
1413
|
<span className='divider-heading'>Number Formatting</span>
|
|
@@ -1103,8 +1474,17 @@ const EditorPanel = () => {
|
|
|
1103
1474
|
<CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
|
|
1104
1475
|
<CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
|
|
1105
1476
|
<CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
|
|
1106
|
-
<TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='
|
|
1477
|
+
<TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='max value' type='number' placeholder='Auto' updateField={updateField} />
|
|
1107
1478
|
<span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
|
|
1479
|
+
{config.visualizationType === 'Deviation Bar' && (
|
|
1480
|
+
<>
|
|
1481
|
+
<TextField value={config.xAxis.min} section='xAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />
|
|
1482
|
+
<span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
|
|
1483
|
+
<TextField value={config.xAxis.target} section='xAxis' fieldName='target' type='number' label='Deviation point' placeholder='Auto' updateField={updateField} />
|
|
1484
|
+
<TextField value={config.xAxis.targetLabel || 'Target'} section='xAxis' fieldName='targetLabel' type='text' label='Deviation point Label' updateField={updateField} />
|
|
1485
|
+
<CheckBox value={config.xAxis.showTargetLabel} section='xAxis' fieldName='showTargetLabel' label='Display Deviation point label' updateField={updateField} />
|
|
1486
|
+
</>
|
|
1487
|
+
)}
|
|
1108
1488
|
</>
|
|
1109
1489
|
) : (
|
|
1110
1490
|
config.visualizationType !== 'Pie' && (
|
|
@@ -1112,9 +1492,9 @@ const EditorPanel = () => {
|
|
|
1112
1492
|
<CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
|
|
1113
1493
|
<CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
|
|
1114
1494
|
<CheckBox value={config.yAxis.hideTicks} section='yAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
|
|
1115
|
-
<TextField value={config.yAxis.max} section='yAxis' fieldName='max' type='number' label='
|
|
1495
|
+
<TextField value={config.yAxis.max} section='yAxis' fieldName='max' type='number' label='max value' placeholder='Auto' updateField={updateField} />
|
|
1116
1496
|
<span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
|
|
1117
|
-
<TextField value={config.yAxis.min} section='yAxis' fieldName='min' type='number' label='
|
|
1497
|
+
<TextField value={config.yAxis.min} section='yAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />
|
|
1118
1498
|
<span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
|
|
1119
1499
|
</>
|
|
1120
1500
|
)
|
|
@@ -1193,7 +1573,7 @@ const EditorPanel = () => {
|
|
|
1193
1573
|
<AccordionItemPanel>
|
|
1194
1574
|
{config.visualizationType !== 'Pie' && (
|
|
1195
1575
|
<>
|
|
1196
|
-
<Select value={config.xAxis.type} section='xAxis' fieldName='type' label='Data Type' updateField={updateField} options={['categorical', 'date']} />
|
|
1576
|
+
<Select value={config.xAxis.type} section='xAxis' fieldName='type' label='Data Type' updateField={updateField} options={config.visualizationType !== 'Scatter Plot' ? ['categorical', 'date'] : ['categorical', 'continuous', 'date']} />
|
|
1197
1577
|
<Select
|
|
1198
1578
|
value={config.xAxis.dataKey || ''}
|
|
1199
1579
|
section='xAxis'
|
|
@@ -1244,6 +1624,66 @@ const EditorPanel = () => {
|
|
|
1244
1624
|
<>
|
|
1245
1625
|
<TextField value={config.xAxis.label} section='xAxis' fieldName='label' label='Label' updateField={updateField} />
|
|
1246
1626
|
|
|
1627
|
+
{config.xAxis.type === 'continuous' && (
|
|
1628
|
+
<>
|
|
1629
|
+
<TextField
|
|
1630
|
+
value={config.dataFormat.bottomPrefix}
|
|
1631
|
+
section='dataFormat'
|
|
1632
|
+
fieldName='bottomPrefix'
|
|
1633
|
+
label='Prefix'
|
|
1634
|
+
updateField={updateField}
|
|
1635
|
+
tooltip={
|
|
1636
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1637
|
+
<Tooltip.Target>
|
|
1638
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1639
|
+
</Tooltip.Target>
|
|
1640
|
+
<Tooltip.Content>
|
|
1641
|
+
{config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
|
|
1642
|
+
{config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
|
|
1643
|
+
</Tooltip.Content>
|
|
1644
|
+
</Tooltip>
|
|
1645
|
+
}
|
|
1646
|
+
/>
|
|
1647
|
+
|
|
1648
|
+
<TextField
|
|
1649
|
+
value={config.dataFormat.bottomSuffix}
|
|
1650
|
+
section='dataFormat'
|
|
1651
|
+
fieldName='bottomSuffix'
|
|
1652
|
+
label='Suffix'
|
|
1653
|
+
updateField={updateField}
|
|
1654
|
+
tooltip={
|
|
1655
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1656
|
+
<Tooltip.Target>
|
|
1657
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1658
|
+
</Tooltip.Target>
|
|
1659
|
+
<Tooltip.Content>
|
|
1660
|
+
{config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
|
|
1661
|
+
{config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
|
|
1662
|
+
</Tooltip.Content>
|
|
1663
|
+
</Tooltip>
|
|
1664
|
+
}
|
|
1665
|
+
/>
|
|
1666
|
+
|
|
1667
|
+
<CheckBox
|
|
1668
|
+
value={config.dataFormat.bottomAbbreviated}
|
|
1669
|
+
section='dataFormat'
|
|
1670
|
+
fieldName='bottomAbbreviated'
|
|
1671
|
+
label='Abbreviate Axis Values'
|
|
1672
|
+
updateField={updateField}
|
|
1673
|
+
tooltip={
|
|
1674
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1675
|
+
<Tooltip.Target>
|
|
1676
|
+
<Icon display='question' />
|
|
1677
|
+
</Tooltip.Target>
|
|
1678
|
+
<Tooltip.Content>
|
|
1679
|
+
<p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
|
|
1680
|
+
</Tooltip.Content>
|
|
1681
|
+
</Tooltip>
|
|
1682
|
+
}
|
|
1683
|
+
/>
|
|
1684
|
+
</>
|
|
1685
|
+
)}
|
|
1686
|
+
|
|
1247
1687
|
{config.xAxis.type === 'date' && (
|
|
1248
1688
|
<>
|
|
1249
1689
|
<p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>
|
|
@@ -1316,6 +1756,16 @@ const EditorPanel = () => {
|
|
|
1316
1756
|
|
|
1317
1757
|
<TextField value={config.xAxis.size} type='number' min='0' section='xAxis' fieldName='size' label={config.orientation === 'horizontal' ? 'Size (Width)' : 'Size (Height)'} className='number-narrow' updateField={updateField} />
|
|
1318
1758
|
|
|
1759
|
+
{/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
|
|
1760
|
+
{/* <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
|
|
1761
|
+
|
|
1762
|
+
{config.xAxis.type === 'continuous' && (
|
|
1763
|
+
<>
|
|
1764
|
+
<CheckBox value={config.dataFormat.bottomCommas} section='dataFormat' fieldName='bottomCommas' label='Add commas' updateField={updateField} />
|
|
1765
|
+
<TextField value={config.dataFormat.bottomRoundTo} type='number' section='dataFormat' fieldName='bottomRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
|
|
1766
|
+
</>
|
|
1767
|
+
)}
|
|
1768
|
+
|
|
1319
1769
|
{config.yAxis.labelPlacement !== 'Below Bar' && <TextField value={config.xAxis.tickRotation} type='number' min='0' section='xAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
|
|
1320
1770
|
{config.orientation === 'horizontal' ? (
|
|
1321
1771
|
<>
|
|
@@ -1392,13 +1842,14 @@ const EditorPanel = () => {
|
|
|
1392
1842
|
</AccordionItem>
|
|
1393
1843
|
)}
|
|
1394
1844
|
|
|
1395
|
-
|
|
1396
|
-
<
|
|
1397
|
-
<
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
<
|
|
1401
|
-
|
|
1845
|
+
{visHasLegend() && (
|
|
1846
|
+
<AccordionItem>
|
|
1847
|
+
<AccordionItemHeading>
|
|
1848
|
+
<AccordionItemButton>Legend</AccordionItemButton>
|
|
1849
|
+
</AccordionItemHeading>
|
|
1850
|
+
<AccordionItemPanel>
|
|
1851
|
+
<CheckBox value={config.legend.reverseLabelOrder} section='legend' fieldName='reverseLabelOrder' label='Reverse Labels' updateField={updateField} />
|
|
1852
|
+
{/* <fieldset className="checkbox-group">
|
|
1402
1853
|
<CheckBox value={config.legend.dynamicLegend} section="legend" fieldName="dynamicLegend" label="Dynamic Legend" updateField={updateField}/>
|
|
1403
1854
|
{config.legend.dynamicLegend && (
|
|
1404
1855
|
<>
|
|
@@ -1409,35 +1860,44 @@ const EditorPanel = () => {
|
|
|
1409
1860
|
</>
|
|
1410
1861
|
)}
|
|
1411
1862
|
</fieldset> */}
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
<CheckBox value={config.legend.showLegendValuesTooltip} section='legend' fieldName='showLegendValuesTooltip' label='Show Legend Values in Tooltip' updateField={updateField} />
|
|
1863
|
+
<CheckBox
|
|
1864
|
+
value={config.legend.hide ? true : false}
|
|
1865
|
+
section='legend'
|
|
1866
|
+
fieldName='hide'
|
|
1867
|
+
label='Hide Legend'
|
|
1868
|
+
updateField={updateField}
|
|
1869
|
+
tooltip={
|
|
1870
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1871
|
+
<Tooltip.Target>
|
|
1872
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1873
|
+
</Tooltip.Target>
|
|
1874
|
+
<Tooltip.Content>
|
|
1875
|
+
<p>With a single-series chart, consider hiding the legend to reduce visual clutter.</p>
|
|
1876
|
+
</Tooltip.Content>
|
|
1877
|
+
</Tooltip>
|
|
1878
|
+
}
|
|
1879
|
+
/>
|
|
1430
1880
|
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1881
|
+
{/* {config.visualizationType === 'Box Plot' &&
|
|
1882
|
+
<>
|
|
1883
|
+
<CheckBox value={config.boxplot.legend.displayHowToReadText} fieldName='displayHowToReadText' section='boxplot' subsection='legend' label='Display How To Read Text' updateField={updateField} />
|
|
1884
|
+
<TextField type='textarea' value={config.boxplot.legend.howToReadText} updateField={updateField} fieldName='howToReadText' section='boxplot' subsection='legend' label='How to read text' />
|
|
1885
|
+
</>
|
|
1886
|
+
} */}
|
|
1887
|
+
|
|
1888
|
+
{config.visualizationType !== 'Box Plot' && <CheckBox value={config.legend.showLegendValuesTooltip ? true : false} section='legend' fieldName='showLegendValuesTooltip' label='Show Legend Values in Tooltip' updateField={updateField} />}
|
|
1889
|
+
|
|
1890
|
+
{config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && config.runtime.seriesKeys.length === 1 && (
|
|
1891
|
+
<Select value={config.legend.colorCode} section='legend' fieldName='colorCode' label='Color code by category' initial='Select' updateField={updateField} options={getDataValueOptions(data)} />
|
|
1892
|
+
)}
|
|
1893
|
+
<Select value={config.legend.behavior} section='legend' fieldName='behavior' label='Legend Behavior (When clicked)' updateField={updateField} options={['highlight', 'isolate']} />
|
|
1894
|
+
<TextField value={config.legend.label} section='legend' fieldName='label' label='Title' updateField={updateField} />
|
|
1895
|
+
<Select value={config.legend.position} section='legend' fieldName='position' label='Position' updateField={updateField} options={['right', 'left', 'bottom']} />
|
|
1896
|
+
{config.legend.position === 'bottom' && <CheckBox value={config.legend.singleRow} section='legend' fieldName='singleRow' label='Single Row Legend' updateField={updateField} />}
|
|
1897
|
+
<TextField type='textarea' value={config.legend.description} updateField={updateField} section='legend' fieldName='description' label='Legend Description' />
|
|
1898
|
+
</AccordionItemPanel>
|
|
1899
|
+
</AccordionItem>
|
|
1900
|
+
)}
|
|
1441
1901
|
|
|
1442
1902
|
<AccordionItem>
|
|
1443
1903
|
<AccordionItemHeading>
|
|
@@ -1561,11 +2021,18 @@ const EditorPanel = () => {
|
|
|
1561
2021
|
</>
|
|
1562
2022
|
)}
|
|
1563
2023
|
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
2024
|
+
{config.visualizationType === 'Box Plot' && (
|
|
2025
|
+
<fieldset className='fieldset fieldset--boxplot'>
|
|
2026
|
+
<legend className=''>Box Plot Settings</legend>
|
|
2027
|
+
<Select value={config.boxplot.borders} fieldName='borders' section='boxplot' label='Box Plot Borders' updateField={updateField} options={['true', 'false']} />
|
|
2028
|
+
<CheckBox value={config.boxplot.plotOutlierValues} fieldName='plotOutlierValues' section='boxplot' label='Plot Outliers' updateField={updateField} />
|
|
2029
|
+
<CheckBox value={config.boxplot.plotNonOutlierValues} fieldName='plotNonOutlierValues' section='boxplot' label='Plot non-outlier values' updateField={updateField} />
|
|
2030
|
+
</fieldset>
|
|
2031
|
+
)}
|
|
1567
2032
|
|
|
1568
|
-
<
|
|
2033
|
+
<Select value={config.fontSize} fieldName='fontSize' label='Font Size' updateField={updateField} options={['small', 'medium', 'large']} />
|
|
2034
|
+
{visHasBarBorders() && <Select value={config.barHasBorder} fieldName='barHasBorder' label='Bar Borders' updateField={updateField} options={['true', 'false']} />}
|
|
2035
|
+
{visCanAnimate() && <CheckBox value={config.animate} fieldName='animate' label='Animate Visualization' updateField={updateField} />}
|
|
1569
2036
|
|
|
1570
2037
|
{/*<CheckBox value={config.animateReplay} fieldName="animateReplay" label="Replay Animation When Filters Are Changed" updateField={updateField} />*/}
|
|
1571
2038
|
|
|
@@ -1594,74 +2061,108 @@ const EditorPanel = () => {
|
|
|
1594
2061
|
<span className='edit-label'>Chart Color Palette</span>
|
|
1595
2062
|
</label>
|
|
1596
2063
|
{/* eslint-enable */}
|
|
1597
|
-
{
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
2064
|
+
{config.visualizationType !== 'Paired Bar' && config.visualizationType !== 'Deviation Bar' && (
|
|
2065
|
+
<>
|
|
2066
|
+
<InputToggle fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={config.isPaletteReversed} />
|
|
2067
|
+
<span>Sequential</span>
|
|
2068
|
+
<ul className='color-palette'>
|
|
2069
|
+
{sequential.map(palette => {
|
|
2070
|
+
const colorOne = {
|
|
2071
|
+
backgroundColor: colorPalettes[palette][2]
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
const colorTwo = {
|
|
2075
|
+
backgroundColor: colorPalettes[palette][3]
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
const colorThree = {
|
|
2079
|
+
backgroundColor: colorPalettes[palette][5]
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
return (
|
|
2083
|
+
<button
|
|
2084
|
+
title={palette}
|
|
2085
|
+
key={palette}
|
|
2086
|
+
onClick={e => {
|
|
2087
|
+
e.preventDefault()
|
|
2088
|
+
updateConfig({ ...config, palette })
|
|
2089
|
+
}}
|
|
2090
|
+
className={config.palette === palette ? 'selected' : ''}
|
|
2091
|
+
>
|
|
2092
|
+
<span style={colorOne}></span>
|
|
2093
|
+
<span style={colorTwo}></span>
|
|
2094
|
+
<span style={colorThree}></span>
|
|
2095
|
+
</button>
|
|
2096
|
+
)
|
|
2097
|
+
})}
|
|
2098
|
+
</ul>
|
|
2099
|
+
<span>Non-Sequential</span>
|
|
2100
|
+
<ul className='color-palette'>
|
|
2101
|
+
{nonSequential.map(palette => {
|
|
2102
|
+
const colorOne = {
|
|
2103
|
+
backgroundColor: colorPalettes[palette][2]
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
const colorTwo = {
|
|
2107
|
+
backgroundColor: colorPalettes[palette][4]
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
const colorThree = {
|
|
2111
|
+
backgroundColor: colorPalettes[palette][6]
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
return (
|
|
2115
|
+
<button
|
|
2116
|
+
title={palette}
|
|
2117
|
+
key={palette}
|
|
2118
|
+
onClick={e => {
|
|
2119
|
+
e.preventDefault()
|
|
2120
|
+
updateConfig({ ...config, palette })
|
|
2121
|
+
}}
|
|
2122
|
+
className={config.palette === palette ? 'selected' : ''}
|
|
2123
|
+
>
|
|
2124
|
+
<span style={colorOne}></span>
|
|
2125
|
+
<span style={colorTwo}></span>
|
|
2126
|
+
<span style={colorThree}></span>
|
|
2127
|
+
</button>
|
|
2128
|
+
)
|
|
2129
|
+
})}
|
|
2130
|
+
</ul>
|
|
2131
|
+
</>
|
|
2132
|
+
)}
|
|
2133
|
+
{(config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') && (
|
|
2134
|
+
<>
|
|
2135
|
+
<InputToggle section='twoColor' fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={config.twoColor.isPaletteReversed} />
|
|
2136
|
+
<ul className='color-palette'>
|
|
2137
|
+
{twoColorPalettes.map(palette => {
|
|
2138
|
+
const colorOne = {
|
|
2139
|
+
backgroundColor: twoColorPalette[palette][0]
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
const colorTwo = {
|
|
2143
|
+
backgroundColor: twoColorPalette[palette][1]
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
return (
|
|
2147
|
+
<button
|
|
2148
|
+
title={palette}
|
|
2149
|
+
key={palette}
|
|
2150
|
+
onClick={e => {
|
|
2151
|
+
e.preventDefault()
|
|
2152
|
+
updateConfig({ ...config, twoColor: { ...config.twoColor, palette } })
|
|
2153
|
+
}}
|
|
2154
|
+
className={config.twoColor.palette === palette ? 'selected' : ''}
|
|
2155
|
+
>
|
|
2156
|
+
<span className='two-color' style={colorOne}></span>
|
|
2157
|
+
<span className='two-color' style={colorTwo}></span>
|
|
2158
|
+
</button>
|
|
2159
|
+
)
|
|
2160
|
+
})}
|
|
2161
|
+
</ul>
|
|
2162
|
+
</>
|
|
2163
|
+
)}
|
|
1663
2164
|
|
|
1664
|
-
{
|
|
2165
|
+
{visHasDataCutoff() && (
|
|
1665
2166
|
<>
|
|
1666
2167
|
<TextField
|
|
1667
2168
|
value={config.dataCutoff}
|
|
@@ -1685,7 +2186,7 @@ const EditorPanel = () => {
|
|
|
1685
2186
|
)}
|
|
1686
2187
|
{config.orientation === 'horizontal' && !config.isLollipopChart && config.yAxis.labelPlacement !== 'On Bar' && <TextField type='number' value={config.barHeight || '25'} fieldName='barHeight' label=' Bar Thickness' updateField={updateField} min='15' />}
|
|
1687
2188
|
{((config.visualizationType === 'Bar' && config.orientation !== 'horizontal') || config.visualizationType === 'Combo') && <TextField value={config.barThickness} type='number' fieldName='barThickness' label='Bar Thickness' updateField={updateField} />}
|
|
1688
|
-
{config.orientation === 'horizontal' && <TextField type='number' value={config.barSpace || '
|
|
2189
|
+
{(config.orientation === 'horizontal' || config.visualizationType === 'Paired Bar') && <TextField type='number' value={config.barSpace || '15'} fieldName='barSpace' label='Bar Space' updateField={updateField} min='0' />}
|
|
1689
2190
|
{(config.visualizationType === 'Bar' || config.visualizationType === 'Line' || config.visualizationType === 'Combo') && <CheckBox value={config.topAxis.hasLine} section='topAxis' fieldName='hasLine' label='Add Top Axis Line' updateField={updateField} />}
|
|
1690
2191
|
|
|
1691
2192
|
{config.visualizationType === 'Spark Line' && (
|
|
@@ -1710,6 +2211,25 @@ const EditorPanel = () => {
|
|
|
1710
2211
|
<AccordionItemButton>Data Table</AccordionItemButton>
|
|
1711
2212
|
</AccordionItemHeading>
|
|
1712
2213
|
<AccordionItemPanel>
|
|
2214
|
+
<TextField
|
|
2215
|
+
value={config.table.label}
|
|
2216
|
+
updateField={updateField}
|
|
2217
|
+
section='table'
|
|
2218
|
+
fieldName='label'
|
|
2219
|
+
id='tableLabel'
|
|
2220
|
+
label='Data Table Title'
|
|
2221
|
+
placeholder='Data Table'
|
|
2222
|
+
tooltip={
|
|
2223
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2224
|
+
<Tooltip.Target>
|
|
2225
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2226
|
+
</Tooltip.Target>
|
|
2227
|
+
<Tooltip.Content>
|
|
2228
|
+
<p>Label is required for Data Table for 508 Compliance</p>
|
|
2229
|
+
</Tooltip.Content>
|
|
2230
|
+
</Tooltip>
|
|
2231
|
+
}
|
|
2232
|
+
/>
|
|
1713
2233
|
<CheckBox
|
|
1714
2234
|
value={config.table.show}
|
|
1715
2235
|
section='table'
|
|
@@ -1753,7 +2273,6 @@ const EditorPanel = () => {
|
|
|
1753
2273
|
<CheckBox value={config.table.showDownloadUrl} section='table' fieldName='showDownloadUrl' label='Display Link to Dataset' updateField={updateField} />
|
|
1754
2274
|
{/* <CheckBox value={config.table.showDownloadImgButton} section='table' fieldName='showDownloadImgButton' label='Display Image Button' updateField={updateField} /> */}
|
|
1755
2275
|
{/* <CheckBox value={config.table.showDownloadPdfButton} section='table' fieldName='showDownloadPdfButton' label='Display PDF Button' updateField={updateField} /> */}
|
|
1756
|
-
<TextField value={config.table.label} section='table' fieldName='label' label='Label' updateField={updateField} />
|
|
1757
2276
|
{config.visualizationType !== 'Pie' && <TextField value={config.table.indexLabel} section='table' fieldName='indexLabel' label='Index Column Header' updateField={updateField} />}
|
|
1758
2277
|
</AccordionItemPanel>
|
|
1759
2278
|
</AccordionItem>
|