@cdc/chart 4.26.3 → 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 (192) hide show
  1. package/CONFIG.md +489 -0
  2. package/README.md +42 -17
  3. package/dist/cdcchart.js +39024 -36587
  4. package/examples/feature/bar/additional-column-tooltip.json +3 -3
  5. package/examples/feature/deviation/planet-deviation-config.json +2 -2
  6. package/examples/feature/heatmap/average-age-categorical.json +313 -0
  7. package/examples/feature/heatmap/calendar-heatmap.json +134 -0
  8. package/examples/feature/heatmap/cell-values-bottom-axis.json +181 -0
  9. package/examples/feature/heatmap/sparse-aggregation.json +158 -0
  10. package/examples/feature/paired-bar/paired-bar-example.json +2 -2
  11. package/examples/feature/tests-case-rate/case-rate-example-config.json +2 -2
  12. package/examples/feature/tests-covid/covid-confidence-example-config.json +2 -2
  13. package/examples/feature/tests-covid/covid-example-config.json +2 -2
  14. package/examples/feature/tests-cutoff/cutoff-example-config.json +2 -2
  15. package/examples/feature/tests-non-numerics/planet-pie-example-config-nonnumeric.json +2 -2
  16. package/examples/metadata-variables.json +1 -1
  17. package/examples/minimal-example.json +24 -0
  18. package/examples/private/bump-chart.json +1116 -0
  19. package/examples/private/test-123.json +624 -0
  20. package/examples/private/test2.json +35012 -0
  21. package/package.json +5 -4
  22. package/src/CdcChartComponent.tsx +144 -60
  23. package/src/_stories/Chart.AltText.stories.tsx +136 -0
  24. package/src/_stories/{Chart.HTMLInDataTable.stories.tsx → Chart.HTMLInDataTable.smoke.stories.tsx} +10 -0
  25. package/src/_stories/Chart.HeatMap.stories.tsx +187 -0
  26. package/src/_stories/Chart.Minimal.smoke.stories.tsx +25 -0
  27. package/src/_stories/Chart.Sankey.smoke.stories.tsx +62 -0
  28. package/src/_stories/Chart.SmallMultiples.smoke.stories.tsx +108 -0
  29. package/src/_stories/{Chart.stories.tsx → Chart.smoke.stories.tsx} +12 -0
  30. package/src/_stories/{Chart.tooltip.stories.tsx → Chart.tooltip.smoke.stories.tsx} +68 -0
  31. package/src/_stories/{ChartAxisTitles.stories.tsx → ChartAxisTitles.smoke.stories.tsx} +13 -0
  32. package/src/_stories/ChartBar.Editor.stories.tsx +151 -85
  33. package/src/_stories/ChartBrush.Interaction.stories.tsx +112 -0
  34. package/src/_stories/{ChartBrush.stories.tsx → ChartBrush.smoke.stories.tsx} +13 -4
  35. package/src/_stories/ChartEditor.Editor.stories.tsx +23 -0
  36. package/src/_stories/ChartLine.DashedDates.smoke.stories.tsx +23 -0
  37. package/src/_stories/_mock/alt_text_metadata.json +38 -0
  38. package/src/_stories/_mock/heatmap-average-age-categorical.json +315 -0
  39. package/src/_stories/_mock/heatmap.json +156 -0
  40. package/src/_stories/_mock/line_chart_dashed_dates.json +276 -0
  41. package/src/_stories/_mock/paired-bar-abbr.json +1 -1
  42. package/src/_stories/_mock/paired-bar.json +1 -1
  43. package/src/_stories/_mock/reported_pertussis_cases.json +1643 -0
  44. package/src/_stories/_mock/sankey_mock.json +78 -0
  45. package/src/_stories/_mock/small_multiples/small_multiples_lines.json +1 -1
  46. package/src/components/Annotations/components/AnnotationDraggable.tsx +2 -2
  47. package/src/components/Annotations/components/AnnotationDropdown.tsx +5 -2
  48. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +10 -2
  49. package/src/components/Axis/BottomAxis.tsx +1 -1
  50. package/src/components/Axis/LeftAxis.tsx +15 -14
  51. package/src/components/Axis/LeftAxisGridlines.tsx +14 -13
  52. package/src/components/BarChart/components/BarChart.Horizontal.tsx +9 -5
  53. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +9 -5
  54. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +9 -5
  55. package/src/components/BarChart/components/BarChart.Vertical.tsx +9 -6
  56. package/src/components/BarChart/components/BarChart.tsx +2 -6
  57. package/src/components/BarChart/helpers/useBarChart.ts +1 -1
  58. package/src/components/BoxPlot/BoxPlot.Vertical.tsx +3 -3
  59. package/src/components/Brush/BrushSelector.tsx +88 -187
  60. package/src/components/Brush/brushInteraction.ts +22 -0
  61. package/src/components/Brush/tests/brushInteraction.test.ts +38 -0
  62. package/src/components/EditorPanel/EditorPanel.tsx +946 -960
  63. package/src/components/EditorPanel/EditorPanelContext.ts +1 -1
  64. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +229 -165
  65. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +105 -13
  66. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +169 -116
  67. package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +159 -109
  68. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +3 -3
  69. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +14 -28
  70. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +1 -1
  71. package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +57 -0
  72. package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +56 -0
  73. package/src/components/EditorPanel/useEditorPermissions.test.tsx +70 -0
  74. package/src/components/EditorPanel/useEditorPermissions.ts +32 -21
  75. package/src/components/Forecasting/Forecasting.tsx +2 -2
  76. package/src/components/HeatMap/components/HeatMap.tsx +762 -0
  77. package/src/components/HeatMap/components/HeatMapGradientLegend.tsx +114 -0
  78. package/src/components/HeatMap/heatmap.constants.ts +13 -0
  79. package/src/components/HeatMap/heatmap.css +71 -0
  80. package/src/components/HeatMap/helpers/index.ts +261 -0
  81. package/src/components/HeatMap/index.tsx +5 -0
  82. package/src/components/HeatMap/tests/HeatMap.test.tsx +1040 -0
  83. package/src/components/HeatMap/tests/helpers.test.ts +167 -0
  84. package/src/components/HorizonChart/HorizonChart.tsx +10 -2
  85. package/src/components/HoverLine/HoverLine.tsx +6 -8
  86. package/src/components/Legend/Legend.Component.tsx +4 -4
  87. package/src/components/Legend/LegendGroup/LegendGroup.styles.css +5 -0
  88. package/src/components/Legend/LegendGroup/LegendGroup.tsx +3 -1
  89. package/src/components/Legend/helpers/index.ts +0 -2
  90. package/src/components/LineChart/LineChartProps.ts +1 -0
  91. package/src/components/LineChart/components/LineChart.BumpCircle.tsx +22 -24
  92. package/src/components/LineChart/helpers.test.ts +345 -0
  93. package/src/components/LineChart/helpers.ts +15 -5
  94. package/src/components/LineChart/index.tsx +18 -5
  95. package/src/components/LinearChart/VisualizationRenderer.tsx +11 -1
  96. package/src/components/LinearChart/tests/LinearChart.test.tsx +228 -7
  97. package/src/components/LinearChart/tests/mockConfigContext.ts +1 -0
  98. package/src/components/LinearChart.tsx +155 -77
  99. package/src/components/PairedBarChart.jsx +2 -2
  100. package/src/components/PieChart/PieChart.tsx +15 -10
  101. package/src/components/RadarChart/RadarChart.tsx +3 -1
  102. package/src/components/Regions/components/Regions.tsx +199 -35
  103. package/src/components/Sankey/components/Sankey.tsx +7 -3
  104. package/src/components/Sankey/helpers/getSankeyTooltip.tsx +7 -6
  105. package/src/components/ScatterPlot/ScatterPlot.jsx +19 -17
  106. package/src/components/SmallMultiples/SmallMultipleTile.tsx +31 -3
  107. package/src/components/SmallMultiples/SmallMultiples.css +12 -0
  108. package/src/components/SmallMultiples/SmallMultiples.tsx +15 -9
  109. package/src/components/SmallMultiples/tests/SmallMultipleTile.test.tsx +152 -0
  110. package/src/components/Sparkline/components/SparkLine.tsx +5 -10
  111. package/src/components/WarmingStripes/WarmingStripes.tsx +5 -3
  112. package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +1 -1
  113. package/src/components/WarmingStripes/WarmingStripesGradientLegend.tsx +2 -2
  114. package/src/data/initial-state.js +12 -0
  115. package/src/helpers/axisLabelFontSize.ts +8 -0
  116. package/src/helpers/bumpChartTooltip.ts +54 -0
  117. package/src/helpers/calculateLeftYAxisWidth.ts +197 -0
  118. package/src/helpers/ensureSpecialChartAxisTypes.ts +11 -0
  119. package/src/helpers/getMinMax.ts +2 -3
  120. package/src/helpers/getYAxisAutoPadding.ts +8 -6
  121. package/src/helpers/getYAxisAutoPaddingMode.ts +17 -0
  122. package/src/helpers/handleChartAriaLabels.ts +23 -10
  123. package/src/helpers/seriesHighlight.ts +26 -0
  124. package/src/helpers/tests/axisLabelFontSize.test.ts +15 -0
  125. package/src/helpers/tests/bumpChartTooltip.test.ts +75 -0
  126. package/src/helpers/tests/ensureSpecialChartAxisTypes.test.ts +30 -0
  127. package/src/helpers/tests/getYAxisAutoPadding.test.ts +37 -0
  128. package/src/helpers/tests/getYAxisAutoPaddingMode.test.ts +90 -0
  129. package/src/helpers/tests/handleChartAriaLabels.test.ts +71 -0
  130. package/src/helpers/tests/seriesHighlight.test.ts +61 -0
  131. package/src/helpers/tests/tooltipHelpers.test.ts +151 -0
  132. package/src/helpers/tooltipHelpers.ts +176 -0
  133. package/src/hooks/tests/useScales.test.tsx +105 -0
  134. package/src/hooks/useHighlightedBars.ts +9 -16
  135. package/src/hooks/useProgrammaticTooltip.ts +16 -2
  136. package/src/hooks/useScales.ts +19 -9
  137. package/src/hooks/useSmallMultipleSynchronization.ts +3 -4
  138. package/src/hooks/useTooltip.tsx +167 -38
  139. package/src/index.jsx +5 -2
  140. package/src/scss/main.scss +32 -49
  141. package/src/test/CdcChart.test.jsx +24 -0
  142. package/src/types/ChartConfig.ts +19 -0
  143. package/src/types/ChartContext.ts +2 -0
  144. package/examples/chart-regression-2.json +0 -2360
  145. package/examples/feature/__data__/age-adjusted-rates.json +0 -1486
  146. package/examples/feature/__data__/city-temperature.json +0 -2198
  147. package/examples/feature/bar/Barchart_with_negative.json +0 -34
  148. package/examples/feature/boxplot/box-plot-data.json +0 -71
  149. package/examples/feature/boxplot/boxplot-data.json +0 -156
  150. package/examples/feature/combo/combochart-categories_are_numbers .json +0 -18
  151. package/examples/feature/forest-plot/log.json +0 -26
  152. package/examples/feature/tests-date-exclusions/date-exclusions-data.json +0 -162
  153. package/examples/region-issue.json +0 -2065
  154. package/examples/xaxis.json +0 -493
  155. package/src/_stories/Chart.SmallMultiples.stories.tsx +0 -63
  156. /package/examples/{data → __data__}/data-with-metadata.json +0 -0
  157. /package/examples/feature/bar/{tall-data.json → __data__/tall-data.json} +0 -0
  158. /package/examples/feature/deviation/{planet-deviation-data.json → __data__/planet-deviation-data.json} +0 -0
  159. /package/examples/feature/paired-bar/{paired-bar-data.json → __data__/paired-bar-data.json} +0 -0
  160. /package/examples/feature/paired-bar/{paired-bar-formatted.json → __data__/paired-bar-formatted.json} +0 -0
  161. /package/examples/feature/tests-case-rate/{case-rate-example-data.json → __data__/case-rate-example-data.json} +0 -0
  162. /package/examples/feature/tests-covid/{covid-example-data-confidence.json → __data__/covid-example-data-confidence.json} +0 -0
  163. /package/examples/feature/tests-covid/{covid-example-data.json → __data__/covid-example-data.json} +0 -0
  164. /package/examples/feature/tests-cutoff/{cutoff-example-data.json → __data__/cutoff-example-data.json} +0 -0
  165. /package/examples/feature/tests-non-numerics/{planet-example-data-nonnumeric.json → __data__/planet-example-data-nonnumeric.json} +0 -0
  166. /package/src/_stories/{Chart.Anchors.stories.tsx → Chart.Anchors.smoke.stories.tsx} +0 -0
  167. /package/src/_stories/{Chart.BoxPlot.stories.tsx → Chart.BoxPlot.smoke.stories.tsx} +0 -0
  168. /package/src/_stories/{Chart.CI.stories.tsx → Chart.CI.smoke.stories.tsx} +0 -0
  169. /package/src/_stories/{Chart.Combo.stories.tsx → Chart.Combo.smoke.stories.tsx} +0 -0
  170. /package/src/_stories/{Chart.CustomColors.stories.tsx → Chart.CustomColors.smoke.stories.tsx} +0 -0
  171. /package/src/_stories/{Chart.Defaults.stories.tsx → Chart.Defaults.smoke.stories.tsx} +0 -0
  172. /package/src/_stories/{Chart.DynamicSeries.stories.tsx → Chart.DynamicSeries.smoke.stories.tsx} +0 -0
  173. /package/src/_stories/{Chart.Filters.stories.tsx → Chart.Filters.smoke.stories.tsx} +0 -0
  174. /package/src/_stories/{Chart.Forecast.stories.tsx → Chart.Forecast.smoke.stories.tsx} +0 -0
  175. /package/src/_stories/{Chart.Legend.Gradient.stories.tsx → Chart.Legend.Gradient.smoke.stories.tsx} +0 -0
  176. /package/src/_stories/{Chart.Patterns.stories.tsx → Chart.Patterns.smoke.stories.tsx} +0 -0
  177. /package/src/_stories/{Chart.PreserveDecimals.stories.tsx → Chart.PreserveDecimals.smoke.stories.tsx} +0 -0
  178. /package/src/_stories/{Chart.Regions.Categorical.stories.tsx → Chart.Regions.Categorical.smoke.stories.tsx} +0 -0
  179. /package/src/_stories/{Chart.Regions.DateScale.stories.tsx → Chart.Regions.DateScale.smoke.stories.tsx} +0 -0
  180. /package/src/_stories/{Chart.Regions.DateTimeScale.stories.tsx → Chart.Regions.DateTimeScale.smoke.stories.tsx} +0 -0
  181. /package/src/_stories/{Chart.ScatterPlot.stories.tsx → Chart.ScatterPlot.smoke.stories.tsx} +0 -0
  182. /package/src/_stories/{Chart.SmallestLeftAxisMax.stories.tsx → Chart.SmallestLeftAxisMax.smoke.stories.tsx} +0 -0
  183. /package/src/_stories/{ChartAnnotation.stories.tsx → ChartAnnotation.smoke.stories.tsx} +0 -0
  184. /package/src/_stories/{ChartAxisLabels.stories.tsx → ChartAxisLabels.smoke.stories.tsx} +0 -0
  185. /package/src/_stories/{ChartBrush.Matrix.Continuous.stories.tsx → ChartBrush.Matrix.Continuous.smoke.stories.tsx} +0 -0
  186. /package/src/_stories/{ChartBrush.Matrix.Date.stories.tsx → ChartBrush.Matrix.Date.smoke.stories.tsx} +0 -0
  187. /package/src/_stories/{ChartBrush.Matrix.DateTime.stories.tsx → ChartBrush.Matrix.DateTime.smoke.stories.tsx} +0 -0
  188. /package/src/_stories/{ChartLine.QuadrantAngles.stories.tsx → ChartLine.QuadrantAngles.smoke.stories.tsx} +0 -0
  189. /package/src/_stories/{ChartLine.Suppression.stories.tsx → ChartLine.Suppression.smoke.stories.tsx} +0 -0
  190. /package/src/_stories/{ChartLine.Symbols.stories.tsx → ChartLine.Symbols.smoke.stories.tsx} +0 -0
  191. /package/src/_stories/{ChartPrefixSuffix.stories.tsx → ChartPrefixSuffix.smoke.stories.tsx} +0 -0
  192. /package/src/_stories/{TechAdoptionWithLinks.stories.tsx → TechAdoptionWithLinks.smoke.stories.tsx} +0 -0
