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