@cdc/chart 4.25.5-1 → 4.25.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 (40) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cdcchart.js +32848 -27824
  3. package/index.html +130 -130
  4. package/package.json +2 -2
  5. package/src/CdcChartComponent.tsx +66 -26
  6. package/src/_stories/Chart.stories.tsx +99 -93
  7. package/src/_stories/ChartPrefixSuffix.stories.tsx +29 -32
  8. package/src/_stories/_mock/pie_calculated_area.json +417 -0
  9. package/src/components/BarChart/components/BarChart.Horizontal.tsx +4 -13
  10. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +3 -14
  11. package/src/components/BarChart/components/BarChart.Vertical.tsx +2 -8
  12. package/src/components/Brush/BrushChart.tsx +73 -0
  13. package/src/components/Brush/BrushController..tsx +39 -0
  14. package/src/components/DeviationBar.jsx +0 -1
  15. package/src/components/EditorPanel/EditorPanel.tsx +232 -147
  16. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +2 -2
  17. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +3 -2
  18. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +2 -1
  19. package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +8 -0
  20. package/src/components/EditorPanel/useEditorPermissions.ts +7 -4
  21. package/src/components/HoverLine/HoverLine.tsx +74 -0
  22. package/src/components/Legend/Legend.Suppression.tsx +47 -3
  23. package/src/components/Legend/helpers/index.ts +1 -1
  24. package/src/components/LineChart/index.tsx +3 -6
  25. package/src/components/LinearChart.tsx +161 -132
  26. package/src/components/PieChart/PieChart.tsx +58 -13
  27. package/src/data/initial-state.js +8 -5
  28. package/src/helpers/getNewRuntime.ts +35 -0
  29. package/src/helpers/getPiePercent.ts +22 -0
  30. package/src/helpers/getTransformedData.ts +22 -0
  31. package/src/helpers/tests/getNewRuntime.test.ts +82 -0
  32. package/src/helpers/tests/getPiePercent.test.ts +38 -0
  33. package/src/hooks/useRightAxis.ts +1 -1
  34. package/src/hooks/useScales.ts +8 -3
  35. package/src/hooks/useTooltip.tsx +24 -10
  36. package/src/store/chart.actions.ts +2 -6
  37. package/src/store/chart.reducer.ts +23 -23
  38. package/src/types/ChartConfig.ts +6 -3
  39. package/src/types/ChartContext.ts +0 -2
  40. package/src/components/ZoomBrush.tsx +0 -251
@@ -11,8 +11,7 @@ import _ from 'lodash'
11
11
 
12
12
  // CDC Components
13
13
  import { isDateScale } from '@cdc/core/helpers/cove/date'
14
- import BrushChart from './BrushChart'
15
- import { AreaChart, AreaChartStacked } from './AreaChart'
14
+ import { AreaChartStacked } from './AreaChart'
16
15
  import BarChart from './BarChart'
17
16
  import ConfigContext from '../ConfigContext'
18
17
  import BoxPlot from './BoxPlot'
@@ -43,6 +42,8 @@ import { useEditorPermissions } from './EditorPanel/useEditorPermissions'
43
42
  import Annotation from './Annotations'
44
43
  import { BlurStrokeText } from '@cdc/core/components/BlurStrokeText'
45
44
  import { countNumOfTicks } from '../helpers/countNumOfTicks'
45
+ import HoverLine from './HoverLine/HoverLine'
46
+ import BrushChart from './BrushChart'
46
47
 
47
48
  type LinearChartProps = {
48
49
  parentWidth: number
@@ -59,10 +60,23 @@ const AXIS_LABEL_FONT_SIZE = 18
59
60
  const AXIS_LABEL_FONT_SIZE_SMALL = 14
60
61
  const TICK_LABEL_MARGIN_RIGHT = 4.5
61
62
 
63
+ type TooltipData = {
64
+ dataXPosition?: number
65
+ dataYPosition?: number
66
+ }
67
+
68
+ type UseTooltipReturn<T = TooltipData> = {
69
+ tooltipData: T | null
70
+ showTooltip: (tooltipData: T) => void
71
+ hideTooltip: () => void
72
+ tooltipOpen: boolean
73
+ tooltipLeft: number | null
74
+ tooltipTop: number | null
75
+ }
76
+
62
77
  const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, parentWidth }, svgRef) => {
63
78
  // prettier-ignore
64
79
  const {
65
- brushConfig,
66
80
  colorScale,
67
81
  config,
68
82
  convertLineToBarGraph,
@@ -79,8 +93,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
79
93
  parentRef,
80
94
  tableData,
81
95
  transformedData: data,
82
- updateConfig,
83
96
  seriesHighlight,
97
+ brushConfig
84
98
  } = useContext(ConfigContext)
85
99
 
86
100
  // CONFIG
@@ -99,14 +113,14 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
99
113
  dataFormat,
100
114
  debugSvg
101
115
  } = config
