@cdc/chart 4.26.2 → 4.26.4

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 (165) hide show
  1. package/CONFIG.md +169 -0
  2. package/README.md +42 -17
  3. package/dist/cdcchart.js +39419 -35180
  4. package/examples/__data__/data-with-metadata.json +10 -0
  5. package/examples/feature/bar/additional-column-tooltip.json +3 -3
  6. package/examples/feature/deviation/planet-deviation-config.json +2 -2
  7. package/examples/feature/paired-bar/paired-bar-example.json +2 -2
  8. package/examples/feature/pie/planet-pie-example-config.json +2 -1
  9. package/examples/feature/tests-case-rate/case-rate-example-config.json +2 -2
  10. package/examples/feature/tests-covid/covid-confidence-example-config.json +2 -2
  11. package/examples/feature/tests-covid/covid-example-config.json +2 -2
  12. package/examples/feature/tests-cutoff/cutoff-example-config.json +2 -2
  13. package/examples/feature/tests-non-numerics/planet-pie-example-config-nonnumeric.json +2 -2
  14. package/examples/metadata-variables.json +58 -0
  15. package/examples/minimal-example.json +24 -0
  16. package/examples/private/test2.json +35012 -0
  17. package/package.json +4 -4
  18. package/src/CdcChart.tsx +8 -4
  19. package/src/CdcChartComponent.tsx +326 -290
  20. package/src/_stories/Chart.CustomColors.smoke.stories.tsx +97 -0
  21. package/src/_stories/Chart.Defaults.smoke.stories.tsx +95 -0
  22. package/src/_stories/{Chart.HTMLInDataTable.stories.tsx → Chart.HTMLInDataTable.smoke.stories.tsx} +10 -0
  23. package/src/_stories/Chart.Minimal.smoke.stories.tsx +25 -0
  24. package/src/_stories/{Chart.SmallMultiples.stories.tsx → Chart.SmallMultiples.smoke.stories.tsx} +17 -1
  25. package/src/_stories/Chart.SmallestLeftAxisMax.smoke.stories.tsx +64 -0
  26. package/src/_stories/{Chart.stories.tsx → Chart.smoke.stories.tsx} +48 -2
  27. package/src/_stories/{Chart.tooltip.stories.tsx → Chart.tooltip.smoke.stories.tsx} +68 -0
  28. package/src/_stories/ChartBar.Editor.stories.tsx +177 -115
  29. package/src/_stories/ChartBrush.Editor.stories.tsx +11 -25
  30. package/src/_stories/ChartEditor.Editor.stories.tsx +24 -1
  31. package/src/_stories/{Chart.CustomColors.stories.tsx → ChartLine.DashedDates.smoke.stories.tsx} +4 -4
  32. package/src/_stories/_mock/line_chart_dashed_dates.json +276 -0
  33. package/src/_stories/_mock/paired-bar-abbr.json +421 -0
  34. package/src/_stories/_mock/paired-bar.json +1 -1
  35. package/src/_stories/_mock/pie_custom_colors.json +268 -0
  36. package/src/_stories/_mock/smallest_left_axis_max.json +104 -0
  37. package/src/components/Annotations/components/AnnotationDraggable.styles.css +10 -10
  38. package/src/components/Annotations/components/AnnotationDraggable.tsx +1 -1
  39. package/src/components/Annotations/components/AnnotationDropdown.styles.css +1 -1
  40. package/src/components/Annotations/components/AnnotationList.styles.css +11 -11
  41. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +10 -2
  42. package/src/components/Axis/BottomAxis.tsx +10 -3
  43. package/src/components/Axis/LeftAxis.tsx +2 -4
  44. package/src/components/Axis/LeftAxisGridlines.tsx +1 -3
  45. package/src/components/Axis/PairedBarAxis.tsx +10 -4
  46. package/src/components/BarChart/components/BarChart.Horizontal.tsx +21 -33
  47. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +21 -35
  48. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +21 -36
  49. package/src/components/BarChart/components/BarChart.Vertical.tsx +21 -34
  50. package/src/components/BarChart/components/BarChart.tsx +2 -6
  51. package/src/components/BarChart/helpers/getPatternUrl.ts +94 -0
  52. package/src/components/BarChart/helpers/tests/getPatternUrl.test.ts +134 -0
  53. package/src/components/BarChart/helpers/useBarChart.ts +4 -1
  54. package/src/components/BoxPlot/BoxPlot.Vertical.tsx +3 -3
  55. package/src/components/Brush/BrushSelector.tsx +2 -1
  56. package/src/components/Brush/MiniChartPreview.tsx +21 -26
  57. package/src/components/EditorPanel/EditorPanel.tsx +692 -954
  58. package/src/components/EditorPanel/EditorPanelContext.ts +1 -1
  59. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +218 -167
  60. package/src/components/EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx +0 -78
  61. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +39 -1
  62. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +169 -135
  63. package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +154 -109
  64. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +3 -3
  65. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +95 -28
  66. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +45 -42
  67. package/src/components/EditorPanel/editor-panel.scss +1 -1
  68. package/src/components/EditorPanel/useEditorPermissions.ts +1 -10
  69. package/src/components/Forecasting/Forecasting.tsx +2 -2
  70. package/src/components/ForestPlot/ForestPlot.tsx +26 -22
  71. package/src/components/HorizonChart/HorizonChart.tsx +10 -2
  72. package/src/components/HoverLine/HoverLine.tsx +6 -8
  73. package/src/components/Legend/Legend.Component.tsx +4 -4
  74. package/src/components/Legend/LegendGroup/LegendGroup.styles.css +9 -4
  75. package/src/components/Legend/LegendGroup/LegendGroup.tsx +3 -1
  76. package/src/components/Legend/helpers/createFormatLabels.tsx +3 -2
  77. package/src/components/Legend/helpers/index.ts +0 -2
  78. package/src/components/LineChart/LineChartProps.ts +1 -0
  79. package/src/components/LineChart/components/LineChart.BumpCircle.tsx +3 -2
  80. package/src/components/LineChart/index.tsx +11 -4
  81. package/src/components/LinearChart/VisualizationRenderer.tsx +11 -1
  82. package/src/components/LinearChart/tests/LinearChart.test.tsx +224 -0
  83. package/src/components/LinearChart/tests/mockConfigContext.ts +2 -0
  84. package/src/components/LinearChart.tsx +124 -47
  85. package/src/components/PairedBarChart.jsx +2 -2
  86. package/src/components/PieChart/PieChart.tsx +30 -13
  87. package/src/components/RadarChart/RadarChart.tsx +1 -1
  88. package/src/components/Regions/components/Regions.tsx +36 -26
  89. package/src/components/Sankey/components/Sankey.tsx +3 -3
  90. package/src/components/Sankey/sankey.scss +1 -1
  91. package/src/components/ScatterPlot/ScatterPlot.jsx +19 -17
  92. package/src/components/SmallMultiples/SmallMultipleTile.tsx +1 -0
  93. package/src/components/SmallMultiples/SmallMultiples.css +5 -5
  94. package/src/components/Sparkline/components/SparkLine.tsx +1 -1
  95. package/src/components/Sparkline/index.scss +4 -2
  96. package/src/components/WarmingStripes/WarmingStripes.tsx +5 -3
  97. package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +8 -8
  98. package/src/data/initial-state.js +24 -14
  99. package/src/data/legacy-defaults.ts +18 -0
  100. package/src/helpers/abbreviateNumber.ts +24 -17
  101. package/src/helpers/calculateLeftYAxisWidth.ts +193 -0
  102. package/src/helpers/getChartPatternId.ts +17 -0
  103. package/src/helpers/getMinMax.ts +16 -2
  104. package/src/helpers/seriesColumnSettings.ts +114 -0
  105. package/src/helpers/tests/countNumOfTicks.test.ts +77 -0
  106. package/src/helpers/tests/seriesColumnSettings.test.ts +84 -0
  107. package/src/helpers/tests/tooltipHelpers.test.ts +151 -0
  108. package/src/helpers/tooltipHelpers.ts +176 -0
  109. package/src/hooks/useHighlightedBars.ts +9 -16
  110. package/src/hooks/useProgrammaticTooltip.ts +16 -2
  111. package/src/hooks/useRightAxis.ts +14 -0
  112. package/src/hooks/useScales.ts +92 -56
  113. package/src/hooks/useSmallMultipleSynchronization.ts +3 -4
  114. package/src/hooks/useTooltip.tsx +186 -40
  115. package/src/scss/main.scss +152 -79
  116. package/src/test/CdcChart.test.jsx +26 -2
  117. package/src/types/ChartConfig.ts +5 -0
  118. package/tests/fixtures/chart-config-with-metadata.json +29 -0
  119. package/tests/fixtures/data-with-metadata.json +10 -0
  120. package/examples/chart-regression-2.json +0 -2360
  121. package/examples/feature/__data__/age-adjusted-rates.json +0 -1486
  122. package/examples/feature/__data__/city-temperature.json +0 -2198
  123. package/examples/feature/bar/Barchart_with_negative.json +0 -34
  124. package/examples/feature/boxplot/box-plot-data.json +0 -71
  125. package/examples/feature/boxplot/boxplot-data.json +0 -156
  126. package/examples/feature/combo/combochart-categories_are_numbers .json +0 -18
  127. package/examples/feature/forest-plot/log.json +0 -26
  128. package/examples/feature/tests-date-exclusions/date-exclusions-data.json +0 -162
  129. package/examples/region-issue.json +0 -2065
  130. package/examples/xaxis.json +0 -493
  131. /package/examples/feature/bar/{tall-data.json → __data__/tall-data.json} +0 -0
  132. /package/examples/feature/deviation/{planet-deviation-data.json → __data__/planet-deviation-data.json} +0 -0
  133. /package/examples/feature/paired-bar/{paired-bar-data.json → __data__/paired-bar-data.json} +0 -0
  134. /package/examples/feature/paired-bar/{paired-bar-formatted.json → __data__/paired-bar-formatted.json} +0 -0
  135. /package/examples/feature/tests-case-rate/{case-rate-example-data.json → __data__/case-rate-example-data.json} +0 -0
  136. /package/examples/feature/tests-covid/{covid-example-data-confidence.json → __data__/covid-example-data-confidence.json} +0 -0
  137. /package/examples/feature/tests-covid/{covid-example-data.json → __data__/covid-example-data.json} +0 -0
  138. /package/examples/feature/tests-cutoff/{cutoff-example-data.json → __data__/cutoff-example-data.json} +0 -0
  139. /package/examples/feature/tests-non-numerics/{planet-example-data-nonnumeric.json → __data__/planet-example-data-nonnumeric.json} +0 -0
  140. /package/src/_stories/{Chart.Anchors.stories.tsx → Chart.Anchors.smoke.stories.tsx} +0 -0
  141. /package/src/_stories/{Chart.BoxPlot.stories.tsx → Chart.BoxPlot.smoke.stories.tsx} +0 -0
  142. /package/src/_stories/{Chart.CI.stories.tsx → Chart.CI.smoke.stories.tsx} +0 -0
  143. /package/src/_stories/{Chart.Combo.stories.tsx → Chart.Combo.smoke.stories.tsx} +0 -0
  144. /package/src/_stories/{Chart.DynamicSeries.stories.tsx → Chart.DynamicSeries.smoke.stories.tsx} +0 -0
  145. /package/src/_stories/{Chart.Filters.stories.tsx → Chart.Filters.smoke.stories.tsx} +0 -0
  146. /package/src/_stories/{Chart.Forecast.stories.tsx → Chart.Forecast.smoke.stories.tsx} +0 -0
  147. /package/src/_stories/{Chart.Legend.Gradient.stories.tsx → Chart.Legend.Gradient.smoke.stories.tsx} +0 -0
  148. /package/src/_stories/{Chart.Patterns.stories.tsx → Chart.Patterns.smoke.stories.tsx} +0 -0
  149. /package/src/_stories/{Chart.PreserveDecimals.stories.tsx → Chart.PreserveDecimals.smoke.stories.tsx} +0 -0
  150. /package/src/_stories/{Chart.Regions.Categorical.stories.tsx → Chart.Regions.Categorical.smoke.stories.tsx} +0 -0
  151. /package/src/_stories/{Chart.Regions.DateScale.stories.tsx → Chart.Regions.DateScale.smoke.stories.tsx} +0 -0
  152. /package/src/_stories/{Chart.Regions.DateTimeScale.stories.tsx → Chart.Regions.DateTimeScale.smoke.stories.tsx} +0 -0
  153. /package/src/_stories/{Chart.ScatterPlot.stories.tsx → Chart.ScatterPlot.smoke.stories.tsx} +0 -0
  154. /package/src/_stories/{ChartAnnotation.stories.tsx → ChartAnnotation.smoke.stories.tsx} +0 -0
  155. /package/src/_stories/{ChartAxisLabels.stories.tsx → ChartAxisLabels.smoke.stories.tsx} +0 -0
  156. /package/src/_stories/{ChartAxisTitles.stories.tsx → ChartAxisTitles.smoke.stories.tsx} +0 -0
  157. /package/src/_stories/{ChartBrush.Matrix.Continuous.stories.tsx → ChartBrush.Matrix.Continuous.smoke.stories.tsx} +0 -0
  158. /package/src/_stories/{ChartBrush.Matrix.Date.stories.tsx → ChartBrush.Matrix.Date.smoke.stories.tsx} +0 -0
  159. /package/src/_stories/{ChartBrush.Matrix.DateTime.stories.tsx → ChartBrush.Matrix.DateTime.smoke.stories.tsx} +0 -0
  160. /package/src/_stories/{ChartBrush.stories.tsx → ChartBrush.smoke.stories.tsx} +0 -0
  161. /package/src/_stories/{ChartLine.QuadrantAngles.stories.tsx → ChartLine.QuadrantAngles.smoke.stories.tsx} +0 -0
  162. /package/src/_stories/{ChartLine.Suppression.stories.tsx → ChartLine.Suppression.smoke.stories.tsx} +0 -0
  163. /package/src/_stories/{ChartLine.Symbols.stories.tsx → ChartLine.Symbols.smoke.stories.tsx} +0 -0
  164. /package/src/_stories/{ChartPrefixSuffix.stories.tsx → ChartPrefixSuffix.smoke.stories.tsx} +0 -0
  165. /package/src/_stories/{TechAdoptionWithLinks.stories.tsx → TechAdoptionWithLinks.smoke.stories.tsx} +0 -0
