@cdc/chart 4.24.5 → 4.24.9-1

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 (86) hide show
  1. package/dist/cdcchart.js +50526 -42181
  2. package/examples/cases-year.json +13379 -0
  3. package/examples/feature/annotations/index.json +542 -0
  4. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +76 -15
  5. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +5 -5
  6. package/examples/xaxis.json +493 -0
  7. package/index.html +20 -10
  8. package/package.json +5 -4
  9. package/src/CdcChart.tsx +461 -172
  10. package/src/_stories/Chart.Legend.Gradient.tsx +19 -0
  11. package/src/_stories/Chart.stories.tsx +18 -171
  12. package/src/_stories/ChartAnnotation.stories.tsx +32 -0
  13. package/src/_stories/_mock/annotation_category_mock.json +473 -0
  14. package/src/_stories/_mock/annotation_date-linear_mock.json +530 -0
  15. package/{examples/feature/line/line-chart.json → src/_stories/_mock/annotation_date-time_mock.json} +150 -69
  16. package/src/_stories/_mock/legend.gradient_mock.json +236 -0
  17. package/src/_stories/_mock/line_chart_two_points_new_chart.json +128 -0
  18. package/src/_stories/_mock/line_chart_two_points_regression_test.json +127 -0
  19. package/src/_stories/_mock/lollipop.json +171 -0
  20. package/src/components/Annotations/components/AnnotationDraggable.styles.css +31 -0
  21. package/src/components/Annotations/components/AnnotationDraggable.tsx +207 -0
  22. package/src/components/Annotations/components/AnnotationDropdown.styles.css +14 -0
  23. package/src/components/Annotations/components/AnnotationDropdown.tsx +72 -0
  24. package/src/components/Annotations/components/AnnotationList.styles.css +45 -0
  25. package/src/components/Annotations/components/AnnotationList.tsx +42 -0
  26. package/src/components/Annotations/components/findNearestDatum.ts +138 -0
  27. package/src/components/Annotations/components/helpers/index.tsx +46 -0
  28. package/src/components/Annotations/index.tsx +13 -0
  29. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +1 -1
  30. package/src/components/AreaChart/components/AreaChart.jsx +1 -1
  31. package/src/components/Axis/Categorical.Axis.tsx +145 -0
  32. package/src/components/BarChart/components/BarChart.Horizontal.tsx +47 -44
  33. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +0 -1
  34. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +11 -14
  35. package/src/components/BarChart/components/BarChart.Vertical.tsx +67 -30
  36. package/src/components/BarChart/helpers/index.ts +91 -0
  37. package/src/components/BrushChart.tsx +205 -0
  38. package/src/components/EditorPanel/EditorPanel.tsx +1794 -403
  39. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +320 -0
  40. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +282 -18
  41. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +43 -8
  42. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +4 -4
  43. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +4 -13
  44. package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
  45. package/src/components/EditorPanel/components/panels.scss +4 -0
  46. package/src/components/EditorPanel/editor-panel.scss +35 -3
  47. package/src/components/EditorPanel/{useEditorPermissions.js → useEditorPermissions.ts} +105 -17
  48. package/src/components/Legend/Legend.Component.tsx +185 -194
  49. package/src/components/Legend/Legend.Suppression.tsx +146 -0
  50. package/src/components/Legend/Legend.tsx +21 -5
  51. package/src/components/Legend/helpers/createFormatLabels.tsx +1 -1
  52. package/src/components/Legend/helpers/index.ts +35 -0
  53. package/src/components/LegendWrapper.tsx +26 -0
  54. package/src/components/LineChart/LineChartProps.ts +1 -15
  55. package/src/components/LineChart/components/LineChart.BumpCircle.tsx +103 -0
  56. package/src/components/LineChart/components/LineChart.Circle.tsx +57 -8
  57. package/src/components/LineChart/helpers.ts +72 -14
  58. package/src/components/LineChart/index.tsx +117 -42
  59. package/src/components/LinearChart.tsx +1366 -0
  60. package/src/components/PairedBarChart.jsx +9 -9
  61. package/src/components/PieChart/PieChart.tsx +75 -18
  62. package/src/components/Sankey/index.tsx +89 -30
  63. package/src/components/ScatterPlot/ScatterPlot.jsx +22 -8
  64. package/src/components/Sparkline/components/SparkLine.tsx +2 -2
  65. package/src/components/ZoomBrush.tsx +90 -44
  66. package/src/data/initial-state.js +25 -7
  67. package/src/helpers/handleChartTabbing.ts +8 -0
  68. package/src/helpers/isConvertLineToBarGraph.ts +4 -0
  69. package/src/hooks/{useBarChart.js → useBarChart.ts} +2 -40
  70. package/src/hooks/useColorScale.ts +1 -1
  71. package/src/hooks/useLegendClasses.ts +68 -0
  72. package/src/hooks/useMinMax.ts +12 -7
  73. package/src/hooks/useScales.ts +58 -26
  74. package/src/hooks/useTooltip.tsx +135 -25
  75. package/src/scss/DataTable.scss +2 -1
  76. package/src/scss/main.scss +128 -28
  77. package/src/types/ChartConfig.ts +83 -10
  78. package/src/types/ChartContext.ts +14 -4
  79. package/tests-examples/helpers/testZeroValue.test.ts +30 -0
  80. package/src/components/BrushHandle.jsx +0 -17
  81. package/src/components/LineChart/index.scss +0 -1
  82. package/src/components/LinearChart.jsx +0 -774
  83. package/src/helpers/filterData.ts +0 -18
  84. package/src/helpers/tests/computeMarginBottom.test.ts +0 -21
  85. package/src/hooks/useLegendClasses.js +0 -31
  86. /package/src/hooks/{useReduceData.js → useReduceData.ts} +0 -0