102
- const { suffix, onlyShowTopPrefixSuffix } = dataFormat
103
- const { labelsAboveGridlines, hideAxis } = config.yAxis
116
+ const { labelsAboveGridlines, hideAxis, inlineLabel } = config.yAxis
104
117
 
105
118
  // HOOKS % STATES
106
119
  const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, data)
107
120
  const { visSupportsReactTooltip } = useEditorPermissions()
108
121
  const { hasTopAxis } = getTopAxis(config)
109
122
  const [animatedChart, setAnimatedChart] = useState(false)
123
+ const [showHoverLine, setShowHoverLine] = useState(false)
110
124
  const [point, setPoint] = useState({ x: 0, y: 0 })
111
125
  const [suffixWidth, setSuffixWidth] = useState(0)
112
126
  const [yAxisAutoPadding, setYAxisAutoPadding] = useState(0)
@@ -121,6 +135,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
121
135
  const xAxisTitleRef = useRef(null)
122
136
  const lastMaxValue = useRef(maxValue)
123
137
  const gridLineRefs = useRef([])
138
+ const tooltipRef = useRef(null)
124
139
 
125
140
  const dataRef = useIntersectionObserver(triggerRef, {
126
141
  freezeOnceVisible: false
@@ -132,8 +147,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
132
147
  const isLogarithmicAxis = config.yAxis.type === 'logarithmic'
133
148
  const isForestPlot = visualizationType === 'Forest Plot'
134
149
  const isDateTime = config.xAxis.type === 'date-time'
135
- const suffixHasNoSpace = !suffix.includes(' ')
136
- const labelsOverflow = onlyShowTopPrefixSuffix && !suffixHasNoSpace
150
+ const inlineLabelHasNoSpace = !inlineLabel?.includes(' ')
151
+ const labelsOverflow = inlineLabel && !inlineLabelHasNoSpace
137
152
  const padding = orientation === 'horizontal' ? Number(config.xAxis.size) : Number(config.yAxis.size)
138
153
  const yLabelOffset = isNaN(parseInt(`${runtime.yAxis.labelOffset}`)) ? 0 : parseInt(`${runtime.yAxis.labelOffset}`)
139
154
  const tickLabelFontSize = isMobileHeightViewport(currentViewport) ? TICK_LABEL_FONT_SIZE_SMALL : TICK_LABEL_FONT_SIZE
@@ -218,7 +233,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
218
233
  yMax
219
234
  }
220
235
  const { min, max, leftMax, rightMax } = useMinMax(properties)
221
- const { yScaleRight, hasRightAxis } = useRightAxis({ config, yMax, data, updateConfig })
236
+ const { yScaleRight, hasRightAxis } = useRightAxis({ config, yMax, data })
222
237
  const { xScale, yScale, seriesScale, g1xScale, g2xScale, xScaleNoPadding, xScaleAnnotation } = useScales({
223
238
  ...properties,
224
239
  min,
@@ -238,7 +253,9 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
238
253
  const handleNumTicks = isForestPlot ? config.data.length : yTickCount
239
254
 
240
255
  // Tooltip Helpers
241
- const { tooltipData, showTooltip, hideTooltip, tooltipOpen, tooltipLeft, tooltipTop } = useTooltip()
256
+
257
+ const { tooltipData, showTooltip, hideTooltip, tooltipOpen, tooltipLeft, tooltipTop } =
258
+ useTooltip<UseTooltipReturn<TooltipData>>()
242
259
 
243
260
  // prettier-ignore
244
261
  const {
@@ -247,11 +264,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
247
264
  handleTooltipMouseOff,
248
265
  TooltipListItem,
249
266
  } = useCoveTooltip({
250
- xScale,
251
- yScale,
252
- seriesScale,
253
- showTooltip,
254
- hideTooltip
267
+ xScale,
268
+ yScale,
269
+ seriesScale,
270
+ showTooltip,
271
+ hideTooltip
255
272
  })
256
273
  // get the number of months between the first and last date
257
274
  const { dataKey } = runtime.xAxis
@@ -375,7 +392,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
375
392
  if (!suffixEl) return setSuffixWidth(0)
376
393
  const suffixElWidth = suffixEl.getBBox().width
377
394
  setSuffixWidth(suffixElWidth)
378
- }, [config.dataFormat.suffix, config.dataFormat.onlyShowTopPrefixSuffix])
395
+ }, [config.dataFormat.suffix, inlineLabel])
379
396
 
