@cdc/chart 4.23.8 → 4.23.10-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/cdcchart.js +43990 -44283
  2. package/examples/feature/__data__/area-chart-date-apple.json +1 -5073
  3. package/examples/feature/area/area-chart-date-apple.json +73 -10316
  4. package/examples/feature/area/area-chart-date-city-temperature.json +204 -80
  5. package/examples/{private/confidence_interval_test.json → feature/area/area-chart-stacked.json} +65 -74
  6. package/examples/feature/bar/lollipop.json +156 -0
  7. package/examples/feature/combo/planet-combo-example-config.json +99 -9
  8. package/examples/feature/filters/bar-filter.json +5027 -0
  9. package/examples/feature/legend-highlights/highlights.json +567 -0
  10. package/examples/private/TESTING.json +0 -0
  11. package/examples/private/forest-plot.json +356 -0
  12. package/examples/private/{tooltip-issue.json → full.json} +25288 -25239
  13. package/examples/private/missing-color.json +333 -0
  14. package/index.html +30 -8
  15. package/package.json +3 -2
  16. package/src/{CdcChart.jsx → CdcChart.tsx} +81 -74
  17. package/src/_stories/Chart.stories.tsx +188 -0
  18. package/src/components/AreaChart.Stacked.jsx +73 -0
  19. package/src/components/AreaChart.jsx +24 -26
  20. package/src/components/BarChart.StackedVertical.jsx +2 -0
  21. package/src/components/DeviationBar.jsx +67 -13
  22. package/src/components/EditorPanel.jsx +493 -454
  23. package/src/components/Forecasting.jsx +5 -5
  24. package/src/components/ForestPlotSettings.jsx +5 -6
  25. package/src/components/Legend.jsx +18 -9
  26. package/src/components/LineChart.Circle.tsx +102 -0
  27. package/src/components/{LineChart.jsx → LineChart.tsx} +9 -48
  28. package/src/components/LinearChart.jsx +460 -443
  29. package/src/components/PieChart.jsx +54 -25
  30. package/src/components/Series.jsx +63 -17
  31. package/src/components/SparkLine.jsx +7 -19
  32. package/src/data/initial-state.js +10 -1
  33. package/src/hooks/useBarChart.js +1 -1
  34. package/src/hooks/useEditorPermissions.js +87 -24
  35. package/src/hooks/useLegendClasses.js +14 -11
  36. package/src/hooks/useReduceData.js +6 -1
  37. package/src/hooks/useScales.js +4 -4
  38. package/src/hooks/useTooltip.jsx +21 -8
  39. package/src/scss/legend.scss +206 -0
  40. package/src/scss/main.scss +25 -24
  41. package/src/components/DataTable.jsx +0 -374
  42. /package/src/{components → hooks}/useIntersectionObserver.jsx +0 -0
@@ -1,15 +1,17 @@
1
1
  import React, { useContext, useState, useEffect, useRef } from 'react'
2
2
  import { animated, useTransition, interpolate } from 'react-spring'
3
- import { Tooltip as ReactTooltip } from 'react-tooltip'
4
-
5
- import Pie from '@visx/shape/lib/shapes/Pie'
6
3
  import chroma from 'chroma-js'
4
+
5
+ // visx
6
+ import { Pie } from '@visx/shape'
7
7
  import { Group } from '@visx/group'
8
8
  import { Text } from '@visx/text'
9
- import useIntersectionObserver from './useIntersectionObserver'
9
+ import { useTooltip, TooltipWithBounds } from '@visx/tooltip'
10
10
 
11
+ // cove
11
12
  import ConfigContext from '../ConfigContext'
12
-
13
+ import { useTooltip as useCoveTooltip } from '../hooks/useTooltip'
14
+ import useIntersectionObserver from '../hooks/useIntersectionObserver'
13
15
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
14
16
 
