@cdc/chart 4.24.2 → 4.24.4
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 +47933 -36918
- package/examples/chart-regression-1.json +378 -0
- package/examples/chart-regression-2.json +2360 -0
- package/examples/feature/filters/url-filter.json +1076 -0
- package/examples/feature/line/line-chart.json +362 -37
- package/examples/feature/regions/index.json +50 -4
- package/examples/feature/sankey/sankey-example-data.json +1364 -0
- package/examples/feature/sankey/sankey_chart_data.csv +20 -0
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +306 -19
- package/examples/region-issue.json +2065 -0
- package/examples/sparkline.json +868 -0
- package/examples/test.json +5409 -0
- package/index.html +130 -123
- package/package.json +4 -2
- package/src/CdcChart.tsx +178 -94
- package/src/_stories/ChartEditor.stories.tsx +14 -3
- package/src/_stories/_mock/url_filter.json +1076 -0
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +2 -1
- package/src/components/AreaChart/components/AreaChart.jsx +2 -1
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +46 -63
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +36 -56
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +32 -39
- package/src/components/BarChart/components/BarChart.Vertical.tsx +44 -59
- package/src/components/BoxPlot/BoxPlot.jsx +2 -1
- package/src/components/DeviationBar.jsx +3 -3
- package/src/components/EditorPanel/EditorPanel.tsx +1684 -1564
- package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +1 -1
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +107 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +48 -4
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +41 -0
- package/src/components/EditorPanel/components/Panels/index.tsx +9 -7
- package/src/components/EditorPanel/components/panels.scss +11 -0
- package/src/components/EditorPanel/editor-panel.scss +0 -724
- package/src/components/EditorPanel/useEditorPermissions.js +40 -14
- package/src/components/Legend/Legend.Component.tsx +43 -63
- package/src/components/Legend/Legend.tsx +8 -4
- package/src/components/LineChart/LineChartProps.ts +1 -0
- package/src/components/LineChart/helpers.ts +2 -2
- package/src/components/LineChart/index.tsx +7 -7
- package/src/components/LinearChart.jsx +11 -31
- package/src/components/PairedBarChart.jsx +6 -10
- package/src/components/PieChart/PieChart.tsx +3 -3
- package/src/components/Regions/components/Regions.tsx +120 -78
- package/src/components/Sankey/index.tsx +434 -0
- package/src/components/Sankey/sankey.scss +153 -0
- package/src/components/Sankey/types/index.ts +16 -0
- package/src/components/ScatterPlot/ScatterPlot.jsx +1 -0
- package/src/components/Sparkline/{SparkLine.jsx → components/SparkLine.tsx} +14 -30
- package/src/components/Sparkline/index.scss +3 -0
- package/src/components/Sparkline/index.tsx +1 -1
- package/src/components/ZoomBrush.tsx +2 -1
- package/src/data/initial-state.js +46 -2
- package/src/helpers/computeMarginBottom.ts +2 -1
- package/src/helpers/tests/computeMarginBottom.test.ts +2 -1
- package/src/hooks/useBarChart.js +5 -2
- package/src/hooks/useScales.ts +47 -18
- package/src/hooks/useTooltip.tsx +9 -8
- package/src/scss/main.scss +33 -29
- package/src/types/ChartConfig.ts +32 -14
- package/src/types/ChartContext.ts +7 -0
package/src/CdcChart.tsx
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import React, { useState, useEffect, useCallback, useRef } from 'react'
|
|
1
|
+
import React, { useState, useEffect, useCallback, useRef, useId } from 'react'
|
|
2
2
|
|
|
3
3
|
// IE11
|
|
4
4
|
import ResizeObserver from 'resize-observer-polyfill'
|
|
5
5
|
import 'whatwg-fetch'
|
|
6
6
|
import * as d3 from 'd3-array'
|
|
7
|
+
import Layout from '@cdc/core/components/Layout'
|
|
8
|
+
import Button from '@cdc/core/components/elements/Button'
|
|
7
9
|
|
|
8
10
|
// External Libraries
|
|
9
11
|
import { scaleOrdinal } from '@visx/scale'
|
|
@@ -15,8 +17,10 @@ import 'react-tooltip/dist/react-tooltip.css'
|
|
|
15
17
|
|
|
16
18
|
// Primary Components
|
|
17
19
|
import ConfigContext from './ConfigContext'
|
|
18
|
-
import PieChart from './components/PieChart
|
|
20
|
+
import PieChart from './components/PieChart'
|
|
21
|
+
import SankeyChart from './components/Sankey'
|
|
19
22
|
import LinearChart from './components/LinearChart'
|
|
23
|
+
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
20
24
|
|
|
21
25
|
import { colorPalettesChart as colorPalettes, twoColorPalette } from '@cdc/core/data/colorPalettes'
|
|
22
26
|
|
|
@@ -46,6 +50,7 @@ import { DataTransform } from '@cdc/core/helpers/DataTransform'
|
|
|
46
50
|
import cacheBustingString from '@cdc/core/helpers/cacheBustingString'
|
|
47
51
|
import isNumber from '@cdc/core/helpers/isNumber'
|
|
48
52
|
import coveUpdateWorker from '@cdc/core/helpers/coveUpdateWorker'
|
|
53
|
+
import { getQueryStringFilterValue } from '@cdc/core/helpers/queryStringUtils'
|
|
49
54
|
|
|
50
55
|
import './scss/main.scss'
|
|
51
56
|
// load both then config below determines which to use
|
|
@@ -55,6 +60,7 @@ import Title from '@cdc/core/components/ui/Title'
|
|
|
55
60
|
import { ChartConfig } from './types/ChartConfig'
|
|
56
61
|
import { Label } from './types/Label'
|
|
57
62
|
import { isSolrCsv, isSolrJson } from '@cdc/core/helpers/isSolr'
|
|
63
|
+
import SkipTo from '@cdc/core/components/elements/SkipTo'
|
|
58
64
|
|
|
59
65
|
export default function CdcChart({ configUrl, config: configObj, isEditor = false, isDebug = false, isDashboard = false, setConfig: setParentConfig, setEditing, hostname, link, setSharedFilter, setSharedFilterValue, dashboardConfig }) {
|
|
60
66
|
const transform = new DataTransform()
|
|
@@ -64,7 +70,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
64
70
|
const [stateData, setStateData] = useState(config.data || [])
|
|
65
71
|
const [excludedData, setExcludedData] = useState<Record<string, number>[] | undefined>(undefined)
|
|
66
72
|
const [filteredData, setFilteredData] = useState<Record<string, any>[] | undefined>(undefined)
|
|
67
|
-
const [seriesHighlight, setSeriesHighlight] = useState<string[]>([])
|
|
73
|
+
const [seriesHighlight, setSeriesHighlight] = useState<string[]>(configObj && configObj?.legend?.seriesHighlight?.length ? [...configObj?.legend?.seriesHighlight] : [])
|
|
68
74
|
const [currentViewport, setCurrentViewport] = useState('lg')
|
|
69
75
|
const [dimensions, setDimensions] = useState<[number?, number?]>([])
|
|
70
76
|
const [externalFilters, setExternalFilters] = useState<any[]>()
|
|
@@ -75,6 +81,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
75
81
|
type Config = typeof config
|
|
76
82
|
let legendMemo = useRef(new Map()) // map collection
|
|
77
83
|
let innerContainerRef = useRef()
|
|
84
|
+
const legendRef = useRef(null)
|
|
78
85
|
|
|
79
86
|
if (isDebug) console.log('Chart config, isEditor', config, isEditor)
|
|
80
87
|
|
|
@@ -89,8 +96,8 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
89
96
|
if (config.table && (!config.table?.label || config.table?.label === '')) config.table.label = 'Data Table'
|
|
90
97
|
|
|
91
98
|
const { barBorderClass, lineDatapointClass, contentClasses, sparkLineStyles } = useDataVizClasses(config)
|
|
92
|
-
|
|
93
|
-
const handleChartTabbing = config.
|
|
99
|
+
const legendId = useId()
|
|
100
|
+
const handleChartTabbing = !config.legend?.hide ? legendId : config?.title ? `dataTableSection__${config.title.replace(/\s/g, '')}` : `dataTableSection`
|
|
94
101
|
|
|
95
102
|
const reloadURLData = async () => {
|
|
96
103
|
if (config.dataUrl) {
|
|
@@ -219,6 +226,15 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
219
226
|
}
|
|
220
227
|
}
|
|
221
228
|
let newConfig = { ...defaults, ...response }
|
|
229
|
+
if (newConfig.filters) {
|
|
230
|
+
newConfig.filters.forEach((filter, index) => {
|
|
231
|
+
const queryStringFilterValue = getQueryStringFilterValue(filter)
|
|
232
|
+
if (queryStringFilterValue) {
|
|
233
|
+
newConfig.filters[index].active = queryStringFilterValue
|
|
234
|
+
}
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
|
|
222
238
|
if (newConfig.visualizationType === 'Box Plot') {
|
|
223
239
|
newConfig.legend.hide = true
|
|
224
240
|
}
|
|
@@ -253,7 +269,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
253
269
|
if (newConfig.exclusions && newConfig.exclusions.active) {
|
|
254
270
|
if (newConfig.xAxis.type === 'categorical' && newConfig.exclusions.keys?.length > 0) {
|
|
255
271
|
newExcludedData = data.filter(e => !newConfig.exclusions.keys.includes(e[newConfig.xAxis.dataKey]))
|
|
256
|
-
} else if (newConfig.xAxis
|
|
272
|
+
} else if (isDateScale(newConfig.xAxis) && (newConfig.exclusions.dateStart || newConfig.exclusions.dateEnd) && newConfig.xAxis.dateParseFormat) {
|
|
257
273
|
// Filter dates
|
|
258
274
|
const timestamp = e => new Date(e).getTime()
|
|
259
275
|
|
|
@@ -297,13 +313,9 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
297
313
|
setFilteredData(currentData)
|
|
298
314
|
}
|
|
299
315
|
|
|
300
|
-
if (
|
|
301
|
-
newConfig.xAxis.sortDates = false
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if (newConfig.xAxis.sortDates && newConfig.barThickness > 0.1) {
|
|
316
|
+
if (newConfig.xAxis.type === 'date-time' && newConfig.barThickness > 0.1) {
|
|
305
317
|
newConfig.barThickness = 0.035
|
|
306
|
-
} else if (
|
|
318
|
+
} else if (newConfig.xAxis.type !== 'date-time' && newConfig.barThickness < 0.1) {
|
|
307
319
|
newConfig.barThickness = 0.35
|
|
308
320
|
}
|
|
309
321
|
|
|
@@ -433,7 +445,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
433
445
|
if (series.type === 'Forecasting') {
|
|
434
446
|
newConfig.runtime.forecastingSeriesKeys.push(series)
|
|
435
447
|
}
|
|
436
|
-
if (series.type === 'Bar') {
|
|
448
|
+
if (series.type === 'Bar' || series.type === 'Combo') {
|
|
437
449
|
newConfig.runtime.barSeriesKeys.push(series.dataKey)
|
|
438
450
|
}
|
|
439
451
|
if (series.type === 'Line' || series.type === 'dashed-sm' || series.type === 'dashed-md' || series.type === 'dashed-lg') {
|
|
@@ -483,6 +495,13 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
483
495
|
newConfig.runtime.uniqueId = Date.now()
|
|
484
496
|
newConfig.runtime.editorErrorMessage = newConfig.visualizationType === 'Pie' && !newConfig.yAxis.dataKey ? 'Data Key property in Y Axis section must be set for pie charts.' : ''
|
|
485
497
|
|
|
498
|
+
// Sankey Description box error message
|
|
499
|
+
newConfig.runtime.editorErrorMessage = newConfig.visualizationType === 'Sankey' && !newConfig.description ? 'SUBTEXT/CITATION field is empty: A description of the Sankey Diagram data must be inputted.' : ''
|
|
500
|
+
|
|
501
|
+
if (newConfig.legend.seriesHighlight?.length) {
|
|
502
|
+
setSeriesHighlight(newConfig.legend?.seriesHighlight)
|
|
503
|
+
}
|
|
504
|
+
|
|
486
505
|
setConfig(newConfig)
|
|
487
506
|
}
|
|
488
507
|
|
|
@@ -698,7 +717,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
698
717
|
// Called on reset button click, unhighlights all data series
|
|
699
718
|
const highlightReset = () => {
|
|
700
719
|
try {
|
|
701
|
-
const legend =
|
|
720
|
+
const legend = legendRef.current
|
|
702
721
|
if (!legend) throw new Error('No legend available to set previous focus on.')
|
|
703
722
|
legend.focus()
|
|
704
723
|
} catch (e) {
|
|
@@ -903,6 +922,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
903
922
|
}
|
|
904
923
|
|
|
905
924
|
const missingRequiredSections = () => {
|
|
925
|
+
if (config.visualizationType === 'Sankey') return false // skip checks for now
|
|
906
926
|
if (config.visualizationType === 'Forecasting') return false // skip required checks for now.
|
|
907
927
|
if (config.visualizationType === 'Forest Plot') return false // skip required checks for now.
|
|
908
928
|
if (config.visualizationType === 'Pie') {
|
|
@@ -990,6 +1010,63 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
990
1010
|
return formattedValue
|
|
991
1011
|
}
|
|
992
1012
|
|
|
1013
|
+
const Confirm = () => {
|
|
1014
|
+
const confirmDone = e => {
|
|
1015
|
+
if (e) {
|
|
1016
|
+
e.preventDefault()
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
let newConfig = { ...config }
|
|
1020
|
+
delete newConfig.newViz
|
|
1021
|
+
|
|
1022
|
+
updateConfig(newConfig)
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
const styles = {
|
|
1026
|
+
position: 'relative',
|
|
1027
|
+
height: '100vh',
|
|
1028
|
+
width: '100%',
|
|
1029
|
+
display: 'flex',
|
|
1030
|
+
justifyContent: 'center',
|
|
1031
|
+
alignItems: 'center',
|
|
1032
|
+
gridArea: 'content'
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
return (
|
|
1036
|
+
<section className='waiting' style={styles}>
|
|
1037
|
+
<section className='waiting-container'>
|
|
1038
|
+
<h3>Finish Configuring</h3>
|
|
1039
|
+
<p>Set all required options to the left and confirm below to display a preview of the chart.</p>
|
|
1040
|
+
<Button className='btn' style={{ margin: '1em auto' }} disabled={missingRequiredSections()} onClick={e => confirmDone(e)}>
|
|
1041
|
+
I'm Done
|
|
1042
|
+
</Button>
|
|
1043
|
+
</section>
|
|
1044
|
+
</section>
|
|
1045
|
+
)
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
const Error = () => {
|
|
1049
|
+
const styles = {
|
|
1050
|
+
position: 'absolute',
|
|
1051
|
+
background: 'white',
|
|
1052
|
+
zIndex: '999',
|
|
1053
|
+
height: '100vh',
|
|
1054
|
+
width: '100%',
|
|
1055
|
+
display: 'flex',
|
|
1056
|
+
justifyContent: 'center',
|
|
1057
|
+
alignItems: 'center',
|
|
1058
|
+
gridArea: 'content'
|
|
1059
|
+
}
|
|
1060
|
+
return (
|
|
1061
|
+
<section className='waiting' style={styles}>
|
|
1062
|
+
<section className='waiting-container'>
|
|
1063
|
+
<h3>Error With Configuration</h3>
|
|
1064
|
+
<p>{config.runtime.editorErrorMessage}</p>
|
|
1065
|
+
</section>
|
|
1066
|
+
</section>
|
|
1067
|
+
)
|
|
1068
|
+
}
|
|
1069
|
+
|
|
993
1070
|
// this is passed DOWN into the various components
|
|
994
1071
|
// then they do a lookup based on the bin number as index into here (TT)
|
|
995
1072
|
const applyLegendToRow = rowObj => {
|
|
@@ -1024,6 +1101,17 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
1024
1101
|
// Prevent render if loading
|
|
1025
1102
|
let body = <Loading />
|
|
1026
1103
|
|
|
1104
|
+
const getChartWrapperClasses = () => {
|
|
1105
|
+
const classes = ['chart-container', 'p-relative']
|
|
1106
|
+
if (config.legend.position === 'bottom') classes.push('bottom')
|
|
1107
|
+
if (config.legend.hide) classes.push('legend-hidden')
|
|
1108
|
+
if (lineDatapointClass) classes.push(lineDatapointClass)
|
|
1109
|
+
if (!config.barHasBorder) classes.push('chart-bar--no-border')
|
|
1110
|
+
if (isDebug) classes.push('debug')
|
|
1111
|
+
classes.push(...contentClasses)
|
|
1112
|
+
return classes
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1027
1115
|
if (!loading) {
|
|
1028
1116
|
const tableLink = (
|
|
1029
1117
|
<a href={`#data-table-${config.dataKey}`} className='margin-left-href'>
|
|
@@ -1033,90 +1121,92 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
1033
1121
|
body = (
|
|
1034
1122
|
<>
|
|
1035
1123
|
{isEditor && <EditorPanel />}
|
|
1036
|
-
|
|
1037
|
-
<
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
<
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
</div>
|
|
1065
|
-
{description && (
|
|
1066
|
-
<div className='subtext' style={{ padding: '35px 0 15px' }}>
|
|
1067
|
-
{parse(description)}
|
|
1124
|
+
<Layout.Responsive isEditor={isEditor}>
|
|
1125
|
+
{config.newViz && <Confirm />}
|
|
1126
|
+
{undefined === config.newViz && isEditor && config.runtime && config.runtime?.editorErrorMessage && <Error />}
|
|
1127
|
+
{!missingRequiredSections() && !config.newViz && (
|
|
1128
|
+
<div className='cdc-chart-inner-container cove-component__content' aria-label={handleChartAriaLabels(config)} tabIndex={0}>
|
|
1129
|
+
<Title showTitle={config.showTitle} isDashboard={isDashboard} title={title} superTitle={config.superTitle} classes={['chart-title', `${config.theme}`, 'cove-component__header']} style={undefined} />
|
|
1130
|
+
|
|
1131
|
+
{/* Filters */}
|
|
1132
|
+
{config.filters && !externalFilters && config.visualizationType !== 'Spark Line' && <Filters config={config} setConfig={setConfig} setFilteredData={setFilteredData} filteredData={filteredData} excludedData={excludedData} filterData={filterData} dimensions={dimensions} />}
|
|
1133
|
+
<SkipTo skipId={handleChartTabbing} skipMessage='Skip Over Chart Container' />
|
|
1134
|
+
{/* Visualization */}
|
|
1135
|
+
{config?.introText && config.visualizationType !== 'Spark Line' && <section className='introText'>{parse(config.introText)}</section>}
|
|
1136
|
+
|
|
1137
|
+
<div style={{ marginBottom: computeMarginBottom(config, legend, currentViewport) }} className={getChartWrapperClasses().join(' ')}>
|
|
1138
|
+
{/* All charts except sparkline */}
|
|
1139
|
+
{config.visualizationType !== 'Spark Line' && chartComponents[config.visualizationType]}
|
|
1140
|
+
|
|
1141
|
+
{/* Sparkline */}
|
|
1142
|
+
{config.visualizationType === 'Spark Line' && (
|
|
1143
|
+
<>
|
|
1144
|
+
<Filters config={config} setConfig={setConfig} setFilteredData={setFilteredData} filteredData={filteredData} excludedData={excludedData} filterData={filterData} dimensions={dimensions} />
|
|
1145
|
+
{config?.introText && (
|
|
1146
|
+
<section className='introText' style={{ padding: '0px 0 35px' }}>
|
|
1147
|
+
{parse(config.introText)}
|
|
1148
|
+
</section>
|
|
1149
|
+
)}
|
|
1150
|
+
<div style={{ height: `100px`, width: `100%`, ...sparkLineStyles }}>
|
|
1151
|
+
<ParentSize>{parent => <SparkLine width={parent.width} height={parent.height} />}</ParentSize>
|
|
1068
1152
|
</div>
|
|
1069
|
-
|
|
1070
|
-
|
|
1153
|
+
{description && (
|
|
1154
|
+
<div className='subtext' style={{ padding: '35px 0 15px' }}>
|
|
1155
|
+
{parse(description)}
|
|
1156
|
+
</div>
|
|
1157
|
+
)}
|
|
1158
|
+
</>
|
|
1159
|
+
)}
|
|
1160
|
+
{/* Sankey */}
|
|
1161
|
+
{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} />}
|
|
1163
|
+
</div>
|
|
1164
|
+
{/* Link */}
|
|
1165
|
+
{isDashboard && config.table && config.table.show && config.table.showDataTableLink ? tableLink : link && link}
|
|
1166
|
+
|
|
1167
|
+
{/* Description */}
|
|
1168
|
+
{description && config.visualizationType !== 'Spark Line' && <div className={'column ' + config.isResponsiveTicks ? 'subtext--responsive-ticks' : 'subtext'}>{parse(description)}</div>}
|
|
1169
|
+
|
|
1170
|
+
{/* buttons */}
|
|
1171
|
+
<MediaControls.Section classes={['download-buttons']}>
|
|
1172
|
+
{config.table.showDownloadImgButton && <MediaControls.Button text='Download Image' title='Download Chart as Image' type='image' state={config} elementToCapture={imageId} />}
|
|
1173
|
+
{config.table.showDownloadPdfButton && <MediaControls.Button text='Download PDF' title='Download Chart as PDF' type='pdf' state={config} elementToCapture={imageId} />}
|
|
1174
|
+
</MediaControls.Section>
|
|
1175
|
+
|
|
1176
|
+
{/* Data Table */}
|
|
1177
|
+
{((config.xAxis.dataKey && config.table.show && config.visualizationType !== 'Spark Line' && config.visualizationType !== 'Sankey') || (config.visualizationType === 'Sankey' && config.table.show)) && (
|
|
1178
|
+
<DataTable
|
|
1179
|
+
config={config}
|
|
1180
|
+
rawData={config.visualizationType === 'Sankey' ? config?.data?.[0]?.tableData : config.table.customTableConfig ? filterData(config.filters, config.data) : config.data}
|
|
1181
|
+
runtimeData={config.visualizationType === 'Sankey' ? config?.data?.[0]?.tableData : transform.applySuppression(filteredData || excludedData, config.suppressedData)}
|
|
1182
|
+
expandDataTable={config.table.expanded}
|
|
1183
|
+
columns={config.columns}
|
|
1184
|
+
displayDataAsText={displayDataAsText}
|
|
1185
|
+
displayGeoName={displayGeoName}
|
|
1186
|
+
applyLegendToRow={applyLegendToRow}
|
|
1187
|
+
tableTitle={config.table.label}
|
|
1188
|
+
indexTitle={config.table.indexLabel}
|
|
1189
|
+
vizTitle={title}
|
|
1190
|
+
viewport={currentViewport}
|
|
1191
|
+
tabbingId={handleChartTabbing}
|
|
1192
|
+
colorScale={colorScale}
|
|
1193
|
+
/>
|
|
1071
1194
|
)}
|
|
1072
|
-
{
|
|
1195
|
+
{config?.footnotes && <section className='footnotes'>{parse(config.footnotes)}</section>}
|
|
1196
|
+
{/* show pdf or image button */}
|
|
1073
1197
|
</div>
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
{/* Description */}
|
|
1078
|
-
{description && config.visualizationType !== 'Spark Line' && <div className={'column ' + config.isResponsiveTicks ? 'subtext--responsive-ticks' : 'subtext'}>{parse(description)}</div>}
|
|
1079
|
-
|
|
1080
|
-
{/* buttons */}
|
|
1081
|
-
<MediaControls.Section classes={['download-buttons']}>
|
|
1082
|
-
{config.table.showDownloadImgButton && <MediaControls.Button text='Download Image' title='Download Chart as Image' type='image' state={config} elementToCapture={imageId} />}
|
|
1083
|
-
{config.table.showDownloadPdfButton && <MediaControls.Button text='Download PDF' title='Download Chart as PDF' type='pdf' state={config} elementToCapture={imageId} />}
|
|
1084
|
-
</MediaControls.Section>
|
|
1085
|
-
|
|
1086
|
-
{/* Data Table */}
|
|
1087
|
-
{config.xAxis.dataKey && config.table.show && config.visualizationType !== 'Spark Line' && (
|
|
1088
|
-
<DataTable
|
|
1089
|
-
config={config}
|
|
1090
|
-
rawData={config.table.customTableConfig ? filterData(config.filters, config.data) : config.data}
|
|
1091
|
-
runtimeData={transform.applySuppression(filteredData || excludedData, config.suppressedData)}
|
|
1092
|
-
expandDataTable={config.table.expanded}
|
|
1093
|
-
columns={config.columns}
|
|
1094
|
-
displayDataAsText={displayDataAsText}
|
|
1095
|
-
displayGeoName={displayGeoName}
|
|
1096
|
-
applyLegendToRow={applyLegendToRow}
|
|
1097
|
-
tableTitle={config.table.label}
|
|
1098
|
-
indexTitle={config.table.indexLabel}
|
|
1099
|
-
vizTitle={title}
|
|
1100
|
-
viewport={currentViewport}
|
|
1101
|
-
tabbingId={handleChartTabbing}
|
|
1102
|
-
colorScale={colorScale}
|
|
1103
|
-
/>
|
|
1104
|
-
)}
|
|
1105
|
-
{config?.footnotes && <section className='footnotes'>{parse(config.footnotes)}</section>}
|
|
1106
|
-
{/* show pdf or image button */}
|
|
1107
|
-
</div>
|
|
1108
|
-
)}
|
|
1198
|
+
)}
|
|
1199
|
+
</Layout.Responsive>
|
|
1109
1200
|
</>
|
|
1110
1201
|
)
|
|
1111
1202
|
}
|
|
1112
1203
|
|
|
1113
|
-
const getXAxisData = d => (config.runtime.xAxis
|
|
1204
|
+
const getXAxisData = d => (isDateScale(config.runtime.xAxis) ? parseDate(d[config.runtime.originalXAxis.dataKey]).getTime() : d[config.runtime.originalXAxis.dataKey])
|
|
1114
1205
|
const getYAxisData = (d, seriesKey) => d[seriesKey]
|
|
1115
1206
|
|
|
1116
1207
|
const capitalize = str => {
|
|
1117
1208
|
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
1118
1209
|
}
|
|
1119
|
-
|
|
1120
1210
|
const contextValues = {
|
|
1121
1211
|
capitalize,
|
|
1122
1212
|
computeMarginBottom,
|
|
@@ -1167,17 +1257,11 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
|
|
|
1167
1257
|
debugSvg: isDebug
|
|
1168
1258
|
}
|
|
1169
1259
|
|
|
1170
|
-
const classes = ['cdc-open-viz-module', 'type-chart', `${currentViewport}`, `font-${config.fontSize}`, `${config.theme}`]
|
|
1171
|
-
|
|
1172
|
-
config.visualizationType === 'Spark Line' && classes.push(`type-sparkline`)
|
|
1173
|
-
isEditor && classes.push('spacing-wrapper')
|
|
1174
|
-
isEditor && classes.push('isEditor')
|
|
1175
|
-
|
|
1176
1260
|
return (
|
|
1177
1261
|
<ConfigContext.Provider value={contextValues}>
|
|
1178
|
-
<
|
|
1262
|
+
<Layout.VisualizationWrapper config={config} isEditor={isEditor} currentViewport={currentViewport} ref={outerContainerRef} imageId={imageId} showEditorPanel={config?.showEditorPanel}>
|
|
1179
1263
|
{body}
|
|
1180
|
-
</
|
|
1264
|
+
</Layout.VisualizationWrapper>
|
|
1181
1265
|
</ConfigContext.Provider>
|
|
1182
1266
|
)
|
|
1183
1267
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
-
|
|
2
|
+
import { userEvent, within } from '@storybook/testing-library'
|
|
3
3
|
import Chart from '../CdcChart'
|
|
4
|
-
|
|
5
4
|
import pieChartExample from './_mock/pie_config.json'
|
|
6
5
|
import pieData from './_mock/pie_data.json'
|
|
6
|
+
import urlFilterExample from './_mock/url_filter.json'
|
|
7
7
|
|
|
8
8
|
const meta: Meta<typeof Chart> = {
|
|
9
|
-
title: 'Components/Templates/Editor
|
|
9
|
+
title: 'Components/Templates/Chart/Editor',
|
|
10
10
|
component: Chart
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -19,4 +19,15 @@ export const Primary: Story = {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
const sleep = ms => {
|
|
23
|
+
return new Promise(r => setTimeout(r, ms))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const Url_Filter: Story = {
|
|
27
|
+
args: {
|
|
28
|
+
config: urlFilterExample,
|
|
29
|
+
isEditor: true
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
22
33
|
export default meta
|