@cdc/chart 4.24.1 → 4.24.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/cdcchart.js +48948 -37923
  2. package/examples/{private/combo.json → chart-regression-1.json} +40 -31
  3. package/examples/chart-regression-2.json +2360 -0
  4. package/examples/feature/filters/url-filter.json +1076 -0
  5. package/examples/feature/line/line-chart-preliminary.json +84 -37
  6. package/examples/feature/line/line-chart.json +2 -1
  7. package/examples/feature/regions/index.json +55 -5
  8. package/examples/feature/sankey/sankey-example-data.json +1364 -0
  9. package/examples/feature/sankey/sankey_chart_data.csv +20 -0
  10. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +306 -19
  11. package/examples/sparkline.json +868 -0
  12. package/index.html +128 -121
  13. package/package.json +4 -2
  14. package/src/CdcChart.tsx +73 -38
  15. package/src/_stories/ChartEditor.stories.tsx +15 -4
  16. package/src/_stories/_mock/pie_config.json +4 -3
  17. package/src/_stories/_mock/url_filter.json +1076 -0
  18. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +2 -1
  19. package/src/components/AreaChart/components/AreaChart.jsx +2 -25
  20. package/src/components/BarChart/components/BarChart.Horizontal.tsx +39 -49
  21. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +36 -56
  22. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +36 -41
  23. package/src/components/BarChart/components/BarChart.Vertical.tsx +48 -64
  24. package/src/components/BoxPlot/BoxPlot.jsx +11 -9
  25. package/src/components/DeviationBar.jsx +3 -3
  26. package/src/components/EditorPanel/EditorPanel.tsx +1717 -1961
  27. package/src/components/EditorPanel/EditorPanelContext.ts +40 -0
  28. package/src/components/EditorPanel/components/Panels/Panel.BoxPlot.tsx +148 -0
  29. package/src/components/EditorPanel/components/{Panel.ForestPlotSettings.tsx → Panels/Panel.ForestPlotSettings.tsx} +16 -7
  30. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +160 -0
  31. package/src/components/EditorPanel/components/{Panel.Regions.tsx → Panels/Panel.Regions.tsx} +6 -6
  32. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +108 -0
  33. package/src/components/EditorPanel/components/{Panel.Series.tsx → Panels/Panel.Series.tsx} +50 -6
  34. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +338 -0
  35. package/src/components/EditorPanel/components/Panels/index.tsx +19 -0
  36. package/src/components/EditorPanel/components/panels.scss +11 -0
  37. package/src/components/EditorPanel/editor-panel.scss +1 -13
  38. package/src/components/EditorPanel/useEditorPermissions.js +44 -13
  39. package/src/components/Legend/Legend.Component.tsx +207 -0
  40. package/src/components/Legend/Legend.tsx +8 -327
  41. package/src/components/Legend/helpers/createFormatLabels.tsx +140 -0
  42. package/src/components/LineChart/LineChartProps.ts +2 -1
  43. package/src/components/LineChart/components/LineChart.Circle.tsx +85 -52
  44. package/src/components/LineChart/helpers.ts +3 -3
  45. package/src/components/LineChart/index.tsx +99 -23
  46. package/src/components/LinearChart.jsx +12 -33
  47. package/src/components/PairedBarChart.jsx +10 -12
  48. package/src/components/PieChart/PieChart.tsx +80 -27
  49. package/src/components/Regions/components/Regions.tsx +120 -69
  50. package/src/components/Sankey/index.tsx +434 -0
  51. package/src/components/Sankey/sankey.scss +153 -0
  52. package/src/components/Sankey/types/index.ts +16 -0
  53. package/src/components/ScatterPlot/ScatterPlot.jsx +1 -0
  54. package/src/components/Sparkline/{SparkLine.jsx → components/SparkLine.tsx} +14 -30
  55. package/src/components/Sparkline/index.scss +3 -0
  56. package/src/components/Sparkline/index.tsx +1 -1
  57. package/src/components/ZoomBrush.tsx +2 -1
  58. package/src/data/initial-state.js +51 -4
  59. package/src/helpers/computeMarginBottom.ts +4 -3
  60. package/src/helpers/tests/computeMarginBottom.test.ts +2 -1
  61. package/src/hooks/useBarChart.js +5 -2
  62. package/src/hooks/useHighlightedBars.js +1 -1
  63. package/src/hooks/useMinMax.ts +3 -3
  64. package/src/hooks/useScales.ts +28 -18
  65. package/src/hooks/useTooltip.tsx +19 -14
  66. package/src/scss/main.scss +8 -96
  67. package/src/types/ChartConfig.ts +47 -20
  68. package/src/types/ChartContext.ts +17 -4
  69. package/src/types/Label.ts +7 -0
  70. package/examples/private/chart-t.json +0 -3740
  71. package/examples/private/epi-data.csv +0 -13
  72. package/examples/private/epi-data.json +0 -62
  73. package/examples/private/epi.json +0 -403
  74. package/examples/private/occupancy.json +0 -109283
  75. package/examples/private/prod-line-config.json +0 -401
  76. package/examples/private/region-data.json +0 -822
  77. package/examples/private/region-testing.json +0 -312
  78. package/examples/private/scaling.json +0 -45325
  79. package/examples/private/testing-data.json +0 -1739
  80. package/examples/private/testing.json +0 -816
  81. package/src/components/EditorPanel/components/Panel.DateHighlighting.tsx +0 -109
  82. package/src/components/EditorPanel/components/Panels.tsx +0 -13
