@cdc/chart 4.26.4 → 4.26.6

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 (141) hide show
  1. package/CONFIG.md +353 -29
  2. package/LICENSE +201 -0
  3. package/dist/{cdcchart-DQ00cQCm.es.js → cdcchart-BWVIUcAF.es.js} +5 -55
  4. package/dist/cdcchart.js +37885 -35117
  5. package/examples/feature/heatmap/average-age-categorical.json +313 -0
  6. package/examples/feature/heatmap/calendar-heatmap.json +134 -0
  7. package/examples/feature/heatmap/cell-values-bottom-axis.json +181 -0
  8. package/examples/feature/heatmap/sparse-aggregation.json +158 -0
  9. package/examples/private/bad-y-axis.json +543 -0
  10. package/examples/private/bar-chart-negative-value.json +455 -0
  11. package/examples/private/bump-chart.json +1116 -0
  12. package/examples/private/test-123.json +624 -0
  13. package/package.json +4 -3
  14. package/src/CdcChart.tsx +5 -4
  15. package/src/CdcChartComponent.tsx +166 -62
  16. package/src/_stories/Chart.AltText.stories.tsx +136 -0
  17. package/src/_stories/Chart.HeatMap.stories.tsx +187 -0
  18. package/src/_stories/Chart.Sankey.smoke.stories.tsx +62 -0
  19. package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +183 -0
  20. package/src/_stories/Chart.SmallMultiples.smoke.stories.tsx +29 -0
  21. package/src/_stories/Chart.YAxisAutoMaxStrategy.stories.tsx +52 -0
  22. package/src/_stories/Chart.YAxisFilterDomain.stories.tsx +90 -0
  23. package/src/_stories/ChartAnnotation.smoke.stories.tsx +10 -0
  24. package/src/_stories/ChartAxisTitles.smoke.stories.tsx +13 -0
  25. package/src/_stories/ChartBar.Editor.stories.tsx +63 -0
  26. package/src/_stories/ChartBrush.Interaction.stories.tsx +112 -0
  27. package/src/_stories/ChartBrush.smoke.stories.tsx +13 -4
  28. package/src/_stories/_mock/alt_text_metadata.json +38 -0
  29. package/src/_stories/_mock/annotation_event-line_mock.json +1064 -0
  30. package/src/_stories/_mock/heatmap-average-age-categorical.json +315 -0
  31. package/src/_stories/_mock/heatmap.json +156 -0
  32. package/src/_stories/_mock/reported_pertussis_cases.json +1643 -0
  33. package/src/_stories/_mock/sankey_mock.json +78 -0
  34. package/src/_stories/_mock/small_multiples/small_multiples_lines.json +1 -1
  35. package/src/components/Annotations/components/AnnotationDraggable.styles.css +22 -1
  36. package/src/components/Annotations/components/AnnotationDraggable.tsx +220 -120
  37. package/src/components/Annotations/components/AnnotationDropdown.tsx +5 -2
  38. package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +198 -0
  39. package/src/components/Axis/LeftAxis.tsx +17 -11
  40. package/src/components/Axis/LeftAxisGridlines.tsx +22 -12
  41. package/src/components/Axis/RightAxis.tsx +3 -0
  42. package/src/components/Axis/tests/AxisTickValues.test.tsx +86 -0
  43. package/src/components/Brush/BrushSelector.tsx +88 -187
  44. package/src/components/Brush/brushInteraction.ts +22 -0
  45. package/src/components/Brush/tests/brushInteraction.test.ts +38 -0
  46. package/src/components/EditorPanel/EditorPanel.tsx +677 -185
  47. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +114 -52
  48. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +105 -13
  49. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +1 -0
  50. package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +5 -0
  51. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +2 -2
  52. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.test.tsx +98 -0
  53. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +10 -0
  54. package/src/components/EditorPanel/components/Panels/Panel.Visual.test.tsx +484 -0
  55. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +4 -1
  56. package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +262 -0
  57. package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +32 -0
  58. package/src/components/EditorPanel/components/panels.scss +10 -0
  59. package/src/components/EditorPanel/editor-panel.scss +47 -0
  60. package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +61 -0
  61. package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +74 -0
  62. package/src/components/EditorPanel/useEditorPermissions.test.tsx +315 -0
  63. package/src/components/EditorPanel/useEditorPermissions.ts +77 -21
  64. package/src/components/HeatMap/components/HeatMap.tsx +767 -0
  65. package/src/components/HeatMap/components/HeatMapGradientLegend.tsx +128 -0
  66. package/src/components/HeatMap/heatmap.constants.ts +13 -0
  67. package/src/components/HeatMap/heatmap.css +85 -0
  68. package/src/components/HeatMap/helpers/index.ts +261 -0
  69. package/src/components/HeatMap/index.tsx +5 -0
  70. package/src/components/HeatMap/tests/HeatMap.test.tsx +1072 -0
  71. package/src/components/HeatMap/tests/helpers.test.ts +167 -0
  72. package/src/components/Legend/Legend.Component.tsx +2 -2
  73. package/src/components/Legend/helpers/createFormatLabels.test.ts +88 -0
  74. package/src/components/Legend/helpers/createFormatLabels.tsx +6 -1
  75. package/src/components/LineChart/components/LineChart.BumpCircle.tsx +19 -22
  76. package/src/components/LineChart/helpers.test.ts +574 -0
  77. package/src/components/LineChart/helpers.ts +39 -16
  78. package/src/components/LineChart/index.tsx +28 -5
  79. package/src/components/LinearChart/tests/LinearChart.test.tsx +137 -33
  80. package/src/components/LinearChart/tests/mockConfigContext.ts +1 -0
  81. package/src/components/LinearChart.tsx +103 -47
  82. package/src/components/PieChart/PieChart.tsx +4 -1
  83. package/src/components/RadarChart/RadarChart.tsx +3 -1
  84. package/src/components/Regions/components/Regions.tsx +195 -41
  85. package/src/components/Sankey/components/Sankey.tsx +7 -3
  86. package/src/components/Sankey/helpers/getSankeyTooltip.tsx +7 -6
  87. package/src/components/ScatterPlot/ScatterPlot.jsx +3 -3
  88. package/src/components/SmallMultiples/SmallMultipleTile.tsx +33 -3
  89. package/src/components/SmallMultiples/SmallMultiples.css +12 -0
  90. package/src/components/SmallMultiples/SmallMultiples.tsx +50 -15
  91. package/src/components/SmallMultiples/tests/SmallMultipleTile.test.tsx +152 -0
  92. package/src/components/SmallMultiples/tests/SmallMultiples.test.tsx +170 -0
  93. package/src/components/Sparkline/components/SparkLine.tsx +4 -9
  94. package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +1 -1
  95. package/src/components/WarmingStripes/WarmingStripesGradientLegend.tsx +2 -2
  96. package/src/data/initial-state.js +12 -0
  97. package/src/helpers/axisLabelFontSize.ts +8 -0
  98. package/src/helpers/bumpChartTooltip.ts +54 -0
  99. package/src/helpers/calculateLeftYAxisWidth.ts +13 -3
  100. package/src/helpers/colorAssignmentHelpers.ts +102 -0
  101. package/src/helpers/dataHelpers.ts +11 -1
  102. package/src/helpers/ensureSpecialChartAxisTypes.ts +11 -0
  103. package/src/helpers/getAxisMaxOverride.ts +16 -0
  104. package/src/helpers/getCleanTopTickMax.ts +64 -0
  105. package/src/helpers/getColorScale.ts +18 -9
  106. package/src/helpers/getHasBoundarySuppression.ts +26 -0
  107. package/src/helpers/getMinMax.ts +26 -25
  108. package/src/helpers/getYAxisDomainData.ts +38 -0
  109. package/src/helpers/getYAxisFinalizationEligibility.ts +40 -0
  110. package/src/helpers/handleChartAriaLabels.ts +23 -10
  111. package/src/helpers/hasSpacedInlineLabel.ts +10 -0
  112. package/src/helpers/seriesColumnSettings.ts +5 -4
  113. package/src/helpers/seriesHighlight.ts +26 -0
  114. package/src/helpers/smallMultiplesHelpers.ts +5 -0
  115. package/src/helpers/tests/axisLabelFontSize.test.ts +15 -0
  116. package/src/helpers/tests/bumpChartTooltip.test.ts +75 -0
  117. package/src/helpers/tests/calculateLeftYAxisWidth.test.ts +38 -0
  118. package/src/helpers/tests/dataHelpers.test.ts +135 -0
  119. package/src/helpers/tests/ensureSpecialChartAxisTypes.test.ts +30 -0
  120. package/src/helpers/tests/getAxisMaxOverride.test.ts +36 -0
  121. package/src/helpers/tests/getCleanTopTickMax.test.ts +165 -0
  122. package/src/helpers/tests/getColorScale.test.ts +197 -0
  123. package/src/helpers/tests/getMinMax.test.ts +211 -0
  124. package/src/helpers/tests/getYAxisDomainData.test.ts +119 -0
  125. package/src/helpers/tests/getYAxisFinalizationEligibility.test.ts +185 -0
  126. package/src/helpers/tests/handleChartAriaLabels.test.ts +71 -0
  127. package/src/helpers/tests/hasSpacedInlineLabel.test.ts +75 -0
  128. package/src/helpers/tests/seriesColumnSettings.test.ts +16 -2
  129. package/src/helpers/tests/seriesHighlight.test.ts +61 -0
  130. package/src/helpers/tests/smallMultiplesHelpers.test.ts +99 -0
  131. package/src/hooks/tests/useRightAxis.test.tsx +127 -0
  132. package/src/hooks/tests/useScales.test.tsx +383 -0
  133. package/src/hooks/useRightAxis.ts +30 -13
  134. package/src/hooks/useScales.ts +48 -21
  135. package/src/hooks/useTooltip.tsx +3 -1
  136. package/src/index.jsx +5 -2
  137. package/src/scss/main.scss +32 -49
  138. package/src/test/CdcChart.dataTable.test.tsx +122 -0
  139. package/src/types/ChartConfig.ts +24 -1
  140. package/src/types/ChartContext.ts +5 -0
  141. package/src/helpers/getYAxisAutoPadding.ts +0 -53
