@cdc/chart 4.23.10 → 4.24.1

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 (125) hide show
  1. package/dist/cdcchart.js +34606 -32218
  2. package/examples/feature/bar/additional-column-tooltip.json +446 -0
  3. package/examples/feature/bar/example-bar-chart.json +1 -46
  4. package/examples/feature/bar/lollipop.json +156 -0
  5. package/examples/feature/bar/tall-data.json +98 -0
  6. package/examples/feature/combo/planet-combo-example-config.json +99 -9
  7. package/examples/feature/dev-4261.json +399 -0
  8. package/examples/feature/forest-plot/forest-plot.json +63 -19
  9. package/examples/feature/forest-plot/{broken.json → linear.json} +77 -23
  10. package/examples/feature/forest-plot/log.json +26 -0
  11. package/examples/feature/forest-plot/logarithmic.json +271 -0
  12. package/examples/feature/line/line-chart-preliminary.json +346 -0
  13. package/examples/feature/line/line-points.json +340 -0
  14. package/examples/feature/regions/index.json +462 -0
  15. package/examples/feature/scatterplot/scatterplot.json +272 -33
  16. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +181 -48
  17. package/examples/private/chart-t.json +3740 -0
  18. package/examples/private/combo.json +369 -0
  19. package/examples/private/epi-data.csv +13 -0
  20. package/examples/private/epi-data.json +62 -0
  21. package/examples/private/epi.json +403 -0
  22. package/examples/private/occupancy.json +109283 -0
  23. package/examples/private/prod-line-config.json +401 -0
  24. package/examples/private/region-data.json +822 -0
  25. package/examples/private/region-testing.json +312 -0
  26. package/examples/private/scaling.json +45325 -0
  27. package/examples/private/testing-data.json +1739 -0
  28. package/examples/private/testing.json +816 -0
  29. package/examples/sparkline-multilple.json +846 -0
  30. package/index.html +12 -8
  31. package/package.json +3 -3
  32. package/src/CdcChart.tsx +42 -211
  33. package/src/ConfigContext.tsx +6 -0
  34. package/src/_stories/Chart.stories.tsx +188 -0
  35. package/src/_stories/Chart.tooltip.stories.tsx +305 -0
  36. package/src/_stories/ChartBrush.stories.tsx +19 -0
  37. package/src/_stories/ChartEditor.stories.tsx +22 -0
  38. package/src/_stories/ChartLine.preliminary.tsx +19 -0
  39. package/src/_stories/ChartSuppress.stories.tsx +19 -0
  40. package/src/_stories/_mock/brush_mock.json +393 -0
  41. package/src/_stories/_mock/pie_config.json +191 -0
  42. package/src/_stories/_mock/pie_data.json +218 -0
  43. package/src/_stories/_mock/preliminary_mock.json +346 -0
  44. package/src/_stories/_mock/suppress_mock.json +911 -0
  45. package/src/components/{AreaChart.Stacked.jsx → AreaChart/components/AreaChart.Stacked.jsx} +6 -7
  46. package/src/components/{AreaChart.jsx → AreaChart/components/AreaChart.jsx} +7 -36
  47. package/src/components/AreaChart/index.tsx +4 -0
  48. package/src/components/{BarChart.Horizontal.jsx → BarChart/components/BarChart.Horizontal.tsx} +111 -34
  49. package/src/components/{BarChart.StackedHorizontal.jsx → BarChart/components/BarChart.StackedHorizontal.tsx} +55 -20
  50. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +106 -0
  51. package/src/components/{BarChart.Vertical.jsx → BarChart/components/BarChart.Vertical.tsx} +162 -34
  52. package/src/components/BarChart/components/BarChart.jsx +39 -0
  53. package/src/components/{BarChartType.jsx → BarChart/components/BarChartType.jsx} +0 -2
  54. package/src/components/BarChart/components/context.tsx +13 -0
  55. package/src/components/BarChart/index.tsx +3 -0
  56. package/src/components/{BoxPlot.jsx → BoxPlot/BoxPlot.jsx} +1 -1
  57. package/src/components/BoxPlot/index.tsx +3 -0
  58. package/src/components/DeviationBar.jsx +4 -3
  59. package/src/components/{EditorPanel.jsx → EditorPanel/EditorPanel.tsx} +807 -865
  60. package/src/components/EditorPanel/components/Panel.DateHighlighting.tsx +109 -0
  61. package/src/components/{ForestPlotSettings.jsx → EditorPanel/components/Panel.ForestPlotSettings.tsx} +190 -220
  62. package/src/components/EditorPanel/components/Panel.Regions.tsx +168 -0
  63. package/src/components/{Series.jsx → EditorPanel/components/Panel.Series.tsx} +23 -4
  64. package/src/components/EditorPanel/components/PanelProps.ts +3 -0
  65. package/src/components/EditorPanel/components/Panels.tsx +13 -0
  66. package/src/components/EditorPanel/components/panels.scss +72 -0
  67. package/src/components/EditorPanel/editor-panel.scss +751 -0
  68. package/src/components/EditorPanel/index.tsx +3 -0
  69. package/src/{hooks → components/EditorPanel}/useEditorPermissions.js +50 -5
  70. package/src/components/{Forecasting.jsx → Forecasting/Forecasting.jsx} +1 -1
  71. package/src/components/Forecasting/index.tsx +3 -0
  72. package/src/components/ForestPlot/ForestPlot.tsx +254 -0
  73. package/src/components/ForestPlot/ForestPlotProps.ts +18 -0
  74. package/src/components/ForestPlot/index.scss +1 -0
  75. package/src/components/ForestPlot/index.tsx +3 -0
  76. package/src/components/Legend/Legend.tsx +347 -0
  77. package/src/components/Legend/index.tsx +3 -0
  78. package/src/components/LineChart/LineChartProps.ts +46 -0
  79. package/src/components/{LineChart.Circle.tsx → LineChart/components/LineChart.Circle.tsx} +36 -30
  80. package/src/components/LineChart/helpers.ts +45 -0
  81. package/src/components/LineChart/index.scss +1 -0
  82. package/src/components/{LineChart.tsx → LineChart/index.tsx} +83 -42
  83. package/src/components/LinearChart.jsx +125 -82
  84. package/src/components/PairedBarChart.jsx +2 -2
  85. package/src/components/{PieChart.jsx → PieChart/PieChart.tsx} +16 -7
  86. package/src/components/PieChart/index.tsx +3 -0
  87. package/src/components/Regions/components/Regions.tsx +135 -0
  88. package/src/components/Regions/index.tsx +3 -0
  89. package/src/components/{ScatterPlot.jsx → ScatterPlot/ScatterPlot.jsx} +3 -3
  90. package/src/components/ScatterPlot/index.tsx +3 -0
  91. package/src/components/{SparkLine.jsx → Sparkline/SparkLine.jsx} +2 -2
  92. package/src/components/Sparkline/index.tsx +3 -0
  93. package/src/components/ZoomBrush.tsx +168 -0
  94. package/src/data/initial-state.js +30 -16
  95. package/src/helpers/abbreviateNumber.ts +17 -0
  96. package/src/helpers/computeMarginBottom.ts +55 -0
  97. package/src/helpers/filterData.ts +18 -0
  98. package/src/helpers/generateColorsArray.ts +8 -0
  99. package/src/helpers/getQuartiles.ts +30 -0
  100. package/src/helpers/handleChartAriaLabels.ts +19 -0
  101. package/src/helpers/handleLineType.ts +18 -0
  102. package/src/helpers/lineOptions.ts +18 -0
  103. package/src/helpers/sort.ts +7 -0
  104. package/src/helpers/tests/computeMarginBottom.test.ts +20 -0
  105. package/src/hooks/useBarChart.js +72 -7
  106. package/src/hooks/useColorScale.ts +50 -0
  107. package/src/hooks/{useMinMax.js → useMinMax.ts} +75 -23
  108. package/src/hooks/{useRightAxis.js → useRightAxis.ts} +10 -2
  109. package/src/hooks/{useScales.js → useScales.ts} +64 -17
  110. package/src/hooks/{useTooltip.jsx → useTooltip.tsx} +84 -55
  111. package/src/scss/main.scss +70 -38
  112. package/src/types/ChartConfig.ts +178 -0
  113. package/src/types/ChartContext.ts +54 -0
  114. package/src/types/ForestPlot.ts +53 -0
  115. package/examples/feature/scatterplot/scatterplot-continuous.csv +0 -17
  116. package/src/ConfigContext.jsx +0 -5
  117. package/src/components/BarChart.StackedVertical.jsx +0 -95
  118. package/src/components/BarChart.jsx +0 -30
  119. package/src/components/ForestPlot.jsx +0 -191
  120. package/src/components/Legend.jsx +0 -277
  121. package/src/scss/LinearChart.scss +0 -0
  122. package/src/scss/editor-panel.scss +0 -745
  123. package/src/scss/legend.scss +0 -206
  124. package/src/scss/mixins.scss +0 -0
  125. package/src/scss/variables.scss +0 -1