@@ -8,6 +8,9 @@ import { BarGroup } from '@visx/shape'
8
8
  import { useHighlightedBars } from '../../../hooks/useHighlightedBars'
9
9
  import { FaStar } from 'react-icons/fa'
10
10
  import Regions from './../../Regions'
11
+ import { isDateScale } from '@cdc/core/helpers/cove/date'
12
+
13
+ import createBarElement from '@cdc/core/components/createBarElement'
11
14
 
12
15
  // third party
13
16
  import chroma from 'chroma-js'
@@ -73,7 +76,10 @@ export const BarChartVertical = () => {
73
76
  data={data}
74
77
  keys={config.runtime.barSeriesKeys || config.runtime.seriesKeys}
75
78
  height={yMax}
76
- x0={d => d[config.runtime.originalXAxis.dataKey]}
79
+ x0={d => {
80
+ const rawXValue = d[config.runtime.originalXAxis.dataKey]
81
+ return isDateScale(config.runtime.xAxis) ? parseDate(rawXValue) : rawXValue
82
+ }}
77
83
  x0Scale={xScale}
78
84
  x1Scale={seriesScale}
79
85
  yScale={yScale}
@@ -83,7 +89,7 @@ export const BarChartVertical = () => {
83
89
  >
84
90
  {barGroups => {
85
91
  return barGroups.map((barGroup, index) => (
86
- <Group className={`bar-group-${barGroup.index}-${barGroup.x0}--${index} ${config.orientation}`} key={`bar-group-${barGroup.index}-${barGroup.x0}--${index}`} id={`bar-group-${barGroup.index}-${barGroup.x0}--${index}`} left={(xMax / barGroups.length) * barGroup.index}>
92
+ <Group className={`bar-group-${barGroup.index}-${barGroup.x0}--${index} ${config.orientation}`} key={`bar-group-${barGroup.index}-${barGroup.x0}--${index}`} id={`bar-group-${barGroup.index}-${barGroup.x0}--${index}`} left={barGroup.x0}>
87
93
  {barGroup.bars.map((bar, index) => {
88
94
  const scaleVal = config.useLogScale ? 0.1 : 0
89
95
  const suppresedBarHeight = 20
@@ -96,14 +102,10 @@ export const BarChartVertical = () => {
96
102
  const supprssedBarY = bar.value >= 0 && isNumber(bar.value) ? yScale(scaleVal) - suppresedBarHeight : yScale(0)
97
103
  const barY = config.suppressedData.some(d => bar.key === d.column && String(bar.value) === String(d.value)) ? supprssedBarY : barYBase
98
104
 
99
- let barGroupWidth = (xMax / barGroups.length) * (config.barThickness || 0.8)
100
- let offset = ((xMax / barGroups.length) * (1 - (config.barThickness || 0.8))) / 2
101
- // configure left side offset of lollipop bars
102
- if (config.isLollipopChart) {
103
- offset = xMax / barGroups.length / 2 - lollipopBarWidth / 2
104
- }
105
+ let barGroupWidth = seriesScale.range()[1]
105
106
 
106
107
  let barWidth = config.isLollipopChart ? lollipopBarWidth : barGroupWidth / barGroup.bars.length
108
+ let barX = bar.x + (config.isLollipopChart ? (barGroupWidth / barGroup.bars.length - lollipopBarWidth) / 2 : 0) - (config.xAxis.type === 'date-time' ? barGroupWidth / 2 : 0)
107
109
  setBarWidth(barWidth)
108
110
  setTotalBarsInGroup(barGroup.bars.length)
109
111
 
@@ -112,7 +114,6 @@ export const BarChartVertical = () => {
112
114
 
113
115
  // create new Index for bars with negative values
114
116
  const newIndex = bar.value < 0 ? -1 : index
115
- const borderRadius = applyRadius(newIndex)
116
117
  // tooltips
117
118
 
118
119
  const additionalColTooltip = getAdditionalColumn(bar.key, data[barGroup.index][config.runtime.originalXAxis.dataKey])
@@ -180,57 +181,43 @@ export const BarChartVertical = () => {
180
181
  return _barColor
181
182
  }
182
183
 
183
- const getLeft = () => {
184
- if (barWidth < 50 && barWidth > 15) return barWidth / 2.5
185
- if (barWidth < 15 && barWidth > 5) return barWidth / 6
186
- if (barWidth < 5) return 0
187
- return barWidth / 2
188
- }
189
- const iconStyle: { [key: string]: any } = {
190
- position: 'absolute',
191
- top: bar.value >= 0 && isNumber(bar.value) ? -suppresedBarHeight : undefined,
192
- bottom: bar.value >= 0 && isNumber(bar.value) ? undefined : `-${suppresedBarHeight}px`,
193
- left: getLeft()
194
- }
195
-
196
- if (config.isLollipopChart) {
197
- iconStyle.left = 0
198
- iconStyle.transform = `translateX(0)`
199
- }
200
-
201
- const finalStyle = {
202
- background: getBarBackgroundColor(barColor),
203
- borderColor,
204
- borderStyle: 'solid',
205
- borderWidth: `${borderWidth}px`,
206
- width: barWidth,
207
- height: barHeight,
208
- ...borderRadius,
209
- cursor: dashboardConfig ? 'pointer' : 'default'
210
- }
211
-
212
184
  return (
213
185
  <Group key={`${barGroup.index}--${index}`}>
214
- {/* This feels gross but inline transition was not working well*/}
215
- <style>
216
- {`
217
- .linear #barGroup${barGroup.index} div,
218
- .Combo #barGroup${barGroup.index} div {
219
- transform-origin: 0 ${barY + barHeight}px;
220
- }
221
- `}
222
- </style>
223
186
  <Group key={`bar-sub-group-${barGroup.index}-${barGroup.x0}-${barY}--${index}`}>
224
- <foreignObject
187
+ {createBarElement({
188
+ config: config,
189
+ index: newIndex,
190
+ id: `barGroup${barGroup.index}`,
191
+ background: getBarBackgroundColor(barColor),
192
+ borderColor,
193
+ borderStyle: 'solid',
194
+ borderWidth: `${borderWidth}px`,
195
+ width: barWidth,
196
+ height: barHeight,
197
+ x: barX,
198
+ y: barY,
199
+ onMouseOver: () => onMouseOverBar(xAxisValue, bar.key),
200
+ onMouseLeave: onMouseLeaveBar,
201
+ tooltipHtml: tooltip,
202
+ tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
203
+ onClick: e => {
204
+ e.preventDefault()
205
+ if (setSharedFilter) {
206
+ bar[config.xAxis.dataKey] = xAxisValue
207
+ setSharedFilter(config.uid, bar)
208
+ }
209
+ },
210
+ styleOverrides: {
211
+ transformOrigin: `0 ${barY + barHeight}px`,
212
+ opacity: transparentBar ? 0.2 : 1,
213
+ display: displayBar ? 'block' : 'none',
214
+ cursor: dashboardConfig ? 'pointer' : 'default'
215
+ }
216
+ })}
217
+ <g
218
+ transform={`translate(${barX},${yMax - suppresedBarHeight})`}
225
219
  onMouseOver={() => onMouseOverBar(xAxisValue, bar.key)}
226
220
  onMouseLeave={onMouseLeaveBar}
227
- style={{ overflow: 'visible', transition: 'all 0.2s linear' }}
228
- id={`barGroup${barGroup.index}`}
229
- key={`bar-group-bar-${barGroup.index}-${bar.index}-${bar.value}-${bar.key}`}
230
- x={barWidth * bar.index + offset}
231
- y={barY}
232
- width={barWidth}
233
- height={barHeight}
234
221
  opacity={transparentBar ? 0.2 : 1}
235
222
  display={displayBar ? 'block' : 'none'}
236
223
  data-tooltip-html={tooltip}
@@ -243,16 +230,13 @@ export const BarChartVertical = () => {
243
230
  }
244
231
  }}
245
232
  >
246
- <div style={{ position: 'relative' }}>
247
- <div style={iconStyle}>{getIcon(bar, barWidth)}</div>
248
- <div style={{ ...finalStyle }}></div>
249
- </div>
250
- </foreignObject>
233
+ {getIcon(bar, barWidth)}
234
+ </g>
251
235
 
252
236
  <Text // prettier-ignore
253
237
  display={config.labels && displayBar ? 'block' : 'none'}
254
238
  opacity={transparentBar ? 0.5 : 1}
255
- x={barWidth * (bar.index + 0.5) + offset}
239
+ x={barX + barWidth / 2}
256
240
  y={barY - 5}
257
241
  fill={labelColor}
258
242
  textAnchor='middle'
@@ -263,7 +247,7 @@ export const BarChartVertical = () => {
263
247
  {config.isLollipopChart && config.lollipopShape === 'circle' && (
264
248
  <circle
265
249
  display={displaylollipopShape}
266
- cx={barWidth * (barGroup.bars.length - bar.index - 1) + offset + lollipopShapeSize / 3.5}
250
+ cx={barX + lollipopShapeSize / 3.5}
267
251
  cy={bar.y}
268
252
  r={lollipopShapeSize / 2}
269
253
  fill={barColor}
@@ -276,7 +260,7 @@ export const BarChartVertical = () => {
276
260
  {config.isLollipopChart && config.lollipopShape === 'square' && (
277
261
  <rect
278
262
  display={displaylollipopShape}
279
- x={offset - lollipopBarWidth / 2}
263
+ x={barX - lollipopBarWidth / 2}
280
264
  y={barY}
281
265
  width={lollipopShapeSize}
282
266
  height={lollipopShapeSize}
@@ -304,7 +288,7 @@ export const BarChartVertical = () => {
304
288
  let upperPos
305
289
  let lowerPos
306
290
  let tickWidth = 5
307
- xPos = xScale(getXAxisData(d))
291
+ xPos = xScale(getXAxisData(d)) + (config.xAxis.type !== 'date' || config.xAxis.type !== 'date-time' ? seriesScale.range()[1] / 2 : 0)
308
292
  upperPos = yScale(getYAxisData(d, config.confidenceKeys.lower))
309
293
  lowerPos = yScale(getYAxisData(d, config.confidenceKeys.upper))
310
294
  return (
@@ -7,6 +7,7 @@ import { colorPalettesChart } from '@cdc/core/data/colorPalettes'
7
7
 
8
8
  const CoveBoxPlot = ({ xScale, yScale }) => {
9
9
  const { config, setConfig } = useContext(ConfigContext)
10
+ const { boxplot } = config
10
11
 
11
12
  useEffect(() => {
12
13
  if (config.legend.hide === false) {
@@ -25,10 +26,10 @@ const CoveBoxPlot = ({ xScale, yScale }) => {
25
26
  const handleTooltip = d => {
26
27
  return `
27
28
  <strong>${d.columnCategory}</strong></br>
28
- ${config.boxplot.labels.q1}: ${d.columnFirstQuartile}<br/>
29
- ${config.boxplot.labels.q3}: ${d.columnThirdQuartile}<br/>
30
- ${config.boxplot.labels.iqr}: ${d.columnIqr}<br/>
31
- ${config.boxplot.labels.median}: ${d.columnMedian}
29
+ ${boxplot.labels.q1}: ${d.columnFirstQuartile}<br/>
30
+ ${boxplot.labels.q3}: ${d.columnThirdQuartile}<br/>
31
+ ${boxplot.labels.iqr}: ${d.columnIqr}<br/>
32
+ ${boxplot.labels.median}: ${d.columnMedian}
32
33
  `
33
34
  }
34
35
 
@@ -46,12 +47,12 @@ const CoveBoxPlot = ({ xScale, yScale }) => {
46
47
  return (
47
48
  <ErrorBoundary component='BoxPlot'>
48
49
  <Group className='boxplot' key={`boxplot-group`}>
49
- {config.boxplot.plots.map((d, i) => {
50
+ {boxplot.plots.map((d, i) => {
50
51
  const offset = boxWidth - constrainedWidth
51
52
  const radius = 4
52
53
  return (
53
54
  <Group key={`boxplotplot-${i}`}>
54
- {config.boxplot.plotNonOutlierValues &&
55
+ {boxplot.plotNonOutlierValues &&
55
56
  d.nonOutlierValues.map((value, index) => {
56
57
  return <circle cx={xScale(d.columnCategory) + Number(config.yAxis.size) + boxWidth / 2} cy={yScale(value)} r={radius} fill={'#ccc'} style={{ opacity: 1, fillOpacity: 1, stroke: 'black' }} key={`boxplot-${i}--circle-${index}`} />
57
58
  })}
@@ -69,7 +70,7 @@ const CoveBoxPlot = ({ xScale, yScale }) => {
69
70
  fillOpacity={fillOpacity}
70
71
  stroke='black'
71
72
  valueScale={yScale}
72
- outliers={config.boxplot.plotOutlierValues ? d.columnOutliers : []}
73
+ outliers={boxplot.plotOutlierValues ? d.columnOutliers : []}
73
74
  outlierProps={{
74
75
  style: {
75
76
  fill: `${color_0}`,
@@ -84,7 +85,7 @@ const CoveBoxPlot = ({ xScale, yScale }) => {
84
85
  boxProps={{
85
86
  style: {
86
87
  stroke: 'black',
87
- strokeWidth: config.boxplot.borders === 'true' ? 1 : 0
88
+ strokeWidth: boxplot.borders === 'true' ? 1 : 0
88
89
  }
89
90
  }}
90
91
  maxProps={{
@@ -95,7 +96,8 @@ const CoveBoxPlot = ({ xScale, yScale }) => {
95
96
  container
96
97
  containerProps={{
97
98
  'data-tooltip-html': handleTooltip(d),
98
- 'data-tooltip-id': tooltip_id
99
+ 'data-tooltip-id': tooltip_id,
100
+ tabIndex: -1
99
101
  }}
100
102
  />
101
103
  </Group>
@@ -4,8 +4,8 @@ import { useContext, useEffect, useRef, useState } from 'react'
4
4
  import ConfigContext from '../ConfigContext'
5
5
  import { Text } from '@visx/text'
6
6
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
7
- import chroma from 'chroma-js'
8
7
  import useIntersectionObserver from '../hooks/useIntersectionObserver'
8
+ import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
9
9
 
10
10
  export default function DeviationBar({ height, xScale }) {
11
11
  const { transformedData: data, config, formatNumber, twoColorPalette, getTextWidth, updateConfig, parseDate, formatDate, currentViewport } = useContext(ConfigContext)
@@ -160,8 +160,7 @@ export default function DeviationBar({ height, xScale }) {
160
160
  // colors
161
161
  const [leftColor, rightColor] = twoColorPalette[twoColor.palette]
162
162
  const barColor = { left: leftColor, right: rightColor }
163
- const isBarColorDark = chroma.contrast('#000000', barColor[barPosition]) < 4.9
164
- const fill = isBarColorDark ? '#FFFFFF' : '#000000'
163
+ const fill = getContrastColor('#000', barColor[barPosition])
165
164
 
166
165
  let textProps = getTextProps(config.isLollipopChart, textFits, lollipopShapeSize, fill)
167
166
  // tooltips
@@ -187,6 +186,7 @@ export default function DeviationBar({ height, xScale }) {
187
186
  height={barHeight}
188
187
  data-tooltip-html={tooltip}
189
188
  data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
189
+ tabIndex={-1}
190
190
  >
191
191
  <div style={{ width: barWidth, height: barHeight, border: `${borderWidth}px solid #333`, backgroundColor: barColor[barPosition], ...borderRadius }}></div>
192
192
  </foreignObject>