380
397
  // forest plot x-axis label positioning
381
398
  useEffect(() => {
@@ -401,11 +418,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
401
418
  const topLabelOnGridline = topYLabelRef.current && yAxis.labelsAboveGridlines
402
419
 
403
420
  // Heights to add
404
-
405
421
  const brushHeight = brush?.active ? brush?.height + brush?.height : 0
422
+ const brushHeightWithMargin = config.brush?.active ? brushHeight + brushHeight : 0
406
423
  const forestRowsHeight = isForestPlot ? config.data.length * forestPlot.rowHeight : 0
407
424
  const topLabelOnGridlineHeight = topLabelOnGridline ? topYLabelRef.current.getBBox().height : 0
408
- const additionalHeight = axisBottomHeight + brushHeight + forestRowsHeight + topLabelOnGridlineHeight
425
+ const additionalHeight = axisBottomHeight + brushHeightWithMargin + forestRowsHeight + topLabelOnGridlineHeight
409
426
  const newHeight = initialHeight + additionalHeight
410
427
  if (!parentRef.current) return
411
428
 
@@ -471,6 +488,23 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
471
488
  setYAxisAutoPadding(newPadding * 100 + 0.1)
472
489
  }, [maxValue, labelsOverflow, yScale, handleNumTicks])
473
490
 
491
+ useEffect(() => {
492
+ if (!tooltipOpen) return
493
+ if (!tooltipRef.current) return
494
+
495
+ const { dataXPosition } = tooltipData as { [key: string]: number }
496
+
497
+ if (!dataXPosition) return
498
+
499
+ const { width: tooltipWidth } = tooltipRef.current.node.getBoundingClientRect()
500
+
501
+ const rightSideRemainingSpace = parentWidth - dataXPosition
502
+
503
+ const rightSide = rightSideRemainingSpace <= tooltipWidth && dataXPosition > parentWidth / 2 - 10
504
+ const maxWidth = rightSide ? dataXPosition - 10 : parentWidth - (dataXPosition + 6)
505
+ tooltipRef.current.node.style.maxWidth = `${maxWidth}px`
506
+ }, [tooltipOpen, tooltipData])
507
+
474
508
  // Render Functions
475
509
  const generatePairedBarAxis = () => {
476
510
  const axisMaxHeight = bottomLabelStart + BOTTOM_LABEL_PADDING
@@ -629,12 +663,13 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
629
663
  onMouseMove={onMouseMove}
630
664
  width={parentWidth + config.yAxis.rightAxisSize}
631
665
  height={isNoDataAvailable ? 1 : parentHeight}
632
- className={`linear ${config.animate ? 'animated' : ''} ${animatedChart && config.animate ? 'animate' : ''} ${
633
- debugSvg && 'debug'
634
- } ${isDraggingAnnotation && 'dragging-annotation'}`}
666
+ className={`linear ${config.animate ? 'animated' : ''} ${animatedChart && config.animate ? 'animate' : ''} ${debugSvg && 'debug'
667
+ } ${isDraggingAnnotation && 'dragging-annotation'}`}
635
668
  role='img'
636
669
  aria-label={handleChartAriaLabels(config)}
637
670
  style={{ overflow: 'visible' }}
671
+ onMouseLeave={() => setShowHoverLine(false)}
672
+ onMouseEnter={() => setShowHoverLine(true)}
638
673
  >
639
674
  {!isDraggingAnnotation && <Bar width={parentWidth} height={initialHeight} fill={'transparent'}></Bar>}{' '}
640
675
  {/* GRID LINES */}
@@ -722,20 +757,20 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
722
757
  )}