@@ -36,6 +36,11 @@ 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 { hasSpacedInlineLabel } from '../helpers/hasSpacedInlineLabel'
41
+ import { getYAxisDomainData, getYAxisFilterDomainBehavior } from '../helpers/getYAxisDomainData'
42
+ import { getHasBoundarySuppression } from '../helpers/getHasBoundarySuppression'
43
+ import { getExcludedData } from '../helpers/getExcludedData'
39
44
 
40
45
  // Hooks
41
46
  import useReduceData from '../hooks/useReduceData'
@@ -69,9 +74,6 @@ const DEFAULT_LEFT_Y_AXIS_WIDTH = 50
69
74
  // Font sizes
70
75
  const TICK_LABEL_FONT_SIZE = 16
71
76
  const TICK_LABEL_FONT_SIZE_SMALL = 13
72
- const AXIS_LABEL_FONT_SIZE = 18
73
- const AXIS_LABEL_FONT_SIZE_SMALL = 14
74
-
75
77
  // Label positioning constants
76
78
  const BELOW_BAR_TEXT_OFFSET = -6.5
77
79
  const LABEL_PADDING_OFFSET = 8
@@ -118,10 +120,16 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
118
120
  legendRef,
119
121
  parseDate,
120
122
  parentRef,
123
+ excludedData,
121
124
  tableData,
