@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
@@ -0,0 +1,3 @@
1
+ import EditorPanel from './EditorPanel'
2
+
3
+ export default EditorPanel
@@ -1,9 +1,9 @@
1
1
  import React, { useContext } from 'react'
2
- import ConfigContext from '../ConfigContext'
2
+ import ConfigContext from '../../ConfigContext'
3
3
 
4
4
  export const useEditorPermissions = () => {
5
5
  const { config } = useContext(ConfigContext)
6
- const { visualizationType, series, orientation } = config
6
+ const { visualizationType, series, orientation, visualizationSubType } = config
7
7
 
8
8
  // Overall support for the chart types
9
9
  // prettier-ignore
@@ -24,6 +24,12 @@ export const useEditorPermissions = () => {
24
24
 
25
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
26
 
27
+ const visSupportsDateCategoryAxis = () => {
28
+ const disabledCharts = ['Forest Plot']
29
+ if (disabledCharts.includes(visualizationType)) return false
30
+ return true
31
+ }
32
+
27
33
  const visSupportsSuperTitle = () => {
28
34
  const disabledCharts = ['Spark Line']
29
35
  if (disabledCharts.includes(visualizationType)) return false
@@ -84,6 +90,15 @@ export const useEditorPermissions = () => {
84
90
  }
85
91
  }
86
92
 
93
+ const visHasDataSuppression = () => {
94
+ if ((visualizationType === 'Bar' || 'Combo') && visualizationSubType === 'regular') {
95
+ return true
96
+ }
97
+ }
98
+ const visHasBrushChart = () => {
99
+ return ['Line', 'Bar', 'Area Chart', 'Combo'].includes(visualizationType) && orientation === 'vertical'
100
+ }
101
+
87
102
  const visHasBarBorders = () => {
88
103
  const disabledCharts = ['Box Plot', 'Scatter Plot', 'Pie']
89
104
  if (disabledCharts.includes(visualizationType)) return false
@@ -154,13 +169,13 @@ export const useEditorPermissions = () => {
154
169
  }
155
170
 
156
171
  const visSupportsDateCategoryTickRotation = () => {
157
- const disabledCharts = ['Forest Plot', 'Spark Line']
172
+ const disabledCharts = ['Spark Line']
158
173
  if (disabledCharts.includes(visualizationType)) return false
159
174
  return true
160
175
  }
161
176
 
162
177
  const visSupportsDateCategoryNumTicks = () => {
163
- const disabledCharts = ['Forest Plot', 'Spark Line']
178
+ const disabledCharts = ['Spark Line']
164
179
  if (disabledCharts.includes(visualizationType)) return false
165
180
  return true
166
181
  }
@@ -177,6 +192,18 @@ export const useEditorPermissions = () => {
177
192
  return true
178
193
  }
179
194
 
195
+ const visSupportsValueAxisMax = () => {
196
+ const disabledCharts = ['Forest Plot']
197
+ if (disabledCharts.includes(visualizationType)) return false
198
+ return true
199
+ }
200
+
201
+ const visSupportsValueAxisMin = () => {
202
+ const disabledCharts = ['Forest Plot']
203
+ if (disabledCharts.includes(visualizationType)) return false
204
+ return true
205
+ }
206
+
180
207
  const visSupportsFilters = () => {
181
208
  const disabledCharts = ['Forest Plot']
182
209
  if (disabledCharts.includes(visualizationType)) return false
@@ -192,16 +219,22 @@ export const useEditorPermissions = () => {
192
219
 
193
220
  // implement later
194
221
  const visSupportsValueAxisTicks = () => {
222
+ const disabledCharts = ['Forest Plot']
223
+ if (disabledCharts.includes(visualizationType)) return false
195
224
  return true
196
225
  }
197
226
 
198
227
  // implement later
199
228
  const visSupportsValueAxisLine = () => {
229
+ const disabledCharts = ['Forest Plot']
230
+ if (disabledCharts.includes(visualizationType)) return false
200
231
  return true
201
232
  }
202
233
 
203
234
  // implement later
204
235
  const visSupportsValueAxisLabels = () => {
236
+ const disabledCharts = ['Forest Plot']
237
+ if (disabledCharts.includes(visualizationType)) return false
205
238
  return true
206
239
  }
207
240
 
@@ -242,6 +275,12 @@ export const useEditorPermissions = () => {
242
275
  return true
243
276
  }
244
277
 
278
+ const visSupportsReactTooltip = () => {
279
+ if (['Deviation Bar', 'Box Plot', 'Scatter Plot', 'Paired Bar'].includes(visualizationType) || (visualizationType === 'Bar' && config.tooltips.singleSeries)) {
280
+ return true
281
+ }
282
+ }
283
+
245
284
  return {
246
285
  enabledChartTypes,
247
286
  headerColors,
@@ -250,11 +289,14 @@ export const useEditorPermissions = () => {
250
289
  visHasBarBorders,
251
290
  visHasDataCutoff,
252
291
  visHasLabelOnData,
292
+ visHasDataSuppression,
253
293
  visHasLegend,
294
+ visHasBrushChart,
254
295
  visHasNumbersOnBars,
255
296
  visSupportsBarSpace,
256
297
  visSupportsBarThickness,
257
298
  visSupportsChartHeight,
299
+ visSupportsDateCategoryAxis,
258
300
  visSupportsDateCategoryAxisLabel,
259
301
  visSupportsDateCategoryAxisLine,
260
302
  visSupportsDateCategoryAxisTicks,
@@ -276,6 +318,9 @@ export const useEditorPermissions = () => {
276
318
  visSupportsValueAxisGridLines,
277
319
  visSupportsValueAxisLabels,
278
320
  visSupportsValueAxisLine,
279
- visSupportsValueAxisTicks
321
+ visSupportsValueAxisTicks,
322
+ visSupportsReactTooltip,
323
+ visSupportsValueAxisMax,
324
+ visSupportsValueAxisMin
280
325
  }
281
326
  }
@@ -1,7 +1,7 @@
1
1
  import React, { useContext } from 'react'
2
2
 
3
3
  // cdc
4
- import ConfigContext from '../ConfigContext'
4
+ import ConfigContext from '../../ConfigContext'
5
5
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
6
6
  import { colorPalettesChart, sequentialPalettes } from '@cdc/core/data/colorPalettes'
7
7
 
@@ -0,0 +1,3 @@
1
+ import Forecasting from './Forecasting'
2
+
3
+ export default Forecasting
@@ -0,0 +1,254 @@
1
+ import { useContext, useEffect, useState } from 'react'
2
+
3
+ // visx
4
+ import { Group } from '@visx/group'
5
+ import { Line, Bar, Circle, LinePath } from '@visx/shape'
6
+ import { Text } from '@visx/text'
7
+ import { scaleLinear } from '@visx/scale'
8
+ import { curveLinearClosed } from '@visx/curve'
9
+
10
+ // types
11
+ import { type ForestPlotProps } from '@cdc/chart/src/components/ForestPlot/ForestPlotProps'
12
+ import { type ChartConfig } from '@cdc/chart/src/types/ChartConfig'
13
+ import { type ChartContext } from '@cdc/chart/src/types/ChartContext'
14
+
15
+ // cdc
16
+ import ConfigContext from '../../ConfigContext'
17
+ import { getFontSize } from '@cdc/core/helpers/cove/number'
18
+
19
+ const ForestPlot = (props: ForestPlotProps) => {
20
+ const { rawData: data, updateConfig } = useContext<ChartContext>(ConfigContext)
21
+ const { xScale, yScale, config, height, width, handleTooltipMouseOff, handleTooltipMouseOver } = props
22
+ const { forestPlot } = config as ChartConfig
23
+ const labelPosition = config.xAxis.tickWidthMax + 10
24
+ const [initialLogTicksSet, setInitialLogTicks] = useState(false)
25
+
26
+ useEffect(() => {
27
+ try {
28
+ const defaultColumns = ['estimateField', 'lower', 'upper', 'estimateRadius']
29
+ const newConfig = config
30
+
31
+ // Setting a default number of colums.additionalColumn1, columns.additionalColumn2, etc.
32
+ // to loop through to clean up which columns are being displayed by default for forest plots
33
+ // Set tooltip and data table properties according to the default forestPlot column names above.
34
+ const colsToCheck = 10
35
+ for (let i = 0; i < colsToCheck; i++) {
36
+ defaultColumns.forEach(col => {
37
+ if (config.forestPlot[col] && config.forestPlot[col] !== newConfig.columns[config.forestPlot[`additionalColumn${i}`]]?.name) {
38
+ delete newConfig.columns[`additionalColumn${i}`] // Remove old value if found to prevent duplicates
39
+ newConfig.columns[config.forestPlot[col]] = {}
40
+ newConfig.columns[config.forestPlot[col]].dataKey = newConfig.forestPlot[col]
41
+ newConfig.columns[config.forestPlot[col]].name = newConfig.forestPlot[col]
42
+ newConfig.columns[config.forestPlot[col]].dataTable = true
43
+ newConfig.columns[config.forestPlot[col]].tooltips = true
44
+ newConfig.columns[config.forestPlot[col]].label = newConfig.forestPlot[col]
45
+ }
46
+ })
47
+ }
48
+
49
+ // Add weight column into tooltip and data table.
50
+ if (config.forestPlot.radius.scalingColumn) {
51
+ newConfig.columns[config.forestPlot.radius.scalingColumn] = {}
52
+ newConfig.columns[config.forestPlot.radius.scalingColumn].dataKey = newConfig.forestPlot.radius.scalingColumn
53
+ newConfig.columns[config.forestPlot.radius.scalingColumn].name = newConfig.forestPlot.radius.scalingColumn
54
+ newConfig.columns[config.forestPlot.radius.scalingColumn].label = newConfig.forestPlot.radius.scalingColumn
55
+ newConfig.columns[config.forestPlot.radius.scalingColumn].dataTable = true
56
+ newConfig.columns[config.forestPlot.radius.scalingColumn].tooltips = true
57
+ }
58
+
59
+ if (newConfig.table.showVertical) {
60
+ newConfig.table.indexLabel = config.xAxis.dataKey
61
+ }
62
+
63
+ updateConfig(newConfig)
64
+ } catch (e) {
65
+ console.log(e.message)
66
+ }
67
+ }, [])
68
+
69
+ useEffect(() => {
70
+ if (!initialLogTicksSet && config.forestPlot.type === 'Logarithmic') {
71
+ updateConfig({
72
+ ...config,
73
+ dataFormat: {
74
+ ...config.dataFormat,
75
+ roundTo: 2
76
+ }
77
+ })
78
+ setInitialLogTicks(true)
79
+ }
80
+ }, [config.forestPlot.type])
81
+
82
+ const pooledData = config.data.find(d => d[config.xAxis.dataKey] === config.forestPlot.pooledResult.column)
83
+
84
+ const regressionPoints = pooledData
85
+ ? [
86
+ { x: xScale(pooledData[config.forestPlot.lower]), y: height - Number(config.forestPlot.rowHeight) },
87
+ { x: xScale(pooledData[config.forestPlot.estimateField]), y: height - forestPlot.pooledResult.diamondHeight - Number(config.forestPlot.rowHeight) },
88
+ { x: xScale(pooledData[config.forestPlot.upper]), y: height - Number(config.forestPlot.rowHeight) },
89
+ { x: xScale(pooledData[config.forestPlot.estimateField]), y: height + forestPlot.pooledResult.diamondHeight - Number(config.forestPlot.rowHeight) },
90
+ { x: xScale(pooledData[config.forestPlot.lower]), y: height - Number(config.forestPlot.rowHeight) }
91
+ ]
92
+ : []
93
+
94
+ const topMarginOffset = config.forestPlot.rowHeight
95
+
96
+ const topLine = [
97
+ { x: 0, y: topMarginOffset },
98
+ { x: width, y: topMarginOffset }
99
+ ]
100
+
101
+ const bottomLine = [
102
+ { x: 0, y: height },
103
+ { x: width, y: height }
104
+ ]
105
+
106
+ type Columns = {
107
+ forestPlot?: boolean
108
+ }
109
+
110
+ const columnsOnChart: Columns[] = Object.entries(config.columns)
111
+ .map(entry => entry[1])
112
+ .filter(entry => entry.forestPlot === true)
113
+
114
+ return (
115
+ <>
116
+ <Group width={width}>
117
+ {forestPlot.title && (
118
+ <Text className={`forest-plot--title`} x={forestPlot.type === 'Linear' ? xScale(0) : xScale(1)} y={0} textAnchor='middle' verticalAnchor='start' fontSize={getFontSize(config.fontSize)} fill={'black'}>
119
+ {forestPlot.title}
120
+ </Text>
121
+ )}
122
+
123
+ {/* Line of no effect on Continuous Scale. */}
124
+ {forestPlot.lineOfNoEffect.show && forestPlot.type === 'Linear' && <Line from={{ x: xScale(0), y: 0 + topMarginOffset }} to={{ x: xScale(0), y: height }} className='forestplot__line-of-no-effect' stroke={forestPlot.regression.baseLineColor || 'black'} />}
125
+
126
+ {/* Line of no effect on Logarithmic Scale. */}
127
+ {forestPlot.lineOfNoEffect.show && forestPlot.type === 'Logarithmic' && <Line from={{ x: xScale(1), y: 0 + topMarginOffset }} to={{ x: xScale(1), y: height }} className='forestplot__line-of-no-effect' stroke={forestPlot.regression.baseLineColor || 'black'} />}
128
+
129
+ {data.map((d, i) => {
130
+ // calculate both square and circle size based on radius.min and radius.max
131
+ const scaleRadius = scaleLinear({
132
+ domain: data.map(d => d[forestPlot.radius.scalingColumn]),
133
+ range: [forestPlot.radius.min, forestPlot.radius.max]
134
+ })
135
+
136
+ // glyph settings
137
+ const rectSize = forestPlot.radius.scalingColumn !== '' ? scaleRadius(data[i][forestPlot.radius.scalingColumn]) : 4
138
+ const shapeColor = forestPlot.colors.shape ? forestPlot.colors.shape : 'black'
139
+ const lineColor = forestPlot.colors.line ? forestPlot.colors.line : 'black'
140
+
141
+ // ci size
142
+ const ciEndSize = 4
143
+
144
+ // Don't run calculations on the pooled column
145
+ const isTotalColumn = d[config.xAxis.dataKey] === forestPlot.pooledResult.column
146
+
147
+ return !isTotalColumn ? (
148
+ <Group>
149
+ {/* Confidence Interval Paths */}
150
+ <path
151
+ stroke={lineColor}
152
+ strokeWidth={1}
153
+ className='lower-ci'
154
+ d={`
155
+ M${xScale(d[forestPlot.lower])} ${yScale(i) - Number(ciEndSize)}
156
+ L${xScale(d[forestPlot.lower])} ${yScale(i) + Number(ciEndSize)}
157
+ `}
158
+ />
159
+
160
+ <path
161
+ stroke={lineColor}
162
+ strokeWidth={1}
163
+ className='upper-ci'
164
+ d={`
165
+ M${xScale(d[forestPlot.upper])} ${yScale(i) - Number(ciEndSize)}
166
+ L${xScale(d[forestPlot.upper])} ${yScale(i) + Number(ciEndSize)}
167
+ `}
168
+ />
169
+
170
+ {/* main line */}
171
+ <line stroke={lineColor} className={`line-${d[config.yAxis.dataKey]}`} key={i} x1={xScale(d[forestPlot.lower])} x2={xScale(d[forestPlot.upper])} y1={yScale(i)} y2={yScale(i)} />
172
+ {forestPlot.shape === 'circle' && (
173
+ <Circle className='forest-plot--circle' cx={xScale(Number(d[forestPlot.estimateField]))} cy={yScale(i)} r={forestPlot.radius.scalingColumn !== '' ? scaleRadius(data[i][forestPlot.radius.scalingColumn]) : 4} fill={shapeColor} style={{ opacity: 1, filter: 'unset' }} />
174
+ )}
175
+ {forestPlot.shape === 'square' && <rect className='forest-plot--square' x={xScale(Number(d[forestPlot.estimateField]))} y={yScale(i) - rectSize / 2} width={rectSize} height={rectSize} fill={shapeColor} style={{ opacity: 1, filter: 'unset' }} />}
176
+ {forestPlot.shape === 'text' && (
177
+ <Text className='forest-plot--text' x={xScale(Number(d[forestPlot.estimateField]))} y={yScale(i)} textAnchor='middle' verticalAnchor='middle' fontSize={getFontSize(config.fontSize)} fill={shapeColor}>
178
+ {d[forestPlot.estimateField]}
179
+ </Text>
180
+ )}
181
+ </Group>
182
+ ) : (
183
+ <LinePath data={regressionPoints} x={d => d.x} y={d => d.y - getFontSize(config.fontSize) / 2} stroke='black' strokeWidth={2} fill={'black'} curve={curveLinearClosed} />
184
+ )
185
+ })}
186
+
187
+ {/* regression diamond */}
188
+ {regressionPoints && forestPlot.regression.showDiamond && <LinePath data={regressionPoints} x={d => d.x} y={d => d.y} stroke='black' strokeWidth={2} fill={forestPlot.regression.baseLineColor} curve={curveLinearClosed} />}
189
+ {/* regression text */}
190
+ {forestPlot.regression.description && (
191
+ <Text x={0 - Number(config.xAxis.size)} width={width} y={height - config.forestPlot.rowHeight - Number(forestPlot.rowHeight) / 3} verticalAnchor='start' textAnchor='start' style={{ fontWeight: 'bold', fontSize: 12 }}>
192
+ {forestPlot.regression.description}
193
+ </Text>
194
+ )}
195
+
196
+ <Bar key='forest-plot-tooltip-area' className='forest-plot-tooltip-area' width={width} height={height} fill={false ? 'red' : 'transparent'} fillOpacity={0.5} onMouseMove={e => handleTooltipMouseOver(e, data)} onMouseOut={handleTooltipMouseOff} />
197
+ </Group>
198
+ <Line from={topLine[0]} to={topLine[1]} style={{ stroke: 'black', strokeWidth: 2 }} className='forestplot__top-line' />
199
+ <Line from={bottomLine[0]} to={bottomLine[1]} style={{ stroke: 'black', strokeWidth: 2 }} className='forestplot__bottom-line' />
200
+
201
+ {/* column data */}
202
+ {columnsOnChart.map(column => {
203
+ return data.map((d, i) => {
204
+ return (
205
+ <Text className={`${d[column.name]}`} x={column.forestPlotAlignRight ? width : column.forestPlotStartingPoint} y={yScale(i)} textAnchor={column.forestPlotAlignRight ? 'end' : 'start'} verticalAnchor='middle' fontSize={getFontSize(config.fontSize)} fill={'black'}>
206
+ {d[column.name]}
207
+ </Text>
208
+ )
209
+ })
210
+ })}
211
+
212
+ {/* X Axis DataKey Cols*/}
213
+ {!forestPlot.hideDateCategoryCol &&
214
+ data.map((d, i) => {
215
+ return (
216
+ <Text className={`${d[config.xAxis.dataKey]}`} x={0} y={yScale(i)} textAnchor={'start'} verticalAnchor='middle' fontSize={getFontSize(config.fontSize)} fill={'black'}>
217
+ {d[config.xAxis.dataKey]}
218
+ </Text>
219
+ )
220
+ })}
221
+
222
+ {/* X Axis Datakey Header */}
223
+ {!forestPlot.hideDateCategoryCol && config.xAxis.dataKey && (
224
+ <Text className={config.xAxis.dataKey} x={0} y={0} textAnchor={'start'} verticalAnchor='start' fontSize={getFontSize(config.fontSize)} fill={'black'}>
225
+ {config.xAxis.dataKey}
226
+ </Text>
227
+ )}
228
+
229
+ {/* column headers */}
230
+ {columnsOnChart.map(column => {
231
+ return (
232
+ <Text className={`${column.label}`} x={column.forestPlotAlignRight ? width : column.forestPlotStartingPoint} y={0} textAnchor={column.forestPlotAlignRight ? 'end' : 'start'} verticalAnchor='start' fontSize={getFontSize(config.fontSize)} fill={'black'}>
233
+ {column.label}
234
+ </Text>
235
+ )
236
+ })}
237
+
238
+ {/* left bottom label */}
239
+ {forestPlot.leftLabel && (
240
+ <Text className='forest-plot__left-label' x={forestPlot.type === 'Linear' ? xScale(0) - 25 : xScale(1) - 25} y={height + labelPosition} textAnchor='end' verticalAnchor='start'>
241
+ {forestPlot.leftLabel}
242
+ </Text>
243
+ )}
244
+
245
+ {forestPlot.rightLabel && (
246
+ <Text className='forest-plot__right-label' x={forestPlot.type === 'Linear' ? xScale(0) + 25 : xScale(1) + 25} y={height + labelPosition} textAnchor='start' verticalAnchor='start'>
247
+ {forestPlot.rightLabel}
248
+ </Text>
249
+ )}
250
+ </>
251
+ )
252
+ }
253
+
254
+ export default ForestPlot
@@ -0,0 +1,18 @@
1
+ import { type ChartConfig } from '@cdc/chart/src/types/ChartConfig'
2
+
3
+ export type ForestPlotProps = {
4
+ /** xScale - scaling function for bottom axis */
5
+ xScale: Function
6
+ /** yScale - scaling function for left axis */
7
+ yScale: Function
8
+ /** config - standard chart config */
9
+ config: ChartConfig
10
+ /** height - height of chart */
11
+ height: number
12
+ /** width - width of chart */
13
+ width: number
14
+ /** handleTooltipMouseOff - helper function for hiding tooltip */
15
+ handleTooltipMouseOff: Function
16
+ /** handleTooltipMousOver - helper function for showing tooltip */
17
+ handleTooltipMouseOver: Function
18
+ }
@@ -0,0 +1 @@
1
+ // Forest Plot Styles...
@@ -0,0 +1,3 @@
1
+ import ForestPlot from './ForestPlot'
2
+
3
+ export default ForestPlot