@@ -1,774 +0,0 @@
1
- import React, { useContext, useEffect, useRef, useState } from 'react'
2
-
3
- // Libraries
4
- import { AxisLeft, AxisBottom, AxisRight, AxisTop } from '@visx/axis'
5
- import { Group } from '@visx/group'
6
- import { Line, Bar } from '@visx/shape'
7
- import { Text } from '@visx/text'
8
- import { Tooltip as ReactTooltip } from 'react-tooltip'
9
- import { useTooltip, TooltipWithBounds } from '@visx/tooltip'
10
- import { isDateScale } from '@cdc/core/helpers/cove/date'
11
-
12
- // CDC Components
13
- import { AreaChart, AreaChartStacked } from './AreaChart'
14
- import BarChart from './BarChart'
15
- import ConfigContext from '../ConfigContext'
16
- import BoxPlot from './BoxPlot'
17
- import ScatterPlot from './ScatterPlot'
18
- import DeviationBar from './DeviationBar'
19
- import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
20
- import Forecasting from './Forecasting'
21
- import LineChart from './LineChart'
22
- import ForestPlot from './ForestPlot'
23
- import PairedBarChart from './PairedBarChart'
24
- import useIntersectionObserver from './../hooks/useIntersectionObserver'
25
- import Regions from './Regions'
26
-
27
- // Hooks
28
- import useMinMax from '../hooks/useMinMax'
29
- import useReduceData from '../hooks/useReduceData'
30
- import useRightAxis from '../hooks/useRightAxis'
31
- import useScales, { getTickValues } from '../hooks/useScales'
32
- import useTopAxis from '../hooks/useTopAxis'
33
- import { useTooltip as useCoveTooltip } from '../hooks/useTooltip'
34
- import { useEditorPermissions } from './EditorPanel/useEditorPermissions'
35
-
36
- // styles
37
- import ZoomBrush from './ZoomBrush'
38
-
39
- const LinearChart = props => {
40
- const { transformedData: data, tableData, dimensions, config, parseDate, formatDate, currentViewport, formatNumber, handleChartAriaLabels, updateConfig, handleLineType, getTextWidth, brushConfig } = useContext(ConfigContext)
41
- // todo: start destructuring this file for conciseness
42
- const { visualizationType, visualizationSubType, orientation, xAxis, yAxis, runtime, debugSvg } = config
43
-
44
- // configure width
45
- let [width] = dimensions
46
- if (config && config.legend && !config.legend.hide && config.legend.position !== 'bottom' && ['lg', 'md'].includes(currentViewport)) {
47
- width = width * 0.73
48
- }
49
- // configure height , yMax, xMax
50
- const { horizontal: heightHorizontal } = config.heights
51
- const isHorizontal = orientation === 'horizontal' || config.visualizationType === 'Forest Plot'
52
- const shouldAbbreviate = true
53
- let height = config.aspectRatio ? width * config.aspectRatio : config.visualizationType === 'Forest Plot' ? config.heights['vertical'] : config.heights[orientation]
54
- const xMax = width - runtime.yAxis.size - (visualizationType === 'Combo' ? config.yAxis.rightAxisSize : 0)
55
- let yMax = height - (orientation === 'horizontal' ? 0 : (runtime.xAxis.padding || 0))
56
-
57
- if (config.visualizationType === 'Forest Plot') {
58
- height = height + config.data.length * config.forestPlot.rowHeight
59
- yMax = yMax + config.data.length * config.forestPlot.rowHeight
60
- width = dimensions[0]
61
- }
62
- if (config.brush?.active) {
63
- height = height + config.brush?.height
64
- }
65
-
66
- // hooks % states
67
- const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, data)
68
- const { visSupportsReactTooltip } = useEditorPermissions()
69
- const { hasTopAxis } = useTopAxis(config)
70
- const [animatedChart, setAnimatedChart] = useState(false)
71
- const [point, setPoint] = useState({ x: 0, y: 0 })
72
-
73
- // refs
74
- const triggerRef = useRef()
75
- const svgRef = useRef()
76
- const dataRef = useIntersectionObserver(triggerRef, {
77
- freezeOnceVisible: false
78
- })
79
-
80
- // getters & functions
81
- const getXAxisData = d => (isDateScale(config.runtime.xAxis) ? parseDate(d[config.runtime.originalXAxis.dataKey]).getTime() : d[config.runtime.originalXAxis.dataKey])
82
- const getYAxisData = (d, seriesKey) => d[seriesKey]
83
- const xAxisDataMapped = config.brush.active && brushConfig.data?.length ? brushConfig.data.map(d => getXAxisData(d)) : data.map(d => getXAxisData(d))
84
- const section = config.orientation === 'horizontal' || config.visualizationType === 'Forest Plot' ? 'yAxis' : 'xAxis'
85
- const properties = { data, tableData, config, minValue, maxValue, isAllLine, existPositiveValue, xAxisDataMapped, xMax, yMax }
86
- const { min, max, leftMax, rightMax } = useMinMax(properties)
87
- const { yScaleRight, hasRightAxis } = useRightAxis({ config, yMax, data, updateConfig })
88
- const { xScale, yScale, seriesScale, g1xScale, g2xScale, xScaleNoPadding, xScaleBrush } = useScales({ ...properties, min, max, leftMax, rightMax, dimensions })
89
-
90
- // sets the portal x/y for where tooltips should appear on the page.
91
- const [chartPosition, setChartPosition] = useState(null)
92
- useEffect(() => {
93
- setChartPosition(svgRef?.current?.getBoundingClientRect())
94
- }, [svgRef, config.legend])
95
-
96
- const handleLeftTickFormatting = (tick, index) => {
97
- if (config.useLogScale && tick === 0.1) {
98
- //when logarithmic scale applied change value of first tick
99
- tick = 0
100
- }
101
-
102
- if (config.data && !config.data[index] && visualizationType === 'Forest Plot') return
103
- if (config.visualizationType === 'Forest Plot') return config.data[index][config.xAxis.dataKey]
104
- if (isDateScale(runtime.yAxis)) return formatDate(parseDate(tick))
105
- if (orientation === 'vertical') return formatNumber(tick, 'left', shouldAbbreviate)
106
- return tick
107
- }
108
-
109
- const handleBottomTickFormatting = tick => {
110
- if (config.useLogScale && tick === 0.1) {
111
- // when logarithmic scale applied change value FIRST of tick
112
- tick = 0
113
- }
114
-
115
- if (isDateScale(runtime.xAxis) && config.visualizationType !== 'Forest Plot') return formatDate(tick)
116
- if (orientation === 'horizontal' && config.visualizationType !== 'Forest Plot') return formatNumber(tick, 'left', shouldAbbreviate)
117
- if (config.xAxis.type === 'continuous' && config.visualizationType !== 'Forest Plot') return formatNumber(tick, 'bottom', shouldAbbreviate)
118
- if (config.visualizationType === 'Forest Plot') return formatNumber(tick, 'left', config.dataFormat.abbreviated, config.runtime.xAxis.prefix, config.runtime.xAxis.suffix, Number(config.dataFormat.roundTo))
119
- return tick
120
- }
121
-
122
- const countNumOfTicks = axis => {
123
- const { numTicks } = runtime[axis]
124
- let tickCount = undefined
125
-
126
- if (axis === 'yAxis') {
127
- tickCount = isHorizontal && !numTicks ? data.length : isHorizontal && numTicks ? numTicks : !isHorizontal && !numTicks ? undefined : !isHorizontal && numTicks && numTicks
128
- // to fix edge case of small numbers with decimals
129
- if (tickCount === undefined && !config.dataFormat.roundTo) {
130
- // then it is set to Auto
131
- if (Number(max) <= 3) {
132
- tickCount = 2
133
- } else {
134
- tickCount = 4 // same default as standalone components
135
- }
136
- }
137
- if (Number(tickCount) > Number(max)) {
138
- // cap it and round it so its an integer
139
- tickCount = Number(min) < 0 ? Math.round(max) * 2 : Math.round(max)
140
- }
141
- }
142
-
143
- if (axis === 'xAxis') {
144
- tickCount = isHorizontal && !numTicks ? undefined : isHorizontal && numTicks ? numTicks : !isHorizontal && !numTicks ? undefined : !isHorizontal && numTicks && numTicks
145
- if (isHorizontal && tickCount === undefined && !config.dataFormat.roundTo) {
146
- // then it is set to Auto
147
- // - check for small numbers situation
148
- if (max <= 3) {
149
- tickCount = 2
150
- } else {
151
- tickCount = 4 // same default as standalone components
152
- }
153
- }
154
-
155
- if (config.visualizationType === 'Forest Plot') {
156
- tickCount = config.yAxis.numTicks !== '' ? config.yAxis.numTicks : 4
157
- }
158
- }
159
-
160
- return tickCount
161
- }
162
-
163
- // Tooltip Helpers
164
- const { tooltipData, showTooltip, hideTooltip, tooltipOpen, tooltipLeft, tooltipTop } = useTooltip()
165
-
166
- // prettier-ignore
167
- const {
168
- handleTooltipMouseOver,
169
- handleTooltipClick,
170
- handleTooltipMouseOff,
171
- tooltipStyles,
172
- TooltipListItem,
173
- getXValueFromCoordinateDate,
174
- getXValueFromCoordinate
175
- } = useCoveTooltip({
176
- xScale,
177
- yScale,
178
- showTooltip,
179
- hideTooltip
180
- })
181
-
182
- // Make sure the chart is visible if in the editor
183
- /* eslint-disable react-hooks/exhaustive-deps */
184
- useEffect(() => {
185
- const element = document.querySelector('.isEditor')
186
- if (element) {
187
- // parent element is visible
188
- setAnimatedChart(prevState => true)
189
- }
190
- }) /* eslint-disable-line */
191
-
192
- // If the chart is in view, set to animate if it has not already played
193
- useEffect(() => {
194
- if (dataRef?.isIntersecting === true && config.animate) {
195
- setTimeout(() => {
196
- setAnimatedChart(prevState => true)
197
- }, 500)
198
- }
199
- }, [dataRef?.isIntersecting, config.animate])
200
-
201
- const chartHasTooltipGuides = () => {
202
- const { visualizationType } = config
203
- if (visualizationType === 'Combo' && runtime.forecastingSeriesKeys > 0) return true
204
- if (visualizationType === 'Area Chart') return true
205
- if (visualizationType === 'Line') return true
206
- if (visualizationType === 'Bar') return true
207
- return false
208
- }
209
-
210
- const padding = orientation === 'horizontal' ? Number(config.xAxis.padding) : Number(config.yAxis.size)
211
- const fontSize = { small: 16, medium: 18, large: 20 }
212
-
213
- const handleNumTicks = () => {
214
- // On forest plots we need to return every "study" or y axis value.
215
- if (config.visualizationType === 'Forest Plot') return config.data.length
216
- return countNumOfTicks('yAxis')
217
- }
218
-
219
- const onMouseMove = event => {
220
- const svgRect = event.currentTarget.getBoundingClientRect()
221
- const x = event.clientX - svgRect.left
222
- const y = event.clientY - svgRect.top
223
-
224
- setPoint({
225
- x,
226
- y
227
- })
228
- }
229
-
230
- const generatePairedBarAxis = () => {
231
- let axisMaxHeight = 40;
232
-
233
- return <>
234
- <AxisBottom top={yMax} left={Number(runtime.yAxis.size)} label={runtime.xAxis.label} tickFormat={isDateScale(runtime.xAxis) ? formatDate : formatNumber} scale={g1xScale} stroke='#333' tickStroke='#333' numTicks={runtime.xAxis.numTicks || undefined}>
235
- {props => {
236
- return (
237
- <Group className='bottom-axis'>
238
- {props.ticks.map((tick, i) => {
239
- const angle = tick.index !== 0 ? config.yAxis.tickRotation : 0
240
- const textAnchor = tick.index !== 0 && config.yAxis.tickRotation && config.yAxis.tickRotation > 0 ? 'end' : 'middle'
241
-
242
- const textWidth = getTextWidth(tick.value, `normal ${fontSize[config.fontSize]}px sans-serif`)
243
- const axisHeight = textWidth * Math.sin(angle * (Math.PI / 180)) + 25;
244
-
245
- if(axisHeight > axisMaxHeight) axisMaxHeight = axisHeight
246
-
247
- return (
248
- <Group key={`vx-tick-${tick.value}-${i}`} className={'vx-axis-tick'}>
249
- {!runtime.yAxis.hideTicks && <Line from={tick.from} to={tick.to} stroke='#333' />}
250
- {!runtime.yAxis.hideLabel && (
251
- <Text x={tick.to.x} y={tick.to.y} angle={-angle} verticalAnchor='start' textAnchor={textAnchor}>
252
- {formatNumber(tick.value, 'left')}
253
- </Text>
254
- )}
255
- </Group>
256
- )
257
- })}
258
- {!runtime.yAxis.hideAxis && <Line from={props.axisFromPoint} to={props.axisToPoint} stroke='#333' />}
259
- </Group>
260
- )
261
- }}
262
- </AxisBottom>
263
- <AxisBottom
264
- top={yMax}
265
- left={Number(runtime.yAxis.size)}
266
- label={runtime.xAxis.label}
267
- tickFormat={isDateScale(runtime.xAxis) ? formatDate : runtime.xAxis.dataKey !== 'Year' ? formatNumber : tick => tick}
268
- scale={g2xScale}
269
- stroke='#333'
270
- tickStroke='#333'
271
- numTicks={runtime.xAxis.numTicks || undefined}
272
- >
273
- {props => {
274
- return (
275
- <>
276
- <Group className='bottom-axis'>
277
- {props.ticks.map((tick, i) => {
278
- const angle = tick.index !== 0 ? config.yAxis.tickRotation : 0
279
- const textAnchor = tick.index !== 0 && config.yAxis.tickRotation && config.yAxis.tickRotation > 0 ? 'end' : 'middle'
280
-
281
- const textWidth = getTextWidth(tick.value, `normal ${fontSize[config.fontSize]}px sans-serif`)
282
- const axisHeight = textWidth * Math.sin(angle * (Math.PI / 180)) + 25;
283
-
284
- if(axisHeight > axisMaxHeight) axisMaxHeight = axisHeight
285
-
286
- return (
287
- <Group key={`vx-tick-${tick.value}-${i}`} className={'vx-axis-tick'}>
288
- {!runtime.yAxis.hideTicks && <Line from={tick.from} to={tick.to} stroke='#333' />}
289
- {!runtime.yAxis.hideLabel && (
290
- <Text x={tick.to.x} y={tick.to.y} angle={-angle} verticalAnchor='start' textAnchor={textAnchor}>
291
- {formatNumber(tick.value, 'left')}
292
- </Text>
293
- )}
294
- </Group>
295
- )
296
- })}
297
- {!runtime.yAxis.hideAxis && <Line from={props.axisFromPoint} to={props.axisToPoint} stroke='#333' />}
298
- </Group>
299
- <Group>
300
- <Text x={xMax / 2} y={axisMaxHeight + 20} stroke='#333' textAnchor={'middle'} verticalAnchor='start'>
301
- {runtime.xAxis.label}
302
- </Text>
303
- </Group>
304
- {svgRef.current ? svgRef.current.setAttribute('height', (Number(height) + Number(axisMaxHeight) + (runtime.xAxis.label ? 50 : 0)) + 'px') : ''}
305
- </>
306
- )
307
- }}
308
- </AxisBottom>
309
- </>
310
- }
311
-
312
- return isNaN(width) ? (
313
- <React.Fragment></React.Fragment>
314
- ) : (
315
- <ErrorBoundary component='LinearChart'>
316
- {/* ! Notice - div needed for tooltip boundaries (flip/flop) */}
317
- <div style={{ width: `${width}px`, overflow: 'visible' }} className='tooltip-boundary'>
318
- <svg
319
- // onMouseLeave={() => setPoint(null)}
320
- onMouseMove={onMouseMove}
321
- width={'100%'}
322
- height={height}
323
- className={`linear ${config.animate ? 'animated' : ''} ${animatedChart && config.animate ? 'animate' : ''} ${debugSvg && 'debug'}`}
324
- role='img'
325
- aria-label={handleChartAriaLabels(config)}
326
- ref={svgRef}
327
- style={{ overflow: 'visible' }}
328
- >
329
- <Bar width={width} height={height} fill={'transparent'}></Bar> {/* Highlighted regions */}
330
- {/* Y axis */}
331
- {!['Spark Line', 'Forest Plot'].includes(visualizationType) && (
332
- <AxisLeft scale={yScale} tickLength={config.useLogScale ? 6 : 8} left={Number(runtime.yAxis.size) - config.yAxis.axisPadding} label={runtime.yAxis.label || runtime.yAxis.label} stroke='#333' tickFormat={(tick, i) => handleLeftTickFormatting(tick, i)} numTicks={handleNumTicks()}>
333
- {props => {
334
- const axisCenter = config.orientation === 'horizontal' ? (props.axisToPoint.y - props.axisFromPoint.y) / 2 : (props.axisFromPoint.y - props.axisToPoint.y) / 2
335
- const horizontalTickOffset = yMax / props.ticks.length / 2 - (yMax / props.ticks.length) * (1 - config.barThickness) + 5
336
- return (
337
- <Group className='left-axis'>
338
- {props.ticks.map((tick, i) => {
339
- const minY = props.ticks[0].to.y
340
- const barMinHeight = 15 // 15 is the min height for bars by default
341
- const showTicks = String(tick.value).startsWith('1') || tick.value === 0.1 ? 'block' : 'none'
342
- const tickLength = showTicks === 'block' ? 7 : 0
343
- const to = { x: tick.to.x - tickLength, y: tick.to.y }
344
-
345
- return (
346
- <Group key={`vx-tick-${tick.value}-${i}`} className={'vx-axis-tick'}>
347
- {!runtime.yAxis.hideTicks && <Line key={`${tick.value}--hide-hideTicks`} from={tick.from} to={config.useLogScale ? to : tick.to} stroke={config.yAxis.tickColor} display={orientation === 'horizontal' ? 'none' : 'block'} />}
348
-
349
- {runtime.yAxis.gridLines ? <Line key={`${tick.value}--hide-hideGridLines`} display={(config.useLogScale && showTicks).toString()} from={{ x: tick.from.x + xMax, y: tick.from.y }} to={tick.from} stroke='rgba(0,0,0,0.3)' /> : ''}
350
-
351
- {orientation === 'horizontal' && visualizationSubType !== 'stacked' && config.yAxis.labelPlacement === 'On Date/Category Axis' && !config.yAxis.hideLabel && (
352
- <Text
353
- transform={`translate(${tick.to.x - 5}, ${config.isLollipopChart ? tick.to.y - minY : tick.to.y - minY + (Number(config.barHeight * config.series.length) - barMinHeight) / 2}) rotate(-${config.runtime.horizontal ? config.runtime.yAxis.tickRotation || 0 : 0})`}
354
- verticalAnchor={'start'}
355
- textAnchor={'end'}
356
- >
357
- {tick.formattedValue}
358
- </Text>
359
- )}
360
-
361
- {orientation === 'horizontal' && visualizationSubType === 'stacked' && config.yAxis.labelPlacement === 'On Date/Category Axis' && !config.yAxis.hideLabel && (
362
- <Text transform={`translate(${tick.to.x - 5}, ${tick.to.y - minY + (Number(config.barHeight) - barMinHeight) / 2}) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`} verticalAnchor={'start'} textAnchor={'end'}>
363
- {tick.formattedValue}
364
- </Text>
365
- )}
366
-
367
- {orientation === 'horizontal' && visualizationType === 'Paired Bar' && !config.yAxis.hideLabel && (
368
- <Text transform={`translate(${tick.to.x - 5}, ${tick.to.y - minY + Number(config.barHeight) / 2}) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`} textAnchor={'end'} verticalAnchor='middle'>
369
- {tick.formattedValue}
370
- </Text>
371
- )}
372
- {orientation === 'horizontal' && visualizationType === 'Deviation Bar' && !config.yAxis.hideLabel && (
373
- <Text transform={`translate(${tick.to.x - 5}, ${config.isLollipopChart ? tick.to.y - minY + 2 : tick.to.y - minY + Number(config.barHeight) / 2}) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`} textAnchor={'end'} verticalAnchor='middle'>
374
- {tick.formattedValue}
375
- </Text>
376
- )}
377
-
378
- {orientation === 'vertical' && visualizationType !== 'Paired Bar' && !config.yAxis.hideLabel && (
379
- <Text
380
- display={config.useLogScale ? showTicks : 'block'}
381
- dx={config.useLogScale ? -6 : 0}
382
- x={config.runtime.horizontal ? tick.from.x + 2 : tick.to.x}
383
- y={tick.to.y + (config.runtime.horizontal ? horizontalTickOffset : 0)}
384
- angle={-Number(config.yAxis.tickRotation) || 0}
385
- verticalAnchor={config.runtime.horizontal ? 'start' : 'middle'}
386
- textAnchor={config.runtime.horizontal ? 'start' : 'end'}
387
- fill={config.yAxis.tickLabelColor}
388
- >
389
- {tick.formattedValue}
390
- </Text>
391
- )}
392
- </Group>
393
- )
394
- })}
395
- {!config.yAxis.hideAxis && <Line from={props.axisFromPoint} to={runtime.horizontal ? { x: 0, y: config.visualizationType === 'Forest Plot' ? height : Number(heightHorizontal) } : props.axisToPoint} stroke='#000' />}
396
- {yScale.domain()[0] < 0 && <Line from={{ x: props.axisFromPoint.x, y: yScale(0) }} to={{ x: xMax, y: yScale(0) }} stroke='#333' />}
397
- {visualizationType === 'Bar' && orientation === 'horizontal' && xScale.domain()[0] < 0 && <Line from={{ x: xScale(0), y: 0 }} to={{ x: xScale(0), y: yMax }} stroke='#333' strokeWidth={2} />}
398
- <Text className='y-label' textAnchor='middle' verticalAnchor='start' transform={`translate(${-1 * runtime.yAxis.size}, ${axisCenter}) rotate(-90)`} fontWeight='bold' fill={config.yAxis.labelColor}>
399
- {props.label}
400
- </Text>
401
- </Group>
402
- )
403
- }}
404
- </AxisLeft>
405
- )}
406
- {/* Right Axis */}
407
- {hasRightAxis && (
408
- <AxisRight scale={yScaleRight} left={Number(width - config.yAxis.rightAxisSize)} label={config.yAxis.rightLabel} tickFormat={tick => formatNumber(tick, 'right')} numTicks={runtime.yAxis.rightNumTicks || undefined} labelOffset={45}>
409
- {props => {
410
- const axisCenter = config.orientation === 'horizontal' ? (props.axisToPoint.y - props.axisFromPoint.y) / 2 : (props.axisFromPoint.y - props.axisToPoint.y) / 2
411
- const horizontalTickOffset = yMax / props.ticks.length / 2 - (yMax / props.ticks.length) * (1 - config.barThickness) + 5
412
- return (
413
- <Group className='right-axis'>
414
- {props.ticks.map((tick, i) => {
415
- return (
416
- <Group key={`vx-tick-${tick.value}-${i}`} className='vx-axis-tick'>
417
- {!runtime.yAxis.rightHideTicks && <Line from={tick.from} to={tick.to} display={runtime.horizontal ? 'none' : 'block'} stroke={config.yAxis.rightAxisTickColor} />}
418
-
419
- {runtime.yAxis.rightGridLines ? <Line from={{ x: tick.from.x + xMax, y: tick.from.y }} to={tick.from} stroke='rgba(0,0,0,0.3)' /> : ''}
420
-
421
- {!config.yAxis.rightHideLabel && (
422
- <Text x={tick.to.x} y={tick.to.y + (runtime.horizontal ? horizontalTickOffset : 0)} verticalAnchor={runtime.horizontal ? 'start' : 'middle'} textAnchor={'start'} fill={config.yAxis.rightAxisTickLabelColor}>
423
- {tick.formattedValue}
424
- </Text>
425
- )}
426
- </Group>
427
- )
428
- })}
429
- {!config.yAxis.rightHideAxis && <Line from={props.axisFromPoint} to={props.axisToPoint} stroke='#333' />}
430
- <Text className='y-label' textAnchor='middle' verticalAnchor='start' transform={`translate(${config.yAxis.rightLabelOffsetSize ? config.yAxis.rightLabelOffsetSize : 0}, ${axisCenter}) rotate(-90)`} fontWeight='bold' fill={config.yAxis.rightAxisLabelColor}>
431
- {props.label}
432
- </Text>
433
- </Group>
434
- )
435
- }}
436
- </AxisRight>
437
- )}
438
- {hasTopAxis && config.topAxis.hasLine && (
439
- <AxisTop
440
- stroke='#333'
441
- left={Number(runtime.yAxis.size)}
442
- scale={xScale}
443
- hideTicks
444
- hideZero
445
- tickLabelProps={() => ({
446
- fill: 'transparent'
447
- })}
448
- />
449
- )}
450
- {/* X axis */}
451
- {visualizationType !== 'Paired Bar' && visualizationType !== 'Spark Line' && (
452
- <AxisBottom
453
- top={runtime.horizontal && config.visualizationType !== 'Forest Plot' ? Number(heightHorizontal) + Number(config.xAxis.axisPadding) : config.visualizationType === 'Forest Plot' ? yMax + Number(config.xAxis.axisPadding) : yMax}
454
- left={config.visualizationType !== 'Forest Plot' ? Number(runtime.yAxis.size) : 0}
455
- label={config[section].label}
456
- tickFormat={handleBottomTickFormatting}
457
- scale={xScale}
458
- stroke='#333'
459
- numTicks={countNumOfTicks('xAxis')}
460
- tickStroke='#333'
461
- tickValues={config.xAxis.manual ? getTickValues(xAxisDataMapped, xScale, config.xAxis.type === 'date-time' ? countNumOfTicks('xAxis') : config.xAxis.manualStep) : undefined}
462
- >
463
- {props => {
464
- const axisCenter = config.visualizationType !== 'Forest Plot' ? (props.axisToPoint.x - props.axisFromPoint.x) / 2 : dimensions[0] / 2
465
- const containsMultipleWords = inputString => /\s/.test(inputString)
466
- const ismultiLabel = props.ticks.some(tick => containsMultipleWords(tick.value))
467
-
468
- // Calculate sumOfTickWidth here, before map function
469
- const defaultTickLength = 8
470
- const tickWidthMax = Math.max(...props.ticks.map(tick => getTextWidth(tick.formattedValue, `normal ${fontSize[config.fontSize]}px sans-serif`)))
471
- // const marginTop = 20 // moved to top bc need for yMax calcs
472
- const accumulator = ismultiLabel ? 180 : 100
473
-
474
- const textWidths = props.ticks.map(tick => getTextWidth(tick.formattedValue, `normal ${fontSize[config.fontSize]}px sans-serif`))
475
- const sumOfTickWidth = textWidths.reduce((a, b) => a + b, accumulator)
476
- const spaceBetweenEachTick = (xMax - sumOfTickWidth) / (props.ticks.length - 1)
477
-
478
- // Check if ticks are overlapping
479
- // Determine the position of each tick
480
- let positions = [0] // The first tick is at position 0
481
- for (let i = 1; i < textWidths.length; i++) {
482
- // The position of each subsequent tick is the position of the previous tick
483
- // plus the width of the previous tick and the space
484
- positions[i] = positions[i - 1] + textWidths[i - 1] + spaceBetweenEachTick
485
- }
486
-
487
- // Check if ticks are overlapping
488
- let areTicksTouching = false
489
- textWidths.forEach((_, i) => {
490
- if (positions[i] + textWidths[i] > positions[i + 1]) {
491
- areTicksTouching = true
492
- return
493
- }
494
- })
495
-
496
- const dynamicMarginTop = areTicksTouching && config.isResponsiveTicks ? tickWidthMax + defaultTickLength + 20 : 0
497
- const rotation = Number(config.xAxis.tickRotation) > 0 ? Number(config.xAxis.tickRotation) : 0
498
-
499
- config.dynamicMarginTop = dynamicMarginTop
500
- config.xAxis.tickWidthMax = tickWidthMax
501
-
502
- let axisMaxHeight = 40;
503
-
504
- const axisContents = <Group className='bottom-axis' width={dimensions[0]}>
505
- {props.ticks.map((tick, i, propsTicks) => {
506
- // when using LogScale show major ticks values only
507
- const showTick = String(tick.value).startsWith('1') || tick.value === 0.1 ? 'block' : 'none'
508
- const tickLength = showTick === 'block' ? 16 : defaultTickLength
509
- const to = { x: tick.to.x, y: tickLength }
510
- const textWidth = getTextWidth(tick.formattedValue, `normal ${fontSize[config.fontSize]}px sans-serif`)
511
- const limitedWidth = 100 / propsTicks.length
512
- //reset rotations by updating config
513
- config.yAxis.tickRotation = config.isResponsiveTicks && config.orientation === 'horizontal' ? 0 : config.yAxis.tickRotation
514
- config.xAxis.tickRotation = config.isResponsiveTicks && config.orientation === 'vertical' ? 0 : config.xAxis.tickRotation
515
- //configure rotation
516
-
517
- const tickRotation = config.isResponsiveTicks && areTicksTouching ? -Number(config.xAxis.maxTickRotation) || -90 : -Number(config.runtime.xAxis.tickRotation)
518
-
519
- const axisHeight = textWidth * Math.sin(tickRotation * -1 * (Math.PI / 180)) + 25;
520
-
521
- if(axisHeight > axisMaxHeight) axisMaxHeight = axisHeight
522
-
523
- return (
524
- <Group key={`vx-tick-${tick.value}-${i}`} className={'vx-axis-tick'}>
525
- {!config.xAxis.hideTicks && <Line from={tick.from} to={orientation === 'horizontal' && config.useLogScale ? to : tick.to} stroke={config.xAxis.tickColor} strokeWidth={showTick === 'block' && config.useLogScale ? 1.3 : 1} />}
526
- {!config.xAxis.hideLabel && (
527
- <Text
528
- dy={config.orientation === 'horizontal' && config.useLogScale ? 8 : 0}
529
- display={config.orientation === 'horizontal' && config.useLogScale ? showTick : 'block'}
530
- x={tick.to.x}
531
- y={tick.to.y}
532
- angle={tickRotation}
533
- verticalAnchor={tickRotation < -50 ? 'middle' : 'start'}
534
- textAnchor={tickRotation ? 'end' : 'middle'}
535
- width={areTicksTouching && !config.isResponsiveTicks && !Number(config[section].tickRotation) ? limitedWidth : undefined}
536
- fill={config.xAxis.tickLabelColor}
537
- >
538
- {tick.formattedValue}
539
- </Text>
540
- )}
541
- </Group>
542
- )
543
- })}
544
- {!config.xAxis.hideAxis && <Line from={props.axisFromPoint} to={props.axisToPoint} stroke='#333' />}
545
- <Text
546
- x={axisCenter}
547
- y={axisMaxHeight + 20}
548
- textAnchor='middle'
549
- verticalAnchor='start'
550
- fontWeight='bold'
551
- fill={config.xAxis.labelColor}
552
- >
553
- {props.label}
554
- </Text>
555
- </Group>
556
-
557
- if(svgRef.current) svgRef.current.setAttribute('height',(Number(height) + Number(axisMaxHeight) + (runtime.xAxis.label ? 50 : 0)) + 'px')
558
-
559
- return axisContents
560
- }}
561
- </AxisBottom>
562
- )}
563
- {visualizationType === 'Paired Bar' && generatePairedBarAxis()}
564
- {visualizationType === 'Deviation Bar' && config.series?.length === 1 && <DeviationBar animatedChart={animatedChart} xScale={xScale} yScale={yScale} width={xMax} height={yMax} />}
565
- {visualizationType === 'Paired Bar' && <PairedBarChart originalWidth={width} width={xMax} height={yMax} />}
566
- {visualizationType === 'Scatter Plot' && (
567
- <ScatterPlot
568
- xScale={xScale}
569
- yScale={yScale}
570
- getXAxisData={getXAxisData}
571
- getYAxisData={getYAxisData}
572
- xMax={xMax}
573
- yMax={yMax}
574
- handleTooltipMouseOver={handleTooltipMouseOver}
575
- handleTooltipMouseOff={handleTooltipMouseOff}
576
- handleTooltipClick={handleTooltipClick}
577
- tooltipData={tooltipData}
578
- showTooltip={showTooltip}
579
- />
580
- )}
581
- {visualizationType === 'Box Plot' && <BoxPlot xScale={xScale} yScale={yScale} />}
582
- {((visualizationType === 'Area Chart' && config.visualizationSubType === 'regular') || visualizationType === 'Combo') && (
583
- <AreaChart xScale={xScale} yScale={yScale} yMax={yMax} xMax={xMax} chartRef={svgRef} width={xMax} height={yMax} handleTooltipMouseOver={handleTooltipMouseOver} handleTooltipMouseOff={handleTooltipMouseOff} tooltipData={tooltipData} showTooltip={showTooltip} />
584
- )}
585
- {((visualizationType === 'Area Chart' && config.visualizationSubType === 'stacked') || visualizationType === 'Combo') && (
586
- <AreaChartStacked xScale={xScale} yScale={yScale} yMax={yMax} xMax={xMax} chartRef={svgRef} width={xMax} height={yMax} handleTooltipMouseOver={handleTooltipMouseOver} handleTooltipMouseOff={handleTooltipMouseOff} tooltipData={tooltipData} showTooltip={showTooltip} />
587
- )}
588
- {(visualizationType === 'Bar' || visualizationType === 'Combo') && (
589
- <BarChart
590
- xScale={xScale}
591
- yScale={yScale}
592
- seriesScale={seriesScale}
593
- xMax={xMax}
594
- yMax={yMax}
595
- getXAxisData={getXAxisData}
596
- getYAxisData={getYAxisData}
597
- animatedChart={animatedChart}
598
- visible={animatedChart}
599
- handleTooltipMouseOver={handleTooltipMouseOver}
600
- handleTooltipMouseOff={handleTooltipMouseOff}
601
- handleTooltipClick={handleTooltipClick}
602
- tooltipData={tooltipData}
603
- showTooltip={showTooltip}
604
- chartRef={svgRef}
605
- />
606
- )}
607
- {(visualizationType === 'Line' || visualizationType === 'Combo') && (
608
- <LineChart
609
- xScale={xScale}
610
- yScale={yScale}
611
- getXAxisData={getXAxisData}
612
- getYAxisData={getYAxisData}
613
- xMax={xMax}
614
- yMax={yMax}
615
- seriesStyle={config.series}
616
- handleTooltipMouseOver={handleTooltipMouseOver}
617
- handleTooltipMouseOff={handleTooltipMouseOff}
618
- handleTooltipClick={handleTooltipClick}
619
- tooltipData={tooltipData}
620
- showTooltip={showTooltip}
621
- chartRef={svgRef}
622
- />
623
- )}
624
- {(visualizationType === 'Forecasting' || visualizationType === 'Combo') && (
625
- <Forecasting
626
- showTooltip={showTooltip}
627
- tooltipData={tooltipData}
628
- xScale={xScale}
629
- yScale={yScale}
630
- width={xMax}
631
- le
632
- height={yMax}
633
- xScaleNoPadding={xScaleNoPadding}
634
- chartRef={svgRef}
635
- getXValueFromCoordinate={getXValueFromCoordinate}
636
- handleTooltipMouseOver={handleTooltipMouseOver}
637
- handleTooltipMouseOff={handleTooltipMouseOff}
638
- isBrush={false}
639
- />
640
- )}
641
- {/* y anchors */}
642
- {config.yAxis.anchors &&
643
- config.yAxis.anchors.map(anchor => {
644
- return <Line strokeDasharray={handleLineType(anchor.lineStyle)} stroke='rgba(0,0,0,1)' className='customAnchor' from={{ x: 0 + config.yAxis.size, y: yScale(anchor.value) }} to={{ x: xMax, y: yScale(anchor.value) }} display={runtime.horizontal ? 'none' : 'block'} />
645
- })}
646
- {visualizationType === 'Forest Plot' && (
647
- <ForestPlot
648
- xScale={xScale}
649
- yScale={yScale}
650
- seriesScale={seriesScale}
651
- width={width}
652
- height={height}
653
- getXAxisData={getXAxisData}
654
- getYAxisData={getYAxisData}
655
- animatedChart={animatedChart}
656
- visible={animatedChart}
657
- handleTooltipMouseOver={handleTooltipMouseOver}
658
- handleTooltipMouseOff={handleTooltipMouseOff}
659
- handleTooltipClick={handleTooltipClick}
660
- tooltipData={tooltipData}
661
- showTooltip={showTooltip}
662
- chartRef={svgRef}
663
- config={config}
664
- />
665
- )}
666
- {/*Zoom Brush */}
667
- {['Line', 'Bar', 'Combo', 'Area Chart'].includes(config.visualizationType) && !isHorizontal && <ZoomBrush xScaleBrush={xScaleBrush} yScale={yScale} xMax={xMax} yMax={yMax} />}
668
- {/* Line chart */}
669
- {/* TODO: Make this just line or combo? */}
670
- {visualizationType !== 'Bar' && visualizationType !== 'Paired Bar' && visualizationType !== 'Box Plot' && visualizationType !== 'Area Chart' && visualizationType !== 'Scatter Plot' && visualizationType !== 'Deviation Bar' && visualizationType !== 'Forecasting' && (
671
- <>
672
- <LineChart xScale={xScale} yScale={yScale} getXAxisData={getXAxisData} getYAxisData={getYAxisData} xMax={xMax} yMax={yMax} seriesStyle={config.series} />
673
- </>
674
- )}
675
- {/* y anchors */}
676
- {config.yAxis.anchors &&
677
- config.yAxis.anchors.map((anchor, index) => {
678
- let anchorPosition = yScale(anchor.value)
679
- // have to move up
680
- // const padding = orientation === 'horizontal' ? Number(config.xAxis.size) : Number(config.yAxis.size)
681
- if (!anchor.value) return
682
- const middleOffset = orientation === 'horizontal' && visualizationType === 'Bar' ? config.barHeight / 4 : 0
683
-
684
- if (!anchorPosition) return
685
-
686
- return (
687
- // prettier-ignore
688
- <Line
689
- key={`yAxis-${anchor.value}--${index}`}
690
- strokeDasharray={handleLineType(anchor.lineStyle)}
691
- stroke={anchor.color ? anchor.color : 'rgba(0,0,0,1)'}
692
- className='anchor-y'
693
- from={{ x: 0 + padding, y: anchorPosition - middleOffset}}
694
- to={{ x: width - config.yAxis.rightAxisSize, y: anchorPosition - middleOffset }}
695
- />
696
- )
697
- })}
698
- {/* x anchors */}
699
- {config.xAxis.anchors &&
700
- config.xAxis.anchors.map((anchor, index) => {
701
- let newX = xAxis
702
- if (orientation === 'horizontal') {
703
- newX = yAxis
704
- }
705
-
706
- let anchorPosition = isDateScale(newX) ? xScale(parseDate(anchor.value, false)) : xScale(anchor.value)
707
-
708
- // have to move up
709
- // const padding = orientation === 'horizontal' ? Number(config.xAxis.size) : Number(config.yAxis.size)
710
-
711
- if (!anchorPosition) return
712
-
713
- return (
714
- // prettier-ignore
715
- <Line
716
- key={`xAxis-${anchor.value}--${index}`}
717
- strokeDasharray={handleLineType(anchor.lineStyle)}
718
- stroke={anchor.color ? anchor.color : 'rgba(0,0,0,1)'}
719
- fill={anchor.color ? anchor.color : 'rgba(0,0,0,1)'}
720
- className='anchor-x'
721
- from={{ x: Number(anchorPosition) + Number(padding), y: 0 }}
722
- to={{ x: Number(anchorPosition) + Number(padding), y: yMax }}
723
- />
724
- )
725
- })}
726
- {/* we are handling regions in bar charts differently, so that we can calculate the bar group into the region space. */}
727
- {/* prettier-ignore */}
728
- {config.visualizationType !== 'Bar' && config.visualizationType !== 'Combo' && (
729
- <Regions xScale={xScale} handleTooltipClick={handleTooltipClick} handleTooltipMouseOff={handleTooltipMouseOff} handleTooltipMouseOver={handleTooltipMouseOver} showTooltip={showTooltip} hideTooltip={hideTooltip} tooltipData={tooltipData} yMax={yMax} width={width} />
730
- )}
731
- {chartHasTooltipGuides && showTooltip && tooltipData && config.visual.verticalHoverLine && (
732
- <Group key='tooltipLine-vertical' className='vertical-tooltip-line'>
733
- <Line from={{ x: tooltipData.dataXPosition - 10, y: 0 }} to={{ x: tooltipData.dataXPosition - 10, y: yMax }} stroke={'black'} strokeWidth={1} pointerEvents='none' strokeDasharray='5,5' className='vertical-tooltip-line' />
734
- </Group>
735
- )}
736
- {chartHasTooltipGuides && showTooltip && tooltipData && config.visual.horizontalHoverLine && (
737
- <Group key='tooltipLine-horizontal' className='horizontal-tooltip-line' left={config.yAxis.size ? config.yAxis.size : 0}>
738
- <Line from={{ x: 0, y: tooltipData.dataYPosition }} to={{ x: xMax, y: tooltipData.dataYPosition }} stroke={'black'} strokeWidth={1} pointerEvents='none' strokeDasharray='5,5' className='horizontal-tooltip-line' />
739
- </Group>
740
- )}
741
- {config.filters && config.filters.values.length === 0 && data.length === 0 && (
742
- <Text x={Number(config.yAxis.size) + Number(xMax / 2)} y={height / 2 - config.xAxis.padding / 2} textAnchor='middle'>
743
- {config.chartMessage.noData}
744
- </Text>
745
- )}
746
- {config.visualizationType === 'Bar' && config.tooltips.singleSeries && config.visual.horizontalHoverLine && (
747
- <Group key='tooltipLine-horizontal' className='horizontal-tooltip-line' left={config.yAxis.size ? config.yAxis.size : 0}>
748
- <Line from={{ x: 0, y: point.y }} to={{ x: xMax, y: point.y }} stroke={'black'} strokeWidth={1} pointerEvents='none' strokeDasharray='5,5' className='horizontal-tooltip-line' />
749
- </Group>
750
- )}
751
- {config.visualizationType === 'Bar' && config.tooltips.singleSeries && config.visual.verticalHoverLine && (
752
- <Group key='tooltipLine-vertical' className='vertical-tooltip-line'>
753
- <Line from={{ x: point.x, y: 0 }} to={{ x: point.x, y: yMax }} stroke={'black'} strokeWidth={1} pointerEvents='none' strokeDasharray='5,5' className='vertical-tooltip-line' />
754
- </Group>
755
- )}
756
- </svg>
757
- {tooltipData && Object.entries(tooltipData.data).length > 0 && tooltipOpen && showTooltip && tooltipData.dataYPosition && tooltipData.dataXPosition && !config.tooltips.singleSeries && (
758
- <>
759
- <style>{`.tooltip {background-color: rgba(255,255,255, ${config.tooltips.opacity / 100}) !important;`}</style>
760
- <style>{`.tooltip {max-width:300px} !important; word-wrap: break-word; `}</style>
761
- <TooltipWithBounds key={Math.random()} className={'tooltip cdc-open-viz-module'} left={tooltipLeft} top={tooltipTop}>
762
- <ul>{typeof tooltipData === 'object' && Object.entries(tooltipData.data).map((item, index) => <TooltipListItem item={item} key={index} />)}</ul>
763
- </TooltipWithBounds>
764
- </>
765
- )}
766
-
767
- {visSupportsReactTooltip() && <ReactTooltip id={`cdc-open-viz-tooltip-${runtime.uniqueId}`} variant='light' arrowColor='rgba(0,0,0,0)' className='tooltip' style={{ background: `rgba(255,255,255, ${config.tooltips.opacity / 100})`, color: 'black' }} />}
768
- <div className='animation-trigger' ref={triggerRef} />
769
- </div>
770
- </ErrorBoundary>
771
- )
772
- }
773
-
774
- export default LinearChart