@cdc/chart 4.23.1 → 4.23.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 (74) hide show
  1. package/dist/cdcchart.js +56289 -702
  2. package/examples/Barchart_with_negative.json +34 -0
  3. package/examples/area-chart.json +187 -0
  4. package/examples/big-small-test-bar.json +328 -0
  5. package/examples/big-small-test-line.json +328 -0
  6. package/examples/big-small-test-negative.json +328 -0
  7. package/examples/box-plot.json +1 -2
  8. package/examples/dynamic-legends.json +1 -1
  9. package/examples/example-bar-chart-nonnumeric.json +36 -0
  10. package/examples/example-bar-chart.json +36 -0
  11. package/examples/example-combo-bar-nonnumeric.json +105 -0
  12. package/examples/example-sparkline.json +76 -0
  13. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart.json +31 -172
  14. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +1 -1
  15. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-confidence.json +1 -0
  16. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-with-confidence.json +96 -14
  17. package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +2 -2
  18. package/examples/gallery/line/line.json +1 -0
  19. package/examples/gallery/paired-bar/paired-bar-chart.json +65 -13
  20. package/examples/horizontal-chart-max-increase.json +38 -0
  21. package/examples/line-chart-max-increase.json +32 -0
  22. package/examples/line-chart-nonnumeric.json +32 -0
  23. package/examples/line-chart.json +21 -63
  24. package/examples/newdata.json +1 -1
  25. package/examples/planet-combo-example-config.json +143 -20
  26. package/examples/planet-deviation-config.json +168 -0
  27. package/examples/planet-deviation-data.json +38 -0
  28. package/examples/planet-example-config.json +139 -20
  29. package/examples/planet-example-data-max-increase.json +56 -0
  30. package/examples/planet-example-data-nonnumeric.json +56 -0
  31. package/examples/planet-example-data.json +9 -9
  32. package/examples/planet-pie-example-config-nonnumeric.json +30 -0
  33. package/examples/scatterplot-continuous.csv +17 -0
  34. package/examples/scatterplot.json +136 -0
  35. package/examples/sparkline-chart-nonnumeric.json +76 -0
  36. package/examples/stacked-vertical-bar-example-negative.json +154 -0
  37. package/examples/stacked-vertical-bar-example-nonnumerics.json +154 -0
  38. package/index.html +91 -0
  39. package/package.json +33 -24
  40. package/src/{CdcChart.tsx → CdcChart.jsx} +196 -124
  41. package/src/components/AreaChart.jsx +198 -0
  42. package/src/components/{BarChart.tsx → BarChart.jsx} +154 -122
  43. package/src/components/BoxPlot.jsx +101 -0
  44. package/src/components/{DataTable.tsx → DataTable.jsx} +109 -28
  45. package/src/components/DeviationBar.jsx +191 -0
  46. package/src/components/{EditorPanel.js → EditorPanel.jsx} +676 -157
  47. package/src/components/{Filters.js → Filters.jsx} +6 -11
  48. package/src/components/Legend.jsx +316 -0
  49. package/src/components/{LineChart.tsx → LineChart.jsx} +22 -26
  50. package/src/components/{LinearChart.tsx → LinearChart.jsx} +214 -91
  51. package/src/components/{PairedBarChart.tsx → PairedBarChart.jsx} +44 -78
  52. package/src/components/{PieChart.tsx → PieChart.jsx} +26 -44
  53. package/src/components/ScatterPlot.jsx +51 -0
  54. package/src/components/SparkLine.jsx +218 -0
  55. package/src/components/{useIntersectionObserver.tsx → useIntersectionObserver.jsx} +2 -2
  56. package/src/data/initial-state.js +51 -5
  57. package/src/hooks/useColorPalette.js +68 -0
  58. package/src/hooks/{useReduceData.ts → useReduceData.js} +26 -16
  59. package/src/hooks/useRightAxis.js +3 -1
  60. package/src/index.jsx +16 -0
  61. package/src/scss/DataTable.scss +22 -0
  62. package/src/scss/editor-panel.scss +5 -0
  63. package/src/scss/main.scss +30 -10
  64. package/src/test/CdcChart.test.jsx +6 -0
  65. package/vite.config.js +4 -0
  66. package/dist/495.js +0 -3
  67. package/dist/703.js +0 -1
  68. package/src/components/BoxPlot.js +0 -92
  69. package/src/components/Legend.js +0 -291
  70. package/src/components/SparkLine.js +0 -185
  71. package/src/hooks/useColorPalette.ts +0 -76
  72. package/src/index.html +0 -67
  73. package/src/index.tsx +0 -18
  74. /package/src/{context.tsx → ConfigContext.jsx} +0 -0
