@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.
Files changed (82) hide show
  1. package/dist/cdcchart.js +48948 -37923
  2. package/examples/{private/combo.json → chart-regression-1.json} +40 -31
  3. package/examples/chart-regression-2.json +2360 -0
  4. package/examples/feature/filters/url-filter.json +1076 -0
  5. package/examples/feature/line/line-chart-preliminary.json +84 -37
  6. package/examples/feature/line/line-chart.json +2 -1
  7. package/examples/feature/regions/index.json +55 -5
  8. package/examples/feature/sankey/sankey-example-data.json +1364 -0
  9. package/examples/feature/sankey/sankey_chart_data.csv +20 -0
  10. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +306 -19
  11. package/examples/sparkline.json +868 -0
  12. package/index.html +128 -121
  13. package/package.json +4 -2
  14. package/src/CdcChart.tsx +73 -38
  15. package/src/_stories/ChartEditor.stories.tsx +15 -4
  16. package/src/_stories/_mock/pie_config.json +4 -3
  17. package/src/_stories/_mock/url_filter.json +1076 -0
  18. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +2 -1
  19. package/src/components/AreaChart/components/AreaChart.jsx +2 -25
  20. package/src/components/BarChart/components/BarChart.Horizontal.tsx +39 -49
  21. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +36 -56
  22. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +36 -41
  23. package/src/components/BarChart/components/BarChart.Vertical.tsx +48 -64
  24. package/src/components/BoxPlot/BoxPlot.jsx +11 -9
  25. package/src/components/DeviationBar.jsx +3 -3
  26. package/src/components/EditorPanel/EditorPanel.tsx +1717 -1961
  27. package/src/components/EditorPanel/EditorPanelContext.ts +40 -0
  28. package/src/components/EditorPanel/components/Panels/Panel.BoxPlot.tsx +148 -0
  29. package/src/components/EditorPanel/components/{Panel.ForestPlotSettings.tsx → Panels/Panel.ForestPlotSettings.tsx} +16 -7
  30. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +160 -0
  31. package/src/components/EditorPanel/components/{Panel.Regions.tsx → Panels/Panel.Regions.tsx} +6 -6
  32. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +108 -0
  33. package/src/components/EditorPanel/components/{Panel.Series.tsx → Panels/Panel.Series.tsx} +50 -6
  34. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +338 -0
  35. package/src/components/EditorPanel/components/Panels/index.tsx +19 -0
  36. package/src/components/EditorPanel/components/panels.scss +11 -0
  37. package/src/components/EditorPanel/editor-panel.scss +1 -13
  38. package/src/components/EditorPanel/useEditorPermissions.js +44 -13
  39. package/src/components/Legend/Legend.Component.tsx +207 -0
  40. package/src/components/Legend/Legend.tsx +8 -327
  41. package/src/components/Legend/helpers/createFormatLabels.tsx +140 -0
  42. package/src/components/LineChart/LineChartProps.ts +2 -1
  43. package/src/components/LineChart/components/LineChart.Circle.tsx +85 -52
  44. package/src/components/LineChart/helpers.ts +3 -3
  45. package/src/components/LineChart/index.tsx +99 -23
  46. package/src/components/LinearChart.jsx +12 -33
  47. package/src/components/PairedBarChart.jsx +10 -12
  48. package/src/components/PieChart/PieChart.tsx +80 -27
  49. package/src/components/Regions/components/Regions.tsx +120 -69
  50. package/src/components/Sankey/index.tsx +434 -0
  51. package/src/components/Sankey/sankey.scss +153 -0
  52. package/src/components/Sankey/types/index.ts +16 -0
  53. package/src/components/ScatterPlot/ScatterPlot.jsx +1 -0
  54. package/src/components/Sparkline/{SparkLine.jsx → components/SparkLine.tsx} +14 -30
  55. package/src/components/Sparkline/index.scss +3 -0
  56. package/src/components/Sparkline/index.tsx +1 -1
  57. package/src/components/ZoomBrush.tsx +2 -1
  58. package/src/data/initial-state.js +51 -4
  59. package/src/helpers/computeMarginBottom.ts +4 -3
  60. package/src/helpers/tests/computeMarginBottom.test.ts +2 -1
  61. package/src/hooks/useBarChart.js +5 -2
  62. package/src/hooks/useHighlightedBars.js +1 -1
  63. package/src/hooks/useMinMax.ts +3 -3
  64. package/src/hooks/useScales.ts +28 -18
  65. package/src/hooks/useTooltip.tsx +19 -14
  66. package/src/scss/main.scss +8 -96
  67. package/src/types/ChartConfig.ts +47 -20
  68. package/src/types/ChartContext.ts +17 -4
  69. package/src/types/Label.ts +7 -0
  70. package/examples/private/chart-t.json +0 -3740
  71. package/examples/private/epi-data.csv +0 -13
  72. package/examples/private/epi-data.json +0 -62
  73. package/examples/private/epi.json +0 -403
  74. package/examples/private/occupancy.json +0 -109283
  75. package/examples/private/prod-line-config.json +0 -401
  76. package/examples/private/region-data.json +0 -822
  77. package/examples/private/region-testing.json +0 -312
  78. package/examples/private/scaling.json +0 -45325
  79. package/examples/private/testing-data.json +0 -1739
  80. package/examples/private/testing.json +0 -816
  81. package/src/components/EditorPanel/components/Panel.DateHighlighting.tsx +0 -109
  82. 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 chroma from 'chroma-js'
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
- let labelColor = '#000000'
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.dataKey}<br/>
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.dataKey}<br/>
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, seriesHighlight, colorScale, currentViewport } = useContext(ConfigContext)
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={colorScale(arc.data[config.runtime.xAxis.dataKey])}
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 (colorScale(arc.data[config.runtime.xAxis.dataKey]) && chroma.contrast(textColor, colorScale(arc.data[config.runtime.xAxis.dataKey])) < 3.5) {
112
- textColor = '000'
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
- data.forEach(d => {
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
- <ErrorBoundary component='PieChart'>
160
- <svg width={width} height={height} className={`animated-pie group ${config.animate === false || animatedPie ? 'animated' : ''}`} role='img' aria-label={handleChartAriaLabels(config)}>
161
- <Group top={centerY} left={centerX}>
162
- {/* prettier-ignore */}
163
- <Pie
164
- data={filteredData || data}
165
- pieValue={d => d[config.runtime.yAxis.dataKey]}
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
- </Group>
173
- </svg>
174
- <div ref={triggerRef} />
175
- {tooltipData && Object.entries(tooltipData.data).length > 0 && tooltipOpen && showTooltip && tooltipData.dataYPosition && tooltipData.dataXPosition && (
176
- <>
177
- <style>{`.tooltip {background-color: rgba(255,255,255, ${config.tooltips.opacity / 100}) !important`}</style>
178
- <TooltipWithBounds key={Math.random()} className={'tooltip cdc-open-viz-module'} left={tooltipLeft} top={tooltipTop}>
179
- <ul>{typeof tooltipData === 'object' && Object.entries(tooltipData.data).map((item, index) => <TooltipListItem item={item} key={index} />)}</ul>
180
- </TooltipWithBounds>
181
- </>
182
- )}
183
- {/* <ReactTooltip id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} variant='light' arrowColor='rgba(0,0,0,0)' className='tooltip' /> */}
184
- </ErrorBoundary>
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 * as d3 from 'd3'
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
- const Regions = ({ xScale, barWidth = 0, totalBarsInGroup = 1, yMax, handleTooltipMouseOff, handleTooltipMouseOver, handleTooltipClick, tooltipData, showTooltip, hideTooltip }: RegionsProps) => {
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
- let from
24
- let to
25
- let width
28
+ const getFromValue = region => {
29
+ let from
26
30
 
27
- if (regions && orientation === 'vertical') {
28
- return regions.map(region => {
29
- if (xAxis.type === 'date' && region.fromType !== 'Previous Days') {
30
- from = xScale(parseDate(region.from).getTime())
31
- to = xScale(parseDate(region.to).getTime())
32
- width = to - from
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
- from = xScale(region.from)
37
- to = xScale(region.to)
38
- width = to - from
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
- if ((visualizationType === 'Bar' || config.visualizationType === 'Combo') && xAxis.type === 'date') {
42
- from = region.fromType !== 'Previous Days' ? xScale(parseDate(region.from).getTime()) - (barWidth * totalBarsInGroup) / 2 : null
43
- to = region.toType !== 'Last Date' ? xScale(parseDate(region.to).getTime()) + (barWidth * totalBarsInGroup) / 2 : null
82
+ from = xScale(from)
83
+ }
44
84
 
45
- width = to - from
46
- }
85
+ if (xAxis.type === 'categorical' && region.fromType !== 'Previous Days') {
86
+ from = xScale(region.from)
87
+ }
47
88
 
48
- if ((visualizationType === 'Bar' || config.visualizationType === 'Combo') && config.xAxis.type === 'categorical') {
49
- from = xScale(region.from)
50
- to = xScale(region.to)
51
- width = to - from
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
- if (region.fromType === 'Previous Days') {
55
- to = region.toType !== 'Last Date' ? xScale(parseDate(region.to).getTime()) + (barWidth * totalBarsInGroup) / 2 : null
56
-
57
- let domain = xScale.domain()
58
- let bisectDate = d3.bisector(d => d).left
59
- let closestValue
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
- from = Number(xScale(closestValue) - (visualizationType === 'Bar' || visualizationType === 'Combo' ? (barWidth * totalBarsInGroup) / 2 : 0))
104
+ const getToValue = region => {
105
+ let to
80
106
 
81
- width = to - from
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
- // set the region max to the charts max range.
85
- if (region.toType === 'Last Date') {
86
- let domainValues = xScale.domain()
87
- let lastDate = domainValues[domainValues.length - 1]
88
- to = Number(xScale(lastDate) + (visualizationType === 'Bar' || visualizationType === 'Combo' ? (barWidth * totalBarsInGroup) / 2 : 0))
89
- width = to - from
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'>