@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
|
@@ -24,6 +24,9 @@ import PairedBarChart from './PairedBarChart'
|
|
|
24
24
|
import useIntersectionObserver from './../hooks/useIntersectionObserver'
|
|
25
25
|
import Regions from './Regions'
|
|
26
26
|
|
|
27
|
+
// Helpers
|
|
28
|
+
import { isConvertLineToBarGraph } from '../helpers/isConvertLineToBarGraph'
|
|
29
|
+
|
|
27
30
|
// Hooks
|
|
28
31
|
import useMinMax from '../hooks/useMinMax'
|
|
29
32
|
import useReduceData from '../hooks/useReduceData'
|
|
@@ -32,27 +35,55 @@ import useScales, { getTickValues } from '../hooks/useScales'
|
|
|
32
35
|
import useTopAxis from '../hooks/useTopAxis'
|
|
33
36
|
import { useTooltip as useCoveTooltip } from '../hooks/useTooltip'
|
|
34
37
|
import { useEditorPermissions } from './EditorPanel/useEditorPermissions'
|
|
38
|
+
import Annotation from './Annotations'
|
|
35
39
|
|
|
36
40
|
// styles
|
|
37
41
|
import ZoomBrush from './ZoomBrush'
|
|
38
42
|
|
|
39
43
|
const LinearChart = props => {
|
|
40
|
-
|
|
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
|
+
|
|
41
63
|
// todo: start destructuring this file for conciseness
|
|
42
64
|
const { visualizationType, visualizationSubType, orientation, xAxis, yAxis, runtime, debugSvg } = config
|
|
43
65
|
|
|
66
|
+
const checkLineToBarGraph = () => {
|
|
67
|
+
return isConvertLineToBarGraph(config.visualizationType, data, config.allowLineToBarGraph)
|
|
68
|
+
}
|
|
69
|
+
|
|
44
70
|
// configure width
|
|
45
71
|
let [width] = dimensions
|
|
46
|
-
if (config && config.legend && !config.legend.hide && config.legend
|
|
72
|
+
if (config && config.legend && !config.legend.hide && config.legend?.position !== 'bottom' && ['lg', 'md'].includes(currentViewport)) {
|
|
47
73
|
width = width * 0.73
|
|
48
74
|
}
|
|
49
75
|
// configure height , yMax, xMax
|
|
50
76
|
const { horizontal: heightHorizontal } = config.heights
|
|
51
77
|
const isHorizontal = orientation === 'horizontal' || config.visualizationType === 'Forest Plot'
|
|
52
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)
|
|
53
82
|
let height = config.aspectRatio ? width * config.aspectRatio : config.visualizationType === 'Forest Plot' ? config.heights['vertical'] : config.heights[orientation]
|
|
83
|
+
height = Number(height)
|
|
54
84
|
const xMax = width - runtime.yAxis.size - (visualizationType === 'Combo' ? config.yAxis.rightAxisSize : 0)
|
|
55
|
-
let yMax = height - (orientation === 'horizontal' ? 0 :
|
|
85
|
+
let yMax = height - (orientation === 'horizontal' ? 0 : xAxisSize)
|
|
86
|
+
height += orientation === 'horizontal' ? xAxisSize : 0
|
|
56
87
|
|
|
57
88
|
if (config.visualizationType === 'Forest Plot') {
|
|
58
89
|
height = height + config.data.length * config.forestPlot.rowHeight
|
|
@@ -69,6 +100,7 @@ const LinearChart = props => {
|
|
|
69
100
|
const { hasTopAxis } = useTopAxis(config)
|
|
70
101
|
const [animatedChart, setAnimatedChart] = useState(false)
|
|
71
102
|
const [point, setPoint] = useState({ x: 0, y: 0 })
|
|
103
|
+
const annotationRefs = useRef(null)
|
|
72
104
|
|
|
73
105
|
// refs
|
|
74
106
|
const triggerRef = useRef()
|
|
@@ -80,12 +112,12 @@ const LinearChart = props => {
|
|
|
80
112
|
// getters & functions
|
|
81
113
|
const getXAxisData = d => (isDateScale(config.runtime.xAxis) ? parseDate(d[config.runtime.originalXAxis.dataKey]).getTime() : d[config.runtime.originalXAxis.dataKey])
|
|
82
114
|
const getYAxisData = (d, seriesKey) => d[seriesKey]
|
|
83
|
-
const xAxisDataMapped = config.brush
|
|
115
|
+
const xAxisDataMapped = config.brush?.active && brushConfig.data?.length ? brushConfig.data.map(d => getXAxisData(d)) : data.map(d => getXAxisData(d))
|
|
84
116
|
const section = config.orientation === 'horizontal' || config.visualizationType === 'Forest Plot' ? 'yAxis' : 'xAxis'
|
|
85
117
|
const properties = { data, tableData, config, minValue, maxValue, isAllLine, existPositiveValue, xAxisDataMapped, xMax, yMax }
|
|
86
118
|
const { min, max, leftMax, rightMax } = useMinMax(properties)
|
|
87
119
|
const { yScaleRight, hasRightAxis } = useRightAxis({ config, yMax, data, updateConfig })
|
|
88
|
-
const { xScale, yScale, seriesScale, g1xScale, g2xScale, xScaleNoPadding, xScaleBrush } = useScales({ ...properties, min, max, leftMax, rightMax, dimensions })
|
|
120
|
+
const { xScale, yScale, seriesScale, g1xScale, g2xScale, xScaleNoPadding, xScaleBrush, xScaleAnnotation } = useScales({ ...properties, min, max, leftMax, rightMax, dimensions })
|
|
89
121
|
|
|
90
122
|
// sets the portal x/y for where tooltips should appear on the page.
|
|
91
123
|
const [chartPosition, setChartPosition] = useState(null)
|
|
@@ -102,6 +134,7 @@ const LinearChart = props => {
|
|
|
102
134
|
if (config.data && !config.data[index] && visualizationType === 'Forest Plot') return
|
|
103
135
|
if (config.visualizationType === 'Forest Plot') return config.data[index][config.xAxis.dataKey]
|
|
104
136
|
if (isDateScale(runtime.yAxis)) return formatDate(parseDate(tick))
|
|
137
|
+
if (orientation === 'vertical' && max - min < 3) return formatNumber(tick, 'left', shouldAbbreviate, false, false, '1')
|
|
105
138
|
if (orientation === 'vertical') return formatNumber(tick, 'left', shouldAbbreviate)
|
|
106
139
|
return tick
|
|
107
140
|
}
|
|
@@ -120,7 +153,10 @@ const LinearChart = props => {
|
|
|
120
153
|
}
|
|
121
154
|
|
|
122
155
|
const countNumOfTicks = axis => {
|
|
123
|
-
|
|
156
|
+
let { numTicks } = runtime[axis]
|
|
157
|
+
if (runtime[axis].viewportNumTicks && runtime[axis].viewportNumTicks[currentViewport]) {
|
|
158
|
+
numTicks = runtime[axis].viewportNumTicks[currentViewport]
|
|
159
|
+
}
|
|
124
160
|
let tickCount = undefined
|
|
125
161
|
|
|
126
162
|
if (axis === 'yAxis') {
|
|
@@ -207,7 +243,7 @@ const LinearChart = props => {
|
|
|
207
243
|
return false
|
|
208
244
|
}
|
|
209
245
|
|
|
210
|
-
const padding = orientation === 'horizontal' ? Number(config.xAxis.
|
|
246
|
+
const padding = orientation === 'horizontal' ? Number(config.xAxis.size) : Number(config.yAxis.size)
|
|
211
247
|
const fontSize = { small: 16, medium: 18, large: 20 }
|
|
212
248
|
|
|
213
249
|
const handleNumTicks = () => {
|
|
@@ -216,6 +252,14 @@ const LinearChart = props => {
|
|
|
216
252
|
return countNumOfTicks('yAxis')
|
|
217
253
|
}
|
|
218
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
|
+
|
|
219
263
|
const onMouseMove = event => {
|
|
220
264
|
const svgRect = event.currentTarget.getBoundingClientRect()
|
|
221
265
|
const x = event.clientX - svgRect.left
|
|
@@ -228,60 +272,22 @@ const LinearChart = props => {
|
|
|
228
272
|
}
|
|
229
273
|
|
|
230
274
|
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;
|
|
275
|
+
let axisMaxHeight = 40
|
|
244
276
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
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
|
-
<>
|
|
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 (
|
|
276
282
|
<Group className='bottom-axis'>
|
|
277
283
|
{props.ticks.map((tick, i) => {
|
|
278
284
|
const angle = tick.index !== 0 ? config.yAxis.tickRotation : 0
|
|
279
285
|
const textAnchor = tick.index !== 0 && config.yAxis.tickRotation && config.yAxis.tickRotation > 0 ? 'end' : 'middle'
|
|
280
286
|
|
|
281
287
|
const textWidth = getTextWidth(tick.value, `normal ${fontSize[config.fontSize]}px sans-serif`)
|
|
282
|
-
const axisHeight = textWidth * Math.sin(angle * (Math.PI / 180)) + 25
|
|
288
|
+
const axisHeight = textWidth * Math.sin(angle * (Math.PI / 180)) + 25
|
|
283
289
|
|
|
284
|
-
if(axisHeight > axisMaxHeight) axisMaxHeight = axisHeight
|
|
290
|
+
if (axisHeight > axisMaxHeight) axisMaxHeight = axisHeight
|
|
285
291
|
|
|
286
292
|
return (
|
|
287
293
|
<Group key={`vx-tick-${tick.value}-${i}`} className={'vx-axis-tick'}>
|
|
@@ -296,17 +302,57 @@ const LinearChart = props => {
|
|
|
296
302
|
})}
|
|
297
303
|
{!runtime.yAxis.hideAxis && <Line from={props.axisFromPoint} to={props.axisToPoint} stroke='#333' />}
|
|
298
304
|
</Group>
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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
|
+
)
|
|
310
356
|
}
|
|
311
357
|
|
|
312
358
|
return isNaN(width) ? (
|
|
@@ -316,17 +362,16 @@ const LinearChart = props => {
|
|
|
316
362
|
{/* ! Notice - div needed for tooltip boundaries (flip/flop) */}
|
|
317
363
|
<div style={{ width: `${width}px`, overflow: 'visible' }} className='tooltip-boundary'>
|
|
318
364
|
<svg
|
|
319
|
-
// onMouseLeave={() => setPoint(null)}
|
|
320
365
|
onMouseMove={onMouseMove}
|
|
321
366
|
width={'100%'}
|
|
322
367
|
height={height}
|
|
323
|
-
className={`linear ${config.animate ? 'animated' : ''} ${animatedChart && config.animate ? 'animate' : ''} ${debugSvg && 'debug'}`}
|
|
368
|
+
className={`linear ${config.animate ? 'animated' : ''} ${animatedChart && config.animate ? 'animate' : ''} ${debugSvg && 'debug'} ${isDraggingAnnotation && 'dragging-annotation'}`}
|
|
324
369
|
role='img'
|
|
325
370
|
aria-label={handleChartAriaLabels(config)}
|
|
326
371
|
ref={svgRef}
|
|
327
372
|
style={{ overflow: 'visible' }}
|
|
328
373
|
>
|
|
329
|
-
<Bar width={width} height={height} fill={'transparent'}></Bar> {/* Highlighted regions */}
|
|
374
|
+
{!isDraggingAnnotation && <Bar width={width} height={height} fill={'transparent'}></Bar>} {/* Highlighted regions */}
|
|
330
375
|
{/* Y axis */}
|
|
331
376
|
{!['Spark Line', 'Forest Plot'].includes(visualizationType) && (
|
|
332
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()}>
|
|
@@ -341,12 +386,13 @@ const LinearChart = props => {
|
|
|
341
386
|
const showTicks = String(tick.value).startsWith('1') || tick.value === 0.1 ? 'block' : 'none'
|
|
342
387
|
const tickLength = showTicks === 'block' ? 7 : 0
|
|
343
388
|
const to = { x: tick.to.x - tickLength, y: tick.to.y }
|
|
389
|
+
const displayFirstGridLine = tick.index !== 0 || config.xAxis.hideAxis
|
|
344
390
|
|
|
345
391
|
return (
|
|
346
392
|
<Group key={`vx-tick-${tick.value}-${i}`} className={'vx-axis-tick'}>
|
|
347
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'} />}
|
|
348
394
|
|
|
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)' /> : ''}
|
|
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)' /> : ''}
|
|
350
396
|
|
|
351
397
|
{orientation === 'horizontal' && visualizationSubType !== 'stacked' && config.yAxis.labelPlacement === 'On Date/Category Axis' && !config.yAxis.hideLabel && (
|
|
352
398
|
<Text
|
|
@@ -395,7 +441,7 @@ const LinearChart = props => {
|
|
|
395
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' />}
|
|
396
442
|
{yScale.domain()[0] < 0 && <Line from={{ x: props.axisFromPoint.x, y: yScale(0) }} to={{ x: xMax, y: yScale(0) }} stroke='#333' />}
|
|
397
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} />}
|
|
398
|
-
<Text className='y-label' textAnchor='middle' verticalAnchor='start' transform={`translate(${-1 * runtime.yAxis.size}, ${axisCenter}) rotate(-90)`} fontWeight='bold' fill={config.yAxis.labelColor}>
|
|
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}>
|
|
399
445
|
{props.label}
|
|
400
446
|
</Text>
|
|
401
447
|
</Group>
|
|
@@ -458,7 +504,7 @@ const LinearChart = props => {
|
|
|
458
504
|
stroke='#333'
|
|
459
505
|
numTicks={countNumOfTicks('xAxis')}
|
|
460
506
|
tickStroke='#333'
|
|
461
|
-
tickValues={config.xAxis.manual ? getTickValues(xAxisDataMapped, xScale, config.xAxis.type === 'date-time' ? countNumOfTicks('xAxis') :
|
|
507
|
+
tickValues={config.xAxis.manual ? getTickValues(xAxisDataMapped, xScale, config.xAxis.type === 'date-time' ? countNumOfTicks('xAxis') : getManualStep()) : undefined}
|
|
462
508
|
>
|
|
463
509
|
{props => {
|
|
464
510
|
const axisCenter = config.visualizationType !== 'Forest Plot' ? (props.axisToPoint.x - props.axisFromPoint.x) / 2 : dimensions[0] / 2
|
|
@@ -499,62 +545,57 @@ const LinearChart = props => {
|
|
|
499
545
|
config.dynamicMarginTop = dynamicMarginTop
|
|
500
546
|
config.xAxis.tickWidthMax = tickWidthMax
|
|
501
547
|
|
|
502
|
-
let axisMaxHeight = 40
|
|
548
|
+
let axisMaxHeight = 40
|
|
503
549
|
|
|
504
|
-
const axisContents =
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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
|
|
516
563
|
|
|
517
|
-
|
|
564
|
+
const tickRotation = config.isResponsiveTicks && areTicksTouching ? -Number(config.xAxis.maxTickRotation) || -90 : -Number(config.runtime.xAxis.tickRotation)
|
|
518
565
|
|
|
519
|
-
|
|
566
|
+
const axisHeight = textWidth * Math.sin(tickRotation * -1 * (Math.PI / 180)) + 25
|
|
520
567
|
|
|
521
|
-
|
|
568
|
+
if (axisHeight > axisMaxHeight) axisMaxHeight = axisHeight
|
|
522
569
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
fontWeight='bold'
|
|
551
|
-
fill={config.xAxis.labelColor}
|
|
552
|
-
>
|
|
553
|
-
{props.label}
|
|
554
|
-
</Text>
|
|
555
|
-
</Group>
|
|
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
|
+
)
|
|
556
597
|
|
|
557
|
-
if(svgRef.current) svgRef.current.setAttribute('height',
|
|
598
|
+
if (svgRef.current) svgRef.current.setAttribute('height', Number(height) + Number(axisMaxHeight) + (runtime.xAxis.label ? 50 : 0) + 'px')
|
|
558
599
|
|
|
559
600
|
return axisContents
|
|
560
601
|
}}
|
|
@@ -585,7 +626,7 @@ const LinearChart = props => {
|
|
|
585
626
|
{((visualizationType === 'Area Chart' && config.visualizationSubType === 'stacked') || visualizationType === 'Combo') && (
|
|
586
627
|
<AreaChartStacked xScale={xScale} yScale={yScale} yMax={yMax} xMax={xMax} chartRef={svgRef} width={xMax} height={yMax} handleTooltipMouseOver={handleTooltipMouseOver} handleTooltipMouseOff={handleTooltipMouseOff} tooltipData={tooltipData} showTooltip={showTooltip} />
|
|
587
628
|
)}
|
|
588
|
-
{(visualizationType === 'Bar' || visualizationType === 'Combo') && (
|
|
629
|
+
{(visualizationType === 'Bar' || visualizationType === 'Combo' || checkLineToBarGraph()) && (
|
|
589
630
|
<BarChart
|
|
590
631
|
xScale={xScale}
|
|
591
632
|
yScale={yScale}
|
|
@@ -604,7 +645,7 @@ const LinearChart = props => {
|
|
|
604
645
|
chartRef={svgRef}
|
|
605
646
|
/>
|
|
606
647
|
)}
|
|
607
|
-
{(visualizationType === 'Line' || visualizationType === 'Combo') && (
|
|
648
|
+
{((visualizationType === 'Line' && !checkLineToBarGraph()) || visualizationType === 'Combo') && (
|
|
608
649
|
<LineChart
|
|
609
650
|
xScale={xScale}
|
|
610
651
|
yScale={yScale}
|
|
@@ -664,10 +705,10 @@ const LinearChart = props => {
|
|
|
664
705
|
/>
|
|
665
706
|
)}
|
|
666
707
|
{/*Zoom Brush */}
|
|
667
|
-
{['Line', 'Bar', 'Combo', 'Area Chart'].includes(config.visualizationType) && !isHorizontal && <ZoomBrush xScaleBrush={xScaleBrush} yScale={yScale} xMax={xMax} yMax={yMax} />}
|
|
708
|
+
{['Line', 'Bar', 'Combo', 'Area Chart'].includes(config.visualizationType) && false && !isHorizontal && <ZoomBrush xScaleBrush={xScaleBrush} yScale={yScale} xMax={xMax} yMax={yMax} />}
|
|
668
709
|
{/* Line chart */}
|
|
669
710
|
{/* TODO: Make this just line or combo? */}
|
|
670
|
-
{
|
|
711
|
+
{!['Paired Bar', 'Box Plot', 'Area Chart', 'Scatter Plot', 'Deviation Bar', 'Forecasting', 'Bar'].includes(visualizationType) && !checkLineToBarGraph() && (
|
|
671
712
|
<>
|
|
672
713
|
<LineChart xScale={xScale} yScale={yScale} getXAxisData={getXAxisData} getYAxisData={getYAxisData} xMax={xMax} yMax={yMax} seriesStyle={config.series} />
|
|
673
714
|
</>
|
|
@@ -686,13 +727,13 @@ const LinearChart = props => {
|
|
|
686
727
|
return (
|
|
687
728
|
// prettier-ignore
|
|
688
729
|
<Line
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
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
|
+
/>
|
|
696
737
|
)
|
|
697
738
|
})}
|
|
698
739
|
{/* x anchors */}
|
|
@@ -743,18 +784,21 @@ const LinearChart = props => {
|
|
|
743
784
|
{config.chartMessage.noData}
|
|
744
785
|
</Text>
|
|
745
786
|
)}
|
|
746
|
-
{config.visualizationType === 'Bar' && config.tooltips.singleSeries && config.visual.horizontalHoverLine && (
|
|
787
|
+
{(config.visualizationType === 'Bar' || checkLineToBarGraph()) && config.tooltips.singleSeries && config.visual.horizontalHoverLine && (
|
|
747
788
|
<Group key='tooltipLine-horizontal' className='horizontal-tooltip-line' left={config.yAxis.size ? config.yAxis.size : 0}>
|
|
748
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' />
|
|
749
790
|
</Group>
|
|
750
791
|
)}
|
|
751
|
-
{config.visualizationType === 'Bar' && config.tooltips.singleSeries && config.visual.verticalHoverLine && (
|
|
792
|
+
{(config.visualizationType === 'Bar' || checkLineToBarGraph()) && config.tooltips.singleSeries && config.visual.verticalHoverLine && (
|
|
752
793
|
<Group key='tooltipLine-vertical' className='vertical-tooltip-line'>
|
|
753
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' />
|
|
754
795
|
</Group>
|
|
755
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>
|
|
756
800
|
</svg>
|
|
757
|
-
{tooltipData && Object.entries(tooltipData.data).length > 0 && tooltipOpen && showTooltip && tooltipData.dataYPosition && tooltipData.dataXPosition &&
|
|
801
|
+
{!isDraggingAnnotation && tooltipData && Object.entries(tooltipData.data).length > 0 && tooltipOpen && showTooltip && tooltipData.dataYPosition && tooltipData.dataXPosition && (
|
|
758
802
|
<>
|
|
759
803
|
<style>{`.tooltip {background-color: rgba(255,255,255, ${config.tooltips.opacity / 100}) !important;`}</style>
|
|
760
804
|
<style>{`.tooltip {max-width:300px} !important; word-wrap: break-word; `}</style>
|
|
@@ -763,8 +807,7 @@ const LinearChart = props => {
|
|
|
763
807
|
</TooltipWithBounds>
|
|
764
808
|
</>
|
|
765
809
|
)}
|
|
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' }} />}
|
|
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' }} />}
|
|
768
811
|
<div className='animation-trigger' ref={triggerRef} />
|
|
769
812
|
</div>
|
|
770
813
|
</ErrorBoundary>
|