@cdc/chart 4.23.6 → 4.23.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdcchart.js +29981 -29995
- package/examples/feature/__data__/area-chart-date-apple.json +5122 -0
- package/examples/feature/__data__/city-temperature.json +2198 -0
- package/examples/feature/__data__/planet-example-data.json +1 -1
- package/examples/feature/area/area-chart-category.json +45 -45
- package/examples/feature/area/area-chart-date-apple.json +10376 -0
- package/examples/feature/area/area-chart-date-city-temperature.json +4528 -0
- package/examples/feature/area/area-chart-date.json +111 -3
- package/examples/feature/combo/right-issues.json +1 -1
- package/examples/feature/forecasting/combo-forecasting.json +72 -46
- package/examples/feature/forecasting/effective_reproduction.json +57 -8
- package/examples/feature/forecasting/forecasting.json +12 -3
- package/examples/feature/forest-plot/broken.json +700 -0
- package/examples/feature/forest-plot/data.csv +24 -0
- package/examples/feature/forest-plot/forest-plot.json +717 -0
- package/examples/feature/line/line-chart.json +11 -11
- package/examples/feature/pie/planet-pie-example-config.json +1 -1
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +167 -20
- package/examples/private/confidence_interval_test.json +248 -0
- package/examples/private/tooltip-issue.json +45275 -0
- package/index.html +13 -11
- package/package.json +4 -3
- package/src/CdcChart.jsx +78 -27
- package/src/components/AreaChart.jsx +65 -151
- package/src/components/BarChart.Horizontal.jsx +251 -0
- package/src/components/BarChart.StackedHorizontal.jsx +118 -0
- package/src/components/BarChart.StackedVertical.jsx +93 -0
- package/src/components/BarChart.Vertical.jsx +204 -0
- package/src/components/BarChart.jsx +17 -667
- package/src/components/BarChartType.jsx +15 -0
- package/src/components/BrushHandle.jsx +17 -0
- package/src/components/DataTable.jsx +67 -22
- package/src/components/EditorPanel.jsx +426 -358
- package/src/components/Forecasting.jsx +23 -86
- package/src/components/ForestPlot.jsx +191 -0
- package/src/components/ForestPlotSettings.jsx +508 -0
- package/src/components/Legend.jsx +10 -8
- package/src/components/LineChart.jsx +31 -6
- package/src/components/LinearChart.jsx +317 -230
- package/src/components/Series.jsx +40 -4
- package/src/data/initial-state.js +50 -3
- package/src/hooks/useBarChart.js +186 -0
- package/src/hooks/useEditorPermissions.js +218 -0
- package/src/hooks/useMinMax.js +18 -5
- package/src/hooks/useRightAxis.js +2 -1
- package/src/hooks/useScales.js +45 -2
- package/src/hooks/useTooltip.jsx +407 -0
- package/src/scss/main.scss +11 -17
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useContext
|
|
1
|
+
import React, { useContext } from 'react'
|
|
2
2
|
|
|
3
3
|
// cdc
|
|
4
4
|
import ConfigContext from '../ConfigContext'
|
|
@@ -6,43 +6,21 @@ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
|
6
6
|
import { colorPalettesChart } from '@cdc/core/data/colorPalettes'
|
|
7
7
|
|
|
8
8
|
// visx & d3
|
|
9
|
-
import { useTooltipInPortal, defaultStyles } from '@visx/tooltip'
|
|
10
9
|
import { curveMonotoneX } from '@visx/curve'
|
|
11
|
-
import { Bar, Area, LinePath
|
|
10
|
+
import { Bar, Area, LinePath } from '@visx/shape'
|
|
12
11
|
import { Group } from '@visx/group'
|
|
13
12
|
|
|
14
|
-
const Forecasting = ({ xScale, yScale, height, width,
|
|
15
|
-
const { transformedData: data, rawData, config, seriesHighlight
|
|
13
|
+
const Forecasting = ({ xScale, yScale, height, width, handleTooltipMouseOver, handleTooltipMouseOff }) => {
|
|
14
|
+
const { transformedData: data, rawData, config, seriesHighlight } = useContext(ConfigContext)
|
|
16
15
|
const { xAxis, yAxis, legend, runtime } = config
|
|
17
16
|
const DEBUG = false
|
|
18
17
|
|
|
19
|
-
// sets the portal x/y for where tooltips should appear on the page.
|
|
20
|
-
const [chartPosition, setChartPosition] = useState(null)
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
setChartPosition(chartRef.current.getBoundingClientRect())
|
|
23
|
-
}, [chartRef])
|
|
24
|
-
|
|
25
|
-
// a unique id is needed for tooltips.
|
|
26
|
-
const tooltip_id = `cdc-open-viz-tooltip-${config.runtime.uniqueId}`
|
|
27
|
-
|
|
28
|
-
// it appears we need to use TooltipInPortal.
|
|
29
|
-
const { TooltipInPortal } = useTooltipInPortal({
|
|
30
|
-
detectBounds: true,
|
|
31
|
-
// when tooltip containers are scrolled, this will correctly update the Tooltip position
|
|
32
|
-
scroll: true
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
const TooltipListItem = ({ item }) => {
|
|
36
|
-
const [label, value] = item
|
|
37
|
-
return label === config.xAxis.dataKey ? `${label}: ${value}` : `${label}: ${formatNumber(value, 'left')}`
|
|
38
|
-
}
|
|
39
|
-
|
|
40
18
|
return (
|
|
41
19
|
data && (
|
|
42
20
|
<ErrorBoundary component='ForecastingChart'>
|
|
43
|
-
<Group className='forecasting-items' key='forecasting-items-wrapper' left={yAxis.size}>
|
|
21
|
+
<Group className='forecasting-items' key='forecasting-items-wrapper' left={Number(yAxis.size)}>
|
|
44
22
|
{runtime.forecastingSeriesKeys?.map((group, index) => {
|
|
45
|
-
if (!group || !group.stages) return
|
|
23
|
+
if (!group || !group.stages) return false
|
|
46
24
|
return group.stages.map((stage, stageIndex) => {
|
|
47
25
|
const { behavior } = legend
|
|
48
26
|
const groupData = rawData.filter(d => d[group.stageColumn] === stage.key)
|
|
@@ -54,13 +32,24 @@ const Forecasting = ({ xScale, yScale, height, width, chartRef, handleTooltipMou
|
|
|
54
32
|
{group.confidenceIntervals?.map((ciGroup, ciGroupIndex) => {
|
|
55
33
|
const palette = colorPalettesChart[stage.color]
|
|
56
34
|
|
|
35
|
+
const getFill = () => {
|
|
36
|
+
if (displayArea) return palette[ciGroupIndex] ? palette[ciGroupIndex] : 'transparent'
|
|
37
|
+
return 'transparent'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const getStroke = () => {
|
|
41
|
+
if (displayArea) return palette[2] ? palette[2] : 'transparent'
|
|
42
|
+
return 'transparent'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (ciGroup.high === '' || ciGroup.low === '') return
|
|
57
46
|
return (
|
|
58
47
|
<Group key={`forecasting-areas--stage-${stage.key.replaceAll(' ', '-')}--group-${stageIndex}-${ciGroupIndex}`}>
|
|
59
48
|
{/* prettier-ignore */}
|
|
60
49
|
<Area
|
|
61
50
|
curve={curveMonotoneX}
|
|
62
51
|
data={groupData}
|
|
63
|
-
fill={
|
|
52
|
+
fill={getFill()}
|
|
64
53
|
opacity={transparentArea ? 0.1 : 0.5}
|
|
65
54
|
x={d => xScale(Date.parse(d[xAxis.dataKey]))}
|
|
66
55
|
y0={d => yScale(d[ciGroup.low])}
|
|
@@ -70,26 +59,10 @@ const Forecasting = ({ xScale, yScale, height, width, chartRef, handleTooltipMou
|
|
|
70
59
|
{ciGroupIndex === 0 && (
|
|
71
60
|
<>
|
|
72
61
|
{/* prettier-ignore */}
|
|
73
|
-
<LinePath
|
|
74
|
-
data={groupData}
|
|
75
|
-
x={ d => xScale(Date.parse(d[xAxis.dataKey])) }
|
|
76
|
-
y={ d => yScale(d[ciGroup.high])}
|
|
77
|
-
curve={curveMonotoneX}
|
|
78
|
-
stroke={displayArea ? palette[2] : 'transparent'}
|
|
79
|
-
strokeWidth={1}
|
|
80
|
-
strokeOpacity={1}
|
|
81
|
-
/>
|
|
62
|
+
<LinePath data={groupData} x={d => Number(xScale(Date.parse(d[xAxis.dataKey])))} y={d => Number(yScale(d[ciGroup.high]))} curve={curveMonotoneX} stroke={getStroke()} strokeWidth={1} strokeOpacity={1} />
|
|
82
63
|
|
|
83
64
|
{/* prettier-ignore */}
|
|
84
|
-
<LinePath
|
|
85
|
-
data={groupData}
|
|
86
|
-
x={ d => xScale(Date.parse(d[xAxis.dataKey])) }
|
|
87
|
-
y={ d => yScale(d[ciGroup.low])}
|
|
88
|
-
curve={curveMonotoneX}
|
|
89
|
-
stroke={displayArea ? palette[2] : 'transparent'}
|
|
90
|
-
strokeWidth={1}
|
|
91
|
-
strokeOpacity={1}
|
|
92
|
-
/>
|
|
65
|
+
<LinePath data={groupData} x={d => Number(xScale(Date.parse(d[xAxis.dataKey])))} y={d => Number(yScale(d[ciGroup.low]))} curve={curveMonotoneX} stroke={getStroke()} strokeWidth={1} strokeOpacity={1} />
|
|
93
66
|
</>
|
|
94
67
|
)}
|
|
95
68
|
</Group>
|
|
@@ -99,46 +72,10 @@ const Forecasting = ({ xScale, yScale, height, width, chartRef, handleTooltipMou
|
|
|
99
72
|
)
|
|
100
73
|
})
|
|
101
74
|
})}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
<TooltipInPortal key={Math.random()} top={tooltipData.dataYPosition + chartPosition?.top} left={tooltipData.dataXPosition + chartPosition?.left} style={defaultStyles}>
|
|
105
|
-
<ul
|
|
106
|
-
style={{
|
|
107
|
-
listStyle: 'none',
|
|
108
|
-
paddingLeft: 'unset',
|
|
109
|
-
fontFamily: 'sans-serif',
|
|
110
|
-
margin: 'auto',
|
|
111
|
-
lineHeight: '1rem'
|
|
112
|
-
}}
|
|
113
|
-
data-tooltip-id={tooltip_id}
|
|
114
|
-
>
|
|
115
|
-
{typeof tooltipData === 'object' &&
|
|
116
|
-
Object.entries(tooltipData.data).map((item, index) => (
|
|
117
|
-
<li style={{ padding: '2.5px 0' }} key={`li-${index}`}>
|
|
118
|
-
<TooltipListItem item={item} />
|
|
119
|
-
</li>
|
|
120
|
-
))}
|
|
121
|
-
</ul>
|
|
122
|
-
</TooltipInPortal>
|
|
123
|
-
)}
|
|
124
|
-
{config?.runtime?.forecastingSeriesKeys?.length > 0 && (config.visualizationType === 'Combo' || config.visualizationType === 'Forecasting') && (
|
|
125
|
-
<Group key='tooltip-hover-section'>
|
|
126
|
-
<Bar key={'bars'} width={Number(width)} height={Number(height)} fill={DEBUG ? 'red' : 'transparent'} fillOpacity={0.05} onMouseMove={e => handleTooltipMouseOver(e, data)} onMouseOut={handleTooltipMouseOff} />
|
|
127
|
-
</Group>
|
|
128
|
-
)}
|
|
129
|
-
</Group>
|
|
130
|
-
|
|
131
|
-
{showTooltip && tooltipData && config.visual.verticalHoverLine && (
|
|
132
|
-
<Group key='tooltipLine-vertical' className='vertical-tooltip-line'>
|
|
133
|
-
<Line from={{ x: tooltipData.dataXPosition - 10, y: 0 }} to={{ x: tooltipData.dataXPosition - 10, y: height }} stroke={'black'} strokeWidth={1} pointerEvents='none' strokeDasharray='5,5' className='vertical-tooltip-line' />
|
|
75
|
+
<Group key='tooltip-hover-section'>
|
|
76
|
+
<Bar key={'bars'} width={Number(width)} height={Number(height)} fill={DEBUG ? 'red' : 'transparent'} fillOpacity={0.05} onMouseMove={e => handleTooltipMouseOver(e, data)} onMouseOut={handleTooltipMouseOff} />
|
|
134
77
|
</Group>
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
{showTooltip && tooltipData && config.visual.horizontalHoverLine && (
|
|
138
|
-
<Group key='tooltipLine-horizontal' className='horizontal-tooltip-line' left={config.yAxis.size ? config.yAxis.size : 0}>
|
|
139
|
-
<Line from={{ x: 0, y: tooltipData.dataYPosition }} to={{ x: width, y: tooltipData.dataYPosition }} stroke={'black'} strokeWidth={1} pointerEvents='none' strokeDasharray='5,5' className='horizontal-tooltip-line' />
|
|
140
|
-
</Group>
|
|
141
|
-
)}
|
|
78
|
+
</Group>
|
|
142
79
|
</ErrorBoundary>
|
|
143
80
|
)
|
|
144
81
|
)
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import React, { useContext, useEffect } from 'react'
|
|
2
|
+
|
|
3
|
+
// visx
|
|
4
|
+
import { Group } from '@visx/group'
|
|
5
|
+
import { Line, Bar, Circle, LinePath } from '@visx/shape'
|
|
6
|
+
import { GlyphDiamond } from '@visx/glyph'
|
|
7
|
+
import { Text } from '@visx/text'
|
|
8
|
+
import { scaleLinear } from '@visx/scale'
|
|
9
|
+
import { curveLinearClosed } from '@visx/curve'
|
|
10
|
+
|
|
11
|
+
// cdc
|
|
12
|
+
import ConfigContext from '../ConfigContext'
|
|
13
|
+
import { getFontSize } from '@cdc/core/helpers/cove/number'
|
|
14
|
+
|
|
15
|
+
const ForestPlot = props => {
|
|
16
|
+
const { transformedData: data, updateConfig, dimensions, rawData } = useContext(ConfigContext)
|
|
17
|
+
const { xScale, yScale, config, height, width, handleTooltipMouseOff, handleTooltipMouseOver, maxWidth, maxHeight } = props
|
|
18
|
+
const { forestPlot, runtime, dataFormat } = config
|
|
19
|
+
const [screenWidth, screenHeight] = dimensions
|
|
20
|
+
|
|
21
|
+
// Requirements for forest plot
|
|
22
|
+
// - force legend to be hidden for this chart type
|
|
23
|
+
// - reset the date category axis to zero
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!config.legend.hide) {
|
|
26
|
+
updateConfig({
|
|
27
|
+
...config,
|
|
28
|
+
legend: {
|
|
29
|
+
...config.legend,
|
|
30
|
+
hide: true
|
|
31
|
+
},
|
|
32
|
+
xAxis: {
|
|
33
|
+
...config.xAxis,
|
|
34
|
+
size: 0
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
}, [])
|
|
39
|
+
|
|
40
|
+
const diamondHeight = 5
|
|
41
|
+
|
|
42
|
+
// diamond path
|
|
43
|
+
const regressionPoints = [
|
|
44
|
+
{ x: xScale(forestPlot.regression.lower), y: height - Number(config.forestPlot.rowHeight) },
|
|
45
|
+
{ x: xScale(forestPlot.regression.estimateField), y: height - diamondHeight - Number(config.forestPlot.rowHeight) },
|
|
46
|
+
{ x: xScale(forestPlot.regression.upper), y: height - Number(config.forestPlot.rowHeight) },
|
|
47
|
+
{ x: xScale(forestPlot.regression.estimateField), y: height + diamondHeight - Number(config.forestPlot.rowHeight) },
|
|
48
|
+
{ x: xScale(forestPlot.regression.lower), y: height - Number(config.forestPlot.rowHeight) }
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
const topMarginOffset = config.forestPlot.rowHeight
|
|
52
|
+
|
|
53
|
+
const topLine = [
|
|
54
|
+
{ x: 0, y: topMarginOffset },
|
|
55
|
+
{ x: width, y: topMarginOffset }
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
const bottomLine = [
|
|
59
|
+
{ x: 0, y: height },
|
|
60
|
+
{ x: width, y: height }
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
const columnsOnChart = Object.entries(config.columns)
|
|
64
|
+
.map(entry => entry[1])
|
|
65
|
+
.filter(entry => entry.forestPlot === true)
|
|
66
|
+
|
|
67
|
+
const rightOffset = forestPlot.rightWidthOffset !== 0 ? (Number(forestPlot.rightWidthOffset) / 100) * width : width
|
|
68
|
+
const leftOffset = forestPlot.leftWidthOffset !== 0 ? (Number(forestPlot.leftWidthOffset) / 100) * width : width
|
|
69
|
+
const chartWidth = width - rightOffset - leftOffset
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<>
|
|
73
|
+
<Group>
|
|
74
|
+
{forestPlot.title !== '' && (
|
|
75
|
+
<Text className={`forest-plot--title`} x={xScale(0)} y={0} textAnchor='middle' verticalAnchor='start' fontSize={getFontSize(config.fontSize)} fill={'black'}>
|
|
76
|
+
{forestPlot.title}
|
|
77
|
+
</Text>
|
|
78
|
+
)}
|
|
79
|
+
{forestPlot.regression.showBaseLine && <Line from={{ x: xScale(forestPlot.regression.estimateField), y: 0 + topMarginOffset }} to={{ x: xScale(forestPlot.regression.estimateField), y: height }} className='forestplot__baseline' stroke={forestPlot.regression.baseLineColor || 'black'} />}
|
|
80
|
+
{forestPlot.showZeroLine && <Line from={{ x: xScale(0), y: 0 + topMarginOffset }} to={{ x: xScale(0), y: height }} className='forestplot__zero-line' stroke='gray' strokeDasharray={'5 5'} />}
|
|
81
|
+
|
|
82
|
+
{data.map((d, i) => {
|
|
83
|
+
// calculate both square and circle size based on radius.min and radius.max
|
|
84
|
+
const scaleRadius = scaleLinear({
|
|
85
|
+
domain: xScale.domain(),
|
|
86
|
+
range: [forestPlot.radius.min, forestPlot.radius.max]
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// glyph settings
|
|
90
|
+
const diamondSize = forestPlot.radius.scalingColumn !== '' ? scaleRadius(data[i][forestPlot.estimateField]) * 5 : 4
|
|
91
|
+
const rectSize = forestPlot.radius.scalingColumn !== '' ? scaleRadius(data[i][forestPlot.estimateField]) : 4
|
|
92
|
+
const shapeColor = forestPlot.colors.shape ? forestPlot.colors.shape : 'black'
|
|
93
|
+
const lineColor = forestPlot.colors.line ? forestPlot.colors.line : 'black'
|
|
94
|
+
|
|
95
|
+
// ci size
|
|
96
|
+
const ciEndSize = 4
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<Group>
|
|
100
|
+
{/* Confidence Interval Paths */}
|
|
101
|
+
<path
|
|
102
|
+
stroke={lineColor}
|
|
103
|
+
strokeWidth={1}
|
|
104
|
+
className='lower-ci'
|
|
105
|
+
d={`
|
|
106
|
+
M${xScale(d[forestPlot.lower])} ${yScale(i) - Number(ciEndSize)}
|
|
107
|
+
L${xScale(d[forestPlot.lower])} ${yScale(i) + Number(ciEndSize)}
|
|
108
|
+
`}
|
|
109
|
+
/>
|
|
110
|
+
|
|
111
|
+
<path
|
|
112
|
+
stroke={lineColor}
|
|
113
|
+
strokeWidth={1}
|
|
114
|
+
className='upper-ci'
|
|
115
|
+
d={`
|
|
116
|
+
M${xScale(d[forestPlot.upper])} ${yScale(i) - Number(ciEndSize)}
|
|
117
|
+
L${xScale(d[forestPlot.upper])} ${yScale(i) + Number(ciEndSize)}
|
|
118
|
+
`}
|
|
119
|
+
/>
|
|
120
|
+
|
|
121
|
+
{/* main line */}
|
|
122
|
+
<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)} />
|
|
123
|
+
{forestPlot.shape === 'circle' && (
|
|
124
|
+
<Circle className='forest-plot--circle' cx={xScale(Number(d[forestPlot.estimateField]))} cy={yScale(i)} r={forestPlot.radius.scalingColumn !== '' ? scaleRadius(data[i][forestPlot.estimateField]) : 4} fill={shapeColor} style={{ opacity: 1, filter: 'unset' }} />
|
|
125
|
+
)}
|
|
126
|
+
{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' }} />}
|
|
127
|
+
{forestPlot.shape === 'diamond' && <GlyphDiamond className='forest-plot--diamond' size={diamondSize} top={yScale(i)} left={xScale(Number(d[forestPlot.estimateField]))} fill={shapeColor} />}
|
|
128
|
+
{forestPlot.shape === 'text' && (
|
|
129
|
+
<Text className='forest-plot--text' x={xScale(Number(d[forestPlot.estimateField]))} y={yScale(i)} textAnchor='middle' verticalAnchor='middle' fontSize={getFontSize(config.fontSize)} fill={shapeColor}>
|
|
130
|
+
{d[forestPlot.estimateField]}
|
|
131
|
+
</Text>
|
|
132
|
+
)}
|
|
133
|
+
</Group>
|
|
134
|
+
)
|
|
135
|
+
})}
|
|
136
|
+
|
|
137
|
+
{/* regression diamond */}
|
|
138
|
+
{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} />}
|
|
139
|
+
{/* regression text */}
|
|
140
|
+
{forestPlot.regression.description && (
|
|
141
|
+
<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 }}>
|
|
142
|
+
{forestPlot.regression.description}
|
|
143
|
+
</Text>
|
|
144
|
+
)}
|
|
145
|
+
|
|
146
|
+
<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} />
|
|
147
|
+
</Group>
|
|
148
|
+
<Line from={topLine[0]} to={topLine[1]} style={{ stroke: 'black', strokeWidth: 2 }} className='forestplot__top-line' />
|
|
149
|
+
<Line from={bottomLine[0]} to={bottomLine[1]} style={{ stroke: 'black', strokeWidth: 2 }} className='forestplot__bottom-line' />
|
|
150
|
+
|
|
151
|
+
{/* column data */}
|
|
152
|
+
{columnsOnChart.map(column => {
|
|
153
|
+
return rawData.map((d, i) => {
|
|
154
|
+
return (
|
|
155
|
+
<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'}>
|
|
156
|
+
{d[column.name]}
|
|
157
|
+
</Text>
|
|
158
|
+
)
|
|
159
|
+
})
|
|
160
|
+
})}
|
|
161
|
+
|
|
162
|
+
{/* X Axis DataKey Cols*/}
|
|
163
|
+
{!forestPlot.hideDateCategoryCol &&
|
|
164
|
+
data.map((d, i) => {
|
|
165
|
+
return (
|
|
166
|
+
<Text className={`${d[config.xAxis.dataKey]}`} x={0} y={yScale(i)} textAnchor={'start'} verticalAnchor='middle' fontSize={getFontSize(config.fontSize)} fill={'black'}>
|
|
167
|
+
{d[config.xAxis.dataKey]}
|
|
168
|
+
</Text>
|
|
169
|
+
)
|
|
170
|
+
})}
|
|
171
|
+
|
|
172
|
+
{/* X Axis Datakey Header */}
|
|
173
|
+
{!forestPlot.hideDateCategoryCol && config.xAxis.dataKey && (
|
|
174
|
+
<Text className={config.xAxis.dataKey} x={0} y={0} textAnchor={'start'} verticalAnchor='start' fontSize={getFontSize(config.fontSize)} fill={'black'}>
|
|
175
|
+
{config.xAxis.dataKey}
|
|
176
|
+
</Text>
|
|
177
|
+
)}
|
|
178
|
+
|
|
179
|
+
{/* column headers */}
|
|
180
|
+
{columnsOnChart.map(column => {
|
|
181
|
+
return (
|
|
182
|
+
<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'}>
|
|
183
|
+
{column.label}
|
|
184
|
+
</Text>
|
|
185
|
+
)
|
|
186
|
+
})}
|
|
187
|
+
</>
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export default ForestPlot
|