@cdc/chart 4.24.5 → 4.24.9
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.
- package/dist/cdcchart.js +44197 -38258
- package/examples/cases-year.json +13379 -0
- package/examples/feature/annotations/index.json +542 -0
- package/examples/gallery/bar-chart-vertical/combo-line-chart.json +76 -15
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +5 -5
- package/examples/xaxis.json +493 -0
- package/index.html +20 -10
- package/package.json +5 -4
- package/src/CdcChart.tsx +462 -172
- package/src/_stories/Chart.Legend.Gradient.tsx +19 -0
- package/src/_stories/Chart.stories.tsx +18 -171
- package/src/_stories/ChartAnnotation.stories.tsx +32 -0
- package/src/_stories/_mock/annotation_category_mock.json +473 -0
- package/src/_stories/_mock/annotation_date-linear_mock.json +530 -0
- package/{examples/feature/line/line-chart.json → src/_stories/_mock/annotation_date-time_mock.json} +150 -69
- package/src/_stories/_mock/legend.gradient_mock.json +236 -0
- package/src/_stories/_mock/line_chart_two_points_new_chart.json +128 -0
- package/src/_stories/_mock/line_chart_two_points_regression_test.json +127 -0
- package/src/_stories/_mock/lollipop.json +171 -0
- package/src/components/Annotations/components/AnnotationDraggable.styles.css +31 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +207 -0
- package/src/components/Annotations/components/AnnotationDropdown.styles.css +14 -0
- package/src/components/Annotations/components/AnnotationDropdown.tsx +72 -0
- package/src/components/Annotations/components/AnnotationList.styles.css +45 -0
- package/src/components/Annotations/components/AnnotationList.tsx +42 -0
- package/src/components/Annotations/components/findNearestDatum.ts +138 -0
- package/src/components/Annotations/components/helpers/index.tsx +46 -0
- package/src/components/Annotations/index.tsx +13 -0
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +1 -1
- package/src/components/AreaChart/components/AreaChart.jsx +1 -1
- package/src/components/Axis/Categorical.Axis.tsx +145 -0
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +47 -44
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +0 -1
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +11 -14
- package/src/components/BarChart/components/BarChart.Vertical.tsx +67 -30
- package/src/components/BarChart/helpers/index.ts +91 -0
- package/src/components/BrushChart.tsx +205 -0
- package/src/components/EditorPanel/EditorPanel.tsx +1794 -403
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +320 -0
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +282 -18
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +43 -8
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +4 -4
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +4 -13
- package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
- package/src/components/EditorPanel/components/panels.scss +4 -0
- package/src/components/EditorPanel/editor-panel.scss +35 -3
- package/src/components/EditorPanel/{useEditorPermissions.js → useEditorPermissions.ts} +105 -17
- package/src/components/Legend/Legend.Component.tsx +185 -194
- package/src/components/Legend/Legend.Suppression.tsx +146 -0
- package/src/components/Legend/Legend.tsx +21 -5
- package/src/components/Legend/helpers/createFormatLabels.tsx +1 -1
- package/src/components/Legend/helpers/index.ts +35 -0
- package/src/components/LegendWrapper.tsx +26 -0
- package/src/components/LineChart/LineChartProps.ts +1 -15
- package/src/components/LineChart/components/LineChart.BumpCircle.tsx +103 -0
- package/src/components/LineChart/components/LineChart.Circle.tsx +47 -8
- package/src/components/LineChart/helpers.ts +72 -14
- package/src/components/LineChart/index.tsx +117 -42
- package/src/components/LinearChart.jsx +179 -136
- package/src/components/LinearChart.tsx +1366 -0
- package/src/components/PairedBarChart.jsx +9 -9
- package/src/components/PieChart/PieChart.tsx +75 -18
- package/src/components/Sankey/index.tsx +89 -30
- package/src/components/ScatterPlot/ScatterPlot.jsx +22 -8
- package/src/components/Sparkline/components/SparkLine.tsx +2 -2
- package/src/components/ZoomBrush.tsx +90 -44
- package/src/data/initial-state.js +25 -7
- package/src/helpers/handleChartTabbing.ts +8 -0
- package/src/helpers/isConvertLineToBarGraph.ts +4 -0
- package/src/hooks/{useBarChart.js → useBarChart.ts} +2 -40
- package/src/hooks/useColorScale.ts +1 -1
- package/src/hooks/useLegendClasses.ts +68 -0
- package/src/hooks/useMinMax.ts +12 -7
- package/src/hooks/useScales.ts +58 -26
- package/src/hooks/useTooltip.tsx +135 -25
- package/src/scss/DataTable.scss +2 -1
- package/src/scss/main.scss +128 -28
- package/src/types/ChartConfig.ts +83 -10
- package/src/types/ChartContext.ts +14 -4
- package/tests-examples/helpers/testZeroValue.test.ts +30 -0
- package/LICENSE +0 -201
- package/src/components/BrushHandle.jsx +0 -17
- package/src/components/LineChart/index.scss +0 -1
- package/src/helpers/filterData.ts +0 -18
- package/src/helpers/tests/computeMarginBottom.test.ts +0 -21
- package/src/hooks/useLegendClasses.js +0 -31
- /package/src/hooks/{useReduceData.js → useReduceData.ts} +0 -0
package/src/hooks/useScales.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { useContext } from 'react'
|
|
|
3
3
|
import ConfigContext from '../ConfigContext'
|
|
4
4
|
import { ChartConfig } from '../types/ChartConfig'
|
|
5
5
|
import { ChartContext } from '../types/ChartContext'
|
|
6
|
-
|
|
6
|
+
import * as d3 from 'd3'
|
|
7
7
|
const scaleTypes = {
|
|
8
8
|
TIME: 'time',
|
|
9
9
|
LOG: 'log',
|
|
@@ -27,12 +27,10 @@ const useScales = (properties: useScaleProps) => {
|
|
|
27
27
|
|
|
28
28
|
const { rawData, dimensions } = useContext<ChartContext>(ConfigContext)
|
|
29
29
|
|
|
30
|
-
const [screenWidth
|
|
30
|
+
const [screenWidth] = dimensions
|
|
31
31
|
const seriesDomain = config.runtime.barSeriesKeys || config.runtime.seriesKeys
|
|
32
32
|
const xAxisType = config.runtime.xAxis.type
|
|
33
33
|
const isHorizontal = config.orientation === 'horizontal'
|
|
34
|
-
const getXAxisDataKeys = d => d[config.runtime.originalXAxis.dataKey]
|
|
35
|
-
const xAxisDataKeysMapped = data.map(d => getXAxisDataKeys(d))
|
|
36
34
|
|
|
37
35
|
const { visualizationType } = config
|
|
38
36
|
|
|
@@ -43,12 +41,15 @@ const useScales = (properties: useScaleProps) => {
|
|
|
43
41
|
let g1xScale = null
|
|
44
42
|
let seriesScale = null
|
|
45
43
|
let xScaleNoPadding = null
|
|
46
|
-
let
|
|
44
|
+
let xScaleAnnotation = scaleLinear({
|
|
45
|
+
domain: [0, 100],
|
|
46
|
+
range: [0, xMax]
|
|
47
|
+
})
|
|
47
48
|
|
|
48
49
|
// handle Horizontal bars
|
|
49
50
|
if (isHorizontal) {
|
|
50
51
|
xScale = composeXScale({ min: min * 1.03, ...properties })
|
|
51
|
-
xScale.type = config.
|
|
52
|
+
xScale.type = config.yAxis.type === 'logarithmic' ? scaleTypes.LOG : scaleTypes.LINEAR
|
|
52
53
|
yScale = getYScaleFunction(xAxisType, xAxisDataMapped)
|
|
53
54
|
yScale.rangeRound([0, yMax])
|
|
54
55
|
seriesScale = composeScalePoint(seriesDomain, [0, yMax])
|
|
@@ -56,16 +57,20 @@ const useScales = (properties: useScaleProps) => {
|
|
|
56
57
|
|
|
57
58
|
// handle Vertical bars
|
|
58
59
|
if (!isHorizontal) {
|
|
59
|
-
xScaleBrush = composeScalePoint(xAxisDataKeysMapped, [0, xMax], 0.5)
|
|
60
60
|
xScale = composeScaleBand(xAxisDataMapped, [0, xMax], 1 - config.barThickness)
|
|
61
61
|
yScale = composeYScale(properties)
|
|
62
62
|
seriesScale = composeScaleBand(seriesDomain, [0, xScale.bandwidth()], 0)
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
// handle
|
|
65
|
+
// handle Linear scaled viz
|
|
66
|
+
if (config.xAxis.type === 'date' && !isHorizontal) {
|
|
67
|
+
const xAxisDataMappedSorted = xAxisDataMapped ? xAxisDataMapped.sort() : []
|
|
68
|
+
xScale = composeScaleBand(xAxisDataMappedSorted, [0, xMax], 1 - config.barThickness)
|
|
69
|
+
}
|
|
70
|
+
|
|
66
71
|
if (config.xAxis.type === 'date-time') {
|
|
67
|
-
let xAxisMin = Math.min(...xAxisDataMapped)
|
|
68
|
-
let xAxisMax = Math.max(...xAxisDataMapped)
|
|
72
|
+
let xAxisMin = Math.min(...xAxisDataMapped.map(Number))
|
|
73
|
+
let xAxisMax = Math.max(...xAxisDataMapped.map(Number))
|
|
69
74
|
xAxisMin -= (config.xAxis.padding ? config.xAxis.padding * 0.01 : 0) * (xAxisMax - xAxisMin)
|
|
70
75
|
xAxisMax += (config.xAxis.padding ? config.xAxis.padding * 0.01 : 0) * (xAxisMax - xAxisMin)
|
|
71
76
|
xScale = scaleTime({
|
|
@@ -74,7 +79,20 @@ const useScales = (properties: useScaleProps) => {
|
|
|
74
79
|
})
|
|
75
80
|
|
|
76
81
|
xScale.type = scaleTypes.TIME
|
|
77
|
-
|
|
82
|
+
|
|
83
|
+
let minDistance = Number.MAX_VALUE
|
|
84
|
+
let xAxisDataMappedSorted = xAxisDataMapped ? xAxisDataMapped.sort() : []
|
|
85
|
+
for (let i = 0; i < xAxisDataMappedSorted.length - 1; i++) {
|
|
86
|
+
let distance = xScale(xAxisDataMappedSorted[i + 1]) - xScale(xAxisDataMappedSorted[i])
|
|
87
|
+
|
|
88
|
+
if (distance < minDistance) minDistance = distance
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (xAxisDataMapped.length === 1 || minDistance > xMax / 4) {
|
|
92
|
+
minDistance = xMax / 4
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
seriesScale = composeScaleBand(seriesDomain, [0, (config.barThickness || 1) * minDistance], 0)
|
|
78
96
|
}
|
|
79
97
|
|
|
80
98
|
// handle Deviation bar
|
|
@@ -107,7 +125,9 @@ const useScales = (properties: useScaleProps) => {
|
|
|
107
125
|
// handle Box plot
|
|
108
126
|
if (visualizationType === 'Box Plot') {
|
|
109
127
|
const allOutliers = []
|
|
110
|
-
const hasOutliers =
|
|
128
|
+
const hasOutliers =
|
|
129
|
+
config.boxplot.plots.map(b => b.columnOutliers.map(outlier => allOutliers.push(outlier))) &&
|
|
130
|
+
!config.boxplot.hideOutliers
|
|
111
131
|
|
|
112
132
|
// check if outliers are lower
|
|
113
133
|
if (hasOutliers) {
|
|
@@ -193,8 +213,11 @@ const useScales = (properties: useScaleProps) => {
|
|
|
193
213
|
if (screenWidth > 480) {
|
|
194
214
|
if (config.forestPlot.type === 'Linear') {
|
|
195
215
|
xScale = scaleLinear({
|
|
196
|
-
domain: [
|
|
197
|
-
|
|
216
|
+
domain: [
|
|
217
|
+
Math.min(...data.map(d => parseFloat(d[config.forestPlot.lower]))) - xAxisPadding,
|
|
218
|
+
Math.max(...data.map(d => parseFloat(d[config.forestPlot.upper]))) + xAxisPadding
|
|
219
|
+
],
|
|
220
|
+
range: [leftWidthOffset, Number(screenWidth) - rightWidthOffset]
|
|
198
221
|
})
|
|
199
222
|
xScale.type = scaleTypes.LINEAR
|
|
200
223
|
}
|
|
@@ -212,7 +235,10 @@ const useScales = (properties: useScaleProps) => {
|
|
|
212
235
|
} else {
|
|
213
236
|
if (config.forestPlot.type === 'Linear') {
|
|
214
237
|
xScale = scaleLinear({
|
|
215
|
-
domain: [
|
|
238
|
+
domain: [
|
|
239
|
+
Math.min(...data.map(d => parseFloat(d[config.forestPlot.lower]))) - xAxisPadding,
|
|
240
|
+
Math.max(...data.map(d => parseFloat(d[config.forestPlot.upper]))) + xAxisPadding
|
|
241
|
+
],
|
|
216
242
|
range: [leftWidthOffsetMobile, xMax - rightWidthOffsetMobile],
|
|
217
243
|
type: scaleTypes.LINEAR
|
|
218
244
|
})
|
|
@@ -233,7 +259,7 @@ const useScales = (properties: useScaleProps) => {
|
|
|
233
259
|
}
|
|
234
260
|
}
|
|
235
261
|
}
|
|
236
|
-
return { xScale, yScale, seriesScale, g1xScale, g2xScale, xScaleNoPadding,
|
|
262
|
+
return { xScale, yScale, seriesScale, g1xScale, g2xScale, xScaleNoPadding, xScaleAnnotation }
|
|
237
263
|
}
|
|
238
264
|
|
|
239
265
|
export default useScales
|
|
@@ -273,31 +299,37 @@ export const getTickValues = (xAxisDataMapped, xScale, num) => {
|
|
|
273
299
|
/// helper functions
|
|
274
300
|
const composeXScale = ({ min, max, xMax, config }) => {
|
|
275
301
|
// Adjust min value if using logarithmic scale
|
|
276
|
-
|
|
302
|
+
const isLogarithmicAxis = config.yAxis.type === 'logarithmic'
|
|
303
|
+
min = isLogarithmicAxis && min >= 0 && min < 1 ? min + 0.1 : min
|
|
277
304
|
// Select the appropriate scale function
|
|
278
|
-
const scaleFunc =
|
|
305
|
+
const scaleFunc = isLogarithmicAxis ? scaleLog : scaleLinear
|
|
279
306
|
// Return the configured scale function
|
|
280
307
|
return scaleFunc({
|
|
281
308
|
domain: [min, max],
|
|
282
309
|
range: [0, xMax],
|
|
283
|
-
nice:
|
|
284
|
-
zero:
|
|
310
|
+
nice: isLogarithmicAxis,
|
|
311
|
+
zero: isLogarithmicAxis
|
|
285
312
|
})
|
|
286
313
|
}
|
|
287
314
|
|
|
288
315
|
const composeYScale = ({ min, max, yMax, config, leftMax }) => {
|
|
289
316
|
// Adjust min value if using logarithmic scale
|
|
290
|
-
|
|
317
|
+
const isLogarithmicAxis = config.yAxis.type === 'logarithmic'
|
|
318
|
+
min = isLogarithmicAxis && min >= 0 && min < 1 ? min + 0.1 : min
|
|
291
319
|
// Select the appropriate scale function
|
|
292
|
-
const scaleFunc =
|
|
320
|
+
const scaleFunc = isLogarithmicAxis ? scaleLog : scaleLinear
|
|
293
321
|
|
|
294
322
|
if (config.visualizationType === 'Combo') max = leftMax
|
|
323
|
+
|
|
324
|
+
// If the visualization type is a bump chart then the domain and range need different values
|
|
325
|
+
const domainSet = config.visualizationType === 'Bump Chart' ? [1, max] : [min, max]
|
|
326
|
+
const yRange = config.visualizationType === 'Bump Chart' ? [30, yMax] : [yMax, 0]
|
|
295
327
|
// Return the configured scale function
|
|
296
328
|
return scaleFunc({
|
|
297
|
-
domain:
|
|
298
|
-
range:
|
|
299
|
-
nice:
|
|
300
|
-
zero:
|
|
329
|
+
domain: domainSet,
|
|
330
|
+
range: yRange,
|
|
331
|
+
nice: isLogarithmicAxis,
|
|
332
|
+
zero: isLogarithmicAxis
|
|
301
333
|
})
|
|
302
334
|
}
|
|
303
335
|
|
package/src/hooks/useTooltip.tsx
CHANGED
|
@@ -9,9 +9,20 @@ import { localPoint } from '@visx/event'
|
|
|
9
9
|
import { bisector } from 'd3-array'
|
|
10
10
|
|
|
11
11
|
export const useTooltip = props => {
|
|
12
|
-
const {
|
|
12
|
+
const {
|
|
13
|
+
tableData: data,
|
|
14
|
+
config,
|
|
15
|
+
formatNumber,
|
|
16
|
+
capitalize,
|
|
17
|
+
formatDate,
|
|
18
|
+
formatTooltipsDate,
|
|
19
|
+
parseDate,
|
|
20
|
+
setSharedFilter,
|
|
21
|
+
isDraggingAnnotation
|
|
22
|
+
} = useContext<ChartContext>(ConfigContext)
|
|
13
23
|
const { xScale, yScale, showTooltip, hideTooltip } = props
|
|
14
24
|
const { xAxis, visualizationType, orientation, yAxis, runtime } = config
|
|
25
|
+
|
|
15
26
|
/**
|
|
16
27
|
* Provides the tooltip information based on the tooltip data array and svg cursor coordinates
|
|
17
28
|
* @function getTooltipInformation
|
|
@@ -19,6 +30,42 @@ export const useTooltip = props => {
|
|
|
19
30
|
* @param {Object} eventSvgCoords - The object containing the SVG coordinates of the event.
|
|
20
31
|
* @return {Object} - The tooltip information with tooltip data.
|
|
21
32
|
*/
|
|
33
|
+
|
|
34
|
+
// function handles only Single series hovred data tooltips
|
|
35
|
+
const findDataKeyByThreshold = (mouseY, datapoint) => {
|
|
36
|
+
let sum = 0
|
|
37
|
+
let threshold = Number(yScale.invert(mouseY))
|
|
38
|
+
let hoveredKey = null
|
|
39
|
+
let hoveredValue = null
|
|
40
|
+
|
|
41
|
+
for (let key of config.runtime?.seriesKeys) {
|
|
42
|
+
if (datapoint.hasOwnProperty(key)) {
|
|
43
|
+
sum += Number(datapoint[key])
|
|
44
|
+
if (sum >= threshold) {
|
|
45
|
+
hoveredValue = datapoint[key]
|
|
46
|
+
hoveredKey = key
|
|
47
|
+
break
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Return null if no matching data is found
|
|
53
|
+
return [hoveredKey, hoveredValue]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const getFormattedValue = (seriesKey, value, config, getAxisPosition) => {
|
|
57
|
+
// handle case where data is missing
|
|
58
|
+
const showMissingDataValue = config.general.showMissingDataLabel && (!value || value === 'null')
|
|
59
|
+
let formattedValue = seriesKey === config.xAxis.dataKey ? value : formatNumber(value, getAxisPosition(seriesKey))
|
|
60
|
+
|
|
61
|
+
formattedValue =
|
|
62
|
+
showMissingDataValue && (config.visualizationSubType === 'stacked' ? !config.general.hideNullValue : true)
|
|
63
|
+
? 'N/A'
|
|
64
|
+
: formattedValue
|
|
65
|
+
|
|
66
|
+
return formattedValue
|
|
67
|
+
}
|
|
68
|
+
|
|
22
69
|
const getTooltipInformation = (tooltipDataArray, eventSvgCoords) => {
|
|
23
70
|
const { x, y } = eventSvgCoords
|
|
24
71
|
let initialTooltipData = tooltipDataArray || {}
|
|
@@ -45,7 +92,10 @@ export const useTooltip = props => {
|
|
|
45
92
|
* @return {void} - The tooltip information is displayed
|
|
46
93
|
*/
|
|
47
94
|
const handleTooltipMouseOver = (e, additionalChartData) => {
|
|
95
|
+
if (visualizationType === 'Bump Chart') return
|
|
48
96
|
e.stopPropagation()
|
|
97
|
+
if (isDraggingAnnotation) return
|
|
98
|
+
|
|
49
99
|
const eventSvgCoords = localPoint(e)
|
|
50
100
|
const { x, y } = eventSvgCoords
|
|
51
101
|
|
|
@@ -54,10 +104,13 @@ export const useTooltip = props => {
|
|
|
54
104
|
|
|
55
105
|
const closestXScaleValue = getXValueFromCoordinate(x - Number(config.yAxis.size || 0))
|
|
56
106
|
|
|
57
|
-
const includedSeries =
|
|
107
|
+
const includedSeries =
|
|
108
|
+
visualizationType !== 'Pie'
|
|
109
|
+
? config.runtime.series.filter(series => series.tooltip === true).map(item => item.dataKey)
|
|
110
|
+
: config.runtime.series.map(item => item.dataKey)
|
|
58
111
|
includedSeries.push(config.xAxis.dataKey)
|
|
59
112
|
if (config.visualizationType === 'Forecasting') {
|
|
60
|
-
config.series.map(s => {
|
|
113
|
+
config.runtime.series.map(s => {
|
|
61
114
|
s.confidenceIntervals.map(c => {
|
|
62
115
|
if (c.showInTooltip) {
|
|
63
116
|
includedSeries.push(c.high)
|
|
@@ -84,7 +137,7 @@ export const useTooltip = props => {
|
|
|
84
137
|
const resolvedScaleValues = orientation === 'vertical' ? yScaleValues : xScaleValues
|
|
85
138
|
|
|
86
139
|
const getAxisPosition = seriesKey => {
|
|
87
|
-
const seriesObj = config.series.filter(s => s.dataKey === seriesKey)[0]
|
|
140
|
+
const seriesObj = config.runtime.series.filter(s => s.dataKey === seriesKey)[0]
|
|
88
141
|
const position = seriesObj?.axis ? String(seriesObj.axis).toLowerCase() : 'left'
|
|
89
142
|
return position
|
|
90
143
|
}
|
|
@@ -133,22 +186,34 @@ export const useTooltip = props => {
|
|
|
133
186
|
if (visualizationType === 'Forest Plot') {
|
|
134
187
|
tooltipItems.push([config.xAxis.dataKey, getClosestYValue(y)])
|
|
135
188
|
}
|
|
136
|
-
|
|
137
|
-
if (visualizationType !== 'Pie' && visualizationType !== 'Forest Plot') {
|
|
189
|
+
// handle tooltip for all hovered series
|
|
190
|
+
if (visualizationType !== 'Pie' && visualizationType !== 'Forest Plot' && !config.tooltips.singleSeries) {
|
|
138
191
|
tooltipItems.push(
|
|
139
192
|
...getIncludedTooltipSeries()
|
|
140
|
-
?.filter(
|
|
193
|
+
?.filter(
|
|
194
|
+
seriesKey =>
|
|
195
|
+
config.runtime.series?.find(item => item.dataKey === seriesKey && item?.tooltip) ||
|
|
196
|
+
config.xAxis?.dataKey == seriesKey ||
|
|
197
|
+
visualizationType === 'Forecasting'
|
|
198
|
+
)
|
|
141
199
|
?.flatMap(seriesKey => {
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
formattedValue = suppressed.label
|
|
146
|
-
}
|
|
147
|
-
return resolvedScaleValues?.[0]?.[seriesKey] ? [[seriesKey, formattedValue, getAxisPosition(seriesKey)]] : []
|
|
200
|
+
const value = resolvedScaleValues[0]?.[seriesKey]
|
|
201
|
+
const formattedValue = getFormattedValue(seriesKey, value, config, getAxisPosition)
|
|
202
|
+
return [[seriesKey, formattedValue, getAxisPosition(seriesKey)]]
|
|
148
203
|
})
|
|
149
204
|
)
|
|
150
205
|
}
|
|
151
206
|
|
|
207
|
+
// handle tooltip for single hovered series
|
|
208
|
+
if (visualizationType !== 'Pie' && visualizationType !== 'Forest Plot' && config.tooltips.singleSeries) {
|
|
209
|
+
const [seriesKey, value] = findDataKeyByThreshold(y, resolvedScaleValues[0])
|
|
210
|
+
if (seriesKey && value) {
|
|
211
|
+
tooltipItems.push([config.xAxis.dataKey, closestXScaleValue])
|
|
212
|
+
const formattedValue = getFormattedValue(seriesKey, value, config, getAxisPosition)
|
|
213
|
+
tooltipItems.push([seriesKey, formattedValue])
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
152
217
|
return [...tooltipItems, ...additionalTooltipItems]
|
|
153
218
|
}
|
|
154
219
|
|
|
@@ -227,7 +292,10 @@ export const useTooltip = props => {
|
|
|
227
292
|
return closestX
|
|
228
293
|
}
|
|
229
294
|
|
|
230
|
-
if (
|
|
295
|
+
if (
|
|
296
|
+
config.xAxis.type === 'categorical' ||
|
|
297
|
+
(visualizationType === 'Combo' && orientation !== 'horizontal' && visualizationType !== 'Forest Plot')
|
|
298
|
+
) {
|
|
231
299
|
let range = xScale.range()[1] - xScale.range()[0]
|
|
232
300
|
let eachBand = range / (xScale.domain().length + 1)
|
|
233
301
|
|
|
@@ -275,6 +343,7 @@ export const useTooltip = props => {
|
|
|
275
343
|
// Get the closest x axis value from the pointer.
|
|
276
344
|
// After getting the closest value, return the data entry with that x scale value.
|
|
277
345
|
// Pass the config.visual uid (not uuid) along with that data entry to setSharedFilters
|
|
346
|
+
if (config.visualizationType === 'Bump Chart') return
|
|
278
347
|
const eventSvgCoords = localPoint(e)
|
|
279
348
|
const { x } = eventSvgCoords
|
|
280
349
|
if (!x) throw new Error('COVE: no x value in handleTooltipClick.')
|
|
@@ -323,7 +392,6 @@ export const useTooltip = props => {
|
|
|
323
392
|
const yScaleValues = dataToSearch.map(object => {
|
|
324
393
|
return Object.fromEntries(Object.entries(object).filter(([key, value]) => includedSeries.includes(key)))
|
|
325
394
|
})
|
|
326
|
-
|
|
327
395
|
return yScaleValues
|
|
328
396
|
} catch (error) {
|
|
329
397
|
console.error('COVE', error)
|
|
@@ -345,7 +413,7 @@ export const useTooltip = props => {
|
|
|
345
413
|
|
|
346
414
|
// loop through series for items to add to tooltip.
|
|
347
415
|
// there is probably a better way of doing this.
|
|
348
|
-
config.series?.forEach(s => {
|
|
416
|
+
config.runtime.series?.forEach(s => {
|
|
349
417
|
if (s.type === 'Forecasting') {
|
|
350
418
|
stageColumns.push(s.stageColumn)
|
|
351
419
|
|
|
@@ -373,7 +441,10 @@ export const useTooltip = props => {
|
|
|
373
441
|
standardLoopItems = [runtime.xAxis.dataKey, ...runtime?.seriesKeys]
|
|
374
442
|
break
|
|
375
443
|
case 'Bar':
|
|
376
|
-
standardLoopItems =
|
|
444
|
+
standardLoopItems =
|
|
445
|
+
orientation === 'vertical'
|
|
446
|
+
? [runtime.xAxis.dataKey, ...runtime?.seriesKeys]
|
|
447
|
+
: [runtime.yAxis.dataKey, ...runtime?.seriesKeys]
|
|
377
448
|
break
|
|
378
449
|
case 'Pie':
|
|
379
450
|
standardLoopItems = [runtime.xAxis.dataKey, ...runtime?.seriesKeys]
|
|
@@ -383,7 +454,13 @@ export const useTooltip = props => {
|
|
|
383
454
|
}
|
|
384
455
|
|
|
385
456
|
if (config.dashboard) {
|
|
386
|
-
standardLoopItems = [
|
|
457
|
+
standardLoopItems = [
|
|
458
|
+
runtime.xAxis.dataKey,
|
|
459
|
+
...runtime?.barSeriesKeys,
|
|
460
|
+
...runtime?.lineSeriesKeys,
|
|
461
|
+
...stageColumns,
|
|
462
|
+
...ciItems
|
|
463
|
+
]
|
|
387
464
|
}
|
|
388
465
|
|
|
389
466
|
return standardLoopItems
|
|
@@ -416,7 +493,7 @@ export const useTooltip = props => {
|
|
|
416
493
|
* @returns user defined series name.
|
|
417
494
|
*/
|
|
418
495
|
const getSeriesNameFromLabel = originalColumnName => {
|
|
419
|
-
let series = config.series.filter(s => s.dataKey === originalColumnName)
|
|
496
|
+
let series = config.runtime.series.filter(s => s.dataKey === originalColumnName)
|
|
420
497
|
if (series[0]?.name) return series[0]?.name
|
|
421
498
|
return originalColumnName
|
|
422
499
|
}
|
|
@@ -426,18 +503,51 @@ export const useTooltip = props => {
|
|
|
426
503
|
const [key, value, axisPosition] = additionalData
|
|
427
504
|
|
|
428
505
|
if (visualizationType === 'Forest Plot') {
|
|
429
|
-
if (key === config.xAxis.dataKey)
|
|
506
|
+
if (key === config.xAxis.dataKey)
|
|
507
|
+
return (
|
|
508
|
+
<li className='tooltip-heading'>{`${capitalize(config.xAxis.dataKey ? `${config.xAxis.dataKey}: ` : '')} ${
|
|
509
|
+
isDateScale(yAxis) ? formatDate(parseDate(key, false)) : value
|
|
510
|
+
}`}</li>
|
|
511
|
+
)
|
|
430
512
|
return <li className='tooltip-body'>{`${getSeriesNameFromLabel(key)}: ${formatNumber(value, 'left')}`}</li>
|
|
431
513
|
}
|
|
432
|
-
const formattedDate = config.tooltips.dateDisplayFormat
|
|
514
|
+
const formattedDate = config.tooltips.dateDisplayFormat
|
|
515
|
+
? formatTooltipsDate(parseDate(value, false))
|
|
516
|
+
: formatDate(parseDate(value, false))
|
|
433
517
|
|
|
434
518
|
// TOOLTIP HEADING
|
|
435
|
-
if (visualizationType === 'Bar' && orientation === 'horizontal' && key === config.xAxis.dataKey)
|
|
436
|
-
|
|
437
|
-
|
|
519
|
+
if (visualizationType === 'Bar' && orientation === 'horizontal' && key === config.xAxis.dataKey)
|
|
520
|
+
return (
|
|
521
|
+
<li className='tooltip-heading'>{`${capitalize(
|
|
522
|
+
config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ` : ''
|
|
523
|
+
)} ${config.xAxis.type === 'date' ? formattedDate : value}`}</li>
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
if (key === config.xAxis.dataKey)
|
|
527
|
+
return (
|
|
528
|
+
<li className='tooltip-heading'>{`${capitalize(
|
|
529
|
+
config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ` : ''
|
|
530
|
+
)} ${isDateScale(xAxis) ? formattedDate : value}`}</li>
|
|
531
|
+
)
|
|
438
532
|
|
|
439
533
|
// TOOLTIP BODY
|
|
440
|
-
|
|
534
|
+
// handle suppressed tooltip items
|
|
535
|
+
const { label, displayGray } =
|
|
536
|
+
(config.visualizationSubType !== 'stacked' &&
|
|
537
|
+
config.general.showSuppressedSymbol &&
|
|
538
|
+
config.preliminaryData?.find(
|
|
539
|
+
pd =>
|
|
540
|
+
pd.label &&
|
|
541
|
+
pd.type === 'suppression' &&
|
|
542
|
+
pd.displayTooltip &&
|
|
543
|
+
value === pd.value &&
|
|
544
|
+
(!pd.column || key === pd.column)
|
|
545
|
+
)) ||
|
|
546
|
+
{}
|
|
547
|
+
const newValue = label || value
|
|
548
|
+
const style = displayGray ? { color: '#8b8b8a' } : {}
|
|
549
|
+
|
|
550
|
+
return <li style={style} className='tooltip-body'>{`${getSeriesNameFromLabel(key)}: ${newValue}`}</li>
|
|
441
551
|
}
|
|
442
552
|
|
|
443
553
|
return {
|