@@ -1,18 +1,20 @@
1
1
  import { useContext } from 'react'
2
2
  import ConfigContext from '../ConfigContext'
3
- import { defaultStyles } from '@visx/tooltip'
3
+ import { type ChartContext } from '../types/ChartContext'
4
4
 
5
5
  // third party
6
6
  import { localPoint } from '@visx/event'
7
7
  import { bisector } from 'd3-array'
8
+ import { DataTransform } from '@cdc/core/helpers/DataTransform'
9
+ const transform = new DataTransform()
8
10
 
9
11
  import { formatNumber as formatColNumber } from '@cdc/core/helpers/cove/number'
10
12
 
11
13
  export const useTooltip = props => {
12
- const { tableData: data, config, formatNumber, capitalize, formatDate, parseDate } = useContext(ConfigContext)
14
+ const { tableData, config, formatNumber, capitalize, formatDate, parseDate, setSharedFilter } = useContext<ChartContext>(ConfigContext)
13
15
  const { xScale, yScale, showTooltip, hideTooltip } = props
14
- const { xAxis, visualizationType, orientation, yAxis, runtime } = config
15
-
16
+ const { xAxis, visualizationType, orientation, yAxis, runtime, barWidth } = config
17
+ const data = transform.applySuppression(tableData, config.suppressedData)
16
18
  /**
17
19
  * Provides the tooltip information based on the tooltip data array and svg cursor coordinates
18
20
  * @function getTooltipInformation
@@ -51,13 +53,12 @@ export const useTooltip = props => {
51
53
  const { x, y } = eventSvgCoords
52
54
 
53
55
  // Additional data for pie charts
54
- const { data: pieChartData, arc } = additionalChartData
56
+ const { data: pieChartData, arc } = additionalChartData ?? {}
55
57
 
56
58
  const closestXScaleValue = getXValueFromCoordinate(x - Number(config.yAxis.size || 0))
57
59
 
58
60
  const includedSeries = visualizationType !== 'Pie' ? config.series.filter(series => series.tooltip === true).map(item => item.dataKey) : config.series.map(item => item.dataKey)
59
61
  includedSeries.push(config.xAxis.dataKey)
60
-
61
62
  if (config.visualizationType === 'Forecasting') {
62
63
  config.series.map(s => {
63
64
  s.confidenceIntervals.map(c => {
@@ -68,15 +69,23 @@ export const useTooltip = props => {
68
69
  })
69
70
  })
70
71
  }
72
+ function getColumnNames(columns) {
73
+ let names = []
74
+ for (let key in columns) {
75
+ if (columns.hasOwnProperty(key)) {
76
+ names.push(columns[key].name)
77
+ }
78
+ }
79
+ return names
80
+ }
81
+ includedSeries.push(...getColumnNames(config.columns))
82
+ includedSeries.push(...getColumnNames(config.columns))
71
83
 
72
84
  const yScaleValues = getYScaleValues(closestXScaleValue, includedSeries)
73
-
74
85
  const xScaleValues = data.filter(d => d[xAxis.dataKey] === getClosestYValue(y))
75
86
 
76
87
  const resolvedScaleValues = orientation === 'vertical' ? yScaleValues : xScaleValues
77
88
 
78
- const forestPlotXValue = visualizationType === 'Forest Plot' ? data?.filter(d => d[xAxis.dataKey] === getClosestYValue(y))[0][config.forestPlot.estimateField] : null
79
-
80
89
  const getAxisPosition = seriesKey => {
81
90
  const seriesObj = config.series.filter(s => s.dataKey === seriesKey)[0]
82
91
  const position = seriesObj?.axis ? String(seriesObj.axis).toLowerCase() : 'left'
@@ -84,49 +93,62 @@ export const useTooltip = props => {
84
93
  }
85
94
 
86
95
  const getTooltipDataArray = () => {
87
- if (visualizationType === 'Forest Plot') {
88
- const columns = config.columns
89
- const columnsWithTooltips = []
90
-
91
- for (const [colKeys, colVals] of Object.entries(columns)) {
92
- const formattingParams = {
93
- addColPrefix: config.columns[colKeys].prefix,
94
- addColSuffix: config.columns[colKeys].suffix,
95
- addColRoundTo: config.columns[colKeys].roundToPlace ? config.columns[colKeys].roundToPlace : '',
96
- addColCommas: config.columns[colKeys].commas
97
- }
98
-
99
- let closestValue = getClosestYValue(y, colVals.name)
100
-
101
- const formattedValue = formatColNumber(closestValue, 'left', true, config, formattingParams)
96
+ const columns = config.columns
97
+ const columnsWithTooltips = []
98
+ const tooltipItems = []
99
+
100
+ for (const [colKeys, colVals] of Object.entries(columns)) {
101
+ const formattingParams = {
102
+ addColPrefix: config.columns[colKeys].prefix,
103
+ addColSuffix: config.columns[colKeys].suffix,
104
+ addColRoundTo: config.columns[colKeys].roundToPlace ? config.columns[colKeys].roundToPlace : '',
105
+ addColCommas: config.columns[colKeys].commas
106
+ }
107
+ let closestValue = null
102
108
 
103
- if (colVals.tooltips) {
104
- columnsWithTooltips.push([colVals.label, formattedValue])
105
- }
109
+ if (config.visualizationType === 'Pie') {
110
+ closestValue = arc?.data[colVals.name]
111
+ } else {
112
+ closestValue = resolvedScaleValues[0]?.[colVals.name]
106
113
  }
107
114
 
108
- const tooltipItems = []
109
- tooltipItems.push([config.xAxis.dataKey, getClosestYValue(y)])
115
+ const formattedValue = formatColNumber(closestValue, 'left', true, config, formattingParams)
110
116
 
111
- columnsWithTooltips.forEach(columnData => {
112
- tooltipItems.push([columnData[0], columnData[1]])
113
- })
114
- return tooltipItems
117
+ if (colVals.tooltips) {
118
+ columnsWithTooltips.push([colVals.label, formattedValue])
119
+ }
115
120
  }
121
+ const additionalTooltipItems = []
122
+
123
+ columnsWithTooltips.forEach(columnData => {
124
+ additionalTooltipItems.push([columnData[0], columnData[1]])
125
+ })
116
126
 
117
127
  if (visualizationType === 'Pie') {
118
- return [
128
+ tooltipItems.push(
129
+ // ignore
119
130
  [config.xAxis.dataKey, pieChartData],
120
131
  [config.runtime.yAxis.dataKey, formatNumber(arc?.data[config.runtime.yAxis.dataKey])],
121
132
  ['Percent', `${Math.round((((arc?.endAngle - arc?.startAngle) * 180) / Math.PI / 360) * 100) + '%'}`]
122
- ]
133
+ )
123
134
  }
124
135
 
125
- return getIncludedTooltipSeries()
126
- .filter(Boolean)
127
- .flatMap((seriesKey, index) => {
128
- return resolvedScaleValues[0][seriesKey] ? [[seriesKey, resolvedScaleValues[0][seriesKey], getAxisPosition(seriesKey)]] : []
129
- })
136
+ if (visualizationType === 'Forest Plot') {
137
+ tooltipItems.push([config.xAxis.dataKey, getClosestYValue(y)])
138
+ }
139
+
140
+ if (visualizationType !== 'Pie' && visualizationType !== 'Forest Plot') {
141
+ tooltipItems.push(
142
+ ...getIncludedTooltipSeries()
143
+ ?.filter(Boolean)
144
+ ?.flatMap(seriesKey => {
145
+ const formattedValue = seriesKey === config.xAxis.dataKey ? resolvedScaleValues[0]?.[seriesKey] : formatNumber(resolvedScaleValues[0]?.[seriesKey], getAxisPosition(seriesKey))
146
+ return resolvedScaleValues?.[0]?.[seriesKey] ? [[seriesKey, formattedValue, getAxisPosition(seriesKey)]] : []
147
+ })
148
+ )
149
+ }
150
+
151
+ return [...tooltipItems, ...additionalTooltipItems]
130
152
  }
131
153
 
132
154
  // Returns an array of arrays.
@@ -180,9 +202,11 @@ export const useTooltip = props => {
180
202
  * @function getXValueFromCoordinate
181
203
  * @returns {String} - the closest x value to the cursor position
182
204
  */
183
- const getXValueFromCoordinate = x => {
205
+ const getXValueFromCoordinate = (x, isClick = false) => {
184
206
  if (visualizationType === 'Pie') return
185
207
  if (orientation === 'horizontal') return
208
+
209
+ // Check the type of x equal to point or if the type of xAxis is equal to continuous or date
186
210
  if (xScale.type === 'point' || xAxis.type === 'continuous' || xAxis.type === 'date') {
187
211
  // Find the closest x value by calculating the minimum distance
188
212
  let closestX = null
@@ -191,11 +215,12 @@ export const useTooltip = props => {
191
215
 
192
216
  data.forEach(d => {
193
217
  const xPosition = xAxis.type === 'date' ? xScale(parseDate(d[xAxis.dataKey])) : xScale(d[xAxis.dataKey])
194
- const distance = Math.abs(Number(xPosition - offset))
218
+ let bwOffset = config.barHeight
219
+ const distance = Math.abs(Number(xPosition - offset + (isClick ? bwOffset * 2 : 0)))
195
220
 
196
- if (distance < minDistance) {
221
+ if (distance <= minDistance) {
197
222
  minDistance = distance
198
- closestX = xAxis.type === 'date' ? parseDate(d[xAxis.dataKey]) : d[xAxis.dataKey]
223
+ closestX = xAxis.type === 'date' ? d[xAxis.dataKey] : d[xAxis.dataKey]
199
224
  }
200
225
  })
201
226
  return closestX
@@ -226,7 +251,6 @@ export const useTooltip = props => {
226
251
  const yPositionOnPlot = visualizationType !== 'Forest Plot' ? yScale(d[config.xAxis.dataKey]) : yScale(index)
227
252
 
228
253
  const distance = Math.abs(yPositionOnPlot - yPosition)
229
-
230
254
  if (distance < minDistance) {
231
255
  minDistance = distance
232
256
  closestYValue = key ? d[key] : d[config.xAxis.dataKey]
@@ -251,11 +275,20 @@ export const useTooltip = props => {
251
275
  const eventSvgCoords = localPoint(e)
252
276
  const { x } = eventSvgCoords
253
277
  if (!x) throw new Error('COVE: no x value in handleTooltipClick.')
254
- let closestXScaleValue = getXValueFromCoordinate(x)
278
+ let closestXScaleValue = getXValueFromCoordinate(x, true)
279
+ let datum = config.data?.filter(item => item[config.xAxis.dataKey] === closestXScaleValue)
255
280
  if (!closestXScaleValue) throw new Error('COVE: no closest x scale value in handleTooltipClick')
256
- let datum = config.data.filter(item => item[config.xAxis.dataKey] === closestXScaleValue)
281
+ if (xAxis.type === 'date' && closestXScaleValue) {
282
+ closestXScaleValue = new Date(closestXScaleValue)
283
+ closestXScaleValue = formatDate(closestXScaleValue)
284
+ datum = config.data?.filter(item => formatDate(new Date(item[config.xAxis.dataKey])) === closestXScaleValue)
285
+ }
286
+
287
+ if (!datum[0]) {
288
+ throw new Error(`COVE: no data found matching the closest xScale value: ${closestXScaleValue}`)
289
+ }
257
290
 
258
- if (setSharedFilter) {
291
+ if (setSharedFilter && config?.uid && datum?.[0]) {
259
292
  setSharedFilter(config.uid, datum[0])
260
293
  }
261
294
  } catch (e) {
@@ -272,16 +305,13 @@ export const useTooltip = props => {
272
305
  */
273
306
  const getYScaleValues = (closestXScaleValue, includedSeries) => {
274
307
  try {
275
- const formattedDate = formatDate(closestXScaleValue)
276
-
277
308
  let dataToSearch
278
309
 
279
310
  if (xAxis.type === 'categorical') {
280
311
  dataToSearch = data.filter(d => d[xAxis.dataKey] === closestXScaleValue)
281
312
  } else {
282
- dataToSearch = data.filter(d => formatDate(parseDate(d[xAxis.dataKey])) === formattedDate)
313
+ dataToSearch = data.filter(d => d[xAxis.dataKey] === closestXScaleValue)
283
314
  }
284
-
285
315
  // Return an empty array if no matching data is found.
286
316
  if (!dataToSearch || dataToSearch.length === 0) {
287
317
  return []
@@ -328,7 +358,7 @@ export const useTooltip = props => {
328
358
  if (!config.dashboard) {
329
359
  switch (visualizationType) {
330
360
  case 'Combo':
331
- standardLoopItems = [runtime.xAxis.dataKey, ...runtime?.seriesKeys, ...stageColumns, ...ciItems]
361
+ standardLoopItems = [runtime.xAxis.dataKey, ...runtime?.seriesKeys, ...ciItems]
332
362
  break
333
363
  case 'Forecasting':
334
364
  standardLoopItems = [runtime.xAxis.dataKey, ...stageColumns, ...ciItems]
@@ -346,7 +376,6 @@ export const useTooltip = props => {
346
376
  standardLoopItems = [runtime.xAxis.dataKey, ...runtime?.seriesKeys]
347
377
  default:
348
378
  throw new Error('No visualization type found in handleTooltipMouseOver')
349
- break
350
379
  }
351
380
  }
352
381
 
@@ -403,7 +432,7 @@ export const useTooltip = props => {
403
432
  if (key === config.xAxis.dataKey) return <li className='tooltip-heading'>{`${capitalize(config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ` : '')} ${config.xAxis.type === 'date' ? value : value}`}</li>
404
433
 
405
434
  // TOOLTIP BODY
406
- return <li className='tooltip-body'>{`${getSeriesNameFromLabel(key)}: ${formatNumber(value, axisPosition)}`}</li>
435
+ return <li className='tooltip-body'>{`${getSeriesNameFromLabel(key)}: ${value}`}</li>
407
436
  }
408
437
 
409
438
  return {
@@ -1,8 +1,73 @@
1
1
  @import '@cdc/core/styles/base';
2
2
  @import '@cdc/core/styles/heading-colors';
3
- @import 'mixins';
4
- @import 'variables';
5
3
  @import '@cdc/core/styles/v2/themes/color-definitions';
4
+ .dash-container {
5
+ display: flex;
6
+ align-items: center;
7
+ flex-direction: row;
8
+ }
9
+
10
+ .legend-dash-left {
11
+ margin-left: 8px !important;
12
+ display: flex;
13
+ flex-direction: column;
14
+ }
15
+
16
+ .dash-inner {
17
+ width: 20px;
18
+ margin-left: 0px !important;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ }
23
+
24
+ .dashes {
25
+ display: inline-block;
26
+
27
+ &.open-circles {
28
+ width: 12px;
29
+ height: 12px;
30
+ border: 2px solid currentColor;
31
+ border-radius: 50%;
32
+ }
33
+
34
+ &.dashed-small {
35
+ margin: 0 0px;
36
+ font-size: 20px;
37
+ }
38
+
39
+ &.dashed-medium,
40
+ &.dashed-large {
41
+ span {
42
+ display: inline-block;
43
+ position: relative;
44
+ margin-right: 12px;
45
+ margin-left: 0 !important;
46
+
47
+ &::before {
48
+ content: '';
49
+ display: block;
50
+ height: 2px;
51
+ background-color: currentColor;
52
+ position: absolute;
53
+ top: 50%;
54
+ transform: translateY(-20%);
55
+ width: 10px;
56
+ }
57
+ }
58
+ }
59
+
60
+ &.dashed-large {
61
+ span {
62
+ margin-right: 12px;
63
+ margin-left: 0 !important;
64
+
65
+ &::before {
66
+ width: 13px;
67
+ }
68
+ }
69
+ }
70
+ }
6
71
 
7
72
  .form-container {
8
73
  overflow-y: auto;
@@ -17,7 +82,6 @@
17
82
 
18
83
  .cdc-open-viz-module.type-chart {
19
84
  @import 'DataTable';
20
- @import 'editor-panel';
21
85
 
22
86
  border-radius: 3px;
23
87
 
@@ -74,34 +138,6 @@
74
138
  }
75
139
  }
76
140
 
77
- .chart-title {
78
- position: relative;
79
- padding: 0.6em 0.8em;
80
- margin: 0;
81
- color: #fff;
82
- font-size: 1.1em;
83
- border-bottom-width: 3px;
84
- border-bottom-style: solid;
85
-
86
- border-top-left-radius: 3px;
87
- border-top-right-radius: 3px;
88
-
89
- em {
90
- font-style: italic;
91
- }
92
-
93
- strong {
94
- font-weight: bold;
95
- }
96
-
97
- &:not(:empty) {
98
- margin: 0 0 1rem 0 !important;
99
- padding: 0.6em 0.8em;
100
- border-bottom-width: 3px;
101
- border-bottom-style: solid;
102
- }
103
- }
104
-
105
141
  .chart-description {
106
142
  margin-bottom: 20px;
107
143
  }
@@ -560,14 +596,14 @@
560
596
 
561
597
  &.animated {
562
598
  .vertical rect,
563
- .vertical foreignObject {
599
+ .vertical foreignObject div {
564
600
  opacity: 0;
565
601
  animation: growBar 0.5s linear forwards;
566
602
  animation-play-state: paused;
567
603
  }
568
604
 
569
605
  .horizontal rect,
570
- .horizontal foreignObject {
606
+ .horizontal foreignObject div {
571
607
  opacity: 0;
572
608
  animation: growBarH 0.5s linear forwards;
573
609
  animation-play-state: paused;
@@ -575,7 +611,7 @@
575
611
 
576
612
  &.animate {
577
613
  rect,
578
- foreignObject {
614
+ foreignObject div {
579
615
  animation-play-state: running;
580
616
  }
581
617
  }
@@ -674,10 +710,6 @@
674
710
  background: transparent;
675
711
  }
676
712
 
677
- .chart-title:not(:empty) {
678
- margin-bottom: 0 !important;
679
- }
680
-
681
713
  .cove-component__content .chart-container {
682
714
  padding: 1em;
683
715
  }
@@ -0,0 +1,178 @@
1
+ import { Axis } from '@cdc/core/types/Axis'
2
+ import { type ForestPlotConfigSettings } from './ForestPlot'
3
+ import { type Column } from '@cdc/core/types/Column'
4
+ import { type Series } from '@cdc/core/types/Series'
5
+ import { Runtime } from '@cdc/core/types/Runtime'
6
+ import { FilterBehavior } from '@cdc/core/types/FilterBehavior'
7
+ import { Table } from '@cdc/core/types/Table'
8
+
9
+ export type ChartColumns = Record<string, Column>
10
+
11
+ type Region = {
12
+ from: string
13
+ to: string
14
+ label: string
15
+ color: string
16
+ background: string
17
+ range: 'Custom' | string
18
+ }
19
+
20
+ type BoxPlot = {
21
+ firstQuartilePercentage: number
22
+ [key: string]: any
23
+ }
24
+
25
+ type DataFormat = {
26
+ abbreviated: boolean
27
+ bottomAbbreviated: boolean
28
+ bottomCommas: boolean
29
+ bottomPrefix: string
30
+ bottomRoundTo: number
31
+ bottomSuffix: string
32
+ commas: boolean
33
+ prefix: string
34
+ rightCommas: boolean
35
+ rightPrefix: string
36
+ rightRoundTo: number
37
+ rightSuffix: string
38
+ roundTo: number
39
+ suffix: string
40
+ }
41
+
42
+ type Exclusions = {
43
+ keys: string[]
44
+ active: boolean
45
+ dateStart: string
46
+ dateEnd: string
47
+ }
48
+
49
+ type Filter = {
50
+ type: 'url'
51
+ columnName: string
52
+ showDropdown: boolean
53
+ filterStyle: string
54
+ label: string
55
+ order: 'asc' | 'desc' | 'cust'
56
+ values: string[]
57
+ }
58
+
59
+ export type Legend = {
60
+ additionalCategories: string[]
61
+ // general legend onClick behavior
62
+ behavior: 'highlight' | 'isolate' | string
63
+ colorCode: string
64
+ description: string
65
+ // show or hide the legend
66
+ hide: boolean
67
+ highlightOnHover: boolean
68
+ label: string
69
+ lineMode: boolean
70
+ position: string
71
+ reverseLabelOrder: boolean
72
+ singleRow: boolean
73
+ type: string
74
+ verticalSorted: boolean
75
+ }
76
+
77
+ type Visual = {
78
+ border?: boolean
79
+ borderColorTheme?: boolean
80
+ accent?: boolean
81
+ background?: boolean
82
+ hideBackgroundColor?: boolean
83
+ verticalHoverLine?: boolean
84
+ horizontalHoverLine?: boolean
85
+ }
86
+
87
+ type AllChartsConfig = {
88
+ animate: boolean
89
+ general: {
90
+ boxplot: BoxPlot
91
+ }
92
+ barHasBorder: 'true' | 'false'
93
+ barHeight: number
94
+ barSpace: number
95
+ barStyle: string
96
+ barThickness: number
97
+ boxplot: BoxPlot
98
+ brush: {
99
+ active: boolean
100
+ height: number
101
+ }
102
+ chartMessage: { noData?: string }
103
+ colorMatchLineSeriesLabels: boolean
104
+ columns: ChartColumns
105
+ confidenceKeys: Record<string, any>
106
+ data: Object[]
107
+ dataCutoff: number
108
+ dataFormat: DataFormat
109
+ dataKey: string
110
+ description: string
111
+ dynamicMarginTop: number
112
+ exclusions: Exclusions
113
+ filters: Filter[]
114
+ filterBehavior: FilterBehavior
115
+ fontSize: 'small' | 'medium' | 'large'
116
+ footnotes: string
117
+ forestPlot: ForestPlotConfigSettings
118
+ heights: {
119
+ vertical: number
120
+ }
121
+ highlightedBarValues: { value: any; color: string; borderWidth: number; legendLabel: string }[]
122
+ introText: string
123
+ isLollipopChart: boolean
124
+ isLegendValue: boolean
125
+ isResponsiveTicks: boolean
126
+ isPaletteReversed: boolean
127
+ labels: boolean
128
+ legend: Legend
129
+ lineDatapointColor: 'Same as Line' | 'Lighter than Line'
130
+ lineDatapointStyle: 'hidden' | 'always show' | 'hover'
131
+ lollipopColorStyle: 'regular' | 'two-tone'
132
+ lollipopShape: string
133
+ lollipopSize: 'small' | 'medium' | 'large'
134
+ newViz: Object
135
+ orientation: 'vertical' | 'horizontal'
136
+ palette: string
137
+ pieType?: string
138
+ roundingStyle: string
139
+ runtime: Runtime
140
+ series: Series
141
+ showLineSeriesLabels: boolean
142
+ showTitle: boolean
143
+ stackedAreaChartLineType: string
144
+ suppressedData?: { label: string; icon: string; value: string }[]
145
+ superTitle: string
146
+ theme: string
147
+ table: Table
148
+ tipRounding: string
149
+ title: string
150
+ tooltips: {
151
+ singleSeries: boolean
152
+ opacity: number
153
+ }
154
+ topAxis: { hasLine: boolean }
155
+ twoColor: { palette: string }
156
+ type: string
157
+ useLogScale: boolean
158
+ visual: Visual
159
+ visualizationType: 'Area Chart' | 'Bar' | 'Box Plot' | 'Deviation Bar' | 'Forest Plot' | 'Line' | 'Paired Bar' | 'Pie' | 'Scatter Plot' | 'Spark Line' | 'Combo' | 'Forecasting'
160
+ visualizationSubType: string
161
+ xAxis: Axis
162
+ yAxis: Axis
163
+ xScale: Function
164
+ yScale: Function
165
+ regions: Region[]
166
+ }
167
+
168
+ export type ForestPlotConfig = {
169
+ visualizationType: 'Forest Plot'
170
+ forestPlot: ForestPlotConfigSettings
171
+ } & AllChartsConfig
172
+
173
+ export type LineChartConfig = {
174
+ visualizationType: 'Line'
175
+ lineDatapointStyle: 'hidden' | 'always show' | 'hover'
176
+ } & AllChartsConfig
177
+
178
+ export type ChartConfig = LineChartConfig | ForestPlotConfig | AllChartsConfig
@@ -0,0 +1,54 @@
1
+ import { type ChartConfig } from './ChartConfig'
2
+ import { PickD3Scale } from '@visx/scale'
3
+
4
+ type ColorScale = PickD3Scale<'ordinal', any, any>
5
+
6
+ type TransformedData = {
7
+ dataKey?: string
8
+ [key: string]: any
9
+ }
10
+
11
+ type SharedChartContext = {
12
+ colorScale?: ColorScale
13
+ config: ChartConfig
14
+ currentViewport?: string
15
+ highlight?: Function
16
+ highlightReset?: Function
17
+ }
18
+
19
+ // Line Chart Specific Context
20
+ type LineChartContext = SharedChartContext & {
21
+ dimensions: [screenWidth: number, screenHeight: number]
22
+ formatDate: Function
23
+ formatNumber: Function
24
+ handleLineType: Function
25
+ isNumber: unknown
26
+ isDebug?: boolean
27
+ parseDate: Function
28
+ rawData: Object[]
29
+ seriesHighlight: String[]
30
+ tableData: Object[]
31
+ transformedData: TransformedData[]
32
+ updateConfig: Function
33
+ visualizationType: 'Line'
34
+ }
35
+
36
+ export type ChartContext =
37
+ | LineChartContext
38
+ | (SharedChartContext & {
39
+ dimensions: [screenWidth: number, screenHeight: number]
40
+ formatDate?: Function
41
+ formatNumber?: Function
42
+ handleLineType?: Function
43
+ isNumber?: boolean
44
+ // url param added to allow various console logs and chart helpers
45
+ isDebug?: boolean
46
+ parseDate?: Function
47
+ rawData?: Object[]
48
+ seriesHighlight?: String[]
49
+ tableData?: Object[]
50
+ transformedData?: TransformedData[]
51
+ setSharedFilter?: Function
52
+ sharedFilterValue?: string
53
+ updateConfig?: Function
54
+ })
@@ -0,0 +1,53 @@
1
+ import { type Color } from '@cdc/core/types/Color'
2
+
3
+ export type ForestPlotConfigSettings = {
4
+ colors: {
5
+ // color of line of no effect
6
+ line: Color
7
+ // color for effect estimate shape
8
+ shape: Color
9
+ }
10
+ // description - appears below the study column.
11
+ description: {
12
+ show: boolean
13
+ text: string
14
+ location: number
15
+ }
16
+ // column chose for the effect estimate
17
+ estimateField: string
18
+ // column chose for the esimate radius
19
+ estimateRadius: string
20
+ hideDateCategoryCol: boolean
21
+ leftWidthOffset: number
22
+ lineOfNoEffect: {
23
+ show: boolean
24
+ }
25
+ lower: string
26
+ upper: string
27
+ // type - determines the type of scale we're using, including the position of line of effect (0 or 1)
28
+ type: 'Linear' | 'Logarithmic'
29
+ pooledResult: {
30
+ diamondHeight: number
31
+ column: string
32
+ }
33
+ // rowHeight - height of study
34
+ rowHeight: number
35
+ // radius - scaling for effect estimates
36
+ radius: {
37
+ min: number
38
+ max: number
39
+ scalingColumn: string
40
+ }
41
+ result: {
42
+ show: boolean
43
+ text: string
44
+ location: number
45
+ }
46
+ rightWidthOffset: number
47
+ shape: string
48
+ startAt: number
49
+ title: string // centered title above the chart
50
+ // labels under chart
51
+ leftLabel: string
52
+ rightLabel: string
53
+ }