@cdc/chart 4.23.8 → 4.23.10-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/cdcchart.js +43990 -44283
  2. package/examples/feature/__data__/area-chart-date-apple.json +1 -5073
  3. package/examples/feature/area/area-chart-date-apple.json +73 -10316
  4. package/examples/feature/area/area-chart-date-city-temperature.json +204 -80
  5. package/examples/{private/confidence_interval_test.json → feature/area/area-chart-stacked.json} +65 -74
  6. package/examples/feature/bar/lollipop.json +156 -0
  7. package/examples/feature/combo/planet-combo-example-config.json +99 -9
  8. package/examples/feature/filters/bar-filter.json +5027 -0
  9. package/examples/feature/legend-highlights/highlights.json +567 -0
  10. package/examples/private/TESTING.json +0 -0
  11. package/examples/private/forest-plot.json +356 -0
  12. package/examples/private/{tooltip-issue.json → full.json} +25288 -25239
  13. package/examples/private/missing-color.json +333 -0
  14. package/index.html +30 -8
  15. package/package.json +3 -2
  16. package/src/{CdcChart.jsx → CdcChart.tsx} +81 -74
  17. package/src/_stories/Chart.stories.tsx +188 -0
  18. package/src/components/AreaChart.Stacked.jsx +73 -0
  19. package/src/components/AreaChart.jsx +24 -26
  20. package/src/components/BarChart.StackedVertical.jsx +2 -0
  21. package/src/components/DeviationBar.jsx +67 -13
  22. package/src/components/EditorPanel.jsx +493 -454
  23. package/src/components/Forecasting.jsx +5 -5
  24. package/src/components/ForestPlotSettings.jsx +5 -6
  25. package/src/components/Legend.jsx +18 -9
  26. package/src/components/LineChart.Circle.tsx +102 -0
  27. package/src/components/{LineChart.jsx → LineChart.tsx} +9 -48
  28. package/src/components/LinearChart.jsx +460 -443
  29. package/src/components/PieChart.jsx +54 -25
  30. package/src/components/Series.jsx +63 -17
  31. package/src/components/SparkLine.jsx +7 -19
  32. package/src/data/initial-state.js +10 -1
  33. package/src/hooks/useBarChart.js +1 -1
  34. package/src/hooks/useEditorPermissions.js +87 -24
  35. package/src/hooks/useLegendClasses.js +14 -11
  36. package/src/hooks/useReduceData.js +6 -1
  37. package/src/hooks/useScales.js +4 -4
  38. package/src/hooks/useTooltip.jsx +21 -8
  39. package/src/scss/legend.scss +206 -0
  40. package/src/scss/main.scss +25 -24
  41. package/src/components/DataTable.jsx +0 -374
  42. /package/src/{components → hooks}/useIntersectionObserver.jsx +0 -0
@@ -10,10 +10,8 @@ import { AreaClosed, LinePath, Bar } from '@visx/shape'
10
10
  import { Group } from '@visx/group'
11
11
  import { bisector } from 'd3-array'
12
12
 
