@cdc/chart 4.24.1 → 4.24.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdcchart.js +48948 -37923
- package/examples/{private/combo.json → chart-regression-1.json} +40 -31
- package/examples/chart-regression-2.json +2360 -0
- package/examples/feature/filters/url-filter.json +1076 -0
- package/examples/feature/line/line-chart-preliminary.json +84 -37
- package/examples/feature/line/line-chart.json +2 -1
- package/examples/feature/regions/index.json +55 -5
- 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/sparkline.json +868 -0
- package/index.html +128 -121
- package/package.json +4 -2
- package/src/CdcChart.tsx +73 -38
- package/src/_stories/ChartEditor.stories.tsx +15 -4
- package/src/_stories/_mock/pie_config.json +4 -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 -25
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +39 -49
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +36 -56
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +36 -41
- package/src/components/BarChart/components/BarChart.Vertical.tsx +48 -64
- package/src/components/BoxPlot/BoxPlot.jsx +11 -9
- package/src/components/DeviationBar.jsx +3 -3
- package/src/components/EditorPanel/EditorPanel.tsx +1717 -1961
- package/src/components/EditorPanel/EditorPanelContext.ts +40 -0
- package/src/components/EditorPanel/components/Panels/Panel.BoxPlot.tsx +148 -0
- package/src/components/EditorPanel/components/{Panel.ForestPlotSettings.tsx → Panels/Panel.ForestPlotSettings.tsx} +16 -7
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +160 -0
- package/src/components/EditorPanel/components/{Panel.Regions.tsx → Panels/Panel.Regions.tsx} +6 -6
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +108 -0
- package/src/components/EditorPanel/components/{Panel.Series.tsx → Panels/Panel.Series.tsx} +50 -6
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +338 -0
- package/src/components/EditorPanel/components/Panels/index.tsx +19 -0
- package/src/components/EditorPanel/components/panels.scss +11 -0
- package/src/components/EditorPanel/editor-panel.scss +1 -13
- package/src/components/EditorPanel/useEditorPermissions.js +44 -13
- package/src/components/Legend/Legend.Component.tsx +207 -0
- package/src/components/Legend/Legend.tsx +8 -327
- package/src/components/Legend/helpers/createFormatLabels.tsx +140 -0
- package/src/components/LineChart/LineChartProps.ts +2 -1
- package/src/components/LineChart/components/LineChart.Circle.tsx +85 -52
- package/src/components/LineChart/helpers.ts +3 -3
- package/src/components/LineChart/index.tsx +99 -23
- package/src/components/LinearChart.jsx +12 -33
- package/src/components/PairedBarChart.jsx +10 -12
- package/src/components/PieChart/PieChart.tsx +80 -27
- package/src/components/Regions/components/Regions.tsx +120 -69
- 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 +51 -4
- package/src/helpers/computeMarginBottom.ts +4 -3
- package/src/helpers/tests/computeMarginBottom.test.ts +2 -1
- package/src/hooks/useBarChart.js +5 -2
- package/src/hooks/useHighlightedBars.js +1 -1
- package/src/hooks/useMinMax.ts +3 -3
- package/src/hooks/useScales.ts +28 -18
- package/src/hooks/useTooltip.tsx +19 -14
- package/src/scss/main.scss +8 -96
- package/src/types/ChartConfig.ts +47 -20
- package/src/types/ChartContext.ts +17 -4
- package/src/types/Label.ts +7 -0
- package/examples/private/chart-t.json +0 -3740
- package/examples/private/epi-data.csv +0 -13
- package/examples/private/epi-data.json +0 -62
- package/examples/private/epi.json +0 -403
- package/examples/private/occupancy.json +0 -109283
- package/examples/private/prod-line-config.json +0 -401
- package/examples/private/region-data.json +0 -822
- package/examples/private/region-testing.json +0 -312
- package/examples/private/scaling.json +0 -45325
- package/examples/private/testing-data.json +0 -1739
- package/examples/private/testing.json +0 -816
- package/src/components/EditorPanel/components/Panel.DateHighlighting.tsx +0 -109
- package/src/components/EditorPanel/components/Panels.tsx +0 -13
|
@@ -5,7 +5,7 @@ import { scaleLinear } from '@visx/scale'
|
|
|
5
5
|
import { Text } from '@visx/text'
|
|
6
6
|
|
|
7
7
|
import ConfigContext from '../ConfigContext'
|
|
8
|
-
import
|
|
8
|
+
import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
|
|
9
9
|
|
|
10
10
|
const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
11
11
|
const { config, colorScale, transformedData: data, formatNumber, seriesHighlight, getTextWidth } = useContext(ConfigContext)
|
|
@@ -20,6 +20,7 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
20
20
|
const groupOne = {
|
|
21
21
|
parentKey: config.dataDescription.seriesKey,
|
|
22
22
|
dataKey: config.series[0].dataKey,
|
|
23
|
+
dataKeyLabel: config.runtime.seriesLabels[config.series[0].dataKey] || config.series[0].dataKey,
|
|
23
24
|
color: colorScale(config.runtime.seriesLabels[config.series[0].dataKey]),
|
|
24
25
|
max: Math.max.apply(
|
|
25
26
|
Math,
|
|
@@ -31,6 +32,7 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
31
32
|
const groupTwo = {
|
|
32
33
|
parentKey: config.dataDescription.seriesKey,
|
|
33
34
|
dataKey: config.series[1].dataKey,
|
|
35
|
+
dataKeyLabel: config.runtime.seriesLabels[config.series[1].dataKey] || config.series[1].dataKey,
|
|
34
36
|
color: colorScale(config.runtime.seriesLabels[config.series[1].dataKey]),
|
|
35
37
|
max: Math.max.apply(
|
|
36
38
|
Math,
|
|
@@ -45,21 +47,14 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
45
47
|
})
|
|
46
48
|
|
|
47
49
|
// Set label color
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (groupOne.color && chroma.contrast(labelColor, groupOne.color) < 4.9) {
|
|
51
|
-
groupOne.labelColor = '#FFFFFF'
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (groupTwo.color && chroma.contrast(labelColor, groupTwo.color) < 4.9) {
|
|
55
|
-
groupTwo.labelColor = '#FFFFFF'
|
|
56
|
-
}
|
|
50
|
+
groupOne.labelColor = groupOne.color ? getContrastColor('#000', groupOne.color) : '#000'
|
|
51
|
+
groupTwo.labelColor = groupTwo.color ? getContrastColor('#000', groupTwo.color) : '#000'
|
|
57
52
|
|
|
58
53
|
const label = config.yAxis.label ? `${config.yAxis.label}: ` : ''
|
|
59
54
|
|
|
60
55
|
const dataTipOne = d => {
|
|
61
56
|
return `<p>
|
|
62
|
-
${config.dataDescription.seriesKey}: ${groupOne.
|
|
57
|
+
${config.dataDescription.seriesKey}: ${groupOne.dataKeyLabel}<br/>
|
|
63
58
|
${config.xAxis.dataKey}: ${d[config.xAxis.dataKey]}<br/>
|
|
64
59
|
${label}${formatNumber(d[groupOne.dataKey], 'left')}
|
|
65
60
|
</p>`
|
|
@@ -67,7 +62,7 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
67
62
|
|
|
68
63
|
const dataTipTwo = d => {
|
|
69
64
|
return `<p>
|
|
70
|
-
${config.dataDescription.seriesKey}: ${groupTwo.
|
|
65
|
+
${config.dataDescription.seriesKey}: ${groupTwo.dataKeyLabel}<br/>
|
|
71
66
|
${config.xAxis.dataKey}: ${d[config.xAxis.dataKey]}<br/>
|
|
72
67
|
${label}${formatNumber(d[groupTwo.dataKey], 'left')}
|
|
73
68
|
</p>`
|
|
@@ -85,6 +80,7 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
85
80
|
`}
|
|
86
81
|
</style>
|
|
87
82
|
<svg id='cdc-visualization__paired-bar-chart' width={originalWidth} height={height} viewBox={`0 0 ${width + Number(config.runtime.yAxis.size)} ${height}`} role='img' tabIndex={0}>
|
|
83
|
+
<title>{`Paired bar chart graphic with the title ${config.title ? config.title : 'No Title Found'}`}</title>
|
|
88
84
|
<Group top={0} left={Number(config.xAxis.size)}>
|
|
89
85
|
{data
|
|
90
86
|
.filter(item => config.series[0].dataKey === groupOne.dataKey)
|
|
@@ -120,6 +116,7 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
120
116
|
strokeWidth={borderWidth}
|
|
121
117
|
opacity={transparentBar ? 0.5 : 1}
|
|
122
118
|
display={displayBar ? 'block' : 'none'}
|
|
119
|
+
tabIndex={-1}
|
|
123
120
|
/>
|
|
124
121
|
{config.yAxis.displayNumbersOnBar && displayBar && (
|
|
125
122
|
<Text textAnchor={textFits ? 'start' : 'end'} dx={textFits ? 5 : -5} verticalAnchor='middle' x={halfWidth - barWidth} y={y + config.barHeight / 2} fill={textFits ? groupOne.labelColor : '#000'}>
|
|
@@ -171,6 +168,7 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
171
168
|
stroke='#333'
|
|
172
169
|
opacity={transparentBar ? 0.5 : 1}
|
|
173
170
|
display={displayBar ? 'block' : 'none'}
|
|
171
|
+
tabIndex={-1}
|
|
174
172
|
/>
|
|
175
173
|
{config.yAxis.displayNumbersOnBar && displayBar && (
|
|
176
174
|
<Text textAnchor={isTextFits ? 'end' : 'start'} dx={isTextFits ? -5 : 5} verticalAnchor='middle' x={halfWidth + barWidth} y={y + config.barHeight / 2} fill={isTextFits ? groupTwo.labelColor : '#000'}>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import React, { useContext, useState, useEffect, useRef } from 'react'
|
|
1
|
+
import React, { useContext, useState, useEffect, useRef, useMemo } from 'react'
|
|
2
2
|
import { animated, useTransition, interpolate } from 'react-spring'
|
|
3
|
-
import chroma from 'chroma-js'
|
|
4
3
|
|
|
5
4
|
// visx
|
|
6
5
|
import { Pie } from '@visx/shape'
|
|
7
6
|
import { Group } from '@visx/group'
|
|
8
7
|
import { Text } from '@visx/text'
|
|
9
8
|
import { useTooltip, TooltipWithBounds } from '@visx/tooltip'
|
|
9
|
+
import { colorPalettesChart as colorPalettes } from '@cdc/core/data/colorPalettes'
|
|
10
10
|
|
|
11
11
|
// cove
|
|
12
12
|
import ConfigContext from '../../ConfigContext'
|
|
@@ -14,6 +14,10 @@ import { useTooltip as useCoveTooltip } from '../../hooks/useTooltip'
|
|
|
14
14
|
import useIntersectionObserver from '../../hooks/useIntersectionObserver'
|
|
15
15
|
import { handleChartAriaLabels } from '../../helpers/handleChartAriaLabels'
|
|
16
16
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
17
|
+
import LegendComponent from '../Legend/Legend.Component'
|
|
18
|
+
import { createFormatLabels } from '../Legend/helpers/createFormatLabels'
|
|
19
|
+
import { scaleOrdinal } from '@visx/scale'
|
|
20
|
+
import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
|
|
17
21
|
|
|
18
22
|
const enterUpdateTransition = ({ startAngle, endAngle }) => ({
|
|
19
23
|
startAngle,
|
|
@@ -29,7 +33,7 @@ type TooltipData = {
|
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
const PieChart = props => {
|
|
32
|
-
const { transformedData: data, config, dimensions,
|
|
36
|
+
const { transformedData: data, config, colorScale, currentViewport, dimensions, highlight, highlightReset, seriesHighlight } = useContext(ConfigContext)
|
|
33
37
|
const { tooltipData, showTooltip, hideTooltip, tooltipOpen, tooltipLeft, tooltipTop } = useTooltip<TooltipData>()
|
|
34
38
|
const { handleTooltipMouseOver, handleTooltipMouseOff, TooltipListItem } = useCoveTooltip({
|
|
35
39
|
xScale: false,
|
|
@@ -39,6 +43,50 @@ const PieChart = props => {
|
|
|
39
43
|
})
|
|
40
44
|
const [filteredData, setFilteredData] = useState(undefined)
|
|
41
45
|
const [animatedPie, setAnimatePie] = useState(false)
|
|
46
|
+
const pivotColumns = Object.values(config.columns).filter(column => column.showInViz)
|
|
47
|
+
const dataNeedsPivot = pivotColumns.length > 0
|
|
48
|
+
const pivotKey = dataNeedsPivot ? 'pivotColumn' : undefined
|
|
49
|
+
const _data = useMemo(() => {
|
|
50
|
+
if (dataNeedsPivot) {
|
|
51
|
+
let newData = []
|
|
52
|
+
const primaryColumn = config.yAxis.dataKey
|
|
53
|
+
const additionalColumns = pivotColumns.map(column => column.name)
|
|
54
|
+
const allColumns = [primaryColumn, ...additionalColumns]
|
|
55
|
+
const columnToUpdate = config.xAxis.dataKey
|
|
56
|
+
data.forEach(d => {
|
|
57
|
+
allColumns.forEach(col => {
|
|
58
|
+
const data = d[col]
|
|
59
|
+
if (data) {
|
|
60
|
+
newData.push({
|
|
61
|
+
[pivotKey]: data,
|
|
62
|
+
[columnToUpdate]: `${d[columnToUpdate]} - ${col}`
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
return newData
|
|
68
|
+
}
|
|
69
|
+
return data
|
|
70
|
+
}, [data, dataNeedsPivot])
|
|
71
|
+
|
|
72
|
+
const _colorScale = useMemo(() => {
|
|
73
|
+
if (dataNeedsPivot) {
|
|
74
|
+
const keys = {}
|
|
75
|
+
_data.forEach(d => {
|
|
76
|
+
if (!keys[d[config.xAxis.dataKey]]) keys[d[config.xAxis.dataKey]] = true
|
|
77
|
+
})
|
|
78
|
+
const numberOfKeys = Object.entries(keys).length
|
|
79
|
+
let palette = config.customColors || colorPalettes[config.palette]
|
|
80
|
+
palette = palette.slice(0, numberOfKeys)
|
|
81
|
+
|
|
82
|
+
return scaleOrdinal({
|
|
83
|
+
domain: Object.keys(keys),
|
|
84
|
+
range: palette,
|
|
85
|
+
unknown: null
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
return colorScale
|
|
89
|
+
}, [colorScale, dataNeedsPivot])
|
|
42
90
|
|
|
43
91
|
const triggerRef = useRef()
|
|
44
92
|
const dataRef = useIntersectionObserver(triggerRef, {
|
|
@@ -96,7 +144,7 @@ const PieChart = props => {
|
|
|
96
144
|
endAngle
|
|
97
145
|
})
|
|
98
146
|
)}
|
|
99
|
-
fill={
|
|
147
|
+
fill={_colorScale(arc.data[config.runtime.xAxis.dataKey])}
|
|
100
148
|
onMouseEnter={e => handleTooltipMouseOver(e, { data: arc.data[config.runtime.xAxis.dataKey], arc })}
|
|
101
149
|
onMouseLeave={e => handleTooltipMouseOff()}
|
|
102
150
|
/>
|
|
@@ -108,8 +156,8 @@ const PieChart = props => {
|
|
|
108
156
|
const hasSpaceForLabel = arc.endAngle - arc.startAngle >= 0.1
|
|
109
157
|
|
|
110
158
|
let textColor = '#FFF'
|
|
111
|
-
if (
|
|
112
|
-
textColor =
|
|
159
|
+
if (_colorScale(arc.data[config.runtime.xAxis.dataKey])) {
|
|
160
|
+
textColor = getContrastColor(textColor, _colorScale(arc.data[config.runtime.xAxis.dataKey]))
|
|
113
161
|
}
|
|
114
162
|
|
|
115
163
|
return (
|
|
@@ -143,7 +191,7 @@ const PieChart = props => {
|
|
|
143
191
|
if (seriesHighlight.length > 0 && config.legend.behavior !== 'highlight') {
|
|
144
192
|
let newFilteredData = []
|
|
145
193
|
|
|
146
|
-
|
|
194
|
+
_data.forEach(d => {
|
|
147
195
|
if (seriesHighlight.indexOf(d[config.runtime.xAxis.dataKey]) !== -1) {
|
|
148
196
|
newFilteredData.push(d)
|
|
149
197
|
}
|
|
@@ -155,33 +203,38 @@ const PieChart = props => {
|
|
|
155
203
|
}
|
|
156
204
|
}, [seriesHighlight]) // eslint-disable-line
|
|
157
205
|
|
|
206
|
+
const createLegendLabels = createFormatLabels(config, [], _data, _colorScale)
|
|
207
|
+
|
|
158
208
|
return (
|
|
159
|
-
|
|
160
|
-
<
|
|
161
|
-
<
|
|
162
|
-
{
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
209
|
+
<>
|
|
210
|
+
<ErrorBoundary component='PieChart'>
|
|
211
|
+
<svg width={width} height={height} className={`animated-pie group ${config.animate === false || animatedPie ? 'animated' : ''}`} role='img' aria-label={handleChartAriaLabels(config)}>
|
|
212
|
+
<Group top={centerY} left={centerX}>
|
|
213
|
+
{/* prettier-ignore */}
|
|
214
|
+
<Pie
|
|
215
|
+
data={filteredData || _data}
|
|
216
|
+
pieValue={d => d[pivotKey || config.runtime.yAxis.dataKey]}
|
|
166
217
|
pieSortValues={() => -1}
|
|
167
218
|
innerRadius={radius - donutThickness}
|
|
168
219
|
outerRadius={radius}
|
|
169
220
|
>
|
|
170
221
|
{pie => <AnimatedPie {...pie} getKey={d => d.data[config.runtime.xAxis.dataKey]}/>}
|
|
171
222
|
</Pie>
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
223
|
+
</Group>
|
|
224
|
+
</svg>
|
|
225
|
+
<div ref={triggerRef} />
|
|
226
|
+
{tooltipData && Object.entries(tooltipData.data).length > 0 && tooltipOpen && showTooltip && tooltipData.dataYPosition && tooltipData.dataXPosition && (
|
|
227
|
+
<>
|
|
228
|
+
<style>{`.tooltip {background-color: rgba(255,255,255, ${config.tooltips.opacity / 100}) !important`}</style>
|
|
229
|
+
<TooltipWithBounds key={Math.random()} className={'tooltip cdc-open-viz-module'} left={tooltipLeft} top={tooltipTop}>
|
|
230
|
+
<ul>{typeof tooltipData === 'object' && Object.entries(tooltipData.data).map((item, index) => <TooltipListItem item={item} key={index} />)}</ul>
|
|
231
|
+
</TooltipWithBounds>
|
|
232
|
+
</>
|
|
233
|
+
)}
|
|
234
|
+
{/* <ReactTooltip id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} variant='light' arrowColor='rgba(0,0,0,0)' className='tooltip' /> */}
|
|
235
|
+
</ErrorBoundary>
|
|
236
|
+
<LegendComponent config={config} colorScale={_colorScale} seriesHighlight={seriesHighlight} highlight={highlight} highlightReset={highlightReset} currentViewport={currentViewport} formatLabels={createLegendLabels} />
|
|
237
|
+
</>
|
|
185
238
|
)
|
|
186
239
|
}
|
|
187
240
|
|
|
@@ -1,93 +1,153 @@
|
|
|
1
|
-
import React, { useContext } from 'react'
|
|
2
|
-
import { ChartConfig } from '../../../types/ChartConfig'
|
|
1
|
+
import React, { MouseEventHandler, useContext } from 'react'
|
|
3
2
|
import ConfigContext from '../../../ConfigContext'
|
|
4
3
|
import { ChartContext } from '../../../types/ChartContext'
|
|
5
4
|
import { Text } from '@visx/text'
|
|
6
5
|
import { Group } from '@visx/group'
|
|
7
|
-
import
|
|
6
|
+
import { formatDate, isDateScale } from '@cdc/core/helpers/cove/date.js'
|
|
8
7
|
|
|
9
8
|
type RegionsProps = {
|
|
10
9
|
xScale: Function
|
|
11
|
-
barWidth: number
|
|
12
|
-
totalBarsInGroup: number
|
|
13
10
|
yMax: number
|
|
14
11
|
barWidth?: number
|
|
15
12
|
totalBarsInGroup?: number
|
|
13
|
+
handleTooltipMouseOff: MouseEventHandler<SVGElement>
|
|
14
|
+
handleTooltipMouseOver: MouseEventHandler<SVGElement>
|
|
15
|
+
handleTooltipClick: MouseEventHandler<SVGElement>
|
|
16
|
+
tooltipData: unknown
|
|
17
|
+
showTooltip: Function
|
|
18
|
+
hideTooltip: Function
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
// TODO: should regions be removed on categorical axis?
|
|
22
|
+
const Regions: React.FC<RegionsProps> = ({ xScale, barWidth = 0, totalBarsInGroup = 1, yMax, handleTooltipMouseOff, handleTooltipMouseOver, handleTooltipClick, tooltipData, showTooltip, hideTooltip }) => {
|
|
19
23
|
const { parseDate, config } = useContext<ChartContext>(ConfigContext)
|
|
20
24
|
|
|
21
25
|
const { runtime, regions, visualizationType, orientation, xAxis } = config
|
|
26
|
+
const domain = xScale.domain()
|
|
22
27
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
let width
|
|
28
|
+
const getFromValue = region => {
|
|
29
|
+
let from
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
// Fixed Date
|
|
32
|
+
if (!region?.fromType || region.fromType === 'Fixed') {
|
|
33
|
+
const date = new Date(region.from)
|
|
34
|
+
const parsedDate = parseDate(formatDate(config.xAxis.dateParseFormat, date)).getTime()
|
|
35
|
+
from = xScale(parsedDate)
|
|
36
|
+
|
|
37
|
+
if (visualizationType === 'Bar' && xAxis.type === 'date-time') {
|
|
38
|
+
from = from - (barWidth * totalBarsInGroup) / 2
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Previous Date
|
|
43
|
+
if (region.fromType === 'Previous Days') {
|
|
44
|
+
const previousDays = Number(region.from) || 0
|
|
45
|
+
const categoricalDomain = domain.map(d => formatDate(config.xAxis.dateParseFormat, new Date(d)))
|
|
46
|
+
const d = region.toType === 'Last Date' ? new Date(domain[domain.length - 1]).getTime() : new Date(region.to) // on categorical charts force leading zero 03/15/2016 vs 3/15/2016 for valid date format
|
|
47
|
+
const to = config.xAxis.type === 'categorical' ? formatDate(config.xAxis.dateParseFormat, d) : formatDate(config.xAxis.dateParseFormat, d)
|
|
48
|
+
const toDate = new Date(to)
|
|
49
|
+
from = new Date(toDate.setDate(toDate.getDate() - Number(previousDays)))
|
|
50
|
+
|
|
51
|
+
if (xAxis.type === 'date') {
|
|
52
|
+
from = new Date(formatDate(xAxis.dateParseFormat, from)).getTime()
|
|
53
|
+
|
|
54
|
+
let closestDate = domain[0]
|
|
55
|
+
let minDiff = Math.abs(from - closestDate)
|
|
56
|
+
|
|
57
|
+
for (let i = 1; i < domain.length; i++) {
|
|
58
|
+
const diff = Math.abs(from - domain[i])
|
|
59
|
+
if (diff < minDiff) {
|
|
60
|
+
minDiff = diff
|
|
61
|
+
closestDate = domain[i]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
from = closestDate
|
|
33
65
|
}
|
|
34
66
|
|
|
67
|
+
// Here the domain is in the xScale.dateParseFormat
|
|
35
68
|
if (xAxis.type === 'categorical') {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
69
|
+
let closestDate = domain[0]
|
|
70
|
+
let minDiff = Math.abs(new Date(from).getTime() - new Date(closestDate).getTime())
|
|
71
|
+
|
|
72
|
+
for (let i = 1; i < domain.length; i++) {
|
|
73
|
+
const diff = Math.abs(new Date(from).getTime() - new Date(domain[i]).getTime())
|
|
74
|
+
if (diff < minDiff) {
|
|
75
|
+
minDiff = diff
|
|
76
|
+
closestDate = domain[i]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
from = closestDate
|
|
39
80
|
}
|
|
40
81
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
to = region.toType !== 'Last Date' ? xScale(parseDate(region.to).getTime()) + (barWidth * totalBarsInGroup) / 2 : null
|
|
82
|
+
from = xScale(from)
|
|
83
|
+
}
|
|
44
84
|
|
|
45
|
-
|
|
46
|
-
|
|
85
|
+
if (xAxis.type === 'categorical' && region.fromType !== 'Previous Days') {
|
|
86
|
+
from = xScale(region.from)
|
|
87
|
+
}
|
|
47
88
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
89
|
+
if (visualizationType === 'Line' || visualizationType === 'Area Chart') {
|
|
90
|
+
let scalePadding = Number(config.yAxis.size)
|
|
91
|
+
if (xScale.bandwidth) {
|
|
92
|
+
scalePadding += xScale.bandwidth() / 2
|
|
52
93
|
}
|
|
94
|
+
from = from + scalePadding
|
|
95
|
+
}
|
|
53
96
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
let previousDays = Number(region.from)
|
|
62
|
-
let lastDate = region.toType === 'Last Date' ? domain[domain.length - 1] : region.to
|
|
63
|
-
let fromDate = new Date(lastDate)
|
|
64
|
-
|
|
65
|
-
from = new Date(fromDate.setDate(fromDate.getDate() - previousDays)).getTime()
|
|
66
|
-
let targetValue = from
|
|
67
|
-
|
|
68
|
-
let index = bisectDate(domain, targetValue)
|
|
69
|
-
if (index === 0) {
|
|
70
|
-
closestValue = domain[0]
|
|
71
|
-
} else if (index === domain.length) {
|
|
72
|
-
closestValue = domain[domain.length - 1]
|
|
73
|
-
} else {
|
|
74
|
-
let d0 = domain[index - 1]
|
|
75
|
-
let d1 = domain[index]
|
|
76
|
-
closestValue = targetValue - d0 > d1 - targetValue ? d1 : d0
|
|
77
|
-
}
|
|
97
|
+
if (visualizationType === 'Bar' && config.xAxis.type === 'date-time' && region.fromType === 'Previous Days') {
|
|
98
|
+
from = from - (barWidth * totalBarsInGroup) / 2
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return from
|
|
102
|
+
}
|
|
78
103
|
|
|
79
|
-
|
|
104
|
+
const getToValue = region => {
|
|
105
|
+
let to
|
|
80
106
|
|
|
81
|
-
|
|
107
|
+
// when xScale is categorical leading zeros are removed, ie. 03/15/2016 is 3/15/2016
|
|
108
|
+
if (xAxis.type === 'categorical') {
|
|
109
|
+
to = xScale(region.to)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (isDateScale(xAxis)) {
|
|
113
|
+
if (!region?.toType || region.toType === 'Fixed') {
|
|
114
|
+
to = xScale(parseDate(region.to).getTime())
|
|
82
115
|
}
|
|
83
116
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
117
|
+
if (visualizationType === 'Bar' || config.visualizationType === 'Combo') {
|
|
118
|
+
to = region.toType !== 'Last Date' ? xScale(parseDate(region.to).getTime()) + barWidth * totalBarsInGroup : to
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (region.toType === 'Last Date') {
|
|
122
|
+
const lastDate = domain[domain.length - 1]
|
|
123
|
+
to = Number(xScale(lastDate) + ((visualizationType === 'Bar' || visualizationType === 'Combo') && config.xAxis.type === 'date' ? barWidth * totalBarsInGroup : 0))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (visualizationType === 'Line' || visualizationType === 'Area Chart') {
|
|
127
|
+
let scalePadding = Number(config.yAxis.size)
|
|
128
|
+
if (xScale.bandwidth) {
|
|
129
|
+
scalePadding += xScale.bandwidth() / 2
|
|
90
130
|
}
|
|
131
|
+
to = to + scalePadding
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (visualizationType === 'Bar' && config.xAxis.type === 'date-time' && region.toType !== 'Last Date') {
|
|
135
|
+
to = to - (barWidth * totalBarsInGroup) / 2
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if ((visualizationType === 'Bar' || visualizationType === 'Combo') && xAxis.type === 'categorical') {
|
|
139
|
+
to = to + (visualizationType === 'Bar' || visualizationType === 'Combo' ? barWidth * totalBarsInGroup : 0)
|
|
140
|
+
}
|
|
141
|
+
return to
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const getWidth = (to, from) => to - from
|
|
145
|
+
|
|
146
|
+
if (regions && orientation === 'vertical') {
|
|
147
|
+
return regions.map(region => {
|
|
148
|
+
const from = getFromValue(region)
|
|
149
|
+
const to = getToValue(region)
|
|
150
|
+
const width = getWidth(to, from)
|
|
91
151
|
|
|
92
152
|
if (!from) return null
|
|
93
153
|
if (!to) return null
|
|
@@ -111,16 +171,7 @@ const Regions = ({ xScale, barWidth = 0, totalBarsInGroup = 1, yMax, handleToolt
|
|
|
111
171
|
}
|
|
112
172
|
|
|
113
173
|
return (
|
|
114
|
-
<Group
|
|
115
|
-
className='regions regions-group--line'
|
|
116
|
-
left={config.visualizationType === 'Bar' || config.visualizationType === 'Combo' ? 0 : config?.visualizationType === 'Line' ? Number(runtime.yAxis.size) : 0}
|
|
117
|
-
key={region.label}
|
|
118
|
-
onMouseMove={handleTooltipMouseOver}
|
|
119
|
-
onMouseLeave={handleTooltipMouseOff}
|
|
120
|
-
handleTooltipClick={handleTooltipClick}
|
|
121
|
-
tooltipData={JSON.stringify(tooltipData)}
|
|
122
|
-
showTooltip={showTooltip}
|
|
123
|
-
>
|
|
174
|
+
<Group height={100} fill='red' className='regions regions-group--line zzz' key={region.label} onMouseMove={handleTooltipMouseOver} onMouseLeave={handleTooltipMouseOff} handleTooltipClick={handleTooltipClick} tooltipData={JSON.stringify(tooltipData)} showTooltip={showTooltip}>
|
|
124
175
|
<TopRegionBorderShape />
|
|
125
176
|
<HighlightedArea />
|
|
126
177
|
<Text x={from + width / 2} y={5} fill={region.color} verticalAnchor='start' textAnchor='middle'>
|