@@ -0,0 +1,198 @@
1
+ import React, { useContext, useCallback } from 'react'
2
+
3
+ // cdc
4
+ import ConfigContext from '../ConfigContext'
5
+ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
6
+ import { colorPalettesChart } from '@cdc/core/data/colorPalettes'
7
+
8
+ // visx & d3
9
+ import { AreaClosed, LinePath, Bar } from '@visx/shape'
10
+ import { Group } from '@visx/group'
11
+ import * as allCurves from '@visx/curve'
12
+ import { useTooltip, useTooltipInPortal, defaultStyles } from '@visx/tooltip'
13
+ import { localPoint } from '@visx/event'
14
+ import { bisector } from 'd3-array'
15
+
16
+ const CoveAreaChart = ({ xScale, yScale, yMax, xMax }) => {
17
+ // enable various console logs in the file
18
+ const DEBUG = false
19
+
20
+ // import data from context
21
+ const { transformedData: data, config, handleLineType, parseDate, formatDate, formatNumber, seriesHighlight } = useContext(ConfigContext)
22
+
23
+ // import tooltip helpers
24
+ const { tooltipData, showTooltip } = useTooltip()
25
+
26
+ // used for offset on tooltip hover
27
+ let isEditor = window.location.href.includes('editor=true')
28
+
29
+ // here we're inside of the svg,
30
+ // it appears we need to use TooltipInPortal.
31
+ const { TooltipInPortal } = useTooltipInPortal({
32
+ detectBounds: true,
33
+ // when tooltip containers are scrolled, this will correctly update the Tooltip position
34
+ scroll: true
35
+ })
36
+
37
+ // Draw transparent bars over the chart to get tooltip data
38
+ // Turn DEBUG on for additional context.
39
+ let barThickness = xMax / config.data.length
40
+ let barThicknessAdjusted = barThickness * (config.barThickness || 0.8)
41
+ let offset = (barThickness * (1 - (config.barThickness || 0.8))) / 2
42
+
43
+ // Tooltip helper for getting data to the closest date/category hovered.
44
+ const getXValueFromCoordinate = x => {
45
+ if (config.xAxis.type === 'categorical') {
46
+ let eachBand = xScale.step()
47
+ let numerator = x
48
+ const index = Math.floor(Number(numerator) / eachBand)
49
+ return xScale.domain()[index - 1] // fixes off by 1 error
50
+ }
51
+
52
+ if (config.xAxis.type === 'date') {
53
+ const bisectDate = bisector(d => parseDate(d[config.xAxis.dataKey])).left
54
+ const x0 = xScale.invert(x)
55
+ const index = bisectDate(config.data, x0, 1)
56
+ const val = parseDate(config.data[index - 1][config.xAxis.dataKey])
57
+ return val
58
+ }
59
+ }
60
+
61
+ const handleMouseOver = useCallback(
62
+ (e, data) => {
63
+ // get the svg coordinates of the mouse
64
+ // and get the closest values
65
+ const eventSvgCoords = localPoint(e)
66
+ const { x, y } = eventSvgCoords
67
+
68
+ let closestXScaleValue = getXValueFromCoordinate(x)
69
+ let formattedDate = formatDate(closestXScaleValue)
70
+
71
+ let yScaleValues
72
+ if (config.xAxis.type === 'categorical') {
73
+ yScaleValues = data.filter(d => d[config.xAxis.dataKey] === closestXScaleValue)
74
+ } else {
75
+ yScaleValues = data.filter(d => d[config.xAxis.dataKey] === formattedDate)
76
+ }
77
+
78
+ let seriesToInclude = []
79
+ let yScaleMaxValues = []
80
+ let itemsToLoop = [config.runtime.xAxis.dataKey, ...config.runtime.seriesKeys]
81
+
82
+ itemsToLoop.map(seriesKey => {
83
+ return Object.entries(yScaleValues[0]).forEach(item => item[0] === seriesKey && seriesToInclude.push(item))
84
+ })
85
+
86
+ // filter out the series that aren't added to the map.
87
+ seriesToInclude.map(series => yScaleMaxValues.push(Number(yScaleValues[0][series])))
88
+ seriesToInclude = Object.fromEntries(seriesToInclude)
89
+
90
+ let tooltipData = {}
91
+ tooltipData.data = seriesToInclude
92
+ tooltipData.dataXPosition = isEditor ? 300 + x + 20 : x + 20
93
+ tooltipData.dataYPosition = y - 20
94
+
95
+ let tooltipInformation = {
96
+ tooltipData: tooltipData,
97
+ tooltipTop: 0,
98
+ tooltipValues: yScaleValues,
99
+ tooltipLeft: x
100
+ }
101
+
102
+ showTooltip(tooltipInformation)
103
+ },
104
+ [showTooltip] // eslint-disable-line
105
+ )
106
+
107
+ const TooltipListItem = ({ item }) => {
108
+ const [label, value] = item
109
+ return label === config.xAxis.dataKey ? `${label}: ${value}` : `${label}: ${formatNumber(value, 'left')}`
110
+ }
111
+
112
+ const handleX = d => {
113
+ return config.xAxis.type === 'date' ? xScale(parseDate(d[config.xAxis.dataKey])) : xScale(d[config.xAxis.dataKey])
114
+ }
115
+
116
+ const handleY = (d, index) => {
117
+ return yScale(d[config.series[index].dataKey])
118
+ }
119
+
120
+ return (
121
+ data && (
122
+ <ErrorBoundary component='AreaChart'>
123
+ <Group className='area-chart' key='area-wrapper' left={config.yAxis.size}>
124
+ {config.series.map((s, index) => {
125
+ let seriesColor = colorPalettesChart[config.palette][index]
126
+ let curveType = allCurves[s.lineType]
127
+ let transparentArea = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(s.dataKey) === -1
128
+ let displayArea = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(s.dataKey) !== -1
129
+
130
+ data.map(d => xScale(parseDate(d[config.xAxis.dataKey])))
131
+
132
+ return (
133
+ <>
134
+ {/* prettier-ignore */}
135
+ {/* this is the line that appears on top of the area chart */}
136
+ <LinePath data={data} x={d => handleX(d)} y={d => yScale(d[config.series[index].dataKey])} stroke={seriesColor} strokeWidth={2} strokeOpacity={1} shapeRendering='geometricPrecision' curve={curveType} strokeDasharray={s.type ? handleLineType(s.type) : 0} />
137
+
138
+ {/* prettier-ignore */}
139
+ {/* filled in sections */}
140
+ <AreaClosed key={'area-chart'} fill={displayArea ? seriesColor : 'transparent'} fillOpacity={transparentArea ? 0.25 : 0.5} data={data} x={d => handleX(d)} y={d => handleY(d, index)} yScale={yScale} curve={curveType} strokeDasharray={s.type ? handleLineType(s.typ) : 0} />
141
+
142
+ <Bar x={d => handleX(d)} y={d => yScale(d[config.series[index].dataKey])} yScale={yScale} width={xMax} height={yMax} fill={DEBUG ? 'red' : 'transparent'} fillOpacity={0.05} style={DEBUG ? { stroke: 'black', strokeWidth: 2 } : {}} onMouseMove={e => handleMouseOver(e, data)} />
143
+
144
+ {/* circles that appear on hover */}
145
+ {tooltipData && (
146
+ <circle
147
+ cx={config.xAxis.type === 'categorical' ? xScale(tooltipData.data[config.xAxis.dataKey]) : xScale(parseDate(tooltipData.data[config.xAxis.dataKey]))}
148
+ cy={yScale(tooltipData.data[s.dataKey])}
149
+ r={4.5}
150
+ opacity={1}
151
+ fillOpacity={1}
152
+ fill={seriesColor}
153
+ style={{ filter: 'unset', opacity: 1 }}
154
+ />
155
+ )}
156
+
157
+ {/* bars to handle tooltips */}
158
+ {DEBUG &&
159
+ config.data.map((item, index) => {
160
+ return (
161
+ <Bar
162
+ className='bar-here'
163
+ x={barThickness * index + offset}
164
+ y={d => yScale(d[config.series[index].dataKey])}
165
+ yScale={yScale}
166
+ width={barThicknessAdjusted}
167
+ height={yMax}
168
+ fill={'transparent'}
169
+ fillOpacity={1}
170
+ style={{ stroke: 'black', strokeWidth: 2 }}
171
+ onMouseMove={e => handleMouseOver(e, data)}
172
+ />
173
+ )
174
+ })}
175
+
176
+ {tooltipData && (
177
+ <TooltipInPortal key={Math.random()} top={tooltipData.dataYPosition} left={tooltipData.dataXPosition} style={defaultStyles}>
178
+ <Group x={config.yAxis.size + 10} y={0}>
179
+ <ul style={{ listStyle: 'none', paddingLeft: 'unset' }}>
180
+ {Object.entries(tooltipData.data).map(item => (
181
+ <li>
182
+ <TooltipListItem item={item} />
183
+ </li>
184
+ ))}
185
+ </ul>
186
+ </Group>
187
+ </TooltipInPortal>
188
+ )}
189
+ </>
190
+ )
191
+ })}
192
+ </Group>
193
+ </ErrorBoundary>
194
+ )
195
+ )
196
+ }
197
+
198
+ export default CoveAreaChart