723
758
  {((visualizationType === 'Area Chart' && config.visualizationSubType === 'stacked') ||
724
759
  visualizationType === 'Combo') && (
725
- <AreaChartStacked
726
- xScale={xScale}
727
- yScale={yScale}
728
- yMax={yMax}
729
- xMax={xMax}
730
- chartRef={svgRef}
731
- width={xMax}
732
- height={yMax}
733
- handleTooltipMouseOver={handleTooltipMouseOver}
734
- handleTooltipMouseOff={handleTooltipMouseOff}
735
- tooltipData={tooltipData}
736
- showTooltip={showTooltip}
737
- />
738
- )}
760
+ <AreaChartStacked
761
+ xScale={xScale}
762
+ yScale={yScale}
763
+ yMax={yMax}
764
+ xMax={xMax}
765
+ chartRef={svgRef}
766
+ width={xMax}
767
+ height={yMax}
768
+ handleTooltipMouseOver={handleTooltipMouseOver}
769
+ handleTooltipMouseOff={handleTooltipMouseOff}
770
+ tooltipData={tooltipData}
771
+ showTooltip={showTooltip}
772
+ />
773
+ )}
739
774
  {(visualizationType === 'Bar' || visualizationType === 'Combo' || convertLineToBarGraph) && (
740
775
  <BarChart
741
776
  xScale={xScale}
@@ -771,6 +806,27 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
771
806
  showTooltip={showTooltip}
772
807
  />
773
808
  )}
809
+ {/* Line chart */}
810
+ {/* TODO: Make this just line or combo? */}
811
+ {!['Paired Bar', 'Box Plot', 'Area Chart', 'Scatter Plot', 'Deviation Bar', 'Forecasting', 'Bar'].includes(
812
+ visualizationType
813
+ ) &&
814
+ !convertLineToBarGraph && (
815
+ <>
816
+ <LineChart
817
+ xScale={xScale}
818
+ yScale={yScale}
819
+ getXAxisData={getXAxisData}
820
+ getYAxisData={getYAxisData}
821
+ xMax={xMax}
822
+ yMax={yMax}
823
+ seriesStyle={config.runtime.series}
824
+ tooltipData={tooltipData}
825
+ handleTooltipMouseOver={handleTooltipMouseOver}
826
+ handleTooltipMouseOff={handleTooltipMouseOff}
827
+ />
828
+ </>
829
+ )}
774
830
  {(visualizationType === 'Forecasting' || visualizationType === 'Combo') && (
775
831
  <Forecasting
776
832
  showTooltip={showTooltip}
@@ -778,13 +834,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
778
834
  xScale={xScale}
779
835
  yScale={yScale}
780
836
  width={xMax}
781
- le
782
837
  height={yMax}
783
838
  xScaleNoPadding={xScaleNoPadding}
784
839
  chartRef={svgRef}
785
840
  handleTooltipMouseOver={handleTooltipMouseOver}
786
841
  handleTooltipMouseOff={handleTooltipMouseOff}
787
- isBrush={false}
788
842
  />
789
843
  )}
790
844
  {visualizationType === 'Forest Plot' && (
@@ -855,7 +909,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
855
909
  strokeDasharray={handleLineType(anchor.lineStyle)}
856
910
  stroke={anchor.color ? anchor.color : 'rgba(0,0,0,1)'}
857
911
  className='anchor-y'
858
- from={{ x: 0 + padding, y: position - middleOffset}}
912
+ from={{ x: 0 + padding, y: position - middleOffset }}
859
913
  to={{ x: width - config.yAxis.rightAxisSize, y: position - middleOffset }}
860
914
  />
861
915
  )
@@ -887,14 +941,14 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
887
941
  return (
888
942
  // prettier-ignore
889
943
  <Line
890
- key={`xAxis-${anchor.value}--${index}`}
891
- strokeDasharray={handleLineType(anchor.lineStyle)}
892
- stroke={anchor.color ? anchor.color : 'rgba(0,0,0,1)'}
893
- fill={anchor.color ? anchor.color : 'rgba(0,0,0,1)'}
894
- className='anchor-x'
895
- from={{ x: Number(anchorPosition) + Number(padding), y: 0 }}
896
- to={{ x: Number(anchorPosition) + Number(padding), y: yMax }}
897
- />
944
+ key={`xAxis-${anchor.value}--${index}`}
945
+ strokeDasharray={handleLineType(anchor.lineStyle)}
946
+ stroke={anchor.color ? anchor.color : 'rgba(0,0,0,1)'}
947
+ fill={anchor.color ? anchor.color : 'rgba(0,0,0,1)'}
948
+ className='anchor-x'
949
+ from={{ x: Number(anchorPosition) + Number(padding), y: 0 }}
950
+ to={{ x: Number(anchorPosition) + Number(padding), y: yMax }}
951
+ />
898
952
  )
899
953
  })}