@@ -8,8 +8,21 @@ import { isDateScale } from '@cdc/core/helpers/cove/date'
8
8
  // Third-party library imports
9
9
  import { localPoint } from '@visx/event'
10
10
  import { bisector } from 'd3-array'
11
- import _, { get } from 'lodash'
11
+ import _ from 'lodash'
12
12
  import { getHorizontalBarHeights } from '../components/BarChart/helpers/getBarHeights'
13
+ import {
14
+ findColumnConfigByName,
15
+ getSeriesColumnFormattingParams,
16
+ getSeriesOwnedColumnNames
17
+ } from '../helpers/seriesColumnSettings'
18
+ import {
19
+ buildTooltipRow,
20
+ getTooltipSeriesMarker,
21
+ tooltipHasMarkerColumn,
22
+ type TooltipRow
23
+ } from '../helpers/tooltipHelpers'
24
+ import { publishAnalyticsEvent } from '@cdc/core/helpers/metrics/helpers'
25
+ import { getVizSubType, getVizTitle } from '@cdc/core/helpers/metrics/utils'
13
26
 
14
27
  export const useTooltip = props => {
15
28
  // Track the last X-axis value to prevent duplicate analytics events
@@ -17,6 +30,7 @@ export const useTooltip = props => {
17
30
  const {
18
31
  tableData: data,
19
32
  config,
33
+ colorScale,
20
34
  formatNumber,
21
35
  capitalize,
22
36
  formatDate,
@@ -27,7 +41,7 @@ export const useTooltip = props => {
27
41
  } = useContext<ChartContext>(ConfigContext)
28
42
  const { xScale, yScale, seriesScale, showTooltip, hideTooltip, interactionLabel = '' } = props
29
43
  const { xAxis, visualizationType, orientation, yAxis, runtime } = config
30
-
44
+ const seriesOwnedColumnNames = getSeriesOwnedColumnNames(config.series)
31
45
  // Track the latest xScale in a ref to prevent stale closures
32
46
  const xScaleRef = useRef(xScale)
33
47
 
@@ -36,7 +50,7 @@ export const useTooltip = props => {
36
50
  xScaleRef.current = xScale
37
51
  }, [xScale])
38
52
 
39
- const Y_AXIS_SIZE = Number(config.yAxis.size || 0)
53
+ const Y_AXIS_SIZE = Number(props.yAxisWidth || 0)
40
54
 
41
55
  // function handles only Single series hovered data tooltips
42
56
  const findDataKeyByThreshold = (mouseY, datapoint) => {
@@ -72,12 +86,45 @@ export const useTooltip = props => {
72
86
 
73
87
  const getFormattedValue = (seriesKey, value, config, getAxisPosition) => {
74
88
  // handle case where data is missing
75
- const showMissingDataValue = config.general.showMissingDataLabel && (!value || value === 'null')
76
- const formattedValue = seriesKey === config.xAxis.dataKey ? value : formatNumber(value, getAxisPosition(seriesKey))
89
+ const showMissingDataValue =
90
+ config.general.showMissingDataLabel && (value === null || value === undefined || value === '' || value === 'null')
91
+ const seriesColumnConfig = findColumnConfigByName(config.columns || {}, seriesKey)?.columnConfig
92
+ const formattingParams = getSeriesColumnFormattingParams(seriesColumnConfig)
93
+ const formattedValue =
94
+ seriesKey === config.xAxis.dataKey
95
+ ? value
96
+ : formatColNumber(value, getAxisPosition(seriesKey), false, config, formattingParams)
77
97
 
78
98
  return showMissingDataValue ? 'N/A' : formattedValue
79
99
  }
80
100
 
101
+ const createTooltipRow = ({
102
+ key,
103
+ value,
104
+ kind,
105
+ axisPosition,
106
+ seriesKey
107
+ }: {
108
+ key: string
109
+ value: string | number
110
+ kind: TooltipRow['kind']
111
+ axisPosition?: string
112
+ seriesKey?: string
113
+ }): TooltipRow =>
114
+ (() => {
115
+ const marker = kind === 'series' ? getTooltipSeriesMarker(config, colorScale, seriesKey || key) : null
116
+
117
+ return buildTooltipRow({
118
+ key,
119
+ value,
120
+ axisPosition,
121
+ kind,
122
+ seriesKey,
123
+ markerColor: marker?.markerColor ?? null,
124
+ markerShape: marker?.markerShape
125
+ })
126
+ })()
127
+
81
128
  /**
82
129
  * Handles the mouse over event for the tooltip.
83
130
  * @function handleTooltipMouseOver
@@ -96,8 +143,11 @@ export const useTooltip = props => {
96
143
  const singleSeriesValue = getYValueFromCoordinate(y, resolvedScaleValues)
97
144
 
98
145
  const columnsWithTooltips = []
99
- const tooltipItems = [] as any[][]
146
+ const tooltipItems: TooltipRow[] = []
100
147
  for (const [colKey, column] of Object.entries(config.columns)) {
148
+ const columnName = column.name || colKey
149
+ if (seriesOwnedColumnNames.includes(columnName)) continue
150
+
101
151
  const formattingParams = {
102
152
  addColPrefix: column.prefix,
103
153
  addColSuffix: column.suffix,
@@ -114,16 +164,22 @@ export const useTooltip = props => {
114
164
  : resolvedScaleValues[0]?.[colKey]
115
165
  const closestValue = config.visualizationType === 'Pie' ? pieColumnData : columnData
116
166
 
117
- const formattedValue = formatColNumber(closestValue, 'left', true, config, formattingParams)
167
+ const formattedValue = formatColNumber(closestValue, 'left', false, config, formattingParams)
118
168
 
119
169
  if (column.tooltips) {
120
170
  columnsWithTooltips.push([column.label, formattedValue])
121
171
  }
122
172
  }
123
- const additionalTooltipItems = [] as [string, string | number][]
173
+ const additionalTooltipItems: TooltipRow[] = []
124
174
 
125
175
  columnsWithTooltips.forEach(columnData => {
126
- additionalTooltipItems.push([columnData[0], columnData[1]])
176
+ additionalTooltipItems.push(
177
+ createTooltipRow({
178
+ key: columnData[0],
179
+ value: columnData[1],
180
+ kind: 'extra'
181
+ })
182
+ )
127
183
  })
128
184
 
129
185
  if (visualizationType === 'Pie') {
@@ -140,21 +196,46 @@ export const useTooltip = props => {
140
196
  const showPiePercent = config.dataFormat.showPiePercent || false
141
197
 
142
198
  if (showPiePercent && pieData[config.xAxis.dataKey] === 'Calculated Area') {
143
- tooltipItems.push(['', 'Calculated Area'])
199
+ tooltipItems.push(
200
+ createTooltipRow({
201
+ key: '',
202
+ value: 'Calculated Area',
203
+ kind: 'heading'
204
+ })
205
+ )
144
206
  } else {
145
207
  tooltipItems.push(
146
- [config.xAxis.dataKey, pieData[config.xAxis.dataKey]],
147
- [
148
- config.runtime.yAxis.label || config.runtime.yAxis.dataKey,
149
- showPiePercent ? pctString(actualPieValue) : formatNumber(pieData[config.runtime.yAxis.dataKey])
150
- ],
151
- showPiePercent ? [] : ['Percent', pctString(pctOf360)]
208
+ createTooltipRow({
209
+ key: config.xAxis.dataKey,
210
+ value: pieData[config.xAxis.dataKey],
211
+ kind: 'heading'
212
+ }),
213
+ createTooltipRow({
214
+ key: config.runtime.yAxis.label || config.runtime.yAxis.dataKey,
215
+ value: showPiePercent ? pctString(actualPieValue) : formatNumber(pieData[config.runtime.yAxis.dataKey]),
216
+ kind: 'extra'
217
+ })
152
218
  )
219
+ if (!showPiePercent) {
220
+ tooltipItems.push(
221
+ createTooltipRow({
222
+ key: 'Percent',
223
+ value: pctString(pctOf360),
224
+ kind: 'extra'
225
+ })
226
+ )
227
+ }
153
228
  }
154
229
  }
155
230
 
156
231
  if (visualizationType === 'Forest Plot') {
157
- tooltipItems.push([config.xAxis.dataKey, getClosestYValue(y)])
232
+ tooltipItems.push(
233
+ createTooltipRow({
234
+ key: config.xAxis.dataKey,
235
+ value: getClosestYValue(y),
236
+ kind: 'heading'
237
+ })
238
+ )
158
239
  }
159
240
 
160
241
  const isLinearChart = !['Pie', 'Forest Plot'].includes(visualizationType)
@@ -190,9 +271,34 @@ export const useTooltip = props => {
190
271
  ) {
191
272
  return []
192
273
  } else if (seriesObjWithName && seriesObjWithName.name === '') {
193
- return [['', formattedValue, getAxisPosition(seriesKey)]]
274
+ return [
275
+ createTooltipRow({
276
+ key: '',
277
+ value: formattedValue,
278
+ axisPosition: getAxisPosition(seriesKey),
279
+ kind: 'series',
280
+ seriesKey
281
+ })
282
+ ]
283
+ } else if (config.xAxis?.dataKey == seriesKey) {
284
+ return [
285
+ createTooltipRow({
286
+ key: seriesKey,
287
+ value: formattedValue,
288
+ axisPosition: getAxisPosition(seriesKey),
289
+ kind: 'heading'
290
+ })
291
+ ]
194
292
  } else {
195
- return [[seriesKey, formattedValue, getAxisPosition(seriesKey)]]
293
+ return [
294
+ createTooltipRow({
295
+ key: seriesKey,
296
+ value: formattedValue,
297
+ axisPosition: getAxisPosition(seriesKey),
298
+ kind: 'series',
299
+ seriesKey
300
+ })
301
+ ]
196
302
  }
197
303
  })
198
304
  )
@@ -232,7 +338,15 @@ export const useTooltip = props => {
232
338
  if (resolvedScaleValue) {
233
339
  const value = resolvedScaleValue[series.originalDataKey]
234
340
  const formattedValue = getFormattedValue(seriesKey, value, config, getAxisPosition)
235
- tooltipItems.push([seriesKey, formattedValue, getAxisPosition(seriesKey)])
341
+ tooltipItems.push(
342
+ createTooltipRow({
343
+ key: seriesKey,
344
+ value: formattedValue,
345
+ axisPosition: getAxisPosition(seriesKey),
346
+ kind: 'series',
347
+ seriesKey
348
+ })
349
+ )
236
350
  }
237
351
  }
238
352
  })
@@ -246,12 +360,31 @@ export const useTooltip = props => {
246
360
  const xVal = dataColumn[config.xAxis.dataKey]
247
361
  const closestXScaleValue = getXValueFromCoordinate(x - Y_AXIS_SIZE)
248
362
 
249
- tooltipItems.push([config.xAxis.dataKey, closestXScaleValue || xVal])
363
+ tooltipItems.push(
364
+ createTooltipRow({
365
+ key: config.xAxis.dataKey,
366
+ value: closestXScaleValue || xVal,
367
+ kind: 'heading'
368
+ })
369
+ )
250
370
  const formattedValue = getFormattedValue(seriesKey, value, config, getAxisPosition)
251
- tooltipItems.push([seriesKey, formattedValue])
371
+ tooltipItems.push(
372
+ createTooltipRow({
373
+ key: seriesKey,
374
+ value: formattedValue,
375
+ kind: 'series',
376
+ seriesKey
377
+ })
378
+ )
252
379
  } else if (dynamicSeries) {
253
380
  Object.keys(dataColumn).forEach(key => {
254
- tooltipItems.push([key, dataColumn[key]])
381
+ tooltipItems.push(
382
+ createTooltipRow({
383
+ key,
384
+ value: dataColumn[key],
385
+ kind: key === config.xAxis.dataKey ? 'heading' : 'extra'
386
+ })
387
+ )
255
388
  })
256
389
  }
257
390
  }
@@ -268,16 +401,11 @@ export const useTooltip = props => {
268
401
  }
269
402
 
270
403
  // Strip link tags from all tooltip values
271
- const cleanTooltipItems = [...tooltipItems, ...additionalTooltipItems].map(item => {
272
- // item can be [key, value] or [key, value, axisPosition]
273
- if (Array.isArray(item)) {
274
- // Only strip from value (item[1])
275
- const newItem = [...item]
276
- newItem[1] = stripLinkTags(newItem[1])
277
- return newItem
278
- }
279
- return item
280
- })
404
+ const cleanTooltipItems = [...tooltipItems, ...additionalTooltipItems].map(item => ({
405
+ ...item,
406
+ value: stripLinkTags(item.value)
407
+ }))
408
+ const useMarkerColumn = tooltipHasMarkerColumn(cleanTooltipItems)
281
409
 
282
410
  const tooltipInformation = {
283
411
  tooltipLeft: dataXPosition,
@@ -285,7 +413,8 @@ export const useTooltip = props => {
285
413
  tooltipData: {
286
414
  data: cleanTooltipItems,
287
415
  dataXPosition,
288
- dataYPosition
416
+ dataYPosition,
417
+ useMarkerColumn
289
418
  }
290
419
  }
291
420
  showTooltip(tooltipInformation)
@@ -633,13 +762,14 @@ export const useTooltip = props => {
633
762
  */
634
763
  const getSeriesNameFromLabel = originalColumnName => {
635
764
  let series = config.runtime.series.filter(s => s.dataKey === originalColumnName)
636
- if (series[0]?.name) return series[0]?.name
765
+ if (series[0] && series[0].name !== undefined) return series[0]?.name
766
+ const columnConfig = findColumnConfigByName(config.columns || {}, originalColumnName)?.columnConfig
767
+ if (columnConfig?.label !== undefined) return columnConfig.label
637
768
  return originalColumnName
638
769
  }
639
770
 
640
- const TooltipListItem = ({ item }) => {
641
- const [index, additionalData] = item
642
- const [key, value, axisPosition] = additionalData
771
+ const TooltipListItem = ({ row, index, useMarkerColumn = false }) => {
772
+ const { key, value, axisPosition, kind, markerColor, markerShape = 'circle' } = row
643
773
 
644
774
  if (visualizationType === 'Forest Plot') {
645
775
  if (key === config.xAxis.dataKey)
@@ -701,10 +831,26 @@ export const useTooltip = props => {
701
831
  }
702
832
  const activeLabel = getSeriesNameFromLabel(key)
703
833
  const displayText = activeLabel ? `${activeLabel}: ${newValue}` : newValue
834
+ const shouldRenderMarkerSlot = useMarkerColumn && kind !== 'heading'
835
+ const markerSlot = shouldRenderMarkerSlot ? (
836
+ <span className='tooltip-marker-slot' aria-hidden='true'>
837
+ {markerColor ? (
838
+ <span
839
+ className={`tooltip-marker-swatch tooltip-marker-swatch--${markerShape}`}
840
+ style={{ backgroundColor: markerColor }}
841
+ />
842
+ ) : null}
843
+ </span>
844
+ ) : null
845
+ const content = displayText !== undefined ? parse(String(displayText)) : displayText
704
846
 
705
847
  return (
706
- <li style={style} className='tooltip-body mb-1'>
707
- {displayText !== undefined ? parse(String(displayText)) : displayText}
848
+ <li
849
+ style={style}
850
+ className={`tooltip-body mb-1 cove-prose ${shouldRenderMarkerSlot ? 'tooltip-body--marker-layout' : ''}`}
851
+ >
852
+ {markerSlot}
853
+ {shouldRenderMarkerSlot ? <span className='tooltip-body-content'>{content}</span> : content}
708
854
  </li>
709
855
  )
710
856
  }