@cdc/chart 4.24.4 → 4.24.7
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 +39611 -36038
- package/examples/feature/annotations/index.json +542 -0
- package/examples/xaxis.json +493 -0
- package/index.html +9 -8
- package/package.json +5 -4
- package/src/CdcChart.tsx +115 -71
- package/src/_stories/Chart.stories.tsx +26 -171
- package/src/_stories/ChartAnnotation.stories.tsx +32 -0
- package/src/_stories/_mock/annotation_category_mock.json +473 -0
- package/src/_stories/_mock/annotation_date-linear_mock.json +530 -0
- package/src/_stories/_mock/annotation_date-time_mock.json +530 -0
- package/src/_stories/_mock/bar-chart-suppressed.json +474 -0
- package/src/_stories/_mock/line_chart_two_points_new_chart.json +128 -0
- package/src/_stories/_mock/line_chart_two_points_regression_test.json +127 -0
- package/src/_stories/_mock/lollipop.json +171 -0
- package/src/components/Annotations/components/AnnotationDraggable.styles.css +31 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +154 -0
- package/src/components/Annotations/components/AnnotationDropdown.styles.css +14 -0
- package/src/components/Annotations/components/AnnotationDropdown.tsx +72 -0
- package/src/components/Annotations/components/AnnotationList.styles.css +45 -0
- package/src/components/Annotations/components/AnnotationList.tsx +42 -0
- package/src/components/Annotations/components/findNearestDatum.ts +138 -0
- package/src/components/Annotations/components/helpers/index.tsx +46 -0
- package/src/components/Annotations/index.tsx +13 -0
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +1 -1
- package/src/components/AreaChart/components/AreaChart.jsx +2 -2
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +78 -71
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +1 -2
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +11 -11
- package/src/components/BarChart/components/BarChart.Vertical.tsx +100 -87
- package/src/components/BarChart/helpers/index.ts +102 -0
- package/src/components/DeviationBar.jsx +4 -2
- package/src/components/EditorPanel/EditorPanel.tsx +435 -613
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +306 -0
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +135 -7
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +2 -3
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +4 -5
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +3 -2
- package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
- package/src/components/EditorPanel/components/panels.scss +4 -0
- package/src/components/EditorPanel/editor-panel.scss +19 -0
- package/src/components/EditorPanel/useEditorPermissions.js +23 -3
- package/src/components/Legend/Legend.Component.tsx +66 -15
- package/src/components/Legend/helpers/createFormatLabels.tsx +1 -1
- package/src/components/Legend/helpers/index.ts +5 -0
- package/src/components/LineChart/LineChartProps.ts +16 -6
- package/src/components/LineChart/components/LineChart.Circle.tsx +22 -11
- package/src/components/LineChart/helpers.ts +148 -10
- package/src/components/LineChart/index.tsx +71 -44
- package/src/components/LinearChart.jsx +184 -125
- package/src/components/PairedBarChart.jsx +9 -9
- package/src/components/PieChart/PieChart.tsx +4 -4
- package/src/components/Sankey/index.tsx +73 -20
- package/src/components/ScatterPlot/ScatterPlot.jsx +22 -8
- package/src/components/ZoomBrush.tsx +120 -55
- package/src/data/initial-state.js +14 -6
- package/src/helpers/handleChartTabbing.ts +8 -0
- package/src/helpers/isConvertLineToBarGraph.ts +4 -0
- package/src/hooks/{useBarChart.js → useBarChart.ts} +9 -22
- package/src/hooks/useColorScale.ts +1 -1
- package/src/hooks/useMinMax.ts +29 -5
- package/src/hooks/useScales.ts +48 -26
- package/src/hooks/useTooltip.tsx +62 -15
- package/src/scss/main.scss +69 -12
- package/src/types/ChartConfig.ts +53 -16
- package/src/types/ChartContext.ts +13 -0
- package/tests-examples/helpers/testZeroValue.test.ts +30 -0
- package/LICENSE +0 -201
- package/src/_stories/ChartLine.preliminary.tsx +0 -19
- package/src/_stories/ChartSuppress.stories.tsx +0 -19
- package/src/_stories/_mock/suppress_mock.json +0 -911
- package/src/helpers/computeMarginBottom.ts +0 -56
- package/src/helpers/filterData.ts +0 -18
- package/src/helpers/tests/computeMarginBottom.test.ts +0 -21
- /package/src/hooks/{useLegendClasses.js → useLegendClasses.ts} +0 -0
- /package/src/hooks/{useReduceData.js → useReduceData.ts} +0 -0
package/src/CdcChart.tsx
CHANGED
|
@@ -29,17 +29,17 @@ import Legend from './components/Legend'
|
|
|
29
29
|
import defaults from './data/initial-state'
|
|
30
30
|
import EditorPanel from './components/EditorPanel'
|
|
31
31
|
import { abbreviateNumber } from './helpers/abbreviateNumber'
|
|
32
|
+
import { handleChartTabbing } from './helpers/handleChartTabbing'
|
|
32
33
|
import { getQuartiles } from './helpers/getQuartiles'
|
|
33
34
|
import { sortAsc, sortDesc } from './helpers/sort'
|
|
34
|
-
import { filterData } from './helpers/filterData'
|
|
35
35
|
import { handleChartAriaLabels } from './helpers/handleChartAriaLabels'
|
|
36
36
|
import { lineOptions } from './helpers/lineOptions'
|
|
37
37
|
import { handleLineType } from './helpers/handleLineType'
|
|
38
38
|
import { generateColorsArray } from './helpers/generateColorsArray'
|
|
39
|
-
import { computeMarginBottom } from './helpers/computeMarginBottom'
|
|
40
39
|
import Loading from '@cdc/core/components/Loading'
|
|
41
40
|
import Filters from '@cdc/core/components/Filters'
|
|
42
41
|
import MediaControls from '@cdc/core/components/MediaControls'
|
|
42
|
+
import Annotation from './components/Annotations'
|
|
43
43
|
|
|
44
44
|
// Helpers
|
|
45
45
|
import { publish, subscribe, unsubscribe } from '@cdc/core/helpers/events'
|
|
@@ -51,6 +51,7 @@ import cacheBustingString from '@cdc/core/helpers/cacheBustingString'
|
|
|
51
51
|
import isNumber from '@cdc/core/helpers/isNumber'
|
|
52
52
|
import coveUpdateWorker from '@cdc/core/helpers/coveUpdateWorker'
|
|
53
53
|
import { getQueryStringFilterValue } from '@cdc/core/helpers/queryStringUtils'
|
|
54
|
+
import { isConvertLineToBarGraph } from './helpers/isConvertLineToBarGraph'
|
|
54
55
|
|
|
55
56
|
import './scss/main.scss'
|
|
56
57
|
// load both then config below determines which to use
|
|
@@ -59,8 +60,10 @@ import { getFileExtension } from '@cdc/core/helpers/getFileExtension'
|
|
|
59
60
|
import Title from '@cdc/core/components/ui/Title'
|
|
60
61
|
import { ChartConfig } from './types/ChartConfig'
|
|
61
62
|
import { Label } from './types/Label'
|
|
63
|
+
import { type ViewportSize } from './types/ChartConfig'
|
|
62
64
|
import { isSolrCsv, isSolrJson } from '@cdc/core/helpers/isSolr'
|
|
63
65
|
import SkipTo from '@cdc/core/components/elements/SkipTo'
|
|
66
|
+
import { filterVizData } from '@cdc/core/helpers/filterVizData'
|
|
64
67
|
|
|
65
68
|
export default function CdcChart({ configUrl, config: configObj, isEditor = false, isDebug = false, isDashboard = false, setConfig: setParentConfig, setEditing, hostname, link, setSharedFilter, setSharedFilterValue, dashboardConfig }) {
|
|
66
69
|
const transform = new DataTransform()
|
|
@@ -71,18 +74,28 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
71
74
|
const [excludedData, setExcludedData] = useState<Record<string, number>[] | undefined>(undefined)
|
|
72
75
|
const [filteredData, setFilteredData] = useState<Record<string, any>[] | undefined>(undefined)
|
|
73
76
|
const [seriesHighlight, setSeriesHighlight] = useState<string[]>(configObj && configObj?.legend?.seriesHighlight?.length ? [...configObj?.legend?.seriesHighlight] : [])
|
|
74
|
-
const [currentViewport, setCurrentViewport] = useState('lg')
|
|
77
|
+
const [currentViewport, setCurrentViewport] = useState<ViewportSize>('lg')
|
|
75
78
|
const [dimensions, setDimensions] = useState<[number?, number?]>([])
|
|
76
79
|
const [externalFilters, setExternalFilters] = useState<any[]>()
|
|
77
80
|
const [container, setContainer] = useState()
|
|
78
81
|
const [coveLoadedEventRan, setCoveLoadedEventRan] = useState(false)
|
|
82
|
+
const [isDraggingAnnotation, setIsDraggingAnnotation] = useState(false)
|
|
79
83
|
const [dynamicLegendItems, setDynamicLegendItems] = useState<any[]>([])
|
|
80
84
|
const [imageId] = useState(`cove-${Math.random().toString(16).slice(-4)}`)
|
|
85
|
+
const [brushConfig, setBrushConfig] = useState({
|
|
86
|
+
data: [],
|
|
87
|
+
isActive: false,
|
|
88
|
+
isBrushing: false
|
|
89
|
+
})
|
|
81
90
|
type Config = typeof config
|
|
82
91
|
let legendMemo = useRef(new Map()) // map collection
|
|
83
92
|
let innerContainerRef = useRef()
|
|
84
93
|
const legendRef = useRef(null)
|
|
85
94
|
|
|
95
|
+
const handleDragStateChange = isDragging => {
|
|
96
|
+
setIsDraggingAnnotation(isDragging)
|
|
97
|
+
}
|
|
98
|
+
|
|
86
99
|
if (isDebug) console.log('Chart config, isEditor', config, isEditor)
|
|
87
100
|
|
|
88
101
|
// Destructure items from config for more readable JSX
|
|
@@ -97,7 +110,10 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
97
110
|
|
|
98
111
|
const { barBorderClass, lineDatapointClass, contentClasses, sparkLineStyles } = useDataVizClasses(config)
|
|
99
112
|
const legendId = useId()
|
|
100
|
-
|
|
113
|
+
|
|
114
|
+
const checkLineToBarGraph = () => {
|
|
115
|
+
return isConvertLineToBarGraph(config.visualizationType, filteredData, config.allowLineToBarGraph)
|
|
116
|
+
}
|
|
101
117
|
|
|
102
118
|
const reloadURLData = async () => {
|
|
103
119
|
if (config.dataUrl) {
|
|
@@ -160,7 +176,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
160
176
|
if (data) {
|
|
161
177
|
setStateData(data)
|
|
162
178
|
setExcludedData(data)
|
|
163
|
-
setFilteredData(
|
|
179
|
+
setFilteredData(filterVizData(config.filters, data))
|
|
164
180
|
}
|
|
165
181
|
}
|
|
166
182
|
}
|
|
@@ -240,12 +256,14 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
240
256
|
}
|
|
241
257
|
if (undefined === newConfig.table.show) newConfig.table.show = !isDashboard
|
|
242
258
|
|
|
243
|
-
newConfig.series.
|
|
244
|
-
if (
|
|
259
|
+
newConfig.series.forEach(series => {
|
|
260
|
+
if (series.tooltip === undefined || series.tooltip === null) {
|
|
261
|
+
series.tooltip = true
|
|
262
|
+
}
|
|
245
263
|
if (!series.axis) series.axis = 'Left'
|
|
246
264
|
})
|
|
247
265
|
|
|
248
|
-
if (
|
|
266
|
+
if (data) {
|
|
249
267
|
newConfig.data = data
|
|
250
268
|
}
|
|
251
269
|
|
|
@@ -306,17 +324,15 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
306
324
|
newConfig.filters[index].values = filterValues
|
|
307
325
|
// Initial filter should be active
|
|
308
326
|
|
|
309
|
-
newConfig.filters[index].active = newConfig.filters[index].active || filterValues[0]
|
|
327
|
+
newConfig.filters[index].active = !newConfig.filters[index].active || filterValues.indexOf(newConfig.filters[index].active) === -1 ? filterValues[0] : newConfig.filters[index].active
|
|
310
328
|
newConfig.filters[index].filterStyle = newConfig.filters[index].filterStyle ? newConfig.filters[index].filterStyle : 'dropdown'
|
|
311
329
|
})
|
|
312
|
-
currentData =
|
|
330
|
+
currentData = filterVizData(newConfig.filters, newExcludedData)
|
|
313
331
|
setFilteredData(currentData)
|
|
314
332
|
}
|
|
315
333
|
|
|
316
|
-
if (newConfig.xAxis.type === 'date-time' &&
|
|
317
|
-
newConfig.
|
|
318
|
-
} else if (newConfig.xAxis.type !== 'date-time' && newConfig.barThickness < 0.1) {
|
|
319
|
-
newConfig.barThickness = 0.35
|
|
334
|
+
if (newConfig.xAxis.type === 'date-time' && config.orientation === 'horizontal') {
|
|
335
|
+
newConfig.xAxis.type = 'date'
|
|
320
336
|
}
|
|
321
337
|
|
|
322
338
|
//Enforce default values that need to be calculated at runtime
|
|
@@ -481,7 +497,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
481
497
|
|
|
482
498
|
newConfig.runtime.horizontal = false
|
|
483
499
|
newConfig.orientation = 'horizontal'
|
|
484
|
-
} else if (['Box Plot', 'Scatter Plot', 'Area Chart', 'Line', 'Forecasting'].includes(newConfig.visualizationType)) {
|
|
500
|
+
} else if (['Box Plot', 'Scatter Plot', 'Area Chart', 'Line', 'Forecasting'].includes(newConfig.visualizationType) && !checkLineToBarGraph()) {
|
|
485
501
|
newConfig.runtime.xAxis = newConfig.xAxis
|
|
486
502
|
newConfig.runtime.yAxis = newConfig.yAxis
|
|
487
503
|
newConfig.runtime.horizontal = false
|
|
@@ -622,14 +638,14 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
622
638
|
let configCopy = { ...config }
|
|
623
639
|
delete configCopy['filters']
|
|
624
640
|
setConfig(configCopy)
|
|
625
|
-
setFilteredData(
|
|
641
|
+
setFilteredData(filterVizData(externalFilters, excludedData))
|
|
626
642
|
}
|
|
627
643
|
}
|
|
628
644
|
|
|
629
645
|
if (externalFilters && externalFilters.length > 0 && externalFilters.length > 0 && externalFilters[0].hasOwnProperty('active')) {
|
|
630
646
|
let newConfigHere = { ...config, filters: externalFilters }
|
|
631
647
|
setConfig(newConfigHere)
|
|
632
|
-
setFilteredData(
|
|
648
|
+
setFilteredData(filterVizData(externalFilters, excludedData))
|
|
633
649
|
}
|
|
634
650
|
}, [externalFilters]) // eslint-disable-line
|
|
635
651
|
|
|
@@ -749,7 +765,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
749
765
|
}
|
|
750
766
|
|
|
751
767
|
// function calculates the width of given text and its font-size
|
|
752
|
-
function getTextWidth(text, font) {
|
|
768
|
+
function getTextWidth(text: string, font: string): number | undefined {
|
|
753
769
|
const canvas = document.createElement('canvas')
|
|
754
770
|
const context = canvas.getContext('2d')
|
|
755
771
|
if (!context) {
|
|
@@ -907,7 +923,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
907
923
|
}
|
|
908
924
|
|
|
909
925
|
// Select appropriate chart type
|
|
910
|
-
const
|
|
926
|
+
const ChartComponents = {
|
|
911
927
|
'Paired Bar': <LinearChart />,
|
|
912
928
|
Forecasting: <LinearChart />,
|
|
913
929
|
Bar: <LinearChart />,
|
|
@@ -1101,17 +1117,33 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
1101
1117
|
// Prevent render if loading
|
|
1102
1118
|
let body = <Loading />
|
|
1103
1119
|
|
|
1120
|
+
const makeClassName = string => {
|
|
1121
|
+
if (!string || !string.toLowerCase) return
|
|
1122
|
+
return string.toLowerCase().replaceAll(/ /g, '-')
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1104
1125
|
const getChartWrapperClasses = () => {
|
|
1126
|
+
const isLegendOnBottom = legend?.position === 'bottom' || ['sm', 'xs', 'xxs'].includes(currentViewport)
|
|
1105
1127
|
const classes = ['chart-container', 'p-relative']
|
|
1106
|
-
if (config.legend
|
|
1107
|
-
if (config.legend
|
|
1128
|
+
if (config.legend?.position === 'bottom') classes.push('bottom')
|
|
1129
|
+
if (config.legend?.hide) classes.push('legend-hidden')
|
|
1108
1130
|
if (lineDatapointClass) classes.push(lineDatapointClass)
|
|
1109
1131
|
if (!config.barHasBorder) classes.push('chart-bar--no-border')
|
|
1110
|
-
if (
|
|
1132
|
+
if (config.brush?.active && dashboardConfig?.type === 'dashboard' && (!isLegendOnBottom || config.legend.hide)) classes.push('dashboard-brush')
|
|
1111
1133
|
classes.push(...contentClasses)
|
|
1112
1134
|
return classes
|
|
1113
1135
|
}
|
|
1114
1136
|
|
|
1137
|
+
const getChartSubTextClasses = () => {
|
|
1138
|
+
const classes = ['subtext ']
|
|
1139
|
+
const isLegendOnBottom = legend?.position === 'bottom' || ['sm', 'xs', 'xxs'].includes(currentViewport)
|
|
1140
|
+
|
|
1141
|
+
if (config.isResponsiveTicks) classes.push('subtext--responsive-ticks ')
|
|
1142
|
+
if (config.brush?.active && !isLegendOnBottom) classes.push('subtext--brush-active ')
|
|
1143
|
+
if (config.brush?.active && config.legend.hide) classes.push('subtext--brush-active ')
|
|
1144
|
+
return classes
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1115
1147
|
if (!loading) {
|
|
1116
1148
|
const tableLink = (
|
|
1117
1149
|
<a href={`#data-table-${config.dataKey}`} className='margin-left-href'>
|
|
@@ -1125,23 +1157,28 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
1125
1157
|
{config.newViz && <Confirm />}
|
|
1126
1158
|
{undefined === config.newViz && isEditor && config.runtime && config.runtime?.editorErrorMessage && <Error />}
|
|
1127
1159
|
{!missingRequiredSections() && !config.newViz && (
|
|
1128
|
-
<div className=
|
|
1160
|
+
<div className={`cdc-chart-inner-container cove-component__content type-${makeClassName(config.visualizationType)}`} aria-label={handleChartAriaLabels(config)} tabIndex={0}>
|
|
1129
1161
|
<Title showTitle={config.showTitle} isDashboard={isDashboard} title={title} superTitle={config.superTitle} classes={['chart-title', `${config.theme}`, 'cove-component__header']} style={undefined} />
|
|
1130
1162
|
|
|
1131
1163
|
{/* Filters */}
|
|
1132
|
-
{config.filters && !externalFilters && config.visualizationType !== 'Spark Line' && <Filters config={config} setConfig={setConfig} setFilteredData={setFilteredData} filteredData={filteredData} excludedData={excludedData} filterData={
|
|
1133
|
-
<SkipTo skipId={handleChartTabbing} skipMessage='Skip Over Chart Container' />
|
|
1164
|
+
{config.filters && !externalFilters && config.visualizationType !== 'Spark Line' && <Filters config={config} setConfig={setConfig} setFilteredData={setFilteredData} filteredData={filteredData} excludedData={excludedData} filterData={filterVizData} dimensions={dimensions} />}
|
|
1165
|
+
<SkipTo skipId={handleChartTabbing(config, legendId)} skipMessage='Skip Over Chart Container' />
|
|
1166
|
+
{config.annotations?.length > 0 && <SkipTo skipId={handleChartTabbing(config, legendId)} skipMessage={`Skip over annotations`} key={`skip-annotations`} />}
|
|
1167
|
+
|
|
1134
1168
|
{/* Visualization */}
|
|
1135
1169
|
{config?.introText && config.visualizationType !== 'Spark Line' && <section className='introText'>{parse(config.introText)}</section>}
|
|
1136
1170
|
|
|
1137
|
-
<div
|
|
1138
|
-
{/* All charts except sparkline */}
|
|
1139
|
-
{config.visualizationType !== 'Spark Line' &&
|
|
1171
|
+
<div className={getChartWrapperClasses().join(' ')}>
|
|
1172
|
+
{/* All charts except line and sparkline */}
|
|
1173
|
+
{config.visualizationType !== 'Spark Line' && config.visualizationType !== 'Line' && ChartComponents[config.visualizationType]}
|
|
1174
|
+
|
|
1175
|
+
{/* Line Chart */}
|
|
1176
|
+
{config.visualizationType === 'Line' && (checkLineToBarGraph() ? ChartComponents['Bar'] : ChartComponents['Line'])}
|
|
1140
1177
|
|
|
1141
1178
|
{/* Sparkline */}
|
|
1142
1179
|
{config.visualizationType === 'Spark Line' && (
|
|
1143
1180
|
<>
|
|
1144
|
-
<Filters config={config} setConfig={setConfig} setFilteredData={setFilteredData} filteredData={filteredData} excludedData={excludedData} filterData={
|
|
1181
|
+
<Filters config={config} setConfig={setConfig} setFilteredData={setFilteredData} filteredData={filteredData} excludedData={excludedData} filterData={filterVizData} dimensions={dimensions} />
|
|
1145
1182
|
{config?.introText && (
|
|
1146
1183
|
<section className='introText' style={{ padding: '0px 0 35px' }}>
|
|
1147
1184
|
{parse(config.introText)}
|
|
@@ -1159,26 +1196,26 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
1159
1196
|
)}
|
|
1160
1197
|
{/* Sankey */}
|
|
1161
1198
|
{config.visualizationType === 'Sankey' && <ParentSize aria-hidden='true'>{parent => <SankeyChart runtime={config.runtime} width={parent.width} height={parent.height} />}</ParentSize>}
|
|
1162
|
-
{!config.legend.hide && config.visualizationType !== 'Spark Line' && config.visualizationType !== 'Sankey' && <Legend ref={legendRef} />}
|
|
1199
|
+
{!config.legend.hide && config.visualizationType !== 'Spark Line' && config.visualizationType !== 'Sankey' && <Legend ref={legendRef} skipId={handleChartTabbing(config, legendId)} />}
|
|
1163
1200
|
</div>
|
|
1164
1201
|
{/* Link */}
|
|
1165
1202
|
{isDashboard && config.table && config.table.show && config.table.showDataTableLink ? tableLink : link && link}
|
|
1166
|
-
|
|
1167
1203
|
{/* Description */}
|
|
1168
|
-
|
|
1204
|
+
|
|
1205
|
+
{description && config.visualizationType !== 'Spark Line' && <div className={getChartSubTextClasses().join('')}>{parse(description)}</div>}
|
|
1206
|
+
{false && <Annotation.List />}
|
|
1169
1207
|
|
|
1170
1208
|
{/* buttons */}
|
|
1171
1209
|
<MediaControls.Section classes={['download-buttons']}>
|
|
1172
1210
|
{config.table.showDownloadImgButton && <MediaControls.Button text='Download Image' title='Download Chart as Image' type='image' state={config} elementToCapture={imageId} />}
|
|
1173
1211
|
{config.table.showDownloadPdfButton && <MediaControls.Button text='Download PDF' title='Download Chart as PDF' type='pdf' state={config} elementToCapture={imageId} />}
|
|
1174
1212
|
</MediaControls.Section>
|
|
1175
|
-
|
|
1176
1213
|
{/* Data Table */}
|
|
1177
1214
|
{((config.xAxis.dataKey && config.table.show && config.visualizationType !== 'Spark Line' && config.visualizationType !== 'Sankey') || (config.visualizationType === 'Sankey' && config.table.show)) && (
|
|
1178
1215
|
<DataTable
|
|
1179
1216
|
config={config}
|
|
1180
|
-
rawData={config.visualizationType === 'Sankey' ? config?.data?.[0]?.tableData : config.table.customTableConfig ?
|
|
1181
|
-
runtimeData={config.visualizationType === 'Sankey' ? config?.data?.[0]?.tableData :
|
|
1217
|
+
rawData={config.visualizationType === 'Sankey' ? config?.data?.[0]?.tableData : config.table.customTableConfig ? filterVizData(config.filters, config.data) : config.data}
|
|
1218
|
+
runtimeData={config.visualizationType === 'Sankey' ? config?.data?.[0]?.tableData : filteredData || excludedData}
|
|
1182
1219
|
expandDataTable={config.table.expanded}
|
|
1183
1220
|
columns={config.columns}
|
|
1184
1221
|
displayDataAsText={displayDataAsText}
|
|
@@ -1188,10 +1225,11 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
1188
1225
|
indexTitle={config.table.indexLabel}
|
|
1189
1226
|
vizTitle={title}
|
|
1190
1227
|
viewport={currentViewport}
|
|
1191
|
-
tabbingId={handleChartTabbing}
|
|
1228
|
+
tabbingId={handleChartTabbing(config, legendId)}
|
|
1192
1229
|
colorScale={colorScale}
|
|
1193
1230
|
/>
|
|
1194
1231
|
)}
|
|
1232
|
+
{config?.annotations?.length > 0 && <Annotation.Dropdown />}
|
|
1195
1233
|
{config?.footnotes && <section className='footnotes'>{parse(config.footnotes)}</section>}
|
|
1196
1234
|
{/* show pdf or image button */}
|
|
1197
1235
|
</div>
|
|
@@ -1207,54 +1245,60 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
1207
1245
|
const capitalize = str => {
|
|
1208
1246
|
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
1209
1247
|
}
|
|
1248
|
+
|
|
1210
1249
|
const contextValues = {
|
|
1250
|
+
brushConfig,
|
|
1211
1251
|
capitalize,
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
getYAxisData,
|
|
1215
|
-
config,
|
|
1216
|
-
setConfig,
|
|
1217
|
-
rawData: stateData ?? {},
|
|
1218
|
-
excludedData: excludedData,
|
|
1219
|
-
transformedData: clean(filteredData || excludedData), // do this right before passing to components
|
|
1220
|
-
tableData: filteredData || excludedData, // do not clean table data
|
|
1221
|
-
unfilteredData: stateData,
|
|
1222
|
-
seriesHighlight,
|
|
1252
|
+
clean,
|
|
1253
|
+
colorPalettes,
|
|
1223
1254
|
colorScale,
|
|
1224
|
-
|
|
1255
|
+
config,
|
|
1225
1256
|
currentViewport,
|
|
1226
|
-
|
|
1257
|
+
dashboardConfig,
|
|
1258
|
+
debugSvg: isDebug,
|
|
1259
|
+
dimensions,
|
|
1260
|
+
dynamicLegendItems,
|
|
1261
|
+
excludedData: excludedData,
|
|
1227
1262
|
formatDate,
|
|
1228
|
-
formatTooltipsDate,
|
|
1229
1263
|
formatNumber,
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
setParentConfig,
|
|
1235
|
-
missingRequiredSections,
|
|
1236
|
-
setEditing,
|
|
1237
|
-
setFilteredData,
|
|
1264
|
+
formatTooltipsDate,
|
|
1265
|
+
getTextWidth,
|
|
1266
|
+
getXAxisData,
|
|
1267
|
+
getYAxisData,
|
|
1238
1268
|
handleChartAriaLabels,
|
|
1269
|
+
handleLineType,
|
|
1239
1270
|
highlight,
|
|
1240
1271
|
highlightReset,
|
|
1241
|
-
legend,
|
|
1242
|
-
setSeriesHighlight,
|
|
1243
|
-
dynamicLegendItems,
|
|
1244
|
-
setDynamicLegendItems,
|
|
1245
|
-
filterData,
|
|
1246
1272
|
imageId,
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
isNumber,
|
|
1250
|
-
getTextWidth,
|
|
1251
|
-
twoColorPalette,
|
|
1252
|
-
isEditor,
|
|
1273
|
+
isDashboard,
|
|
1274
|
+
isLegendBottom: legend?.position === 'bottom' || ['sm', 'xs', 'xxs'].includes(currentViewport),
|
|
1253
1275
|
isDebug,
|
|
1276
|
+
isDraggingAnnotation,
|
|
1277
|
+
handleDragStateChange,
|
|
1278
|
+
isEditor,
|
|
1279
|
+
isNumber,
|
|
1280
|
+
legend,
|
|
1281
|
+
lineOptions,
|
|
1282
|
+
loading,
|
|
1283
|
+
missingRequiredSections,
|
|
1284
|
+
outerContainerRef,
|
|
1285
|
+
parseDate,
|
|
1286
|
+
rawData: stateData ?? {},
|
|
1287
|
+
seriesHighlight,
|
|
1288
|
+
setBrushConfig,
|
|
1289
|
+
setConfig,
|
|
1290
|
+
setDynamicLegendItems,
|
|
1291
|
+
setEditing,
|
|
1292
|
+
setFilteredData,
|
|
1293
|
+
setParentConfig,
|
|
1294
|
+
setSeriesHighlight,
|
|
1254
1295
|
setSharedFilter,
|
|
1255
1296
|
setSharedFilterValue,
|
|
1256
|
-
|
|
1257
|
-
|
|
1297
|
+
tableData: filteredData || excludedData, // do not clean table data
|
|
1298
|
+
transformedData: clean(filteredData || excludedData), // do this right before passing to components
|
|
1299
|
+
twoColorPalette,
|
|
1300
|
+
unfilteredData: stateData,
|
|
1301
|
+
updateConfig
|
|
1258
1302
|
}
|
|
1259
1303
|
|
|
1260
1304
|
return (
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import SuppressedConfig from './_mock/bar-chart-suppressed.json'
|
|
2
3
|
|
|
3
4
|
import Chart from '../CdcChart'
|
|
5
|
+
import lineChartTwoPointsRegressionTest from './_mock/line_chart_two_points_regression_test.json'
|
|
6
|
+
import lineChartTwoPointsNewChart from './_mock/line_chart_two_points_new_chart.json'
|
|
7
|
+
import lollipop from './_mock/lollipop.json'
|
|
4
8
|
|
|
5
9
|
const meta: Meta<typeof Chart> = {
|
|
6
10
|
title: 'Components/Templates/Chart',
|
|
@@ -9,179 +13,30 @@ const meta: Meta<typeof Chart> = {
|
|
|
9
13
|
|
|
10
14
|
type Story = StoryObj<typeof Chart>
|
|
11
15
|
|
|
16
|
+
export const line_Chart_Two_Points_Regression_Test: Story = {
|
|
17
|
+
args: {
|
|
18
|
+
config: lineChartTwoPointsRegressionTest,
|
|
19
|
+
isEditor: false
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export const line_Chart_Two_Points_New_Chart: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
config: lineChartTwoPointsNewChart,
|
|
25
|
+
isEditor: false
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
12
29
|
export const Lollipop: Story = {
|
|
13
30
|
args: {
|
|
14
|
-
config:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
barHasBorder: 'false',
|
|
24
|
-
isLollipopChart: true,
|
|
25
|
-
lollipopShape: 'circle',
|
|
26
|
-
lollipopColorStyle: 'two-tone',
|
|
27
|
-
visualizationSubType: 'horizontal',
|
|
28
|
-
barStyle: '',
|
|
29
|
-
roundingStyle: 'standard',
|
|
30
|
-
tipRounding: 'top',
|
|
31
|
-
isResponsiveTicks: false,
|
|
32
|
-
general: { showDownloadButton: false },
|
|
33
|
-
padding: { left: 5, right: 5 },
|
|
34
|
-
yAxis: {
|
|
35
|
-
hideAxis: true,
|
|
36
|
-
displayNumbersOnBar: true,
|
|
37
|
-
hideLabel: false,
|
|
38
|
-
hideTicks: false,
|
|
39
|
-
size: '13',
|
|
40
|
-
gridLines: false,
|
|
41
|
-
enablePadding: false,
|
|
42
|
-
min: '',
|
|
43
|
-
max: '',
|
|
44
|
-
labelColor: '#333',
|
|
45
|
-
tickLabelColor: '#333',
|
|
46
|
-
tickColor: '#333',
|
|
47
|
-
rightHideAxis: true,
|
|
48
|
-
rightAxisSize: 50,
|
|
49
|
-
rightLabel: '',
|
|
50
|
-
rightLabelOffsetSize: 0,
|
|
51
|
-
rightAxisLabelColor: '#333',
|
|
52
|
-
rightAxisTickLabelColor: '#333',
|
|
53
|
-
rightAxisTickColor: '#333',
|
|
54
|
-
numTicks: '9',
|
|
55
|
-
axisPadding: 0,
|
|
56
|
-
tickRotation: 0,
|
|
57
|
-
anchors: [],
|
|
58
|
-
type: 'chart',
|
|
59
|
-
title: 'Lollipop Style Horizontal Bar Chart',
|
|
60
|
-
theme: 'theme-blue',
|
|
61
|
-
fontSize: 'medium',
|
|
62
|
-
lineDatapointStyle: 'hover',
|
|
63
|
-
barHasBorder: 'false',
|
|
64
|
-
isLollipopChart: false,
|
|
65
|
-
lollipopShape: 'circle',
|
|
66
|
-
lollipopColorStyle: 'two-tone',
|
|
67
|
-
visualizationSubType: 'horizontal',
|
|
68
|
-
padding: { left: 5, right: 5 },
|
|
69
|
-
yAxis: { size: 50, gridLines: false },
|
|
70
|
-
barThickness: 0.35,
|
|
71
|
-
height: 260,
|
|
72
|
-
xAxis: { type: 'categorical', size: 75, tickRotation: 0, dataKey: 'Vehicle' },
|
|
73
|
-
table: { label: 'Data Table', expanded: true, show: true },
|
|
74
|
-
legend: { behavior: 'isolate', position: 'right' },
|
|
75
|
-
exclusions: { active: false, keys: [] },
|
|
76
|
-
palette: 'qualitative-bold',
|
|
77
|
-
labels: false,
|
|
78
|
-
dataFormat: {},
|
|
79
|
-
confidenceKeys: {},
|
|
80
|
-
data: [
|
|
81
|
-
{ Group: 'Combined Total of Group A', Vehicle: '100', Home: '120', Work: '140', Office: '120' },
|
|
82
|
-
{ Group: 'Combined Total of Group B', Vehicle: '150', Home: '140', Work: '100', Office: '90' },
|
|
83
|
-
{ Group: 'Combined Total of Group C', Vehicle: '90', Home: '90', Work: '80', Office: '80' },
|
|
84
|
-
{ Group: 'Combined Total of Group D', Vehicle: '70', Home: '60', Work: '50', Office: '70' }
|
|
85
|
-
],
|
|
86
|
-
dataFileName: 'CSV_Source_Example_for_Horizontal_Bar_viz-cdcwp1619811744363.csv',
|
|
87
|
-
dataFileSourceType: 'file',
|
|
88
|
-
visualizationType: 'Bar',
|
|
89
|
-
runtime: {
|
|
90
|
-
seriesLabels: { Vehicle: 'Vehicle' },
|
|
91
|
-
seriesLabelsAll: ['Vehicle'],
|
|
92
|
-
originalXAxis: { type: 'categorical', size: 75, tickRotation: 0, dataKey: 'Vehicle' },
|
|
93
|
-
seriesKeys: ['Vehicle'],
|
|
94
|
-
xAxis: { size: 50, gridLines: false },
|
|
95
|
-
yAxis: { type: 'categorical', size: 75, tickRotation: 0, dataKey: 'Vehicle' },
|
|
96
|
-
horizontal: true,
|
|
97
|
-
uniqueId: 1651765968212,
|
|
98
|
-
editorErrorMessage: ''
|
|
99
|
-
},
|
|
100
|
-
description: 'Subtext can be added here for options like citing data sources or insight into reading the bar chart.',
|
|
101
|
-
series: [{ dataKey: 'Vehicle', type: 'Bar' }],
|
|
102
|
-
barHeight: 25,
|
|
103
|
-
barPadding: 40,
|
|
104
|
-
labelPlacement: 'Below Bar',
|
|
105
|
-
label: 'Number of Accidents'
|
|
106
|
-
},
|
|
107
|
-
boxplot: [],
|
|
108
|
-
topAxis: { hasLine: false },
|
|
109
|
-
isLegendValue: false,
|
|
110
|
-
barThickness: 0.35,
|
|
111
|
-
barHeight: 6,
|
|
112
|
-
barSpace: 15,
|
|
113
|
-
heights: { vertical: 300, horizontal: 170.39999999999998 },
|
|
114
|
-
xAxis: {
|
|
115
|
-
anchors: [],
|
|
116
|
-
type: 'categorical',
|
|
117
|
-
showTargetLabel: true,
|
|
118
|
-
targetLabel: 'Target',
|
|
119
|
-
hideAxis: true,
|
|
120
|
-
hideLabel: true,
|
|
121
|
-
hideTicks: true,
|
|
122
|
-
size: '16',
|
|
123
|
-
tickRotation: 0,
|
|
124
|
-
min: '',
|
|
125
|
-
max: '160',
|
|
126
|
-
labelColor: '#333',
|
|
127
|
-
tickLabelColor: '#333',
|
|
128
|
-
tickColor: '#333',
|
|
129
|
-
numTicks: '',
|
|
130
|
-
labelOffset: 65,
|
|
131
|
-
axisPadding: 0,
|
|
132
|
-
target: 0,
|
|
133
|
-
maxTickRotation: 0,
|
|
134
|
-
dataKey: 'Group'
|
|
135
|
-
},
|
|
136
|
-
table: { label: 'Data Table', expanded: false, limitHeight: false, height: '', caption: '', showDownloadUrl: false, showDataTableLink: true, indexLabel: 'Group', download: false, showVertical: true, show: true },
|
|
137
|
-
orientation: 'horizontal',
|
|
138
|
-
color: 'pinkpurple',
|
|
139
|
-
columns: {},
|
|
140
|
-
legend: {
|
|
141
|
-
behavior: 'isolate',
|
|
142
|
-
singleRow: false,
|
|
143
|
-
colorCode: '',
|
|
144
|
-
reverseLabelOrder: false,
|
|
145
|
-
description: '',
|
|
146
|
-
dynamicLegend: false,
|
|
147
|
-
dynamicLegendDefaultText: 'Show All',
|
|
148
|
-
dynamicLegendItemLimit: 5,
|
|
149
|
-
dynamicLegendItemLimitMessage: 'Dynamic Legend Item Limit Hit.',
|
|
150
|
-
dynamicLegendChartMessage: 'Select Options from the Legend',
|
|
151
|
-
position: 'right',
|
|
152
|
-
hide: true,
|
|
153
|
-
label: 'Accident Location'
|
|
154
|
-
},
|
|
155
|
-
exclusions: { active: false, keys: [] },
|
|
156
|
-
palette: 'qualitative-bold',
|
|
157
|
-
isPaletteReversed: false,
|
|
158
|
-
twoColor: { palette: 'monochrome-1', isPaletteReversed: false },
|
|
159
|
-
labels: false,
|
|
160
|
-
dataFormat: { commas: false, prefix: '', suffix: '', abbreviated: false, bottomSuffix: '', bottomPrefix: '', bottomAbbreviated: false },
|
|
161
|
-
confidenceKeys: {},
|
|
162
|
-
visual: { border: true, accent: true, background: true, verticalHoverLine: false, horizontalHoverLine: false },
|
|
163
|
-
useLogScale: false,
|
|
164
|
-
filterBehavior: 'Filter Change',
|
|
165
|
-
highlightedBarValues: [],
|
|
166
|
-
series: [{ dataKey: 'Home', type: 'Bar', tooltip: true }],
|
|
167
|
-
tooltips: { opacity: 90 },
|
|
168
|
-
height: 212,
|
|
169
|
-
data: [
|
|
170
|
-
{ Group: 'Combined Total of Group A', Vehicle: '100', Home: '120', Work: '140', Office: '120' },
|
|
171
|
-
{ Group: 'Combined Total of Group B', Vehicle: '150', Home: '140', Work: '100', Office: '90' },
|
|
172
|
-
{ Group: 'Combined Total of Group C', Vehicle: '90', Home: '90', Work: '80', Office: '80' },
|
|
173
|
-
{ Group: 'Combined Total of Group D', Vehicle: '70', Home: '60', Work: '50', Office: '70' }
|
|
174
|
-
],
|
|
175
|
-
dataFileName: 'CSV_Source_Example_for_Horizontal_Bar_viz-cdcwp1619811744363.csv',
|
|
176
|
-
dataFileSourceType: 'file',
|
|
177
|
-
visualizationType: 'Bar',
|
|
178
|
-
description: 'Subtext can be added here for options like citing data sources or insight into reading the bar chart.',
|
|
179
|
-
barPadding: 47,
|
|
180
|
-
filters: [],
|
|
181
|
-
lollipopSize: 'medium',
|
|
182
|
-
validated: 4.23,
|
|
183
|
-
dynamicMarginTop: 0
|
|
184
|
-
}
|
|
31
|
+
config: lollipop,
|
|
32
|
+
isEditor: false
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const Suppression: Story = {
|
|
37
|
+
args: {
|
|
38
|
+
config: SuppressedConfig,
|
|
39
|
+
isEditor: false
|
|
185
40
|
}
|
|
186
41
|
}
|
|
187
42
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import annotationConfig from './_mock/annotation_category_mock.json'
|
|
3
|
+
import annotationConfigDateLinear from './_mock/annotation_date-linear_mock.json'
|
|
4
|
+
import annotationConfigDateTime from './_mock/annotation_date-time_mock.json'
|
|
5
|
+
import Chart from '../CdcChart'
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Chart> = {
|
|
8
|
+
title: 'Components/Templates/Chart/Annotation',
|
|
9
|
+
component: Chart
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type Story = StoryObj<typeof Chart>
|
|
13
|
+
|
|
14
|
+
export const Chart_Annotation_Categorical: Story = {
|
|
15
|
+
args: {
|
|
16
|
+
config: annotationConfig
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const Chart_Annotation_Date_Linear: Story = {
|
|
21
|
+
args: {
|
|
22
|
+
config: annotationConfigDateLinear
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const Chart_Annotation_Date_Time: Story = {
|
|
27
|
+
args: {
|
|
28
|
+
config: annotationConfigDateTime
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default meta
|