122
125
  transformedData: data,
126
+ yAxisTickValues: sharedYAxisTickValues,
127
+ yAxisDomainData
123
128
  } = useContext(ConfigContext)
124
129
 
130
+ // SVG accessibility: title/desc pattern
131
+ const a11y = handleChartAriaLabels(config)
132
+
125
133
  // CONFIG
126
134
  // todo: start destructuring this file for conciseness
127
135
  const { visualizationType, orientation, xAxis, yAxis, runtime, legend, forestPlot, debugSvg } = config
@@ -129,9 +137,28 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
129
137
  const { inlineLabel } = config.yAxis
130
138
 
131
139
  // 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
140
+ const dataForMinMax = getYAxisDomainData({
141
+ config,
142
+ data,
143
+ tableData,
144
+ fullEligibleDomainData: yAxisDomainData
145
+ })
146
+ const isStableYAxisDomain = getYAxisFilterDomainBehavior(config) === 'stable'
147
+ const rawEligibleYAxisDomainData = Array.isArray(config.yAxisDomainData) && config.yAxisDomainData.length > 0
148
+ ? getExcludedData(config, config.yAxisDomainData)
149
+ : isStableYAxisDomain && Array.isArray(excludedData)
150
+ ? excludedData
151
+ : tableData
152
+ const suppressionDomainData = getYAxisDomainData({
153
+ config,
154
+ data: tableData,
155
+ tableData,
156
+ fullEligibleDomainData: rawEligibleYAxisDomainData
157
+ })
158
+ const hasBoundarySuppression = getHasBoundarySuppression({
159
+ rows: suppressionDomainData,
160
+ config
161
+ })
135
162
  const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, dataForMinMax)