@@ -0,0 +1,78 @@
1
+ {
2
+ "type": "chart",
3
+ "visualizationType": "Sankey",
4
+ "title": "Patient Care Pathway",
5
+ "showTitle": true,
6
+ "enableTooltips": true,
7
+ "heights": {
8
+ "vertical": 500,
9
+ "horizontal": 750
10
+ },
11
+ "data": [
12
+ {
13
+ "links": [
14
+ { "source": "Screened", "target": "Eligible", "value": 850 },
15
+ { "source": "Screened", "target": "Ineligible", "value": 150 },
16
+ { "source": "Eligible", "target": "Enrolled", "value": 700 },
17
+ { "source": "Eligible", "target": "Declined", "value": 150 },
18
+ { "source": "Enrolled", "target": "Completed Treatment", "value": 580 },
19
+ { "source": "Enrolled", "target": "Dropped Out", "value": 120 },
20
+ { "source": "Completed Treatment", "target": "Recovered", "value": 460 },
21
+ { "source": "Completed Treatment", "target": "Ongoing Care", "value": 120 }
22
+ ],
23
+ "tooltips": true,
24
+ "storyNodeText": []
25
+ }
26
+ ],
27
+ "sankey": {
28
+ "title": {
29
+ "defaultColor": "black"
30
+ },
31
+ "iterations": 1,
32
+ "rxValue": 0.9,
33
+ "overallSize": {
34
+ "width": 900,
35
+ "height": 700
36
+ },
37
+ "margin": {
38
+ "margin_y": 25,
39
+ "margin_x": 0
40
+ },
41
+ "nodeSize": {
42
+ "nodeWidth": 26,
43
+ "nodeHeight": 40
44
+ },
45
+ "nodePadding": 55,
46
+ "nodeFontColor": "black",
47
+ "nodeColor": {
48
+ "default": "#005eaa",
49
+ "inactive": "#808080"
50
+ },
51
+ "linkColor": {
52
+ "default": "#7bafd4",
53
+ "inactive": "#D3D3D3"
54
+ },
55
+ "opacity": {
56
+ "nodeOpacityDefault": 1.0,
57
+ "nodeOpacityInactive": 0.1,
58
+ "LinkOpacityDefault": 0.6,
59
+ "LinkOpacityInactive": 0.1
60
+ },
61
+ "storyNodeFontColor": "#006778",
62
+ "storyNodeText": [],
63
+ "nodeValueStyle": {
64
+ "textBefore": "(",
65
+ "textAfter": ")"
66
+ },
67
+ "data": []
68
+ },
69
+ "table": {
70
+ "show": false,
71
+ "expanded": false,
72
+ "label": "Data Table",
73
+ "caption": ""
74
+ },
75
+ "legend": {
76
+ "hide": true
77
+ }
78
+ }
@@ -64,7 +64,7 @@
64
64
  "hideTicks": true,