13
- const AreaChart = ({ xScale, yScale, yMax, xMax, getXAxisData, getYAxisData, chartRef, handleTooltipMouseOver, handleTooltipMouseOff, tooltipData, isDebug, isBrush, brushData, children }) => {
14
- // enable various console logs in the file
15
- const DEBUG = isDebug
16
-
13
+ const AreaChart = props => {
14
+ const { xScale, yScale, yMax, xMax, handleTooltipMouseOver, handleTooltipMouseOff, isDebug, isBrush, brushData, children } = props
17
15
  // import data from context
18
16
  let { transformedData: data, config, handleLineType, parseDate, formatDate, formatNumber, seriesHighlight, colorScale, rawData } = useContext(ConfigContext)
19
17
 
@@ -23,7 +21,7 @@ const AreaChart = ({ xScale, yScale, yMax, xMax, getXAxisData, getYAxisData, cha
23
21
  if (isBrush && isDebug) console.log('###AREAchart BRUSH data, xScale, yScale, yMax, xMax', data, xScale, yScale, yMax, xMax)
24
22
 
25
23
  // Draw transparent bars over the chart to get tooltip data
26
- // Turn DEBUG on for additional context.
24
+ // Turn isDebug on for additional context.
27
25
  if (!data) return
28
26
 
29
27
  // Tooltip helper for getting data to the closest date/category hovered.
@@ -98,29 +96,29 @@ const AreaChart = ({ xScale, yScale, yMax, xMax, getXAxisData, getYAxisData, cha
98
96
  <React.Fragment key={index}>
99
97
  {/* prettier-ignore */}
100
98
  <LinePath
101
- data={seriesData}
102
- x={d => handleX(d)}
103
- y={d => handleY(d, index, s)}
104
- stroke={displayArea ? colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[s.dataKey] : s.dataKey) : '#000' : 'transparent'}
105
- strokeWidth={2}
106
- strokeOpacity={1}
107
- shapeRendering='geometricPrecision'
108
- curve={curveType}
109
- strokeDasharray={s.type ? handleLineType(s.type) : 0}
110
- />
99
+ data={seriesData}
100
+ x={d => handleX(d)}
101
+ y={d => handleY(d, index, s)}
102
+ stroke={displayArea ? colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[s.dataKey] : s.dataKey) : '#000' : 'transparent'}
103
+ strokeWidth={2}
104
+ strokeOpacity={1}
105
+ shapeRendering='geometricPrecision'
106
+ curve={curveType}
107
+ strokeDasharray={s.type ? handleLineType(s.type) : 0}
108
+ />
111
109
 
112
110
  {/* prettier-ignore */}
113
111
  <AreaClosed
114
- key={'area-chart'}
115
- fill={displayArea ? colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[s.dataKey] : s.dataKey) : '#000' : 'transparent'}
116
- fillOpacity={transparentArea ? 0.25 : 0.5}
117
- data={seriesData}
118
- x={d => handleX(d)}
119
- y={d => handleY(d, index, s)}
120
- yScale={yScale}
121
- curve={curveType}
122
- strokeDasharray={s.type ? handleLineType(s.type) : 0}
123
- />
112
+ key={'area-chart'}
113
+ fill={displayArea ? colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[s.dataKey] : s.dataKey) : '#000' : 'transparent'}
114
+ fillOpacity={transparentArea ? 0.25 : 0.5}
115
+ data={seriesData}
116
+ x={d => handleX(d)}
117
+ y={d => handleY(d, index, s)}
118
+ yScale={yScale}
119
+ curve={curveType}
120
+ strokeDasharray={s.type ? handleLineType(s.type) : 0}
121
+ />
124
122
  {getFirstBrushHandleOnly(children, index)}
125
123
  </React.Fragment>
126
124
  )
@@ -128,7 +126,7 @@ const AreaChart = ({ xScale, yScale, yMax, xMax, getXAxisData, getYAxisData, cha
128
126
 
129
127
  {/* Transparent bar for tooltips - disable if AreaChart is a brush */}
130
128
  {/* prettier-ignore */}
131
- {!isBrush && <Bar width={Number(xMax)} height={Number(yMax)} fill={DEBUG ? 'red' : 'transparent'} fillOpacity={0.05} style={DEBUG ? { stroke: 'black', strokeWidth: 2 } : {}} onMouseMove={e => handleTooltipMouseOver(e, rawData)} onMouseLeave={handleTooltipMouseOff} />}
129
+ {!isBrush && <Bar width={Number(xMax)} height={Number(yMax)} fill={isDebug ? 'red' : 'transparent'} fillOpacity={0.05} style={isDebug ? { stroke: 'black', strokeWidth: 2 } : {}} onMouseMove={e => handleTooltipMouseOver(e, rawData)} onMouseLeave={handleTooltipMouseOff} />}
132
130
  </Group>
133
131
  </ErrorBoundary>
134
132
  </svg>
@@ -27,6 +27,8 @@ const BarChartStackedVertical = props => {
27
27
  const xAxisValue = config.runtime.xAxis.type === 'date' ? formatDate(parseDate(data[bar.index][config.runtime.xAxis.dataKey])) : data[bar.index][config.runtime.xAxis.dataKey]
28
28
  const yAxisValue = formatNumber(bar.bar ? bar.bar.data[bar.key] : 0, 'left')
29
29
 
30
+ if(!yAxisValue) return <></>
31
+
30
32
  const style = applyRadius(barStack.index)
31
33
  let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
32
34
  const xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
@@ -1,18 +1,17 @@
1
1
  import { Line } from '@visx/shape'
2
2
  import { Group } from '@visx/group'
3
- import { useContext, useEffect } from 'react'
3
+ 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
7
  import chroma from 'chroma-js'
8
+ import useIntersectionObserver from '../hooks/useIntersectionObserver'
8
9
 
9
10
  export default function DeviationBar({ height, xScale }) {
10
- const { transformedData: data, config, formatNumber, twoColorPalette, getTextWidth, updateConfig, parseDate, formatDate } = useContext(ConfigContext)
11
-
12
- if (!config || config?.series?.length !== 1 || config.orientation !== 'horizontal') return
13
-
11
+ const { transformedData: data, config, formatNumber, twoColorPalette, getTextWidth, updateConfig, parseDate, formatDate, currentViewport } = useContext(ConfigContext)
14
12
  const { barStyle, tipRounding, roundingStyle, twoColor } = config
15
-
13
+ const barRefs = useRef([])
14
+ const [windowWidth, setWindowWidth] = useState(window.innerWidth)
16
15
  const radius = roundingStyle === 'standard' ? '8px' : roundingStyle === 'shallow' ? '5px' : roundingStyle === 'finger' ? '15px' : '0px'
17
16
  const fontSize = { small: 16, medium: 18, large: 20 }
18
17
  const isRounded = config.barStyle === 'rounded'
@@ -76,14 +75,57 @@ export default function DeviationBar({ height, xScale }) {
76
75
  }
77
76
  targetLabel.calculate()
78
77
 
78
+ const targetRef = useRef(null)
79
+
80
+ const entry = useIntersectionObserver(targetRef, {})
81
+
79
82
  useEffect(() => {
80
- if (config.barStyle === 'lollipop' && !config.isLollipopChart) {
81
- updateConfig({ ...config, isLollipopChart: true })
83
+ const handleResize = () => {
84
+ setWindowWidth(window.innerWidth)
85
+ barRefs.current.forEach(bar => {
86
+ bar.style.transition = 'none'
87
+ bar.style.transform = 'translate(0) scale(1)'
88
+ })
82
89
  }
83
- if (isRounded || config.barStyle === 'flat') {
84
- updateConfig({ ...config, isLollipopChart: false })
90
+ window.addEventListener('resize', handleResize)
91
+
92
+ return () => {
93
+ window.removeEventListener('resize', handleResize)
85
94
  }
86
- }, [config.barStyle])
95
+ }, [])
96
+ const [animatedChart, setAnimatedChart] = useState(false)
97
+
98
+ useEffect(() => {
99
+ if (entry?.isIntersecting) {
100
+ setTimeout(() => {
101
+ setAnimatedChart(true)
102
+ }, 100)
103
+ }
104
+ }, [entry?.isIntersecting, config.animate]) // eslint-disable-line
105
+
106
+ useEffect(() => {
107
+ barRefs.current.forEach((bar, i) => {
108
+ if (config.animate) {
109
+ const normalizedTarget = (target / maxVal) * 100
110
+ bar.style.opacity = '0'
111
+ bar.style.transform = `translate(${normalizedTarget / 1.07}%) scale(0, 1)`
112
+ setTimeout(() => {
113
+ bar.style.opacity = '1'
114
+ bar.style.transform = 'translate(0) scale(1)'
115
+ bar.style.transition = 'transform 0.5s ease'
116
+ }, 100)
117
+ } else {
118
+ bar.style.transition = 'none'
119
+ bar.style.opacity = '0'
120
+ }
121
+ if (!config.animate) {
122
+ bar.style.transition = 'none'
123
+ bar.style.opacity = '1'
124
+ }
125
+ })
126
+ }, [config.animate, config, animatedChart])
127
+
128
+ if (!config || config?.series?.length !== 1) return <></>
87
129
 
88
130
  return (
89
131
  <ErrorBoundary component='Deviation Bar'>
@@ -122,7 +164,6 @@ export default function DeviationBar({ height, xScale }) {
122
164
  const fill = isBarColorDark ? '#FFFFFF' : '#000000'
123
165
 
124
166
  let textProps = getTextProps(config.isLollipopChart, textFits, lollipopShapeSize, fill)
125
-
126
167
  // tooltips
127
168
  const xAxisValue = formatNumber(barValue, 'left')
128
169
  const yAxisValue = config.runtime.yAxis.type === 'date' ? formatDate(parseDate(data[index][config.runtime.originalXAxis.dataKey])) : data[index][config.runtime.originalXAxis.dataKey]
@@ -135,7 +176,19 @@ export default function DeviationBar({ height, xScale }) {
135
176
 
136
177
  return (
137
178
  <Group key={`deviation-bar-${config.orientation}-${seriesKey}-${index}`}>
138
- <foreignObject x={barX} y={barY} width={barWidth} height={barHeight} style={{ border: `${borderWidth}px solid #333`, backgroundColor: barColor[barPosition], ...borderRadius }} data-tooltip-html={tooltip} data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} />
179
+ <foreignObject
180
+ ref={el => {
181
+ // targetRef.current = el
182
+ barRefs.current[index] = el
183
+ }}
184
+ x={barX}
185
+ y={barY}
186
+ width={barWidth}
187
+ height={barHeight}
188
+ style={{ border: `${borderWidth}px solid #333`, backgroundColor: barColor[barPosition], ...borderRadius }}
189
+ data-tooltip-html={tooltip}
190
+ data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
191
+ />
139
192
  {config.yAxis.displayNumbersOnBar && (
140
193
  <Text verticalAnchor='middle' x={textX} y={textY} {...textProps[barPosition]}>
141
194
  {formatNumber(d[seriesKey], 'left')}
@@ -155,6 +208,7 @@ export default function DeviationBar({ height, xScale }) {
155
208
 
156
209
  {shouldShowTargetLine && <Line from={{ x: targetX, y: 0 }} to={{ x: targetX, y: height }} stroke='#333' strokeWidth={2} />}
157
210
  </Group>
211
+ <foreignObject y={height / 2} ref={targetRef}></foreignObject>
158
212
  </ErrorBoundary>
159
213
  )
160
214
  }