15
17
  const enterUpdateTransition = ({ startAngle, endAngle }) => ({
@@ -17,9 +19,15 @@ const enterUpdateTransition = ({ startAngle, endAngle }) => ({
17
19
  endAngle
18
20
  })
19
21
 
20
- export default function PieChart() {
21
- const { transformedData: data, config, dimensions, seriesHighlight, colorScale, formatNumber, currentViewport, handleChartAriaLabels } = useContext(ConfigContext)
22
-
22
+ const PieChart = props => {
23
+ const { transformedData: data, config, dimensions, seriesHighlight, colorScale, formatNumber, currentViewport, handleChartAriaLabels, isEditor } = useContext(ConfigContext)
24
+ const { tooltipData, showTooltip, hideTooltip, tooltipOpen, tooltipLeft, tooltipTop } = useTooltip()
25
+ const { handleTooltipMouseOver, handleTooltipMouseOff, TooltipListItem } = useCoveTooltip({
26
+ xScale: false,
27
+ yScale: false,
28
+ showTooltip,
29
+ hideTooltip
30
+ })
23
31
  const [filteredData, setFilteredData] = useState(undefined)
24
32
  const [animatedPie, setAnimatePie] = useState(false)
25
33
 
@@ -29,7 +37,6 @@ export default function PieChart() {
29
37
  })
30
38
 
31
39
  // Make sure the chart is visible if in the editor
32
- /* eslint-disable react-hooks/exhaustive-deps */
33
40
  useEffect(() => {
34
41
  const element = document.querySelector('.isEditor')
35
42
  if (element) {
@@ -46,7 +53,7 @@ export default function PieChart() {
46
53
  }
47
54
  }, [dataRef?.isIntersecting, config.animate]) // eslint-disable-line
48
55
 
49
- function AnimatedPie({ arcs, path, getKey }) {
56
+ const AnimatedPie = ({ arcs, path, getKey }) => {
50
57
  const transitions = useTransition(arcs, getKey, {
51
58
  from: enterUpdateTransition,
52
59
  enter: enterUpdateTransition,
@@ -54,19 +61,24 @@ export default function PieChart() {
54
61
  leave: enterUpdateTransition
55
62
  })
56
63
 
64
+ // DEV-5053
65
+ // onMouseLeave function doesn't work on animated.path for some reason.
66
+ // As a workaround, we continue to fire the tooltipData while hovered,
67
+ // and use this useEffect to hide the tooltip so it doesn't persist when users scroll.
68
+ useEffect(() => {
69
+ const timeout = setTimeout(() => {
70
+ hideTooltip()
71
+ }, 500)
72
+ return () => {
73
+ clearTimeout(timeout)
74
+ }
75
+ }, [tooltipData])
76
+
57
77
  return (
58
78
  <>
59
- {transitions.map(({ item: arc, props, key }) => {
60
- let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${formatNumber(arc.data[config.runtime.yAxis.dataKey])}` : formatNumber(arc.data[config.runtime.yAxis.dataKey])
61
- let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${arc.data[config.runtime.xAxis.dataKey]}` : arc.data[config.runtime.xAxis.dataKey]
62
-
63
- const tooltip = `<div>
64
- ${yAxisTooltip}<br />
65
- ${xAxisTooltip}<br />
66
- Percent: ${Math.round((((arc.endAngle - arc.startAngle) * 180) / Math.PI / 360) * 100) + '%'}
67
- `
79
+ {transitions.map(({ item: arc, props, key }, animatedPieIndex) => {
68
80
  return (
69
- <Group key={key} style={{ opacity: config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(arc.data[config.runtime.xAxis.dataKey]) === -1 ? 0.5 : 1 }}>
81
+ <Group className={arc.data[config.xAxis.dataKey]} key={`${key}-${animatedPieIndex}`} style={{ opacity: config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(arc.data[config.runtime.xAxis.dataKey]) === -1 ? 0.5 : 1 }}>
70
82
  <animated.path
71
83
  d={interpolate([props.startAngle, props.endAngle], (startAngle, endAngle) =>
72
84
  path({
@@ -76,8 +88,8 @@ export default function PieChart() {
76
88
  })
77
89
  )}
78
90
  fill={colorScale(arc.data[config.runtime.xAxis.dataKey])}
79
- data-tooltip-html={tooltip}
80
- data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
91
+ onMouseEnter={e => handleTooltipMouseOver(e, { data: arc.data[config.runtime.xAxis.dataKey], arc })}
92
+ onMouseLeave={e => handleTooltipMouseOff()}
81
93
  />
82
94
  </Group>
83
95
  )
@@ -138,13 +150,30 @@ export default function PieChart() {
138
150
  <ErrorBoundary component='PieChart'>
139
151
  <svg width={width} height={height} className={`animated-pie group ${config.animate === false || animatedPie ? 'animated' : ''}`} role='img' aria-label={handleChartAriaLabels(config)}>
140
152
  <Group top={centerY} left={centerX}>
141
- <Pie data={filteredData || data} pieValue={d => d[config.runtime.yAxis.dataKey]} pieSortValues={() => -1} innerRadius={radius - donutThickness} outerRadius={radius}>
142
- {pie => <AnimatedPie {...pie} getKey={d => d.data[config.runtime.xAxis.dataKey]} />}
153
+ {/* prettier-ignore */}
154
+ <Pie
155
+ data={filteredData || data}
156
+ pieValue={d => d[config.runtime.yAxis.dataKey]}
157
+ pieSortValues={() => -1}
158
+ innerRadius={radius - donutThickness}
159
+ outerRadius={radius}
160
+ >
161
+ {pie => <AnimatedPie {...pie} getKey={d => d.data[config.runtime.xAxis.dataKey]}/>}
143
162
  </Pie>
144
163
  </Group>
145
164
  </svg>
146
165
  <div ref={triggerRef} />
147
- <ReactTooltip id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} variant='light' arrowColor='rgba(0,0,0,0)' className='tooltip' />
166
+ {tooltipData && Object.entries(tooltipData.data).length > 0 && tooltipOpen && showTooltip && tooltipData.dataYPosition && tooltipData.dataXPosition && (
167
+ <>
168
+ <style>{`.tooltip {background-color: rgba(255,255,255, ${config.tooltips.opacity / 100}) !important`}</style>
169
+ <TooltipWithBounds key={Math.random()} className={'tooltip cdc-open-viz-module'} left={tooltipLeft} top={tooltipTop}>
170
+ <ul>{typeof tooltipData === 'object' && Object.entries(tooltipData.data).map((item, index) => <TooltipListItem item={item} key={index} />)}</ul>
171
+ </TooltipWithBounds>
172
+ </>
173
+ )}
174
+ {/* <ReactTooltip id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} variant='light' arrowColor='rgba(0,0,0,0)' className='tooltip' /> */}
148
175
  </ErrorBoundary>
149
176
  )
150
177
  }
178
+
179
+ export default PieChart
@@ -4,13 +4,14 @@ import ConfigContext from '../ConfigContext'
4
4
  // Core
5
5
  import InputSelect from '@cdc/core/components/inputs/InputSelect'
6
6
  import Check from '@cdc/core/assets/icon-check.svg'
7
+ import { approvedCurveTypes } from '@cdc/core/helpers/lineChartHelpers'
7
8
 
8
9
  import Icon from '@cdc/core/components/ui/Icon'
9
10
 
10
11
  // Third Party
11
12
  import { Accordion, AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
12
13
  import { Draggable } from '@hello-pangea/dnd'
13
- import { colorPalettesChart } from '@cdc/core/data/colorPalettes'
14
+ import { colorPalettesChart, sequentialPalettes } from '@cdc/core/data/colorPalettes'
14
15
 
15
16
  const SeriesContext = React.createContext()
16
17
 
@@ -36,9 +37,17 @@ const SeriesDropdownLineType = props => {
36
37
  const { series, index } = props
37
38
 
38
39
  // Run a quick test to determine if we should even show this.
39
- const supportsLineType = ['Line', 'dashed-sm', 'dashed-md', 'dashed-lg', 'Area Chart'].some(item => item.includes(series.type))
40
+ const supportsLineType = () => {
41
+ let supported = false
42
+ if (config.visualizationSubType === 'stacked') return supported
43
+ const supportedCharts = ['Line', 'dashed-sm', 'dashed-md', 'dashed-lg', 'Area Chart']
44
+ if (supportedCharts.some(item => item.includes(series.type))) {
45
+ supported = true
46
+ }
47
+ return supported
48
+ }
40
49
 
41
- if (!supportsLineType) return
50
+ if (!supportsLineType()) return
42
51
 
43
52
  const changeLineType = (i, value) => {
44
53
  let series = [...config.series]
@@ -46,14 +55,6 @@ const SeriesDropdownLineType = props => {
46
55
  updateConfig({ ...config, series })
47
56
  }
48
57
 
49
- const approvedCurveTypes = {
50
- Linear: 'curveLinear',
51
- Cardinal: 'curveCardinal',
52
- Natural: 'curveNatural',
53
- 'Monotone X': 'curveMonotoneX',
54
- Step: 'curveStep'
55
- }
56
-
57
58
  let options = []
58
59
 
59
60
  Object.keys(approvedCurveTypes).map(curveName => {
@@ -218,6 +219,10 @@ const SeriesDropdownForecastColor = props => {
218
219
  // Hide AxisPositionDropdown in certain cases.
219
220
  if (!series) return
220
221
 
222
+ const allowedForecastingColors = () => {
223
+ return Object.keys(sequentialPalettes)
224
+ }
225
+
221
226
  return series?.stages?.map((stage, stageIndex) => (
222
227
  <InputSelect
223
228
  key={`${stage}--${stageIndex}`}
@@ -235,7 +240,7 @@ const SeriesDropdownForecastColor = props => {
235
240
  series: copyOfSeries
236
241
  })
237
242
  }}
238
- options={Object.keys(colorPalettesChart)}
243
+ options={Object.keys(sequentialPalettes)}
239
244
  />
240
245
  ))
241
246
  }
@@ -290,7 +295,7 @@ const SeriesDropdownConfidenceInterval = props => {
290
295
  </>
291
296
  </AccordionItemHeading>
292
297
  <AccordionItemPanel>
293
- {/* <div className='input-group'>
298
+ <div className='input-group'>
294
299
  <label htmlFor='showInTooltip'>Show In Tooltip</label>
295
300
  <div className={'cove-input__checkbox--small'} onClick={e => updateShowInTooltip(e, index, ciIndex)}>
296
301
  <div className={`cove-input__checkbox-box${'blue' ? ' custom-color' : ''}`} style={{ backgroundColor: '' }}>
@@ -298,7 +303,45 @@ const SeriesDropdownConfidenceInterval = props => {
298
303
  </div>
299
304
  <input className='cove-input--hidden' type='checkbox' name={'showInTooltip'} checked={showInTooltip ? showInTooltip : false} readOnly />
300
305
  </div>
301
- </div> */}
306
+ </div>
307
+
308
+ {/* <label>
309
+ High Label
310
+ <input
311
+ type='text'
312
+ key={`series-ci-high-label-${index}`}
313
+ value={series.confidenceIntervals[index]?.highLabel ? series.confidenceIntervals[index]?.highLabel : ''}
314
+ onChange={e => {
315
+ const copiedConfidenceArray = [...config.series[index].confidenceIntervals]
316
+ copiedConfidenceArray[ciIndex].highLabel = e.target.value
317
+ const copyOfSeries = [...config.series] // copy the entire series array
318
+ copyOfSeries[index] = { ...copyOfSeries[index], confidenceIntervals: copiedConfidenceArray }
319
+ updateConfig({
320
+ ...config,
321
+ series: copyOfSeries
322
+ })
323
+ }}
324
+ />
325
+ </label> */}
326
+
327
+ {/* <label>
328
+ Low label
329
+ <input
330
+ type='text'
331
+ key={`series-ci-high-label-${index}`}
332
+ value={series.confidenceIntervals[index]?.lowLabel ? series.confidenceIntervals[index]?.lowLabel : ''}
333
+ onChange={e => {
334
+ const copiedConfidenceArray = [...config.series[index].confidenceIntervals]
335
+ copiedConfidenceArray[ciIndex].lowLabel = e.target.value
336
+ const copyOfSeries = [...config.series] // copy the entire series array
337
+ copyOfSeries[index] = { ...copyOfSeries[index], confidenceIntervals: copiedConfidenceArray }
338
+ updateConfig({
339
+ ...config,
340
+ series: copyOfSeries
341
+ })
342
+ }}
343
+ />
344
+ </label> */}
302
345
 
303
346
  <InputSelect
304
347
  initial='Select an option'
@@ -375,11 +418,15 @@ const SeriesInputName = props => {
375
418
  let series = [...config.series]
376
419
  let seriesLabelsCopy = { ...config.runtime.seriesLabels }
377
420
  series[i].name = value
378
- seriesLabelsCopy[series[i].dataKey] = series[i].name
421
+ seriesLabelsCopy[series[i].dataKey] = series[i].name ? series[i].name : series[i].dataKey
379
422
 
380
423
  let newConfig = {
381
424
  ...config,
382
- series
425
+ series,
426
+ runtime: {
427
+ ...config.runtime,
428
+ seriesLabels: seriesLabelsCopy
429
+ }
383
430
  }
384
431
 
385
432
  updateConfig(newConfig)
@@ -506,7 +553,6 @@ const SeriesItem = props => {
506
553
  <Series.Dropdown.SeriesType series={series} index={i} />
507
554
  <Series.Dropdown.AxisPosition series={series} index={i} />
508
555
  <Series.Dropdown.LineType series={series} index={i} />
509
- {/* <Series.Dropdown.ForecastingStage series={series} index={i} /> */}
510
556
  <Series.Dropdown.ForecastingColor series={series} index={i} />
511
557
  <Series.Dropdown.ConfidenceInterval series={series} index={i} />
512
558
  <Series.Checkbox.DisplayInTooltip series={series} index={i} />
@@ -6,6 +6,7 @@ import { LinePath } from '@visx/shape'
6
6
  import { Text } from '@visx/text'
7
7
  import { scaleLinear, scalePoint } from '@visx/scale'
8
8
  import { AxisBottom } from '@visx/axis'
9
+
9
10
  import { MarkerArrow } from '@visx/marker'
10
11
 
11
12
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
@@ -14,7 +15,8 @@ import useReduceData from '../hooks/useReduceData'
14
15
 
15
16
  import ConfigContext from '../ConfigContext'
16
17
 
17
- export default function SparkLine({ width: parentWidth, height: parentHeight }) {
18
+ const SparkLine = props => {
19
+ const { width: parentWidth, height: parentHeight } = props
18
20
  const { transformedData: data, config, parseDate, formatDate, seriesHighlight, formatNumber, colorScale, handleChartAriaLabels } = useContext(ConfigContext)
19
21
  let width = parentWidth
20
22
  const { minValue, maxValue } = useReduceData(config, data, ConfigContext)
@@ -91,16 +93,14 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
91
93
 
92
94
  return (
93
95
  <ErrorBoundary component='SparkLine'>
94
- <svg role='img' aria-label={handleChartAriaLabels(config)} width={width} height={height} className={'sparkline'} tabIndex={0}>
96
+ <svg role='img' aria-label={handleChartAriaLabels(config)} width={parentWidth} height={100} className={'sparkline'} tabIndex={0}>
95
97
  {config.runtime.lineSeriesKeys?.length > 0
96
98
  ? config.runtime.lineSeriesKeys
97
99
  : config.runtime.seriesKeys.map((seriesKey, index) => (
98
100
  <>
99
101
  <Group
102
+ style={{ width }}
100
103
  className='sparkline-group'
101
- height={parentHeight}
102
- style={{ height: parentHeight }}
103
- top={margin.top}
104
104
  key={`series-${seriesKey}`}
105
105
  opacity={config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(seriesKey) === -1 ? 0.5 : 1}
106
106
  display={config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(seriesKey) !== -1 ? 'block' : 'none'}
@@ -115,25 +115,11 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
115
115
  ${config.seriesLabel ? `${config.seriesLabel}: ${seriesKey}` : ''}
116
116
  </div>`
117
117
 
118
- let circleRadii = 4.5
119
118
  return (
120
119
  <Group key={`series-${seriesKey}-point-${dataIndex}`}>
121
120
  <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'>
122
121
  {formatNumber(d[seriesKey])}
123
122
  </Text>
124
- {/* hide data point circles */}
125
- {/* dataIndex + 1 !== data.length && (config.lineDatapointStyle === 'always show' || config.lineDatapointStyle === 'hover') && (
126
- <circle
127
- key={`${seriesKey}-${dataIndex}`}
128
- r={circleRadii}
129
- cx={xScale(getXAxisData(d))}
130
- cy={yScale(getYAxisData(d, seriesKey))}
131
- fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
132
- style={{ fill: colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000' }}
133
- data-tooltip-html={tooltip}
134
- data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
135
- />
136
- )*/}
137
123
  </Group>
138
124
  )
139
125
  })}
@@ -180,3 +166,5 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
180
166
  </ErrorBoundary>
181
167
  )
182
168
  }
169
+
170
+ export default SparkLine
@@ -1,6 +1,9 @@
1
1
  export default {
2
2
  type: 'chart',
3
3
  debugSvg: false,
4
+ chartMessage: {
5
+ noData: 'No Data Available'
6
+ },
4
7
  title: '',
5
8
  showTitle: true,
6
9
  showDownloadMediaButton: false,
@@ -92,6 +95,7 @@ export default {
92
95
  horizontal: 750
93
96
  },
94
97
  xAxis: {
98
+ sortDates: false,
95
99
  anchors: [],
96
100
  type: 'categorical',
97
101
  showTargetLabel: true,
@@ -139,7 +143,9 @@ export default {
139
143
  dynamicLegendDefaultText: 'Show All',
140
144
  dynamicLegendItemLimit: 5,
141
145
  dynamicLegendItemLimitMessage: 'Dynamic Legend Item Limit Hit.',
142
- dynamicLegendChartMessage: 'Select Options from the Legend'
146
+ dynamicLegendChartMessage: 'Select Options from the Legend',
147
+ lineMode: false,
148
+ verticalSorted: false
143
149
  },
144
150
  exclusions: {
145
151
  active: false,
@@ -216,5 +222,8 @@ export default {
216
222
  brush: {
217
223
  pattern_id: 'brush_pattern',
218
224
  accent_color: '#ddd'
225
+ },
226
+ area: {
227
+ isStacked: false
219
228
  }
220
229
  }
@@ -80,7 +80,7 @@ export const useBarChart = () => {
80
80
  if (!config.legend.colorCode && config.series.length > 1) {
81
81
  return currentBarColor
82
82
  }
83
- const palettesArr = colorPalettes[config.palette]
83
+ const palettesArr = config.customColors ?? colorPalettes[config.palette]
84
84
  const values = tableData.map(d => {
85
85
  return d[config.legend.colorCode]
86
86
  })
@@ -14,7 +14,7 @@ export const useEditorPermissions = () => {
14
14
  'Combo',
15
15
  'Deviation Bar',
16
16
  'Forecasting',
17
- // 'Forest Plot',
17
+ 'Forest Plot',
18
18
  'Line',
19
19
  'Paired Bar',
20
20
  'Pie',
@@ -22,14 +22,28 @@ export const useEditorPermissions = () => {
22
22
  'Spark Line'
23
23
  ]
24
24
 
25
+ const headerColors = ['theme-blue', 'theme-purple', 'theme-brown', 'theme-teal', 'theme-pink', 'theme-orange', 'theme-slate', 'theme-indigo', 'theme-cyan', 'theme-green', 'theme-amber']
26
+
27
+ const visSupportsSuperTitle = () => {
28
+ const disabledCharts = ['Spark Line']
29
+ if (disabledCharts.includes(visualizationType)) return false
30
+ return true
31
+ }
32
+
33
+ const visSupportsFootnotes = () => {
34
+ const disabledCharts = ['Spark Line']
35
+ if (disabledCharts.includes(visualizationType)) return false
36
+ return true
37
+ }
38
+
25
39
  const visHasLabelOnData = () => {
26
- const disabledCharts = ['Area Chart', 'Box Plot', 'Pie', 'Scatter Plot', 'Forest Plot']
40
+ const disabledCharts = ['Area Chart', 'Box Plot', 'Pie', 'Scatter Plot', 'Forest Plot', 'Spark Line']
27
41
  if (disabledCharts.includes(visualizationType)) return false
28
42
  return true
29
43
  }
30
44
 
31
45
  const visCanAnimate = () => {
32
- const disabledCharts = ['Area Chart', 'Scatter Plot', 'Box Plot', 'Forest Plot']
46
+ const disabledCharts = ['Area Chart', 'Scatter Plot', 'Box Plot', 'Forest Plot', 'Spark Line']
33
47
  if (disabledCharts.includes(visualizationType)) return false
34
48
  return true
35
49
  }
@@ -40,6 +54,8 @@ export const useEditorPermissions = () => {
40
54
  return false
41
55
  case 'Forest Plot':
42
56
  return false
57
+ case 'Spark Line':
58
+ return false
43
59
  default:
44
60
  return true
45
61
  }
@@ -82,11 +98,19 @@ export const useEditorPermissions = () => {
82
98
  return false
83
99
  case 'Pie':
84
100
  return false
101
+ case 'Spark Line':
102
+ return false
85
103
  default:
86
104
  return true
87
105
  }
88
106
  }
89
107
 
108
+ const visSupportsTooltipOpacity = () => {
109
+ const disabledCharts = ['Spark Line']
110
+ if (disabledCharts.includes(visualizationType)) return false
111
+ return true
112
+ }
113
+
90
114
  const visSupportsTooltipLines = () => {
91
115
  const enabledCharts = ['Combo', 'Forecasting', 'Area Chart', 'Line', 'Bar']
92
116
  if (enabledCharts.includes(visualizationType)) return true
@@ -94,13 +118,13 @@ export const useEditorPermissions = () => {
94
118
  }
95
119
 
96
120
  const visSupportsSequentialPallete = () => {
97
- const disabledCharts = ['Paired Bar', 'Deviation Bar', 'Forest Plot']
121
+ const disabledCharts = ['Paired Bar', 'Deviation Bar', 'Forest Plot', 'Forecasting']
98
122
  if (disabledCharts.includes(visualizationType)) return false
99
123
  return true
100
124
  }
101
125
 
102
126
  const visSupportsNonSequentialPallete = () => {
103
- const disabledCharts = ['Paired Bar', 'Deviation Bar', 'Forest Plot']
127
+ const disabledCharts = ['Paired Bar', 'Deviation Bar', 'Forest Plot', 'Forecasting']
104
128
  if (disabledCharts.includes(visualizationType)) return false
105
129
  return true
106
130
  }
@@ -112,37 +136,43 @@ export const useEditorPermissions = () => {
112
136
  }
113
137
 
114
138
  const visSupportsDateCategoryAxisLabel = () => {
115
- const disabledCharts = ['Forest Plot']
139
+ const disabledCharts = ['Forest Plot', 'Spark Line']
116
140
  if (disabledCharts.includes(visualizationType)) return false
117
141
  return true
118
142
  }
119
143
 
120
144
  const visSupportsDateCategoryAxisLine = () => {
121
- const disabledCharts = ['Forest Plot']
145
+ const disabledCharts = ['Forest Plot', 'Spark Line']
122
146
  if (disabledCharts.includes(visualizationType)) return false
123
147
  return true
124
148
  }
125
149
 
126
150
  const visSupportsDateCategoryAxisTicks = () => {
127
- const disabledCharts = ['Forest Plot']
151
+ const disabledCharts = ['Forest Plot', 'Spark Line']
128
152
  if (disabledCharts.includes(visualizationType)) return false
129
153
  return true
130
154
  }
131
155
 
132
156
  const visSupportsDateCategoryTickRotation = () => {
133
- const disabledCharts = ['Forest Plot']
157
+ const disabledCharts = ['Forest Plot', 'Spark Line']
134
158
  if (disabledCharts.includes(visualizationType)) return false
135
159
  return true
136
160
  }
137
161
 
138
162
  const visSupportsDateCategoryNumTicks = () => {
139
- const disabledCharts = ['Forest Plot']
163
+ const disabledCharts = ['Forest Plot', 'Spark Line']
164
+ if (disabledCharts.includes(visualizationType)) return false
165
+ return true
166
+ }
167
+
168
+ const visSupportsResponsiveTicks = () => {
169
+ const disabledCharts = ['Spark Line']
140
170
  if (disabledCharts.includes(visualizationType)) return false
141
171
  return true
142
172
  }
143
173
 
144
174
  const visSupportsRegions = () => {
145
- const disabledCharts = ['Forest Plot', 'Pie', 'Paired Bar']
175
+ const disabledCharts = ['Forest Plot', 'Pie', 'Paired Bar', 'Spark Line']
146
176
  if (disabledCharts.includes(visualizationType)) return false
147
177
  return true
148
178
  }
@@ -188,31 +218,64 @@ export const useEditorPermissions = () => {
188
218
  return true
189
219
  }
190
220
 
221
+ const visSupportsChartHeight = () => {
222
+ const disabledCharts = ['Spark Line']
223
+ if (disabledCharts.includes(visualizationType)) return false
224
+ return true
225
+ }
226
+
227
+ const visSupportsLeftValueAxis = () => {
228
+ const disabledCharts = ['Spark Line']
229
+ if (disabledCharts.includes(visualizationType)) return false
230
+ return true
231
+ }
232
+
233
+ const visSupportsRankByValue = () => {
234
+ const disabledCharts = ['Spark Line']
235
+ if (disabledCharts.includes(visualizationType)) return false
236
+ return true
237
+ }
238
+
239
+ const visSupportsDateCategoryHeight = () => {
240
+ const disabledCharts = ['Spark Line']
241
+ if (disabledCharts.includes(visualizationType)) return false
242
+ return true
243
+ }
244
+
191
245
  return {
192
246
  enabledChartTypes,
193
- visHasLabelOnData,
194
- visHasNumbersOnBars,
247
+ headerColors,
248
+ visCanAnimate,
195
249
  visHasAnchors,
196
250
  visHasBarBorders,
197
251
  visHasDataCutoff,
198
- visCanAnimate,
252
+ visHasLabelOnData,
199
253
  visHasLegend,
200
- visSupportsTooltipLines,
201
- visSupportsNonSequentialPallete,
202
- visSupportsSequentialPallete,
203
- visSupportsReverseColorPalette,
254
+ visHasNumbersOnBars,
255
+ visSupportsBarSpace,
256
+ visSupportsBarThickness,
257
+ visSupportsChartHeight,
204
258
  visSupportsDateCategoryAxisLabel,
205
259
  visSupportsDateCategoryAxisLine,
206
260
  visSupportsDateCategoryAxisTicks,
207
- visSupportsDateCategoryTickRotation,
261
+ visSupportsDateCategoryHeight,
208
262
  visSupportsDateCategoryNumTicks,
209
- visSupportsRegions,
263
+ visSupportsDateCategoryTickRotation,
210
264
  visSupportsFilters,
265
+ visSupportsFootnotes,
266
+ visSupportsLeftValueAxis,
267
+ visSupportsNonSequentialPallete,
268
+ visSupportsRankByValue,
269
+ visSupportsRegions,
270
+ visSupportsResponsiveTicks,
271
+ visSupportsReverseColorPalette,
272
+ visSupportsSequentialPallete,
273
+ visSupportsSuperTitle,
274
+ visSupportsTooltipLines,
275
+ visSupportsTooltipOpacity,
211
276
  visSupportsValueAxisGridLines,
212
- visSupportsValueAxisTicks,
213
- visSupportsValueAxisLine,
214
277
  visSupportsValueAxisLabels,
215
- visSupportsBarSpace,
216
- visSupportsBarThickness
278
+ visSupportsValueAxisLine,
279
+ visSupportsValueAxisTicks
217
280
  }
218
281
  }
@@ -2,24 +2,27 @@ export default function useLegendClasses(config) {
2
2
  let containerClasses = ['legend-container']
3
3
  let innerClasses = ['legend-container__inner']
4
4
 
5
- // Legend Positioning
6
- if (config.legend.position === "left") {
7
- containerClasses.push('left')
8
- }
9
- if (config.legend.position === "bottom") {
10
- containerClasses.push('bottom')
11
- innerClasses.push('bottom')
12
- }
5
+ // Legend Positioning
6
+ if (config.legend.position === 'left') {
7
+ containerClasses.push('left')
8
+ }
9
+ if (config.legend.position === 'bottom') {
10
+ containerClasses.push('bottom')
11
+ innerClasses.push('bottom')
12
+ }
13
13
 
14
- if(config.legend.position==='bottom' && config.legend.singleRow){
15
- innerClasses.push('single-row')
16
- }
14
+ if (config.legend.position === 'bottom' && config.legend.singleRow) {
15
+ innerClasses.push('single-row')
16
+ }
17
17
 
18
18
  // Legend > Item Ordering
19
19
  if (config.legend.reverseLabelOrder) {
20
20
  innerClasses.push('d-flex')
21
21
  innerClasses.push('flex-column-reverse')
22
22
  }
23
+ if (config.legend.position === 'bottom' && config.legend.verticalSorted) {
24
+ innerClasses.push('vertical-sorted')
25
+ }
23
26
 
24
27
  return {
25
28
  containerClasses,