65
65
  "size": "40",
66
66
  "gridLines": true,
67
- "enablePadding": true,
67
+ "enablePadding": false,
68
68
  "min": "",
69
69
  "max": "",
70
70
  "labelColor": "#1c1d1f",
@@ -34,7 +34,7 @@ const Annotations = ({
34
34
  const [height] = dimensions
35
35
 
36
36
  const AnnotationComponent = isEditor ? EditableAnnotation : VisxAnnotation
37
- const isMobile = isMobileAnnotationViewport(currentViewport)
37
+ const isMobile = isMobileAnnotationViewport(currentViewport) && config?.general?.mobileAnnotationDisplay !== 'text'
38
38
 
39
39
  /**
40
40
  * Scale dx/dy offsets based on savedDimensions vs current dimensions.
@@ -218,7 +218,7 @@ const Annotations = ({
218
218
  return (
219
219
  <HtmlLabel
220
220
  className='annotation__desktop-label'
221
- containerStyle={{ width: `${labelWidth}px` }}
221
+ containerStyle={{ width: 'fit-content', maxWidth: `${labelWidth}px` }}
222
222
  horizontalAnchor={horizontalAnchor}
223
223
  verticalAnchor={verticalAnchor}
224
224
  showAnchorLine={false}
@@ -27,8 +27,11 @@ const AnnotationDropdown = () => {
27
27
  const handleSectionClasses = () => {
28
28
  const classes = [`data-table-container`, viewport, `w-100`, 'mt-4']
29
29
 
30
- // Show dropdown in mobile mode or if explicitly enabled
31
- if (isMobile || config.general.showAnnotationDropdown) {
30
+ // When mobile annotations show full text on the chart, the auto mobile dropdown is suppressed.
31
+ // The dropdown then follows showAnnotationDropdown only (matching desktop behavior).
32
+ const mobileShowsText = config.general?.mobileAnnotationDisplay === 'text'
33
+
34
+ if ((isMobile && !mobileShowsText) || config.general.showAnnotationDropdown) {
32
35
  classes.push('d-block')
33
36
  } else {
34
37
  classes.push('d-none')
@@ -11,7 +11,15 @@ import { Bar, AreaStack } from '@visx/shape'
11
11
  import { Group } from '@visx/group'
12
12
  import { approvedCurveTypes } from '@cdc/core/helpers/lineChartHelpers'
13
13
 
14
- const AreaChartStacked = ({ xScale, yScale, yMax, xMax, handleTooltipMouseOver, handleTooltipMouseOff }) => {
14
+ const AreaChartStacked = ({
15
+ xScale,
16
+ yScale,
17
+ yMax,
18
+ xMax,
19
+ yAxisWidth,
20
+ handleTooltipMouseOver,
21
+ handleTooltipMouseOff
22
+ }) => {
15
23
  // import data from context
16
24
  let { transformedData: data, config, seriesHighlight, colorScale, rawData, parseDate } = useContext(ConfigContext)
17
25
  // Draw transparent bars over the chart to get tooltip data
@@ -39,7 +47,7 @@ const AreaChartStacked = ({ xScale, yScale, yMax, xMax, handleTooltipMouseOver,
39
47
  <Group
40
48
  className='area-chart'
41
49
  key='area-wrapper'
42
- left={Number(config.yAxis.size) + strokeWidth / 2}
50
+ left={yAxisWidth + strokeWidth / 2}
43
51
  height={Number(yMax)}
44
52
  style={{ overflow: 'hidden' }}
45
53
  >
@@ -205,7 +205,7 @@ const BottomAxis: React.FC<BottomAxisProps> = ({
205
205
  const tickLength = showTick === 'block' ? MAJOR_TICK_LENGTH : DEFAULT_TICK_LENGTH
206
206
  const to = { x: tick.to.x, y: tickLength }
207
207
  const tickSlotWidth = filteredTicks.length > 0 ? xMax / filteredTicks.length : xMax
208
- const limitedWidth = Math.max(Math.min(maxLengthOfTick, tickSlotWidth), 0)
208
+ const limitedWidth = Math.max(Math.min(maxLengthOfTick, tickSlotWidth), 1)
209
209
 
210
210
  // Configure rotation using effective values (computed above without mutations)
211
211
  const tickRotation =
@@ -36,7 +36,6 @@ interface LeftAxisProps {
36
36
  suffixWidth?: number
37
37
  horizontalYAxisLabelSpace?: number
38
38
  categoryLabelSpace?: number
39
- yLabelOffset?: number
40
39
  }
41
40
 
42
41
  const LeftAxis: React.FC<LeftAxisProps> = ({
@@ -53,8 +52,7 @@ const LeftAxis: React.FC<LeftAxisProps> = ({
53
52
  suffixRef,
54
53
  suffixWidth = 0,
55
54
  horizontalYAxisLabelSpace = 0,
56
- categoryLabelSpace = 0,
57
- yLabelOffset = 0
55
+ categoryLabelSpace = 0
58
56
  }) => {
59
57
  const { config, colorScale, seriesHighlight } = useContext(ConfigContext)
60
58
  const { runtime, orientation, visualizationType, visualizationSubType, heights } = config
@@ -62,6 +60,7 @@ const LeftAxis: React.FC<LeftAxisProps> = ({
62
60
  const isLogarithmicAxis = config.yAxis.type === 'logarithmic'
63
61
  const { labelsAboveGridlines, hideAxis, inlineLabel } = config.yAxis
64
62
  const inlineLabelHasNoSpace = !inlineLabel?.includes(' ')
63
+ const showSideTitle = config.yAxis.titlePlacement !== 'top'
65
64
 
66
65
  return (
67
66
  <VisxAxisLeft
@@ -383,17 +382,19 @@ const LeftAxis: React.FC<LeftAxisProps> = ({
383
382
  })
384
383
  })()}
385
384
 
386
- <Text
387
- className='y-label'
388
- textAnchor='middle'
389
- verticalAnchor='start'
390
- transform={`translate(${-1 * yAxisWidth + yLabelOffset}, ${axisCenter}) rotate(-90)`}
391
- fontWeight='bold'
392
- fill={config.yAxis.labelColor}
393
- fontSize={axisLabelFontSize}
394
- >
395
- {!config.hideYAxisLabel ? props.label : null}
396
- </Text>
385
+ {showSideTitle && (
386
+ <Text
387
+ className='y-label'
388
+ textAnchor='middle'
389
+ verticalAnchor='start'
390
+ transform={`translate(${-1 * yAxisWidth}, ${axisCenter}) rotate(-90)`}
391
+ fontWeight='bold'
392
+ fill={config.yAxis.labelColor}
393
+ fontSize={axisLabelFontSize}
394
+ >
395
+ {!config.hideYAxisLabel ? props.label : null}
396
+ </Text>
397
+ )}
397
398
  </Group>
398
399
  )
399
400
  }}
@@ -10,7 +10,6 @@ interface LeftAxisGridlinesProps {
10
10
  xMax: number
11
11
  yAxisWidth: number
12
12
  numTicks: number
13
- yLabelOffset: number
14
13
  axisLabelFontSize: number
15
14
  }
16
15
 
@@ -19,13 +18,13 @@ const LeftAxisGridlines: React.FC<LeftAxisGridlinesProps> = ({
19
18
  xMax,
20
19
  yAxisWidth,
21
20
  numTicks,
22
- yLabelOffset,
23
21
  axisLabelFontSize
24
22
  }) => {
25
23
  const { config } = useContext(ConfigContext)
26
24
  const { runtime } = config
27
25
 
28
26
  const isLogarithmicAxis = config.yAxis.type === 'logarithmic'
27
+ const showSideTitle = config.yAxis.titlePlacement !== 'top'
29
28
 
30
29
  return (
31
30
  <AxisLeft scale={yScale} left={yAxisWidth - config.yAxis.axisPadding} numTicks={numTicks}>
@@ -56,17 +55,19 @@ const LeftAxisGridlines: React.FC<LeftAxisGridlinesProps> = ({
56
55
  </Group>
57
56
  )
58
57
  })}
59
- <Text
60
- className='y-label'
61
- textAnchor='middle'
62
- verticalAnchor='start'
63
- transform={`translate(${-1 * yAxisWidth + yLabelOffset}, ${axisCenter}) rotate(-90)`}
64
- fontWeight='bold'
65
- fill={config.yAxis.labelColor}
66
- fontSize={axisLabelFontSize}
67
- >
68
- {!config.hideYAxisLabel ? props.label : null}
69
- </Text>
58
+ {showSideTitle && (
59
+ <Text
60
+ className='y-label'
61
+ textAnchor='middle'
62
+ verticalAnchor='start'
63
+ transform={`translate(${-1 * yAxisWidth}, ${axisCenter}) rotate(-90)`}
64
+ fontWeight='bold'
65
+ fill={config.yAxis.labelColor}
66
+ fontSize={axisLabelFontSize}
67
+ >
68
+ {!config.hideYAxisLabel ? props.label : null}
69
+ </Text>
70
+ )}
70
71
  </Group>
71
72
  )
72
73
  }}
@@ -26,6 +26,7 @@ import { getBarData } from '../helpers/getBarData'
26
26
  import { getHorizontalBarHeights } from '../helpers/getBarHeights'
27
27
  import { getPatternUrl as getPatternUrlForBar } from '../helpers/getPatternUrl'
28
28
  import { getChartPatternId } from '../../../helpers/getChartPatternId'
29
+ import { buildSeriesTooltipListHtml } from '../../../helpers/tooltipHelpers'
29
30
 
30
31
  const BarChartHorizontal = () => {
31
32
  const { xScale, yScale, yMax, seriesScale, barChart } = useContext<BarChartContextValues>(BarChartContext)
@@ -243,11 +244,14 @@ const BarChartHorizontal = () => {
243
244
  : xAxisValue
244
245
  const additionalColTooltip = getAdditionalColumn(bar.key, hoveredBar)
245
246
  const tooltipBody = `${config.runtime.seriesLabels[bar.key]}: ${yAxisValue}`
246
- const tooltip = `<ul>
247
- <li class="tooltip-heading"">${yAxisTooltip}</li>
248
- <li class="tooltip-body ">${tooltipBody}</li>
249
- <li class="tooltip-body ">${additionalColTooltip}</li>
250
- </li></ul>`
247
+ const tooltip = buildSeriesTooltipListHtml({
248
+ config,
249
+ colorScale,
250
+ heading: yAxisTooltip,
251
+ seriesKey: bar.key,
252
+ seriesText: tooltipBody,
253
+ extraRows: additionalColTooltip ? [additionalColTooltip] : []
254
+ })
251
255
 
252
256
  // configure colors
253
257
  let labelColor = APP_FONT_COLOR
@@ -16,6 +16,7 @@ import createBarElement from '@cdc/core/components/createBarElement'
16
16
  import { getHorizontalBarHeights } from '../helpers/getBarHeights'
17
17
  import { getPatternUrl as getPatternUrlForBar } from '../helpers/getPatternUrl'
18
18
  import { getChartPatternId } from '../../../helpers/getChartPatternId'
19
+ import { buildSeriesTooltipListHtml } from '../../../helpers/tooltipHelpers'
19
20
 
20
21
  const BarChartStackedHorizontal = () => {
21
22
  const { yMax, yScale, xScale, barChart } = useContext<BarChartContextValues>(BarChartContext)
@@ -161,11 +162,14 @@ const BarChartStackedHorizontal = () => {
161
162
  const textWidth = getTextWidth(xAxisValue, `normal ${labelFontSize}px sans-serif`)
162
163
  const additionalColTooltip = getAdditionalColumn(bar.key, hoveredBar)
163
164
  const tooltipBody = `${config.runtime.seriesLabels[bar.key]}: ${xAxisValue}`
164
- const tooltip = `<ul>
165
- <li class="tooltip-heading"">${yAxisTooltip}</li>
166
- <li class="tooltip-body ">${tooltipBody}</li>
167
- <li class="tooltip-body ">${additionalColTooltip}</li>
168
- </li></ul>`
165
+ const tooltip = buildSeriesTooltipListHtml({
166
+ config,
167
+ colorScale,
168
+ heading: yAxisTooltip,
169
+ seriesKey: bar.key,
170
+ seriesText: tooltipBody,
171
+ extraRows: additionalColTooltip ? [additionalColTooltip] : []
172
+ })
169
173
 
170
174
  // Check if this bar should use a pattern
171
175
  const patternUrl = getPatternUrlForBar({
@@ -10,6 +10,7 @@ import { addMinimumBarHeights } from '../helpers'
10
10
  import createBarElement from '@cdc/core/components/createBarElement'
11
11
  import { getPatternUrl as getPatternUrlForBar } from '../helpers/getPatternUrl'
12
12
  import { getChartPatternId } from '../../../helpers/getChartPatternId'
13
+ import { buildSeriesTooltipListHtml } from '../../../helpers/tooltipHelpers'
13
14
 
14
15
  const BarChartStackedVertical = () => {
15
16
  const [barWidth, setBarWidth] = useState(0)
@@ -143,11 +144,14 @@ const BarChartStackedVertical = () => {
143
144
  : xAxisValue
144
145
  const additionalColTooltip = getAdditionalColumn(bar.key, hoveredBar)
145
146
  const tooltipBody = `${config.runtime.seriesLabels[bar.key]}: ${yAxisValue}`
146
- const tooltip = `<ul>
147
- <li class="tooltip-heading"">${xAxisTooltip}</li>
148
- <li class="tooltip-body ">${tooltipBody}</li>
149
- <li class="tooltip-body ">${additionalColTooltip}</li>
150
- </li></ul>`
147
+ const tooltip = buildSeriesTooltipListHtml({
148
+ config,
149
+ colorScale,
150
+ heading: xAxisTooltip,
151
+ seriesKey: bar.key,
152
+ seriesText: tooltipBody,
153
+ extraRows: additionalColTooltip ? [additionalColTooltip] : []
154
+ })
151
155
 
152
156
  setBarWidth(barThickness)
153
157
 
@@ -23,6 +23,7 @@ import _ from 'lodash'
23
23
  import { getBarData } from '../helpers/getBarData'
24
24
  import { getPatternUrl as getPatternUrlForBar } from '../helpers/getPatternUrl'
25
25
  import { getChartPatternId } from '../../../helpers/getChartPatternId'
26
+ import { buildSeriesTooltipListHtml } from '../../../helpers/tooltipHelpers'
26
27
 
27
28
  const BarChartVertical = () => {
28
29
  const { xScale, yScale, xMax, yMax, seriesScale, convertLineToBarGraph, barChart } =
@@ -229,12 +230,14 @@ const BarChartVertical = () => {
229
230
  ? `${config.runtime.xAxis.label}: ${xAxisValue}`
230
231
  : xAxisValue
231
232
  const tooltipBody = `${config.runtime.seriesLabels[bar.key]}: ${yAxisValue}`
232
-
233
- const tooltip = `<ul>
234
- <li class="tooltip-heading">${xAxisTooltip}</li>
235
- <li class="tooltip-body ">${tooltipBody}</li>
236
- ${additionalColTooltip ? '<li class="tooltip-body ">' + additionalColTooltip + '</li>' : ''}
237
- </li></ul>`
233
+ const tooltip = buildSeriesTooltipListHtml({
234
+ config,
235
+ colorScale,
236
+ heading: xAxisTooltip,
237
+ seriesKey: bar.key,
238
+ seriesText: tooltipBody,
239
+ extraRows: additionalColTooltip ? [additionalColTooltip] : []
240
+ })
238
241
  const { barHeight, isSuppressed, getBarY, absentDataLabel } = getBarConfig({
239
242
  bar,
240
243
  defaultBarHeight,
@@ -18,7 +18,7 @@ type BarChartProps = {
18
18
  seriesScale: PositionScale
19
19
  xMax: number
20
20
  yMax: number
21
- yAxisWidth?: number
21
+ yAxisWidth: number
22
22
  handleTooltipMouseOver: MouseEventHandler<SVGRectElement>
23
23
  handleTooltipMouseOff: MouseEventHandler<SVGRectElement>
24
24
  handleTooltipClick: MouseEventHandler<SVGRectElement>
@@ -49,14 +49,10 @@ const BarChart: React.FC<BarChartProps> = ({
49
49
  barChart
50
50
  }
51
51
 
52
- // Use yAxisWidth prop if provided (for horizontal bar charts with dynamic labels)
53
- // otherwise fall back to config value
54
- const leftOffset = yAxisWidth ?? parseFloat(config.runtime.yAxis.size)
55
-
56
52
  return (
57
53
  <ErrorBoundary component='BarChart'>
58
54
  <BarChartContext.Provider value={contextValues}>
59
- <Group left={leftOffset}>
55
+ <Group left={yAxisWidth}>
60
56
  <BarChartType.StackedVertical />
61
57
  <BarChartType.StackedHorizontal />
62
58
  <BarChartType.Vertical />
@@ -193,7 +193,7 @@ export const useBarChart = (handleTooltipMouseOver, handleTooltipMouseOff, confi
193
193
  const formattedValue = formatColNumber(
194
194
  closestVal[config.columns[colKeys].name],
195
195
  'left',
196
- true,
196
+ false,
197
197
  config,
198
198
  formattingParams
199
199
  )
@@ -9,7 +9,7 @@ import { handleTooltip, createPlots } from './helpers/index'
9
9
  import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
10
10
  import _ from 'lodash'
11
11
 
12
- const BoxPlotVertical = ({ xScale, yScale, seriesScale }) => {
12
+ const BoxPlotVertical = ({ xScale, yScale, seriesScale, yAxisWidth }) => {
13
13
  const { config, colorScale, seriesHighlight, transformedData: data } = useContext(ConfigContext)
14
14
  const { boxplot } = config
15
15
 
@@ -23,7 +23,7 @@ const BoxPlotVertical = ({ xScale, yScale, seriesScale }) => {
23
23
  const plots = createPlots(data, config)
24
24
  return (
25
25
  <ErrorBoundary component='BoxPlot Vertical'>
26
- <Group left={Number(config.yAxis.size)} className='boxplot' key={`boxplot-group`}>
26
+ <Group left={yAxisWidth} className='boxplot' key={`boxplot-group`}>
27
27
  {plots.map((d, i) => {
28
28
  const offset = boxWidth - constrainedWidth
29
29
  const radius = 4
@@ -63,7 +63,7 @@ const BoxPlotVertical = ({ xScale, yScale, seriesScale }) => {
63
63
  {displayPlot && (
64
64
  <BoxPlot
65
65
  display={displayPlot ? 'block' : 'none'}
66
- data-left={xScale(d.columnCategory) + config.yAxis.size + offset / 2 + 0.5}
66
+ data-left={xScale(d.columnCategory) + yAxisWidth + offset / 2 + 0.5}
67
67
  key={`box-plot-${i}-${item}`}
68
68
  min={Number(d.min[item.dataKey])}
69
69
  max={Number(d.max[item.dataKey])}