@cdc/chart 4.24.9 → 4.24.10

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