900
954
  {/* we are handling regions in bar charts differently, so that we can calculate the bar group into the region space. */}
@@ -921,35 +975,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
921
975
  {config.chartMessage.noData}
922
976
  </Text>
923
977
  )}
924
- {config.visual.horizontalHoverLine && tooltipData && (
925
- <Group
926
- key={`tooltipLine-horizontal${point.y}${point.x}`}
927
- className='horizontal-tooltip-line'
928
- left={config.yAxis.size ? config.yAxis.size : 0}
929
- >
930
- <Line
931
- from={{ x: 0, y: point.y }}
932
- to={{ x: xMax, y: point.y }}
933
- stroke={'black'}
934
- strokeWidth={1}
935
- pointerEvents='none'
936
- strokeDasharray='5,5'
937
- className='horizontal-tooltip-line'
938
- />
939
- </Group>
940
- )}
941
- {config.visual.verticalHoverLine && tooltipData && (
942
- <Group key={`tooltipLine-vertical${point.y}${point.x}`} className='vertical-tooltip-line'>
943
- <Line
944
- from={{ x: point.x, y: 0 }}
945
- to={{ x: point.x, y: yMax }}
946
- stroke={'black'}
947
- strokeWidth={1}
948
- pointerEvents='none'
949
- strokeDasharray='5,5'
950
- className='vertical-tooltip-line'
951
- />
952
- </Group>
978
+ {showHoverLine && (
979
+ <>
980
+ <HoverLine xMax={xMax} yMax={yMax} point={point} tooltipData={tooltipData} orientation='horizontal' />
981
+ <HoverLine xMax={xMax} yMax={yMax} point={point} tooltipData={tooltipData} orientation='vertical' />
982
+ </>
953
983
  )}
954
984
  <Group left={Number(config.runtime.yAxis.size)}>
955
985
  <Annotation.Draggable
@@ -988,10 +1018,10 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
988
1018
  to={
989
1019
  runtime.horizontal
990
1020
  ? {
991
- x: 0,
992
- y:
993
- config.visualizationType === 'Forest Plot' ? parentHeight : Number(heights.horizontal)
994
- }
1021
+ x: 0,
1022
+ y:
1023
+ config.visualizationType === 'Forest Plot' ? parentHeight : Number(heights.horizontal)
1024
+ }
995
1025
  : props.axisToPoint
996
1026
  }
997
1027
  stroke='#000'
@@ -1021,15 +1051,18 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1021
1051
 
1022
1052
  // Vertical value/suffix vars
1023
1053
  const lastTick = props.ticks.length - 1 === i
1024
- const hideTopTick = lastTick && onlyShowTopPrefixSuffix && suffix && !suffixHasNoSpace
1054
+ const useInlineLabel = lastTick && inlineLabel
1055
+ const hideTopTick = lastTick && inlineLabel && !inlineLabelHasNoSpace
1025
1056
  const valueOnLinePadding = hideAxis ? -8 : -12
1026
1057
  const labelXPadding = labelsAboveGridlines ? valueOnLinePadding : TICK_LABEL_MARGIN_RIGHT
1027
1058
  const labelYPadding = labelsAboveGridlines ? 4 : 0
1028
1059
  const labelX = tick.to.x - labelXPadding
1029
1060
  const labelY = tick.to.y - labelYPadding
1030
1061
  const labelVerticalAnchor = labelsAboveGridlines ? 'end' : 'middle'
1031
- const combineDomSuffixWithValue =
1032
- onlyShowTopPrefixSuffix && labelsAboveGridlines && suffix && lastTick
1062
+ const combineDomInlineLabelWithValue = inlineLabel && labelsAboveGridlines && lastTick
1063
+ const formattedValue = useInlineLabel
1064
+ ? tick.formattedValue.replace(config.dataFormat.suffix, '')
1065
+ : tick.formattedValue
1033
1066
 
1034
1067
  return (
1035
1068
  <Group key={`vx-tick-${tick.value}-${i}`} className={'vx-axis-tick'}>
@@ -1049,13 +1082,12 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1049
1082
  config.yAxis.labelPlacement === 'On Date/Category Axis' &&
1050
1083
  !config.yAxis.hideLabel && (
1051
1084
  <Text
1052
- transform={`translate(${tick.to.x - 5}, ${
1053
- config.isLollipopChart
1085
+ transform={`translate(${tick.to.x - 5}, ${config.isLollipopChart
1054
1086
  ? tick.to.y - minY
1055
1087
  : tick.to.y -
1056
- minY +
1057
- (Number(config.barHeight * config.runtime.series.length) - barMinHeight) / 2
1058
- }) rotate(-${config.runtime.horizontal ? config.runtime.yAxis.tickRotation || 0 : 0})`}
1088
+ minY +
1089
+ (Number(config.barHeight * config.runtime.series.length) - barMinHeight) / 2
1090
+ }) rotate(-${config.runtime.horizontal ? config.runtime.yAxis.tickRotation || 0 : 0})`}
1059
1091
  verticalAnchor={'start'}
1060
1092
  textAnchor={'end'}
1061
1093
  fontSize={tickLabelFontSize}
@@ -1069,9 +1101,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1069
1101
  config.yAxis.labelPlacement === 'On Date/Category Axis' &&
1070
1102
  !config.yAxis.hideLabel && (
1071
1103
  <Text
1072
- transform={`translate(${tick.to.x - 5}, ${
1073
- tick.to.y - minY + (Number(config.barHeight) - barMinHeight) / 2
1074
- }) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`}
1104
+ transform={`translate(${tick.to.x - 5}, ${tick.to.y - minY + (Number(config.barHeight) - barMinHeight) / 2
1105
+ }) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`}
1075
1106
  verticalAnchor={'start'}
1076
1107
  textAnchor={'end'}
1077
1108
  fontSize={tickLabelFontSize}
@@ -1084,9 +1115,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1084
1115
  visualizationType === 'Paired Bar' &&
1085
1116
  !config.yAxis.hideLabel && (
1086
1117
  <Text
1087
- transform={`translate(${tick.to.x - 5}, ${
1088
- tick.to.y - minY + Number(config.barHeight) / 2
1089
- }) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`}
1118
+ transform={`translate(${tick.to.x - 5}, ${tick.to.y - minY + Number(config.barHeight) / 2
1119
+ }) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`}
1090
1120
  textAnchor={'end'}
1091
1121
  verticalAnchor='middle'
1092
1122
  fontSize={tickLabelFontSize}
@@ -1098,11 +1128,10 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1098
1128
  visualizationType === 'Deviation Bar' &&
1099
1129
  !config.yAxis.hideLabel && (
1100
1130
  <Text
1101
- transform={`translate(${tick.to.x - 5}, ${
1102
- config.isLollipopChart
1131
+ transform={`translate(${tick.to.x - 5}, ${config.isLollipopChart
1103
1132
  ? tick.to.y - minY + 2
1104
1133
  : tick.to.y - minY + Number(config.barHeight) / 2
1105
- }) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`}
1134
+ }) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`}
1106
1135
  textAnchor={'end'}
1107
1136
  verticalAnchor='middle'
1108
1137
  fontSize={tickLabelFontSize}
@@ -1133,14 +1162,14 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1133
1162
  seriesHighlight.includes(
1134
1163
  config.runtime.seriesLabelsAll[tick.formattedValue - 1]
1135
1164
  )) && (
1136
- <rect
1137
- x={0 - Number(config.yAxis.size)}
1138
- y={tick.to.y - 8 + (config.runtime.horizontal ? horizontalTickOffset : 7)}
1139
- width={Number(config.yAxis.size) + xScale(xScale.domain()[0])}
1140
- height='2'
1141
- fill={colorScale(config.runtime.seriesLabelsAll[tick.formattedValue - 1])}
1142
- />
1143
- )}
1165
+ <rect
1166
+ x={0 - Number(config.yAxis.size)}
1167
+ y={tick.to.y - 8 + (config.runtime.horizontal ? horizontalTickOffset : 7)}
1168
+ width={Number(config.yAxis.size) + xScale(xScale.domain()[0])}
1169
+ height='2'
1170
+ fill={colorScale(config.runtime.seriesLabelsAll[tick.formattedValue - 1])}
1171
+ />
1172
+ )}
1144
1173
  </>
1145
1174
  )}
