@cdc/chart 4.26.4 → 4.26.5

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 (93) hide show
  1. package/CONFIG.md +349 -29
  2. package/LICENSE +201 -0
  3. package/dist/cdcchart.js +34247 -32805
  4. package/examples/feature/heatmap/average-age-categorical.json +313 -0
  5. package/examples/feature/heatmap/calendar-heatmap.json +134 -0
  6. package/examples/feature/heatmap/cell-values-bottom-axis.json +181 -0
  7. package/examples/feature/heatmap/sparse-aggregation.json +158 -0
  8. package/examples/private/bump-chart.json +1116 -0
  9. package/examples/private/test-123.json +624 -0
  10. package/package.json +4 -3
  11. package/src/CdcChartComponent.tsx +135 -54
  12. package/src/_stories/Chart.AltText.stories.tsx +136 -0
  13. package/src/_stories/Chart.HeatMap.stories.tsx +187 -0
  14. package/src/_stories/Chart.Sankey.smoke.stories.tsx +62 -0
  15. package/src/_stories/Chart.SmallMultiples.smoke.stories.tsx +29 -0
  16. package/src/_stories/ChartAxisTitles.smoke.stories.tsx +13 -0
  17. package/src/_stories/ChartBar.Editor.stories.tsx +63 -0
  18. package/src/_stories/ChartBrush.Interaction.stories.tsx +112 -0
  19. package/src/_stories/ChartBrush.smoke.stories.tsx +13 -4
  20. package/src/_stories/_mock/alt_text_metadata.json +38 -0
  21. package/src/_stories/_mock/heatmap-average-age-categorical.json +315 -0
  22. package/src/_stories/_mock/heatmap.json +156 -0
  23. package/src/_stories/_mock/reported_pertussis_cases.json +1643 -0
  24. package/src/_stories/_mock/sankey_mock.json +78 -0
  25. package/src/_stories/_mock/small_multiples/small_multiples_lines.json +1 -1
  26. package/src/components/Annotations/components/AnnotationDraggable.tsx +1 -1
  27. package/src/components/Annotations/components/AnnotationDropdown.tsx +5 -2
  28. package/src/components/Axis/LeftAxis.tsx +14 -11
  29. package/src/components/Axis/LeftAxisGridlines.tsx +14 -11
  30. package/src/components/Brush/BrushSelector.tsx +88 -187
  31. package/src/components/Brush/brushInteraction.ts +22 -0
  32. package/src/components/Brush/tests/brushInteraction.test.ts +38 -0
  33. package/src/components/EditorPanel/EditorPanel.tsx +310 -49
  34. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +13 -0
  35. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +105 -13
  36. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +1 -0
  37. package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +5 -0
  38. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +2 -2
  39. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +1 -1
  40. package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +57 -0
  41. package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +56 -0
  42. package/src/components/EditorPanel/useEditorPermissions.test.tsx +70 -0
  43. package/src/components/EditorPanel/useEditorPermissions.ts +42 -22
  44. package/src/components/HeatMap/components/HeatMap.tsx +762 -0
  45. package/src/components/HeatMap/components/HeatMapGradientLegend.tsx +114 -0
  46. package/src/components/HeatMap/heatmap.constants.ts +13 -0
  47. package/src/components/HeatMap/heatmap.css +71 -0
  48. package/src/components/HeatMap/helpers/index.ts +261 -0
  49. package/src/components/HeatMap/index.tsx +5 -0
  50. package/src/components/HeatMap/tests/HeatMap.test.tsx +1040 -0
  51. package/src/components/HeatMap/tests/helpers.test.ts +167 -0
  52. package/src/components/LineChart/components/LineChart.BumpCircle.tsx +19 -22
  53. package/src/components/LineChart/helpers.test.ts +345 -0
  54. package/src/components/LineChart/helpers.ts +15 -5
  55. package/src/components/LineChart/index.tsx +7 -1
  56. package/src/components/LinearChart/tests/LinearChart.test.tsx +107 -33
  57. package/src/components/LinearChart/tests/mockConfigContext.ts +1 -0
  58. package/src/components/LinearChart.tsx +58 -37
  59. package/src/components/PieChart/PieChart.tsx +4 -1
  60. package/src/components/RadarChart/RadarChart.tsx +3 -1
  61. package/src/components/Regions/components/Regions.tsx +195 -41
  62. package/src/components/Sankey/components/Sankey.tsx +7 -3
  63. package/src/components/Sankey/helpers/getSankeyTooltip.tsx +7 -6
  64. package/src/components/SmallMultiples/SmallMultipleTile.tsx +30 -3
  65. package/src/components/SmallMultiples/SmallMultiples.css +12 -0
  66. package/src/components/SmallMultiples/SmallMultiples.tsx +15 -9
  67. package/src/components/SmallMultiples/tests/SmallMultipleTile.test.tsx +152 -0
  68. package/src/components/Sparkline/components/SparkLine.tsx +4 -9
  69. package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +1 -1
  70. package/src/components/WarmingStripes/WarmingStripesGradientLegend.tsx +2 -2
  71. package/src/data/initial-state.js +11 -0
  72. package/src/helpers/axisLabelFontSize.ts +8 -0
  73. package/src/helpers/bumpChartTooltip.ts +54 -0
  74. package/src/helpers/calculateLeftYAxisWidth.ts +4 -0
  75. package/src/helpers/ensureSpecialChartAxisTypes.ts +11 -0
  76. package/src/helpers/getMinMax.ts +2 -3
  77. package/src/helpers/getYAxisAutoPadding.ts +8 -6
  78. package/src/helpers/getYAxisAutoPaddingMode.ts +17 -0
  79. package/src/helpers/handleChartAriaLabels.ts +23 -10
  80. package/src/helpers/seriesHighlight.ts +26 -0
  81. package/src/helpers/tests/axisLabelFontSize.test.ts +15 -0
  82. package/src/helpers/tests/bumpChartTooltip.test.ts +75 -0
  83. package/src/helpers/tests/ensureSpecialChartAxisTypes.test.ts +30 -0
  84. package/src/helpers/tests/getYAxisAutoPadding.test.ts +37 -0
  85. package/src/helpers/tests/getYAxisAutoPaddingMode.test.ts +90 -0
  86. package/src/helpers/tests/handleChartAriaLabels.test.ts +71 -0
  87. package/src/helpers/tests/seriesHighlight.test.ts +61 -0
  88. package/src/hooks/tests/useScales.test.tsx +105 -0
  89. package/src/hooks/useScales.ts +19 -9
  90. package/src/index.jsx +5 -2
  91. package/src/scss/main.scss +32 -49
  92. package/src/types/ChartConfig.ts +18 -0
  93. package/src/types/ChartContext.ts +2 -0