136
163
 
137
164
  const { visSupportsSmallMultiples } = useEditorPermissions()
@@ -163,6 +190,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
163
190
  const xAxisLabelRefs = useRef([])
164
191
  const xAxisTitleRef = useRef(null)
165
192
  const tooltipRef = useRef(null)
193
+ const brushLayoutRef = useRef<{ yAxisWidth: number; xMax: number } | null>(null)
194
+ const brushLayoutDepsRef = useRef<{ parentWidth: number; tableData: any } | null>(null)
166
195
 
167
196
  const dataRef = useIntersectionObserver(triggerRef, {
168
197
  freezeOnceVisible: false
@@ -174,10 +203,9 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
174
203
  const isLogarithmicAxis = config.yAxis.type === 'logarithmic'
175
204
  const isForestPlot = visualizationType === 'Forest Plot'
176
205
  const isDateTime = config.xAxis.type === 'date-time'
177
- const inlineLabelHasNoSpace = !inlineLabel?.includes(' ')
178
- const needsYAxisAutoPadding = inlineLabel && !inlineLabelHasNoSpace
206
+ const usesSpacedInlineLabel = hasSpacedInlineLabel(config)
179
207
  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
208
+ const axisLabelFontSize = getAxisLabelFontSize(vizViewport)
181
209
  const GET_TEXT_WIDTH_FONT = `normal ${tickLabelFontSize}px Nunito, sans-serif`
182
210
 
183
211
  // zero if not forest plot
@@ -185,11 +213,10 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
185
213
 
186
214
  // height before bottom axis
187
215
  const initialHeight = useMemo(
188
- () =>
189
- visualizationType === 'Warming Stripes' ? WARMING_STRIPES_HEIGHT : calcInitialHeight(config, currentViewport),
216
+ () => (visualizationType === 'Warming Stripes' ? WARMING_STRIPES_HEIGHT : calcInitialHeight(config, vizViewport)),
190
217
  [
191
218
  visualizationType,
192
- currentViewport,
219
+ vizViewport,
193
220
  config.heights?.vertical,
194
221
  config.heights?.horizontal,
195
222
  config.heights?.mobileVertical,
@@ -254,14 +281,29 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
254
281
  return () => observer.disconnect()
255
282
  }, [axisBottomRef.current])
256
283
 
257
- const { yScaleRight, hasRightAxis } = useRightAxis({ config, yMax, data })
284
+ const { yScaleRight, hasRightAxis, rightTickValues } = useRightAxis({ config, yMax, data: dataForMinMax })
258
285
 
259
286
  // State for computed left-axis width - shared across all linear-chart types.
260
287
  const [currentYAxisWidth, setCurrentYAxisWidth] = useState<number>(DEFAULT_LEFT_Y_AXIS_WIDTH)
261
288
  const yAxisWidth = currentYAxisWidth
262
289
 
263
290
  // Chart width calculation using the current y-axis width
264
- const xMax = parentWidth - yAxisWidth - (hasRightAxis ? config.yAxis.rightAxisSize : 0)
291
+ const xMax = Math.max(0, parentWidth - yAxisWidth - (hasRightAxis ? config.yAxis.rightAxisSize : 0))
292
+
293
+ // Stabilize brush container dimensions when brushDynamicYAxis is enabled.
294
+ // Without this, y-axis rescaling on each brush change creates a feedback loop:
295
+ // brush drag → y-domain change → tick label width change → xMax shift → brush jumps.
296
+ // We freeze the brush coordinate system and only update on real layout changes.
297
+ const isDynamicBrushYAxis = config.xAxis.brushDynamicYAxis
298
+ const isFirstBrushLayout = !brushLayoutDepsRef.current
299
+ const viewportResized = brushLayoutDepsRef.current?.parentWidth !== parentWidth
300
+ const dataReloaded = brushLayoutDepsRef.current?.tableData !== tableData
301
+ if (!isDynamicBrushYAxis || isFirstBrushLayout || viewportResized || dataReloaded) {
302
+ brushLayoutRef.current = { yAxisWidth, xMax }
303
+ brushLayoutDepsRef.current = { parentWidth, tableData }
304
+ }
305
+ const stableBrushYAxisWidth = isDynamicBrushYAxis ? brushLayoutRef.current!.yAxisWidth : yAxisWidth
306
+ const stableBrushXMax = isDynamicBrushYAxis ? brushLayoutRef.current!.xMax : xMax
265
307
 
266
308
  const {
267
309
  xScale,
@@ -273,10 +315,13 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
273
315
  xScaleAnnotation,
274
316
  yScaleAnnotation,
275
317
  min,
276
- max
318
+ max,
319
+ yTickValues
277
320
  } = useScales({
278
321
  data,
279
- tableData,
322
+ tableData: dataForMinMax,
323
+ yAxisDomainData: dataForMinMax,
324
+ hasBoundarySuppression,
280
325
  config,
281
326
  minValue,
282
327
  maxValue,
@@ -285,9 +330,10 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
285
330
  xAxisDataMapped,
286
331
  yMax,
287
332
  xMax,
288
- needsYAxisAutoPadding,
289
- currentViewport
333
+ hasSpacedInlineLabel: usesSpacedInlineLabel,
334
+ currentViewport: vizViewport
290
335
  })
336
+ const effectiveYTickValues = sharedYAxisTickValues ?? yTickValues
291
337
 
292
338
  // Consolidated tick formatters
293
339
  const { handleLeftTickFormatting, handleBottomTickFormatting } = useTickFormatters({
@@ -324,10 +370,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
324
370
  runtime.xAxis?.type
325
371
  ])
326
372
 
327
- const horizontalYAxisLabelSpace = runtime.yAxis.label && !config.hideYAxisLabel ? 30 : 0
373
+ const horizontalYAxisLabelSpace =
374
+ runtime.yAxis.label && !config.hideYAxisLabel && config.yAxis.titlePlacement !== 'top' ? 30 : 0
328
375
 
329
376
  const [yTickCount, xTickCount] = ['yAxis', 'xAxis'].map(axis =>
330
- countNumOfTicks({ axis, max, runtime, currentViewport, isHorizontal, data, config, min })
377
+ countNumOfTicks({ axis, max, runtime, currentViewport: vizViewport, isHorizontal, data, config, min })
331
378
  )
332
379
  const handleNumTicks = isForestPlot ? config.data.length : yTickCount
333
380
 
@@ -341,6 +388,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
341
388
  data,
342
389
  yScale,
343
390
  numTicks: handleNumTicks,
391
+ tickValues: effectiveYTickValues,
344
392
  parentWidth,
345
393
  tickLabelFont: GET_TEXT_WIDTH_FONT,
346
394
  axisLabelFontSize,
@@ -352,6 +400,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
352
400
  config,
353
401
  data,
354
402
  yScale,
403
+ effectiveYTickValues,
355
404
  handleNumTicks,
356
405
  parentWidth,
357
406
  isHorizontal,
@@ -416,11 +465,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
416
465
 
417
466
  const getManualStep = useCallback(() => {
418
467
  let manualStep = config.xAxis.manualStep
419
- if (config.xAxis.viewportStepCount && config.xAxis.viewportStepCount[currentViewport]) {
420
- manualStep = config.xAxis.viewportStepCount[currentViewport]
468
+ if (config.xAxis.viewportStepCount && config.xAxis.viewportStepCount[vizViewport]) {
469
+ manualStep = config.xAxis.viewportStepCount[vizViewport]
421
470
  }
422
471
  return manualStep
423
- }, [config.xAxis.manualStep, config.xAxis.viewportStepCount, currentViewport])
472
+ }, [config.xAxis.manualStep, config.xAxis.viewportStepCount, vizViewport])
424
473
 
425
474
  const smallMultiplesSync = useSmallMultipleSynchronization(xMax, yMax, yAxisWidth, getXValueFromCoordinate)
426
475
 
@@ -508,7 +557,6 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
508
557
 
509
558
  const isForestPlot = visualizationType === 'Forest Plot'
510
559
  const topLabelOnGridline = topYLabelRef.current && yAxis.labelsAboveGridlines
511
-
512
560
  // Heights to add
513
561
  const forestRowsHeight = isForestPlot ? config.data.length * forestPlot.rowHeight : 0
514
562
  const topLabelOnGridlineHeight = topLabelOnGridline ? topYLabelRef.current.getBBox().height : 0
@@ -580,6 +628,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
580
628
  <SmallMultiples
581
629
  config={config}
582
630
  data={data}
631
+ yAxisDomainData={dataForMinMax}
632
+ hasBoundarySuppression={hasBoundarySuppression}
583
633
  svgRef={svgRef}
584
634
  parentWidth={parentWidth}
585
635
  parentHeight={parentHeight}
@@ -601,11 +651,10 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
601
651
  onMouseMove={onMouseMove}
602
652
  width={parentWidth}
603
653
  height={isNoDataAvailable ? 1 : calculatedSvgHeight ?? parentHeight}
604
- className={`linear ${config.animate ? 'animated' : ''} ${animatedChart && config.animate ? 'animate' : ''} ${
605
- debugSvg && 'debug'
606
- } ${isDraggingAnnotation && 'dragging-annotation'}`}
654
+ className={`linear ${config.animate ? 'animated' : ''} ${animatedChart && config.animate ? 'animate' : ''} ${debugSvg && 'debug'
655
+ } ${isDraggingAnnotation && 'dragging-annotation'}`}
607
656
  role='img'
608
- aria-label={handleChartAriaLabels(config)}
657
+ aria-label={a11y}
609
658
  style={{ overflow: 'visible' }}
610
659
  onMouseLeave={() => {
611
660
  setShowHoverLine(false)
@@ -626,6 +675,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
626
675
  xMax={xMax}
627
676
  yAxisWidth={yAxisWidth}
628
677
  numTicks={handleNumTicks}
678
+ tickValues={effectiveYTickValues}
629
679
  axisLabelFontSize={axisLabelFontSize}
630
680
  />
631
681
  )}
@@ -754,18 +804,19 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
754
804
  {/* we are handling regions in bar charts differently, so that we can calculate the bar group into the region space. */}
755
805
  {/* prettier-ignore */}
756
806
  {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
- />
807
+ <Group left={yAxisWidth}>
808
+ <Regions
809
+ xScale={xScale}
810
+ handleTooltipClick={handleTooltipClick}
811
+ handleTooltipMouseOff={handleTooltipMouseOff}
812
+ handleTooltipMouseOver={handleTooltipMouseOver}
813
+ showTooltip={showTooltip}
814
+ hideTooltip={hideTooltip}
815
+ tooltipData={tooltipData}
816
+ yMax={yMax}
817
+ xMax={xMax}
818
+ />
819
+ </Group>
769
820
  )}