1146
1175
  {orientation === 'vertical' &&
@@ -1148,11 +1177,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1148
1177
  visualizationType !== 'Bump Chart' &&
1149
1178
  !config.yAxis.hideLabel && (
1150
1179
  <>
1151
- {/* TOP ONLY SUFFIX: Dom suffix for 'show only top suffix' behavior */}
1152
- {/* top suffix is shown alone and is allowed to 'overflow' to the right */}
1153
- {/* SPECIAL ONE CHAR CASE: a one character top-only suffix does not overflow */}
1180
+ {/* INLINE LABEL BEHAVIOR: Dom suffix for 'inlineLabel' behavior */}
1181
+ {/* inline label is shown alone and is allowed to 'overflow' to the right */}
1182
+ {/* SPECIAL ONE CHAR CASE: a one character inlineLabel does not overflow */}
1154
1183
  {/* IF VALUES ON LINE: suffix is combined with value to avoid having to calculate varying (now left-aligned) value widths */}
1155
- {onlyShowTopPrefixSuffix && lastTick && !labelsAboveGridlines && (
1184
+ {inlineLabel && lastTick && !labelsAboveGridlines && (
1156
1185
  <BlurStrokeText
1157
1186
  innerRef={suffixRef}
1158
1187
  display={isLogarithmicAxis ? showTicks : 'block'}
@@ -1161,7 +1190,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1161
1190
  y={labelY}
1162
1191
  angle={-Number(config.yAxis.tickRotation) || 0}
1163
1192
  verticalAnchor={labelVerticalAnchor}
1164
- textAnchor={suffixHasNoSpace ? 'end' : 'start'}
1193
+ textAnchor={inlineLabelHasNoSpace ? 'end' : 'start'}
1165
1194
  fill={config.yAxis.tickLabelColor}
1166
1195
  stroke={'#fff'}
1167
1196
  paintOrder={'stroke'} // keeps stroke under fill
@@ -1169,7 +1198,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1169
1198
  style={{ whiteSpace: 'pre-wrap' }} // prevents leading spaces from being trimmed
1170
1199
  fontSize={tickLabelFontSize}
1171
1200
  >
1172
- {suffix}
1201
+ {inlineLabel}
1173
1202
  </BlurStrokeText>
1174
1203
  )}
1175
1204
 
@@ -1178,7 +1207,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1178
1207
  innerRef={el => lastTick && (topYLabelRef.current = el)}
1179
1208
  display={isLogarithmicAxis ? showTicks : 'block'}
1180
1209
  dx={isLogarithmicAxis ? -6 : 0}
1181
- x={suffixHasNoSpace ? labelX - suffixWidth : labelX}
1210
+ x={inlineLabelHasNoSpace ? labelX - suffixWidth : labelX}
1182
1211
  y={labelY + (config.runtime.horizontal ? horizontalTickOffset : 0)}
1183
1212
  angle={-Number(config.yAxis.tickRotation) || 0}
1184
1213
  verticalAnchor={config.runtime.horizontal ? 'start' : labelVerticalAnchor}
@@ -1191,7 +1220,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1191
1220
  style={{ whiteSpace: 'pre-wrap' }} // prevents leading spaces from being trimmed
1192
1221
  fontSize={tickLabelFontSize}
1193
1222
  >
1194
- {`${tick.formattedValue}${combineDomSuffixWithValue ? suffix : ''}`}
1223
+ {`${formattedValue}${combineDomInlineLabelWithValue ? inlineLabel : ''}`}
1195
1224
  </BlurStrokeText>
1196
1225
  </>
1197
1226
  )}
@@ -1283,9 +1312,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1283
1312
  className='y-label'
1284
1313
  textAnchor='middle'
1285
1314
  verticalAnchor='start'
1286
- transform={`translate(${
1287
- config.yAxis.rightLabelOffsetSize ? config.yAxis.rightLabelOffsetSize : 0
1288
- }, ${axisCenter}) rotate(-90)`}
1315
+ transform={`translate(${config.yAxis.rightLabelOffsetSize ? config.yAxis.rightLabelOffsetSize : 0
1316
+ }, ${axisCenter}) rotate(-90)`}
1289
1317
  fontWeight='bold'
1290
1318
  fill={config.yAxis.rightAxisLabelColor}
1291
1319
  fontSize={axisLabelFontSize}
@@ -1317,8 +1345,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1317
1345
  runtime.horizontal && config.visualizationType !== 'Forest Plot'
1318
1346
  ? Number(heights.horizontal) + Number(config.xAxis.axisPadding)
1319
1347
  : config.visualizationType === 'Forest Plot'
1320
- ? yMax + Number(config.xAxis.axisPadding)
1321
- : yMax
1348
+ ? yMax + Number(config.xAxis.axisPadding)
1349
+ : yMax
1322
1350
  }
1323
1351
  left={config.visualizationType !== 'Forest Plot' ? Number(runtime.yAxis.size) : 0}
1324
1352
  label={config[section].label}
@@ -1331,8 +1359,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1331
1359
  config.runtime.xAxis.manual
1332
1360
  ? getTickValues(xAxisDataMapped, xScale, isDateTime ? xTickCount : getManualStep(), config)
1333
1361
  : config.runtime.xAxis.type === 'date'
1334
- ? xAxisDataMapped
1335
- : undefined
1362
+ ? xAxisDataMapped
1363
+ : undefined
1336
1364
  }