@@ -72,6 +72,21 @@ const getLeftAxisLabelTransforms = container =>
72
72
  .map(label => label.getAttribute('transform'))
73
73
  .filter(Boolean)
74
74
 
75
+ const sidePlacementYAxis = {
76
+ hideAxis: false,
77
+ hideLabel: false,
78
+ hideTicks: false,
79
+ size: '50',
80
+ gridLines: true,
81
+ label: 'Y-Axis',
82
+ titlePlacement: 'side',
83
+ tickRotation: 0,
84
+ anchors: [],
85
+ axisPadding: 0,
86
+ labelPlacement: 'On Date/Category Axis',
87
+ rightAxisSize: 0
88
+ }
89
+
75
90
  describe('LinearChart', () => {
76
91
  describe('rendering', () => {
77
92
  it('renders without crashing', () => {
@@ -238,26 +253,103 @@ describe('LinearChart', () => {
238
253
  expect(leftAxis).toBeTruthy()
239
254
  })
240
255
 
256
+ it('does not render the side y-axis title inside the svg when titlePlacement is top', () => {
257
+ const { container } = renderLinearChart()
258
+
259
+ expect(container.querySelector('.left-axis text.y-label')).toBeFalsy()
260
+ })
261
+
262
+ it('does not render the top y-axis title inside LinearChart when titlePlacement is top', () => {
263
+ const { container } = renderLinearChart()
264
+
265
+ expect(container.querySelector('.y-axis-top-title')).toBeFalsy()
266
+ })
267
+
268
+ it('renders the side y-axis title inside the svg when titlePlacement is side', () => {
269
+ const { container } = renderLinearChart({
270
+ yAxis: sidePlacementYAxis
271
+ })
272
+
273
+ expect(container.querySelector('.y-axis-top-title')).toBeFalsy()
274
+ expect(container.querySelector('.left-axis text.y-label')).toBeTruthy()
275
+ })
276
+
241
277
  it('renders bottom axis group', () => {
242
278
  const { container } = renderLinearChart()
243
279
  const bottomAxis = container.querySelector('.bottom-axis')
244
280
  expect(bottomAxis).toBeTruthy()
245
281
  })
246
282
 
283
+ it('uses vizViewport for x-axis viewport tick overrides', () => {
284
+ const data = [
285
+ { Date: '2024-01-01', Value: 1 },
286
+ { Date: '2024-02-01', Value: 2 },
287
+ { Date: '2024-03-01', Value: 3 },
288
+ { Date: '2024-04-01', Value: 4 },
289
+ { Date: '2024-05-01', Value: 5 },
290
+ { Date: '2024-06-01', Value: 6 }
291
+ ]
292
+
293
+ const { container } = renderLinearChart(
294
+ {
295
+ data,
296
+ preliminaryData: [],
297
+ series: [{ dataKey: 'Value', axis: 'Left' }],
298
+ xAxis: {
299
+ type: 'date',
300
+ dataKey: 'Date',
301
+ label: 'X-Axis',
302
+ hideAxis: false,
303
+ hideLabel: false,
304
+ hideTicks: false,
305
+ size: '50',
306
+ tickRotation: 0,
307
+ maxTickRotation: 90,
308
+ anchors: [],
309
+ axisPadding: 0,
310
+ dateParseFormat: '%Y-%m-%d',
311
+ dateDisplayFormat: '%b %Y'
312
+ },
313
+ runtime: {
314
+ xAxis: {
315
+ type: 'date',
316
+ dataKey: 'Date',
317
+ label: 'X-Axis',
318
+ numTicks: 6,
319
+ viewportNumTicks: { xxs: 2 }
320
+ },
321
+ yAxis: {
322
+ size: 50,
323
+ label: 'Y-Axis',
324
+ gridLines: true
325
+ },
326
+ originalXAxis: {
327
+ dataKey: 'Date'
328
+ },
329
+ series: [{ dataKey: 'Value', axis: 'Left' }],
330
+ seriesKeys: ['Value'],
331
+ seriesLabels: { Value: 'Value' },
332
+ seriesLabelsAll: ['Value'],
333
+ uniqueId: 'test-chart'
334
+ }
335
+ },
336
+ {
337
+ currentViewport: 'lg',
338
+ vizViewport: 'xxs',
339
+ colorScale: () => '#000',
340
+ transformedData: data,
341
+ tableData: data
342
+ }
343
+ )
344
+
345
+ expect(container.querySelectorAll('.bottom-axis .vx-axis-tick')).toHaveLength(2)
346
+ })
347
+
247
348
  it('hides Y axis when hideAxis is true', () => {
248
349
  const { container } = renderLinearChart({
249
350
  yAxis: {
250
- hideAxis: true,
251
- hideLabel: false,
252
- hideTicks: false,
253
- size: '50',
254
- gridLines: true,
255
- label: 'Y-Axis',
256
- tickRotation: 0,
257
- anchors: [],
258
- axisPadding: 0,
259
- labelPlacement: 'On Date/Category Axis',
260
- rightAxisSize: 0
351
+ ...sidePlacementYAxis,
352
+ hideAxis: true
261
353
  }
262
354
  })
263
355
  // The axis line should be hidden, but grid lines may still render
@@ -288,34 +380,14 @@ describe('LinearChart', () => {
288
380
 
289
381
  const baseRender = renderLinearChart({
290
382
  yAxis: {
291
- hideAxis: false,
292
- hideLabel: false,
293
- hideTicks: false,
294
- size: '50',
295
- gridLines: true,
296
- label: 'Y-Axis',
297
- tickRotation: 0,
298
- anchors: [],
299
- axisPadding: 0,
300
- labelPlacement: 'On Date/Category Axis',
301
- rightAxisSize: 0,
383
+ ...sidePlacementYAxis,
302
384
  labelOffset: 0
303
385
  },
304
386
  runtime: baseRuntime
305
387
  })
306
388
  const offsetRender = renderLinearChart({
307
389
  yAxis: {
308
- hideAxis: false,
309
- hideLabel: false,
310
- hideTicks: false,
311
- size: '50',
312
- gridLines: true,
313
- label: 'Y-Axis',
314
- tickRotation: 0,
315
- anchors: [],
316
- axisPadding: 0,
317
- labelPlacement: 'On Date/Category Axis',
318
- rightAxisSize: 0,
390
+ ...sidePlacementYAxis,
319
391
  labelOffset: 240
320
392
  },
321
393
  runtime: {
@@ -372,6 +444,7 @@ describe('LinearChart', () => {
372
444
  axisPadding: 0,
373
445
  labelOffset: 0
374
446
  },
447
+ yAxis: sidePlacementYAxis,
375
448
  runtime: baseRuntime
376
449
  })
377
450
  const offsetRender = renderLinearChart({
@@ -390,6 +463,7 @@ describe('LinearChart', () => {
390
463
  axisPadding: 0,
391
464
  labelOffset: 240
392
465
  },
466
+ yAxis: sidePlacementYAxis,
393
467
  runtime: {
394
468
  ...baseRuntime,
395
469
  yAxis: {
@@ -34,6 +34,7 @@ export const createMockConfig = (overrides: Partial<ChartConfig> = {}): ChartCon
34
34
  size: '50',
35
35
  gridLines: true,
36
36
  label: 'Y-Axis',
37
+ titlePlacement: 'top',
37
38
  tickRotation: 0,
38
39
  anchors: [],
39
40
  axisPadding: 0,
@@ -36,6 +36,8 @@ import { isLegendWrapViewport, isMobileFontViewport } from '@cdc/core/helpers/vi
36
36
  import { calcInitialHeight } from '../helpers/sizeHelpers'
37
37
  import { calculateHorizontalBarCategoryLabelWidth } from '../helpers/calculateHorizontalBarCategoryLabelWidth'
38
38
  import { calculateLeftYAxisWidth } from '../helpers/calculateLeftYAxisWidth'
39
+ import { getAxisLabelFontSize } from '../helpers/axisLabelFontSize'
40
+ import { getYAxisAutoPaddingMode } from '../helpers/getYAxisAutoPaddingMode'
39
41
 
40
42
  // Hooks
41
43
  import useReduceData from '../hooks/useReduceData'
@@ -69,9 +71,6 @@ const DEFAULT_LEFT_Y_AXIS_WIDTH = 50
69
71
  // Font sizes
70
72
  const TICK_LABEL_FONT_SIZE = 16
71
73
  const TICK_LABEL_FONT_SIZE_SMALL = 13
72
- const AXIS_LABEL_FONT_SIZE = 18
73
- const AXIS_LABEL_FONT_SIZE_SMALL = 14
74
-
75
74
  // Label positioning constants
76
75
  const BELOW_BAR_TEXT_OFFSET = -6.5
77
76
  const LABEL_PADDING_OFFSET = 8
@@ -122,6 +121,9 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
122
121
  transformedData: data,
123
122
  } = useContext(ConfigContext)
124
123
 
124
+ // SVG accessibility: title/desc pattern
125
+ const a11y = handleChartAriaLabels(config)
126
+
125
127
  // CONFIG
126
128
  // todo: start destructuring this file for conciseness
127
129
  const { visualizationType, orientation, xAxis, yAxis, runtime, legend, forestPlot, debugSvg } = config
@@ -129,9 +131,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
129
131
  const { inlineLabel } = config.yAxis
130
132
 
131
133
  // HOOKS % STATES
132
- // When brush is active, use tableData (full dataset) for min/max calculation
133
- // so the y-axis shows the full range, but still use filtered data for rendering
134
- const dataForMinMax = config.xAxis.brushActive && tableData && tableData.length > 0 ? tableData : data
134
+ const useBrushFullRange = config.xAxis.brushActive && !config.xAxis.brushDynamicYAxis
135
+ const dataForMinMax = useBrushFullRange && tableData && tableData.length > 0 ? tableData : data
135
136
  const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, dataForMinMax)
136
137
 
137
138
  const { visSupportsSmallMultiples } = useEditorPermissions()
@@ -163,6 +164,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
163
164
  const xAxisLabelRefs = useRef([])
164
165
  const xAxisTitleRef = useRef(null)
165
166
  const tooltipRef = useRef(null)
167
+ const brushLayoutRef = useRef<{ yAxisWidth: number; xMax: number } | null>(null)
168
+ const brushLayoutDepsRef = useRef<{ parentWidth: number; tableData: any } | null>(null)
166
169
 
167
170
  const dataRef = useIntersectionObserver(triggerRef, {
168
171
  freezeOnceVisible: false
@@ -174,10 +177,9 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
174
177
  const isLogarithmicAxis = config.yAxis.type === 'logarithmic'
175
178
  const isForestPlot = visualizationType === 'Forest Plot'
176
179
  const isDateTime = config.xAxis.type === 'date-time'
177
- const inlineLabelHasNoSpace = !inlineLabel?.includes(' ')
178
- const needsYAxisAutoPadding = inlineLabel && !inlineLabelHasNoSpace
180
+ const yAxisAutoPaddingMode = getYAxisAutoPaddingMode(config)
179
181
  const tickLabelFontSize = isMobileFontViewport(vizViewport) ? TICK_LABEL_FONT_SIZE_SMALL : TICK_LABEL_FONT_SIZE
180
- const axisLabelFontSize = isMobileFontViewport(vizViewport) ? AXIS_LABEL_FONT_SIZE_SMALL : AXIS_LABEL_FONT_SIZE
182
+ const axisLabelFontSize = getAxisLabelFontSize(vizViewport)
181
183
  const GET_TEXT_WIDTH_FONT = `normal ${tickLabelFontSize}px Nunito, sans-serif`
182
184
 
183
185
  // zero if not forest plot
@@ -185,11 +187,10 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
185
187
 
186
188
  // height before bottom axis
187
189
  const initialHeight = useMemo(
188
- () =>
189
- visualizationType === 'Warming Stripes' ? WARMING_STRIPES_HEIGHT : calcInitialHeight(config, currentViewport),
190
+ () => (visualizationType === 'Warming Stripes' ? WARMING_STRIPES_HEIGHT : calcInitialHeight(config, vizViewport)),
190
191
  [
191
192
  visualizationType,
192
- currentViewport,
193
+ vizViewport,
193
194
  config.heights?.vertical,
194
195
  config.heights?.horizontal,
195
196
  config.heights?.mobileVertical,
@@ -263,6 +264,21 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
263
264
  // Chart width calculation using the current y-axis width
264
265
  const xMax = parentWidth - yAxisWidth - (hasRightAxis ? config.yAxis.rightAxisSize : 0)
265
266
 
267
+ // Stabilize brush container dimensions when brushDynamicYAxis is enabled.
268
+ // Without this, y-axis rescaling on each brush change creates a feedback loop:
269
+ // brush drag → y-domain change → tick label width change → xMax shift → brush jumps.
270
+ // We freeze the brush coordinate system and only update on real layout changes.
271
+ const isDynamicBrushYAxis = config.xAxis.brushDynamicYAxis
272
+ const isFirstBrushLayout = !brushLayoutDepsRef.current
273
+ const viewportResized = brushLayoutDepsRef.current?.parentWidth !== parentWidth
274
+ const dataReloaded = brushLayoutDepsRef.current?.tableData !== tableData
275
+ if (!isDynamicBrushYAxis || isFirstBrushLayout || viewportResized || dataReloaded) {
276
+ brushLayoutRef.current = { yAxisWidth, xMax }
277
+ brushLayoutDepsRef.current = { parentWidth, tableData }
278
+ }
279
+ const stableBrushYAxisWidth = isDynamicBrushYAxis ? brushLayoutRef.current!.yAxisWidth : yAxisWidth
280
+ const stableBrushXMax = isDynamicBrushYAxis ? brushLayoutRef.current!.xMax : xMax
281
+
266
282
  const {
267
283
  xScale,
268
284
  yScale,
@@ -285,8 +301,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
285
301
  xAxisDataMapped,
286
302
  yMax,
287
303
  xMax,
288
- needsYAxisAutoPadding,
289
- currentViewport
304
+ yAxisAutoPaddingMode,
305
+ currentViewport: vizViewport
290
306
  })
291
307
 
292
308
  // Consolidated tick formatters
@@ -324,10 +340,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
324
340
  runtime.xAxis?.type
325
341
  ])
326
342
 
327
- const horizontalYAxisLabelSpace = runtime.yAxis.label && !config.hideYAxisLabel ? 30 : 0
343
+ const horizontalYAxisLabelSpace =
344
+ runtime.yAxis.label && !config.hideYAxisLabel && config.yAxis.titlePlacement !== 'top' ? 30 : 0
328
345
 
329
346
  const [yTickCount, xTickCount] = ['yAxis', 'xAxis'].map(axis =>
330
- countNumOfTicks({ axis, max, runtime, currentViewport, isHorizontal, data, config, min })
347
+ countNumOfTicks({ axis, max, runtime, currentViewport: vizViewport, isHorizontal, data, config, min })
331
348
  )
332
349
  const handleNumTicks = isForestPlot ? config.data.length : yTickCount
333
350
 
@@ -416,11 +433,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
416
433
 
417
434
  const getManualStep = useCallback(() => {
418
435
  let manualStep = config.xAxis.manualStep
419
- if (config.xAxis.viewportStepCount && config.xAxis.viewportStepCount[currentViewport]) {
420
- manualStep = config.xAxis.viewportStepCount[currentViewport]
436
+ if (config.xAxis.viewportStepCount && config.xAxis.viewportStepCount[vizViewport]) {
437
+ manualStep = config.xAxis.viewportStepCount[vizViewport]
421
438
  }
422
439
  return manualStep
423
- }, [config.xAxis.manualStep, config.xAxis.viewportStepCount, currentViewport])
440
+ }, [config.xAxis.manualStep, config.xAxis.viewportStepCount, vizViewport])
424
441
 
425
442
  const smallMultiplesSync = useSmallMultipleSynchronization(xMax, yMax, yAxisWidth, getXValueFromCoordinate)
426
443
 
@@ -508,7 +525,6 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
508
525
 
509
526
  const isForestPlot = visualizationType === 'Forest Plot'
510
527
  const topLabelOnGridline = topYLabelRef.current && yAxis.labelsAboveGridlines
511
-
512
528
  // Heights to add
513
529
  const forestRowsHeight = isForestPlot ? config.data.length * forestPlot.rowHeight : 0
514
530
  const topLabelOnGridlineHeight = topLabelOnGridline ? topYLabelRef.current.getBBox().height : 0
@@ -605,7 +621,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
605
621
  debugSvg && 'debug'
606
622
  } ${isDraggingAnnotation && 'dragging-annotation'}`}
607
623
  role='img'
608
- aria-label={handleChartAriaLabels(config)}
624
+ aria-label={a11y}
609
625
  style={{ overflow: 'visible' }}
610
626
  onMouseLeave={() => {
611
627
  setShowHoverLine(false)
@@ -754,18 +770,19 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
754
770
  {/* we are handling regions in bar charts differently, so that we can calculate the bar group into the region space. */}
755
771
  {/* prettier-ignore */}
756
772
  {config.visualizationType !== 'Bar' && config.visualizationType !== 'Combo' && (
757
- <Regions
758
- xScale={xScale}
759
- handleTooltipClick={handleTooltipClick}
760
- handleTooltipMouseOff={handleTooltipMouseOff}
761
- handleTooltipMouseOver={handleTooltipMouseOver}
762
- showTooltip={showTooltip}
763
- hideTooltip={hideTooltip}
764
- tooltipData={tooltipData}
765
- yMax={yMax}
766
- xMax={xMax}
767
- yAxisWidth={yAxisWidth}
768
- />
773
+ <Group left={yAxisWidth}>
774
+ <Regions
775
+ xScale={xScale}
776
+ handleTooltipClick={handleTooltipClick}
777
+ handleTooltipMouseOff={handleTooltipMouseOff}
778
+ handleTooltipMouseOver={handleTooltipMouseOver}
779
+ showTooltip={showTooltip}
780
+ hideTooltip={hideTooltip}
781
+ tooltipData={tooltipData}
782
+ yMax={yMax}
783
+ xMax={xMax}
784
+ />
785
+ </Group>
769
786
  )}
770
787
  {isNoDataAvailable && (
771
788
  <Text
@@ -926,7 +943,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
926
943
  )}
927
944
  {config.visualizationType === 'Bump Chart' && (
928
945
  <ReactTooltip
929
- id={`bump-chart`}
946
+ id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}-bump`}
930
947
  variant='light'
931
948
  arrowColor='rgba(0,0,0,0)'
932
949
  className='tooltip'
@@ -949,8 +966,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
949
966
  style={{
950
967
  position: 'relative',
951
968
  marginTop: `${BRUSH_MARGIN}px`,
952
- left: `${yAxisWidth}px`,
953
- width: `${Math.max(xMax, BRUSH_MIN_WIDTH)}px`,
969
+ left: `${stableBrushYAxisWidth}px`,
970
+ width: `${Math.max(stableBrushXMax, BRUSH_MIN_WIDTH)}px`,
954
971
  height: `${BRUSH_HEIGHT}px`,
955
972
  pointerEvents: 'auto',
956
973
  zIndex: 15,
@@ -961,7 +978,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
961
978
  }}
962
979
  className='brush-overlay'
963
980
  >
964
- <BrushSelector key={brushKeyRef.current} xMax={Math.max(xMax, BRUSH_MIN_WIDTH)} yMax={BRUSH_HEIGHT} />
981
+ <BrushSelector
982
+ key={brushKeyRef.current}
983
+ xMax={Math.max(stableBrushXMax, BRUSH_MIN_WIDTH)}
984
+ yMax={BRUSH_HEIGHT}
985
+ />
965
986
  </div>
966
987
  )}
967
988
  </div>
@@ -44,6 +44,9 @@ const PieChart = React.forwardRef<SVGSVGElement, PieChartProps>((props, ref) =>
44
44
  seriesHighlight,
45
45
  isDraggingAnnotation
46
46
  } = useContext(ConfigContext)
47
+
48
+ const a11y = handleChartAriaLabels(config)
49
+
47
50
  const dispatch = useContext(ChartDispatchContext)
48
51
  const { tooltipData, showTooltip, hideTooltip, tooltipOpen, tooltipLeft, tooltipTop } = useTooltip<TooltipData>()
49
52
  const { handleTooltipMouseOver, handleTooltipMouseOff, TooltipListItem } = useCoveTooltip({
@@ -390,7 +393,7 @@ const PieChart = React.forwardRef<SVGSVGElement, PieChartProps>((props, ref) =>
390
393
  height={height}
391
394
  className={getSvgClasses()}
392
395
  role='img'
393
- aria-label={handleChartAriaLabels(config)}
396
+ aria-label={a11y}
394
397
  onMouseEnter={handleChartMouseEnter}
395
398
  onMouseLeave={() => {
396
399
  handleTooltipMouseOff()
@@ -41,6 +41,8 @@ const RadarChart = React.forwardRef<SVGSVGElement, RadarChartProps>((props, ref)
41
41
  formatNumber
42
42
  } = useContext(ConfigContext)
43
43
 
44
+ const a11y = handleChartAriaLabels(config)
45
+
44
46
  const dispatch = useContext(ChartDispatchContext)
45
47
 
46
48
  const { tooltipData, showTooltip, hideTooltip, tooltipOpen, tooltipLeft, tooltipTop } = useTooltip<TooltipData>()
@@ -232,7 +234,7 @@ const RadarChart = React.forwardRef<SVGSVGElement, RadarChartProps>((props, ref)
232
234
  height={height}
233
235
  className='radar-chart'
234
236
  role='img'
235
- aria-label={handleChartAriaLabels(config)}
237
+ aria-label={a11y}
236
238
  onMouseEnter={handleChartMouseEnter}
237
239
  onMouseLeave={() => {
238
240
  handleTooltipMouseOff()