770
821
  {isNoDataAvailable && (
771
822
  <Text
@@ -821,6 +872,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
821
872
  xMax={xMax}
822
873
  yAxisWidth={yAxisWidth}
823
874
  numTicks={handleNumTicks}
875
+ tickValues={effectiveYTickValues}
824
876
  tickLabelFontSize={tickLabelFontSize}
825
877
  axisLabelFontSize={axisLabelFontSize}
826
878
  handleLeftTickFormatting={handleLeftTickFormatting}
@@ -846,6 +898,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
846
898
  yMax={yMax}
847
899
  xMax={xMax}
848
900
  yAxisWidth={yAxisWidth}
901
+ tickValues={rightTickValues}
849
902
  tickLabelFontSize={tickLabelFontSize}
850
903
  axisLabelFontSize={axisLabelFontSize}
851
904
  />
@@ -897,9 +950,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
897
950
  tooltipData.dataXPosition &&
898
951
  !config.tooltips.singleSeries && (
899
952
  <>
900
- <style>{`.tooltip {background-color: rgba(255,255,255, ${
901
- config.tooltips.opacity / 100
902
- }) !important;`}</style>
953
+ <style>{`.tooltip {background-color: rgba(255,255,255, ${config.tooltips.opacity / 100
954
+ }) !important;`}</style>
903
955
  <style>{`.tooltip {max-width:300px} !important; word-wrap: break-word; `}</style>
904
956
  <TooltipWithBounds
905
957
  ref={tooltipRef}
@@ -926,7 +978,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
926
978
  )}
927
979
  {config.visualizationType === 'Bump Chart' && (
928
980
  <ReactTooltip
929
- id={`bump-chart`}
981
+ id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}-bump`}
930
982
  variant='light'
931
983
  arrowColor='rgba(0,0,0,0)'
932
984
  className='tooltip'
@@ -949,8 +1001,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
949
1001
  style={{
950
1002
  position: 'relative',
951
1003
  marginTop: `${BRUSH_MARGIN}px`,
952
- left: `${yAxisWidth}px`,
953
- width: `${Math.max(xMax, BRUSH_MIN_WIDTH)}px`,
1004
+ left: `${stableBrushYAxisWidth}px`,
1005
+ width: `${Math.max(stableBrushXMax, BRUSH_MIN_WIDTH)}px`,
954
1006
  height: `${BRUSH_HEIGHT}px`,
955
1007
  pointerEvents: 'auto',
956
1008
  zIndex: 15,
@@ -961,7 +1013,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
961
1013
  }}
962
1014
  className='brush-overlay'
963
1015
  >
964
- <BrushSelector key={brushKeyRef.current} xMax={Math.max(xMax, BRUSH_MIN_WIDTH)} yMax={BRUSH_HEIGHT} />
1016
+ <BrushSelector
1017
+ key={brushKeyRef.current}
1018
+ xMax={Math.max(stableBrushXMax, BRUSH_MIN_WIDTH)}
1019
+ yMax={BRUSH_HEIGHT}
1020
+ />
965
1021
  </div>
966
1022
  )}
967
1023
  </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()