1337
1365
  >
1338
1366
  {props => {
@@ -1358,14 +1386,14 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1358
1386
  // filter out every [distanceBetweenTicks] tick starting from the end, so the last tick is always labeled
1359
1387
  const filteredTicks = useDateSpanMonths
1360
1388
  ? [...props.ticks]
1361
- .reverse()
1362
- .filter((_, i) => i % distanceBetweenTicks === 0)
1363
- .reverse()
1364
- .map((tick, i, arr) => ({
1365
- ...tick,
1366
- // reformat in case showYearsOnce, since first month of year may have changed
1367
- formattedValue: handleBottomTickFormatting(tick.value, i, arr)
1368
- }))
1389
+ .reverse()
1390
+ .filter((_, i) => i % distanceBetweenTicks === 0)
1391
+ .reverse()
1392
+ .map((tick, i, arr) => ({
1393
+ ...tick,
1394
+ // reformat in case showYearsOnce, since first month of year may have changed
1395
+ formattedValue: handleBottomTickFormatting(tick.value, i, arr)
1396
+ }))
1369
1397
  : props.ticks
1370
1398
 
1371
1399
  const axisMaxHeight = bottomLabelStart + BOTTOM_LABEL_PADDING
@@ -1495,13 +1523,14 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1495
1523
  showTooltip &&
1496
1524
  !tooltipData?.data?.some(subArray => subArray.some(item => item === undefined)) &&
1497
1525
  tooltipData.dataYPosition &&
1498
- tooltipData.dataXPosition && (
1526
+ tooltipData.dataXPosition &&
1527
+ !config.tooltips.singleSeries && (
1499
1528
  <>
1500
- <style>{`.tooltip {background-color: rgba(255,255,255, ${
1501
- config.tooltips.opacity / 100
1502
- }) !important;`}</style>
1529
+ <style>{`.tooltip {background-color: rgba(255,255,255, ${config.tooltips.opacity / 100
1530
+ }) !important;`}</style>
1503
1531
  <style>{`.tooltip {max-width:300px} !important; word-wrap: break-word; `}</style>
1504
1532
  <TooltipWithBounds
1533
+ ref={tooltipRef}
1505
1534
  key={Math.random()}
1506
1535
  className={'tooltip cdc-open-viz-module'}
1507
1536
  left={tooltipLeft}
@@ -1525,7 +1554,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
1525
1554
  style={{ background: `rgba(255,255,255, ${config.tooltips.opacity / 100})`, color: 'black' }}
1526
1555
  />
1527
1556
  )}
1528
- {visSupportsReactTooltip() && !isDraggingAnnotation && (
1557
+ {!isDraggingAnnotation && (
1529
1558
  <ReactTooltip
1530
1559
  id={`cdc-open-viz-tooltip-${runtime.uniqueId}`}
1531
1560
  variant='light'