@cdc/chart 4.26.2 → 4.26.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONFIG.md +169 -0
- package/README.md +42 -17
- package/dist/cdcchart.js +39419 -35180
- package/examples/__data__/data-with-metadata.json +10 -0
- package/examples/feature/bar/additional-column-tooltip.json +3 -3
- package/examples/feature/deviation/planet-deviation-config.json +2 -2
- package/examples/feature/paired-bar/paired-bar-example.json +2 -2
- package/examples/feature/pie/planet-pie-example-config.json +2 -1
- package/examples/feature/tests-case-rate/case-rate-example-config.json +2 -2
- package/examples/feature/tests-covid/covid-confidence-example-config.json +2 -2
- package/examples/feature/tests-covid/covid-example-config.json +2 -2
- package/examples/feature/tests-cutoff/cutoff-example-config.json +2 -2
- package/examples/feature/tests-non-numerics/planet-pie-example-config-nonnumeric.json +2 -2
- package/examples/metadata-variables.json +58 -0
- package/examples/minimal-example.json +24 -0
- package/examples/private/test2.json +35012 -0
- package/package.json +4 -4
- package/src/CdcChart.tsx +8 -4
- package/src/CdcChartComponent.tsx +326 -290
- package/src/_stories/Chart.CustomColors.smoke.stories.tsx +97 -0
- package/src/_stories/Chart.Defaults.smoke.stories.tsx +95 -0
- package/src/_stories/{Chart.HTMLInDataTable.stories.tsx → Chart.HTMLInDataTable.smoke.stories.tsx} +10 -0
- package/src/_stories/Chart.Minimal.smoke.stories.tsx +25 -0
- package/src/_stories/{Chart.SmallMultiples.stories.tsx → Chart.SmallMultiples.smoke.stories.tsx} +17 -1
- package/src/_stories/Chart.SmallestLeftAxisMax.smoke.stories.tsx +64 -0
- package/src/_stories/{Chart.stories.tsx → Chart.smoke.stories.tsx} +48 -2
- package/src/_stories/{Chart.tooltip.stories.tsx → Chart.tooltip.smoke.stories.tsx} +68 -0
- package/src/_stories/ChartBar.Editor.stories.tsx +177 -115
- package/src/_stories/ChartBrush.Editor.stories.tsx +11 -25
- package/src/_stories/ChartEditor.Editor.stories.tsx +24 -1
- package/src/_stories/{Chart.CustomColors.stories.tsx → ChartLine.DashedDates.smoke.stories.tsx} +4 -4
- package/src/_stories/_mock/line_chart_dashed_dates.json +276 -0
- package/src/_stories/_mock/paired-bar-abbr.json +421 -0
- package/src/_stories/_mock/paired-bar.json +1 -1
- package/src/_stories/_mock/pie_custom_colors.json +268 -0
- package/src/_stories/_mock/smallest_left_axis_max.json +104 -0
- package/src/components/Annotations/components/AnnotationDraggable.styles.css +10 -10
- package/src/components/Annotations/components/AnnotationDraggable.tsx +1 -1
- package/src/components/Annotations/components/AnnotationDropdown.styles.css +1 -1
- package/src/components/Annotations/components/AnnotationList.styles.css +11 -11
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +10 -2
- package/src/components/Axis/BottomAxis.tsx +10 -3
- package/src/components/Axis/LeftAxis.tsx +2 -4
- package/src/components/Axis/LeftAxisGridlines.tsx +1 -3
- package/src/components/Axis/PairedBarAxis.tsx +10 -4
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +21 -33
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +21 -35
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +21 -36
- package/src/components/BarChart/components/BarChart.Vertical.tsx +21 -34
- package/src/components/BarChart/components/BarChart.tsx +2 -6
- package/src/components/BarChart/helpers/getPatternUrl.ts +94 -0
- package/src/components/BarChart/helpers/tests/getPatternUrl.test.ts +134 -0
- package/src/components/BarChart/helpers/useBarChart.ts +4 -1
- package/src/components/BoxPlot/BoxPlot.Vertical.tsx +3 -3
- package/src/components/Brush/BrushSelector.tsx +2 -1
- package/src/components/Brush/MiniChartPreview.tsx +21 -26
- package/src/components/EditorPanel/EditorPanel.tsx +692 -954
- package/src/components/EditorPanel/EditorPanelContext.ts +1 -1
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +218 -167
- package/src/components/EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx +0 -78
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +39 -1
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +169 -135
- package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +154 -109
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +3 -3
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +95 -28
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +45 -42
- package/src/components/EditorPanel/editor-panel.scss +1 -1
- package/src/components/EditorPanel/useEditorPermissions.ts +1 -10
- package/src/components/Forecasting/Forecasting.tsx +2 -2
- package/src/components/ForestPlot/ForestPlot.tsx +26 -22
- package/src/components/HorizonChart/HorizonChart.tsx +10 -2
- package/src/components/HoverLine/HoverLine.tsx +6 -8
- package/src/components/Legend/Legend.Component.tsx +4 -4
- package/src/components/Legend/LegendGroup/LegendGroup.styles.css +9 -4
- package/src/components/Legend/LegendGroup/LegendGroup.tsx +3 -1
- package/src/components/Legend/helpers/createFormatLabels.tsx +3 -2
- package/src/components/Legend/helpers/index.ts +0 -2
- package/src/components/LineChart/LineChartProps.ts +1 -0
- package/src/components/LineChart/components/LineChart.BumpCircle.tsx +3 -2
- package/src/components/LineChart/index.tsx +11 -4
- package/src/components/LinearChart/VisualizationRenderer.tsx +11 -1
- package/src/components/LinearChart/tests/LinearChart.test.tsx +224 -0
- package/src/components/LinearChart/tests/mockConfigContext.ts +2 -0
- package/src/components/LinearChart.tsx +124 -47
- package/src/components/PairedBarChart.jsx +2 -2
- package/src/components/PieChart/PieChart.tsx +30 -13
- package/src/components/RadarChart/RadarChart.tsx +1 -1
- package/src/components/Regions/components/Regions.tsx +36 -26
- package/src/components/Sankey/components/Sankey.tsx +3 -3
- package/src/components/Sankey/sankey.scss +1 -1
- package/src/components/ScatterPlot/ScatterPlot.jsx +19 -17
- package/src/components/SmallMultiples/SmallMultipleTile.tsx +1 -0
- package/src/components/SmallMultiples/SmallMultiples.css +5 -5
- package/src/components/Sparkline/components/SparkLine.tsx +1 -1
- package/src/components/Sparkline/index.scss +4 -2
- package/src/components/WarmingStripes/WarmingStripes.tsx +5 -3
- package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +8 -8
- package/src/data/initial-state.js +24 -14
- package/src/data/legacy-defaults.ts +18 -0
- package/src/helpers/abbreviateNumber.ts +24 -17
- package/src/helpers/calculateLeftYAxisWidth.ts +193 -0
- package/src/helpers/getChartPatternId.ts +17 -0
- package/src/helpers/getMinMax.ts +16 -2
- package/src/helpers/seriesColumnSettings.ts +114 -0
- package/src/helpers/tests/countNumOfTicks.test.ts +77 -0
- package/src/helpers/tests/seriesColumnSettings.test.ts +84 -0
- package/src/helpers/tests/tooltipHelpers.test.ts +151 -0
- package/src/helpers/tooltipHelpers.ts +176 -0
- package/src/hooks/useHighlightedBars.ts +9 -16
- package/src/hooks/useProgrammaticTooltip.ts +16 -2
- package/src/hooks/useRightAxis.ts +14 -0
- package/src/hooks/useScales.ts +92 -56
- package/src/hooks/useSmallMultipleSynchronization.ts +3 -4
- package/src/hooks/useTooltip.tsx +186 -40
- package/src/scss/main.scss +152 -79
- package/src/test/CdcChart.test.jsx +26 -2
- package/src/types/ChartConfig.ts +5 -0
- package/tests/fixtures/chart-config-with-metadata.json +29 -0
- package/tests/fixtures/data-with-metadata.json +10 -0
- package/examples/chart-regression-2.json +0 -2360
- package/examples/feature/__data__/age-adjusted-rates.json +0 -1486
- package/examples/feature/__data__/city-temperature.json +0 -2198
- package/examples/feature/bar/Barchart_with_negative.json +0 -34
- package/examples/feature/boxplot/box-plot-data.json +0 -71
- package/examples/feature/boxplot/boxplot-data.json +0 -156
- package/examples/feature/combo/combochart-categories_are_numbers .json +0 -18
- package/examples/feature/forest-plot/log.json +0 -26
- package/examples/feature/tests-date-exclusions/date-exclusions-data.json +0 -162
- package/examples/region-issue.json +0 -2065
- package/examples/xaxis.json +0 -493
- /package/examples/feature/bar/{tall-data.json → __data__/tall-data.json} +0 -0
- /package/examples/feature/deviation/{planet-deviation-data.json → __data__/planet-deviation-data.json} +0 -0
- /package/examples/feature/paired-bar/{paired-bar-data.json → __data__/paired-bar-data.json} +0 -0
- /package/examples/feature/paired-bar/{paired-bar-formatted.json → __data__/paired-bar-formatted.json} +0 -0
- /package/examples/feature/tests-case-rate/{case-rate-example-data.json → __data__/case-rate-example-data.json} +0 -0
- /package/examples/feature/tests-covid/{covid-example-data-confidence.json → __data__/covid-example-data-confidence.json} +0 -0
- /package/examples/feature/tests-covid/{covid-example-data.json → __data__/covid-example-data.json} +0 -0
- /package/examples/feature/tests-cutoff/{cutoff-example-data.json → __data__/cutoff-example-data.json} +0 -0
- /package/examples/feature/tests-non-numerics/{planet-example-data-nonnumeric.json → __data__/planet-example-data-nonnumeric.json} +0 -0
- /package/src/_stories/{Chart.Anchors.stories.tsx → Chart.Anchors.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.BoxPlot.stories.tsx → Chart.BoxPlot.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.CI.stories.tsx → Chart.CI.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Combo.stories.tsx → Chart.Combo.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.DynamicSeries.stories.tsx → Chart.DynamicSeries.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Filters.stories.tsx → Chart.Filters.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Forecast.stories.tsx → Chart.Forecast.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Legend.Gradient.stories.tsx → Chart.Legend.Gradient.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Patterns.stories.tsx → Chart.Patterns.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.PreserveDecimals.stories.tsx → Chart.PreserveDecimals.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Regions.Categorical.stories.tsx → Chart.Regions.Categorical.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Regions.DateScale.stories.tsx → Chart.Regions.DateScale.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Regions.DateTimeScale.stories.tsx → Chart.Regions.DateTimeScale.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.ScatterPlot.stories.tsx → Chart.ScatterPlot.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartAnnotation.stories.tsx → ChartAnnotation.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartAxisLabels.stories.tsx → ChartAxisLabels.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartAxisTitles.stories.tsx → ChartAxisTitles.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartBrush.Matrix.Continuous.stories.tsx → ChartBrush.Matrix.Continuous.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartBrush.Matrix.Date.stories.tsx → ChartBrush.Matrix.Date.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartBrush.Matrix.DateTime.stories.tsx → ChartBrush.Matrix.DateTime.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartBrush.stories.tsx → ChartBrush.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartLine.QuadrantAngles.stories.tsx → ChartLine.QuadrantAngles.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartLine.Suppression.stories.tsx → ChartLine.Suppression.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartLine.Symbols.stories.tsx → ChartLine.Symbols.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartPrefixSuffix.stories.tsx → ChartPrefixSuffix.smoke.stories.tsx} +0 -0
- /package/src/_stories/{TechAdoptionWithLinks.stories.tsx → TechAdoptionWithLinks.smoke.stories.tsx} +0 -0
|
@@ -4,6 +4,7 @@ import { describe, expect, it, vi, beforeAll } from 'vitest'
|
|
|
4
4
|
import LinearChart from '../../LinearChart'
|
|
5
5
|
import ConfigContext from '../../../ConfigContext'
|
|
6
6
|
import { createMockChartContext } from './mockConfigContext'
|
|
7
|
+
import forestPlotConfig from '../../../../examples/feature/forest-plot/forest-plot.json'
|
|
7
8
|
|
|
8
9
|
// Mock ResizeObserver
|
|
9
10
|
vi.stubGlobal(
|
|
@@ -66,6 +67,11 @@ const renderLinearChart = (
|
|
|
66
67
|
)
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
const getLeftAxisLabelTransforms = container =>
|
|
71
|
+
Array.from(container.querySelectorAll('.left-axis text.y-label'))
|
|
72
|
+
.map(label => label.getAttribute('transform'))
|
|
73
|
+
.filter(Boolean)
|
|
74
|
+
|
|
69
75
|
describe('LinearChart', () => {
|
|
70
76
|
describe('rendering', () => {
|
|
71
77
|
it('renders without crashing', () => {
|
|
@@ -147,6 +153,82 @@ describe('LinearChart', () => {
|
|
|
147
153
|
})
|
|
148
154
|
expect(container).toBeTruthy()
|
|
149
155
|
})
|
|
156
|
+
|
|
157
|
+
it('keeps forest plot lines inside the computed plot bounds at narrow and wide widths', () => {
|
|
158
|
+
const forestContextOverrides = {
|
|
159
|
+
transformedData: forestPlotConfig.data,
|
|
160
|
+
rawData: forestPlotConfig.data
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const narrowRender = renderLinearChart(forestPlotConfig as any, forestContextOverrides, {
|
|
164
|
+
parentWidth: 320,
|
|
165
|
+
parentHeight: 500
|
|
166
|
+
})
|
|
167
|
+
const wideRender = renderLinearChart(forestPlotConfig as any, forestContextOverrides, {
|
|
168
|
+
parentWidth: 960,
|
|
169
|
+
parentHeight: 500
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
const narrowTopLine = narrowRender.container.querySelector('.forestplot__top-line')
|
|
173
|
+
const wideTopLine = wideRender.container.querySelector('.forestplot__top-line')
|
|
174
|
+
const narrowCiLine = narrowRender.container.querySelector('line[class^="line-"]')
|
|
175
|
+
const wideCiLine = wideRender.container.querySelector('line[class^="line-"]')
|
|
176
|
+
|
|
177
|
+
expect(narrowTopLine).toBeTruthy()
|
|
178
|
+
expect(wideTopLine).toBeTruthy()
|
|
179
|
+
expect(narrowCiLine).toBeTruthy()
|
|
180
|
+
expect(wideCiLine).toBeTruthy()
|
|
181
|
+
|
|
182
|
+
const narrowStart = Number(narrowTopLine?.getAttribute('x1'))
|
|
183
|
+
const narrowEnd = Number(narrowTopLine?.getAttribute('x2'))
|
|
184
|
+
const wideStart = Number(wideTopLine?.getAttribute('x1'))
|
|
185
|
+
const wideEnd = Number(wideTopLine?.getAttribute('x2'))
|
|
186
|
+
|
|
187
|
+
expect(narrowStart).toBe(0)
|
|
188
|
+
expect(narrowEnd).toBeLessThanOrEqual(320)
|
|
189
|
+
expect(wideStart).toBe(0)
|
|
190
|
+
expect(wideEnd).toBeLessThanOrEqual(960)
|
|
191
|
+
expect(wideEnd - wideStart).toBeGreaterThan(narrowEnd - narrowStart)
|
|
192
|
+
|
|
193
|
+
expect(Number(narrowCiLine?.getAttribute('x1'))).toBeGreaterThan(narrowStart)
|
|
194
|
+
expect(Number(narrowCiLine?.getAttribute('x2'))).toBeLessThanOrEqual(narrowEnd)
|
|
195
|
+
expect(Number(wideCiLine?.getAttribute('x1'))).toBeGreaterThan(wideStart)
|
|
196
|
+
expect(Number(wideCiLine?.getAttribute('x2'))).toBeLessThanOrEqual(wideEnd)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
it('avoids rendering a duplicate manual bottom border when the forest plot x-axis is visible', () => {
|
|
200
|
+
const { container } = renderLinearChart(
|
|
201
|
+
forestPlotConfig as any,
|
|
202
|
+
{
|
|
203
|
+
transformedData: forestPlotConfig.data,
|
|
204
|
+
rawData: forestPlotConfig.data
|
|
205
|
+
},
|
|
206
|
+
{ parentWidth: 800, parentHeight: 500 }
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
expect(container.querySelector('.forestplot__top-line')).toBeTruthy()
|
|
210
|
+
expect(container.querySelector('.forestplot__bottom-line')).toBeFalsy()
|
|
211
|
+
const bottomAxisLine = container.querySelector('.bottom-axis > line[stroke="#333"]')
|
|
212
|
+
expect(bottomAxisLine?.getAttribute('x1')).toBe('0')
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
it('renders forest plot rows from transformedData instead of rawData', () => {
|
|
216
|
+
const filteredData = forestPlotConfig.data.slice(0, 2)
|
|
217
|
+
const { container } = renderLinearChart(
|
|
218
|
+
forestPlotConfig as any,
|
|
219
|
+
{
|
|
220
|
+
transformedData: filteredData,
|
|
221
|
+
rawData: forestPlotConfig.data
|
|
222
|
+
},
|
|
223
|
+
{ parentWidth: 800, parentHeight: 500 }
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
expect(container.querySelectorAll('.lower-ci')).toHaveLength(filteredData.length)
|
|
227
|
+
expect(container.querySelectorAll('line[class^="line-"]')).toHaveLength(filteredData.length)
|
|
228
|
+
expect(container.textContent).not.toContain(
|
|
229
|
+
String(forestPlotConfig.data[forestPlotConfig.data.length - 1]['Author(s) and Year'])
|
|
230
|
+
)
|
|
231
|
+
})
|
|
150
232
|
})
|
|
151
233
|
|
|
152
234
|
describe('axis rendering', () => {
|
|
@@ -181,6 +263,148 @@ describe('LinearChart', () => {
|
|
|
181
263
|
// The axis line should be hidden, but grid lines may still render
|
|
182
264
|
expect(container.querySelector('svg')).toBeTruthy()
|
|
183
265
|
})
|
|
266
|
+
|
|
267
|
+
it('ignores yAxis.labelOffset when positioning the vertical left-axis title', () => {
|
|
268
|
+
const baseRuntime = {
|
|
269
|
+
xAxis: {
|
|
270
|
+
type: 'date',
|
|
271
|
+
dataKey: 'Date',
|
|
272
|
+
label: 'X-Axis'
|
|
273
|
+
},
|
|
274
|
+
yAxis: {
|
|
275
|
+
size: 50,
|
|
276
|
+
label: 'Y-Axis',
|
|
277
|
+
gridLines: true,
|
|
278
|
+
labelOffset: 0
|
|
279
|
+
},
|
|
280
|
+
originalXAxis: {
|
|
281
|
+
dataKey: 'Date'
|
|
282
|
+
},
|
|
283
|
+
series: [],
|
|
284
|
+
seriesKeys: [],
|
|
285
|
+
seriesLabelsAll: [],
|
|
286
|
+
uniqueId: 'test-chart'
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const baseRender = renderLinearChart({
|
|
290
|
+
yAxis: {
|
|
291
|
+
hideAxis: false,
|
|
292
|
+
hideLabel: false,
|
|
293
|
+
hideTicks: false,
|
|
294
|
+
size: '50',
|
|
295
|
+
gridLines: true,
|
|
296
|
+
label: 'Y-Axis',
|
|
297
|
+
tickRotation: 0,
|
|
298
|
+
anchors: [],
|
|
299
|
+
axisPadding: 0,
|
|
300
|
+
labelPlacement: 'On Date/Category Axis',
|
|
301
|
+
rightAxisSize: 0,
|
|
302
|
+
labelOffset: 0
|
|
303
|
+
},
|
|
304
|
+
runtime: baseRuntime
|
|
305
|
+
})
|
|
306
|
+
const offsetRender = renderLinearChart({
|
|
307
|
+
yAxis: {
|
|
308
|
+
hideAxis: false,
|
|
309
|
+
hideLabel: false,
|
|
310
|
+
hideTicks: false,
|
|
311
|
+
size: '50',
|
|
312
|
+
gridLines: true,
|
|
313
|
+
label: 'Y-Axis',
|
|
314
|
+
tickRotation: 0,
|
|
315
|
+
anchors: [],
|
|
316
|
+
axisPadding: 0,
|
|
317
|
+
labelPlacement: 'On Date/Category Axis',
|
|
318
|
+
rightAxisSize: 0,
|
|
319
|
+
labelOffset: 240
|
|
320
|
+
},
|
|
321
|
+
runtime: {
|
|
322
|
+
...baseRuntime,
|
|
323
|
+
yAxis: {
|
|
324
|
+
...baseRuntime.yAxis,
|
|
325
|
+
labelOffset: 240
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
const baseTransforms = getLeftAxisLabelTransforms(baseRender.container)
|
|
331
|
+
const offsetTransforms = getLeftAxisLabelTransforms(offsetRender.container)
|
|
332
|
+
|
|
333
|
+
expect(baseTransforms.length).toBeGreaterThan(0)
|
|
334
|
+
expect(offsetTransforms).toEqual(baseTransforms)
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('ignores horizontal xAxis.labelOffset when positioning the left-side axis title', () => {
|
|
338
|
+
const baseRuntime = {
|
|
339
|
+
xAxis: {
|
|
340
|
+
type: 'linear',
|
|
341
|
+
dataKey: 'Value',
|
|
342
|
+
label: 'X-Axis'
|
|
343
|
+
},
|
|
344
|
+
yAxis: {
|
|
345
|
+
size: 50,
|
|
346
|
+
label: 'Y-Axis',
|
|
347
|
+
gridLines: true,
|
|
348
|
+
labelOffset: 0
|
|
349
|
+
},
|
|
350
|
+
originalXAxis: {
|
|
351
|
+
dataKey: 'Date'
|
|
352
|
+
},
|
|
353
|
+
series: [],
|
|
354
|
+
seriesKeys: [],
|
|
355
|
+
seriesLabelsAll: [],
|
|
356
|
+
uniqueId: 'test-chart'
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const baseRender = renderLinearChart({
|
|
360
|
+
orientation: 'horizontal',
|
|
361
|
+
xAxis: {
|
|
362
|
+
type: 'linear',
|
|
363
|
+
dataKey: 'Value',
|
|
364
|
+
label: 'X-Axis',
|
|
365
|
+
hideAxis: false,
|
|
366
|
+
hideLabel: false,
|
|
367
|
+
hideTicks: false,
|
|
368
|
+
size: '50',
|
|
369
|
+
tickRotation: 0,
|
|
370
|
+
maxTickRotation: 90,
|
|
371
|
+
anchors: [],
|
|
372
|
+
axisPadding: 0,
|
|
373
|
+
labelOffset: 0
|
|
374
|
+
},
|
|
375
|
+
runtime: baseRuntime
|
|
376
|
+
})
|
|
377
|
+
const offsetRender = renderLinearChart({
|
|
378
|
+
orientation: 'horizontal',
|
|
379
|
+
xAxis: {
|
|
380
|
+
type: 'linear',
|
|
381
|
+
dataKey: 'Value',
|
|
382
|
+
label: 'X-Axis',
|
|
383
|
+
hideAxis: false,
|
|
384
|
+
hideLabel: false,
|
|
385
|
+
hideTicks: false,
|
|
386
|
+
size: '50',
|
|
387
|
+
tickRotation: 0,
|
|
388
|
+
maxTickRotation: 90,
|
|
389
|
+
anchors: [],
|
|
390
|
+
axisPadding: 0,
|
|
391
|
+
labelOffset: 240
|
|
392
|
+
},
|
|
393
|
+
runtime: {
|
|
394
|
+
...baseRuntime,
|
|
395
|
+
yAxis: {
|
|
396
|
+
...baseRuntime.yAxis,
|
|
397
|
+
labelOffset: 240
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
const baseTransforms = getLeftAxisLabelTransforms(baseRender.container)
|
|
403
|
+
const offsetTransforms = getLeftAxisLabelTransforms(offsetRender.container)
|
|
404
|
+
|
|
405
|
+
expect(baseTransforms.length).toBeGreaterThan(0)
|
|
406
|
+
expect(offsetTransforms).toEqual(baseTransforms)
|
|
407
|
+
})
|
|
184
408
|
})
|
|
185
409
|
|
|
186
410
|
describe('SVG dimensions', () => {
|
|
@@ -124,6 +124,8 @@ export const createMockChartContext = (
|
|
|
124
124
|
clean: (s: any) => s,
|
|
125
125
|
formatTooltipsDate: (date: any) => String(date),
|
|
126
126
|
legendId: 'test-legend',
|
|
127
|
+
rawData: config.data,
|
|
128
|
+
updateConfig: () => {},
|
|
127
129
|
...contextOverrides
|
|
128
130
|
} as ChartContext
|
|
129
131
|
}
|
|
@@ -18,8 +18,7 @@ import { Tooltip as ReactTooltip } from 'react-tooltip'
|
|
|
18
18
|
import 'react-tooltip/dist/react-tooltip.css'
|
|
19
19
|
import { Text } from '@visx/text'
|
|
20
20
|
import { useTooltip, TooltipWithBounds } from '@visx/tooltip'
|
|
21
|
-
import
|
|
22
|
-
|
|
21
|
+
import ResizeObserver from 'resize-observer-polyfill'
|
|
23
22
|
// CDC Components
|
|
24
23
|
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
25
24
|
import ConfigContext from '../ConfigContext'
|
|
@@ -36,6 +35,7 @@ import { useTickFormatters } from './LinearChart/utils/tickFormatting'
|
|
|
36
35
|
import { isLegendWrapViewport, isMobileFontViewport } from '@cdc/core/helpers/viewports'
|
|
37
36
|
import { calcInitialHeight } from '../helpers/sizeHelpers'
|
|
38
37
|
import { calculateHorizontalBarCategoryLabelWidth } from '../helpers/calculateHorizontalBarCategoryLabelWidth'
|
|
38
|
+
import { calculateLeftYAxisWidth } from '../helpers/calculateLeftYAxisWidth'
|
|
39
39
|
|
|
40
40
|
// Hooks
|
|
41
41
|
import useReduceData from '../hooks/useReduceData'
|
|
@@ -52,6 +52,7 @@ import Annotation from './Annotations'
|
|
|
52
52
|
import { countNumOfTicks } from '../helpers/countNumOfTicks'
|
|
53
53
|
import HoverLine from './HoverLine/HoverLine'
|
|
54
54
|
import { SmallMultiples } from './SmallMultiples'
|
|
55
|
+
import { type TooltipDisplayData } from '../helpers/tooltipHelpers'
|
|
55
56
|
|
|
56
57
|
type LinearChartProps = {
|
|
57
58
|
parentWidth: number
|
|
@@ -63,6 +64,7 @@ const BOTTOM_LABEL_PADDING = 9
|
|
|
63
64
|
const X_TICK_LABEL_PADDING = 4.5
|
|
64
65
|
const DEFAULT_TICK_LENGTH = 8
|
|
65
66
|
const DEFAULT_MAX_TICK_ROTATION = 90
|
|
67
|
+
const DEFAULT_LEFT_Y_AXIS_WIDTH = 50
|
|
66
68
|
|
|
67
69
|
// Font sizes
|
|
68
70
|
const TICK_LABEL_FONT_SIZE = 16
|
|
@@ -89,10 +91,7 @@ const WARMING_STRIPES_HEIGHT = 78
|
|
|
89
91
|
// Time constants
|
|
90
92
|
const MONTH_AS_MS = 1000 * 60 * 60 * 24 * 30
|
|
91
93
|
|
|
92
|
-
type TooltipData =
|
|
93
|
-
dataXPosition?: number
|
|
94
|
-
dataYPosition?: number
|
|
95
|
-
}
|
|
94
|
+
type TooltipData = Partial<TooltipDisplayData>
|
|
96
95
|
|
|
97
96
|
type UseTooltipReturn<T = TooltipData> = {
|
|
98
97
|
tooltipData: T | null
|
|
@@ -152,6 +151,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
152
151
|
const [suffixWidth, setSuffixWidth] = useState(0)
|
|
153
152
|
const [calculatedSvgHeight, setCalculatedSvgHeight] = useState<number | null>(null)
|
|
154
153
|
const [axisUpdateKey, setAxisUpdateKey] = useState(0)
|
|
154
|
+
const [axisBottomSizeKey, setAxisBottomSizeKey] = useState(0)
|
|
155
155
|
const [synchronizedXValue, setSynchronizedXValue] = useState<any>(null)
|
|
156
156
|
|
|
157
157
|
// REFS
|
|
@@ -176,8 +176,6 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
176
176
|
const isDateTime = config.xAxis.type === 'date-time'
|
|
177
177
|
const inlineLabelHasNoSpace = !inlineLabel?.includes(' ')
|
|
178
178
|
const needsYAxisAutoPadding = inlineLabel && !inlineLabelHasNoSpace
|
|
179
|
-
const padding = orientation === 'horizontal' ? Number(config.xAxis.size) : Number(config.yAxis.size)
|
|
180
|
-
const yLabelOffset = isNaN(parseInt(`${runtime.yAxis.labelOffset}`)) ? 0 : parseInt(`${runtime.yAxis.labelOffset}`)
|
|
181
179
|
const tickLabelFontSize = isMobileFontViewport(vizViewport) ? TICK_LABEL_FONT_SIZE_SMALL : TICK_LABEL_FONT_SIZE
|
|
182
180
|
const axisLabelFontSize = isMobileFontViewport(vizViewport) ? AXIS_LABEL_FONT_SIZE_SMALL : AXIS_LABEL_FONT_SIZE
|
|
183
181
|
const GET_TEXT_WIDTH_FONT = `normal ${tickLabelFontSize}px Nunito, sans-serif`
|
|
@@ -245,13 +243,22 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
245
243
|
setAxisUpdateKey(prev => prev + 1)
|
|
246
244
|
}, [data.length, xAxisDataMapped?.[0], xAxisDataMapped?.[xAxisDataMapped.length - 1]])
|
|
247
245
|
|
|
248
|
-
|
|
246
|
+
// Recompute heights when bottom axis size changes (e.g., font load or wrap).
|
|
247
|
+
useEffect(() => {
|
|
248
|
+
const axisBottomEl = axisBottomRef.current
|
|
249
|
+
if (!axisBottomEl) return
|
|
250
|
+
const observer = new ResizeObserver(() => {
|
|
251
|
+
setAxisBottomSizeKey(prev => prev + 1)
|
|
252
|
+
})
|
|
253
|
+
observer.observe(axisBottomEl)
|
|
254
|
+
return () => observer.disconnect()
|
|
255
|
+
}, [axisBottomRef.current])
|
|
249
256
|
|
|
250
|
-
|
|
251
|
-
const [computedYAxisWidth, setComputedYAxisWidth] = useState<number | null>(null)
|
|
257
|
+
const { yScaleRight, hasRightAxis } = useRightAxis({ config, yMax, data })
|
|
252
258
|
|
|
253
|
-
//
|
|
254
|
-
const
|
|
259
|
+
// State for computed left-axis width - shared across all linear-chart types.
|
|
260
|
+
const [currentYAxisWidth, setCurrentYAxisWidth] = useState<number>(DEFAULT_LEFT_Y_AXIS_WIDTH)
|
|
261
|
+
const yAxisWidth = currentYAxisWidth
|
|
255
262
|
|
|
256
263
|
// Chart width calculation using the current y-axis width
|
|
257
264
|
const xMax = parentWidth - yAxisWidth - (hasRightAxis ? config.yAxis.rightAxisSize : 0)
|
|
@@ -292,39 +299,77 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
292
299
|
shouldAbbreviate
|
|
293
300
|
})
|
|
294
301
|
|
|
295
|
-
//
|
|
302
|
+
// Horizontal charts swap axes at runtime, but the left-side category label visibility
|
|
303
|
+
// still follows config.yAxis.hideLabel to match the actual axis renderers.
|
|
296
304
|
const categoryLabelSpace = useMemo(() => {
|
|
305
|
+
if (config.yAxis.hideLabel) return 0
|
|
306
|
+
|
|
297
307
|
return calculateHorizontalBarCategoryLabelWidth({
|
|
298
308
|
yScale,
|
|
299
309
|
chartWidth: parentWidth,
|
|
300
310
|
formatDate,
|
|
301
311
|
parseDate,
|
|
302
312
|
tickLabelFont: GET_TEXT_WIDTH_FONT,
|
|
303
|
-
xAxisType:
|
|
313
|
+
xAxisType: runtime.xAxis?.type,
|
|
304
314
|
labelPlacement: config.yAxis.labelPlacement
|
|
305
315
|
})
|
|
306
|
-
}, [
|
|
316
|
+
}, [
|
|
317
|
+
config.yAxis.hideLabel,
|
|
318
|
+
config.yAxis.labelPlacement,
|
|
319
|
+
yScale,
|
|
320
|
+
parentWidth,
|
|
321
|
+
formatDate,
|
|
322
|
+
parseDate,
|
|
323
|
+
GET_TEXT_WIDTH_FONT,
|
|
324
|
+
runtime.xAxis?.type
|
|
325
|
+
])
|
|
307
326
|
|
|
308
327
|
const horizontalYAxisLabelSpace = runtime.yAxis.label && !config.hideYAxisLabel ? 30 : 0
|
|
309
328
|
|
|
310
|
-
// Update y-axis width state when computed value changes (for horizontal bar charts)
|
|
311
|
-
useEffect(() => {
|
|
312
|
-
if (isHorizontal && config.visualizationType === 'Bar') {
|
|
313
|
-
const newWidth = categoryLabelSpace + horizontalYAxisLabelSpace
|
|
314
|
-
if (newWidth !== computedYAxisWidth) {
|
|
315
|
-
setComputedYAxisWidth(newWidth)
|
|
316
|
-
}
|
|
317
|
-
} else if (computedYAxisWidth !== null) {
|
|
318
|
-
// Reset to null for non-horizontal bar charts so we use config value
|
|
319
|
-
setComputedYAxisWidth(null)
|
|
320
|
-
}
|
|
321
|
-
}, [isHorizontal, config.visualizationType, categoryLabelSpace, horizontalYAxisLabelSpace, computedYAxisWidth])
|
|
322
|
-
|
|
323
329
|
const [yTickCount, xTickCount] = ['yAxis', 'xAxis'].map(axis =>
|
|
324
330
|
countNumOfTicks({ axis, max, runtime, currentViewport, isHorizontal, data, config, min })
|
|
325
331
|
)
|
|
326
332
|
const handleNumTicks = isForestPlot ? config.data.length : yTickCount
|
|
327
333
|
|
|
334
|
+
const calculatedYAxisWidth = useMemo(() => {
|
|
335
|
+
if (isHorizontal && config.visualizationType === 'Bar') {
|
|
336
|
+
return categoryLabelSpace + horizontalYAxisLabelSpace
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return calculateLeftYAxisWidth({
|
|
340
|
+
config,
|
|
341
|
+
data,
|
|
342
|
+
yScale,
|
|
343
|
+
numTicks: handleNumTicks,
|
|
344
|
+
parentWidth,
|
|
345
|
+
tickLabelFont: GET_TEXT_WIDTH_FONT,
|
|
346
|
+
axisLabelFontSize,
|
|
347
|
+
handleLeftTickFormatting,
|
|
348
|
+
categoryLabelSpace,
|
|
349
|
+
horizontalYAxisLabelSpace
|
|
350
|
+
})
|
|
351
|
+
}, [
|
|
352
|
+
config,
|
|
353
|
+
data,
|
|
354
|
+
yScale,
|
|
355
|
+
handleNumTicks,
|
|
356
|
+
parentWidth,
|
|
357
|
+
isHorizontal,
|
|
358
|
+
GET_TEXT_WIDTH_FONT,
|
|
359
|
+
axisLabelFontSize,
|
|
360
|
+
handleLeftTickFormatting,
|
|
361
|
+
categoryLabelSpace,
|
|
362
|
+
horizontalYAxisLabelSpace
|
|
363
|
+
])
|
|
364
|
+
|
|
365
|
+
useLayoutEffect(() => {
|
|
366
|
+
if (parentWidth <= 0) return
|
|
367
|
+
|
|
368
|
+
if (calculatedYAxisWidth !== currentYAxisWidth) {
|
|
369
|
+
setCurrentYAxisWidth(calculatedYAxisWidth)
|
|
370
|
+
}
|
|
371
|
+
}, [calculatedYAxisWidth, currentYAxisWidth, parentWidth])
|
|
372
|
+
|
|
328
373
|
// Tooltip Helpers
|
|
329
374
|
|
|
330
375
|
const { tooltipData, showTooltip, hideTooltip, tooltipOpen, tooltipLeft, tooltipTop } =
|
|
@@ -342,6 +387,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
342
387
|
xScale,
|
|
343
388
|
yScale,
|
|
344
389
|
seriesScale,
|
|
390
|
+
yAxisWidth,
|
|
345
391
|
showTooltip,
|
|
346
392
|
hideTooltip,
|
|
347
393
|
interactionLabel
|
|
@@ -376,7 +422,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
376
422
|
return manualStep
|
|
377
423
|
}, [config.xAxis.manualStep, config.xAxis.viewportStepCount, currentViewport])
|
|
378
424
|
|
|
379
|
-
const smallMultiplesSync = useSmallMultipleSynchronization(xMax, yMax, getXValueFromCoordinate)
|
|
425
|
+
const smallMultiplesSync = useSmallMultipleSynchronization(xMax, yMax, yAxisWidth, getXValueFromCoordinate)
|
|
380
426
|
|
|
381
427
|
const onMouseMove = event => {
|
|
382
428
|
const svgRect = event.currentTarget.getBoundingClientRect()
|
|
@@ -405,7 +451,9 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
405
451
|
const internalSvgRef = useProgrammaticTooltip({
|
|
406
452
|
svgRef,
|
|
407
453
|
getCoordinateFromXValue,
|
|
454
|
+
getXValueFromCoordinate,
|
|
408
455
|
config,
|
|
456
|
+
yAxisWidth,
|
|
409
457
|
setPoint,
|
|
410
458
|
setShowHoverLine,
|
|
411
459
|
handleTooltipMouseOver,
|
|
@@ -415,7 +463,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
415
463
|
|
|
416
464
|
// Make sure the chart is visible if in the editor
|
|
417
465
|
useEffect(() => {
|
|
418
|
-
const element = document.querySelector('.
|
|
466
|
+
const element = document.querySelector('.is-editor')
|
|
419
467
|
if (element) {
|
|
420
468
|
setAnimatedChart(true)
|
|
421
469
|
}
|
|
@@ -498,7 +546,16 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
498
546
|
const legendIsLeftOrRight =
|
|
499
547
|
legend?.position !== 'top' && legend?.position !== 'bottom' && !isLegendWrapViewport(currentViewport)
|
|
500
548
|
legendRef.current.style.transform = legendIsLeftOrRight ? `translateY(${topLabelOnGridlineHeight}px)` : 'none'
|
|
501
|
-
}, [
|
|
549
|
+
}, [
|
|
550
|
+
axisBottomRef.current,
|
|
551
|
+
config,
|
|
552
|
+
config.xAxis.brushActive,
|
|
553
|
+
currentViewport,
|
|
554
|
+
topYLabelRef.current,
|
|
555
|
+
initialHeight,
|
|
556
|
+
parentWidth,
|
|
557
|
+
axisBottomSizeKey
|
|
558
|
+
])
|
|
502
559
|
|
|
503
560
|
useEffect(() => {
|
|
504
561
|
if (!tooltipOpen) return
|
|
@@ -542,7 +599,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
542
599
|
<svg
|
|
543
600
|
ref={internalSvgRef}
|
|
544
601
|
onMouseMove={onMouseMove}
|
|
545
|
-
width={parentWidth
|
|
602
|
+
width={parentWidth}
|
|
546
603
|
height={isNoDataAvailable ? 1 : calculatedSvgHeight ?? parentHeight}
|
|
547
604
|
className={`linear ${config.animate ? 'animated' : ''} ${animatedChart && config.animate ? 'animate' : ''} ${
|
|
548
605
|
debugSvg && 'debug'
|
|
@@ -569,7 +626,6 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
569
626
|
xMax={xMax}
|
|
570
627
|
yAxisWidth={yAxisWidth}
|
|
571
628
|
numTicks={handleNumTicks}
|
|
572
|
-
yLabelOffset={yLabelOffset}
|
|
573
629
|
axisLabelFontSize={axisLabelFontSize}
|
|
574
630
|
/>
|
|
575
631
|
)}
|
|
@@ -653,8 +709,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
653
709
|
strokeDasharray={handleLineType(anchor.lineStyle)}
|
|
654
710
|
stroke={anchor.color ? anchor.color : 'rgba(0,0,0,1)'}
|
|
655
711
|
className='anchor-y'
|
|
656
|
-
from={{ x: Number(
|
|
657
|
-
to={{ x: Number(
|
|
712
|
+
from={{ x: Number(yAxisWidth), y: position - middleOffset }}
|
|
713
|
+
to={{ x: Number(yAxisWidth) + Number(xMax), y: position - middleOffset }}
|
|
658
714
|
/>
|
|
659
715
|
)
|
|
660
716
|
})}
|
|
@@ -690,8 +746,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
690
746
|
stroke={anchor.color ? anchor.color : 'rgba(0,0,0,1)'}
|
|
691
747
|
fill={anchor.color ? anchor.color : 'rgba(0,0,0,1)'}
|
|
692
748
|
className='anchor-x'
|
|
693
|
-
from={{ x: Number(anchorPosition) + Number(
|
|
694
|
-
to={{ x: Number(anchorPosition) + Number(
|
|
749
|
+
from={{ x: Number(anchorPosition) + Number(yAxisWidth), y: 0 }}
|
|
750
|
+
to={{ x: Number(anchorPosition) + Number(yAxisWidth), y: yMax }}
|
|
695
751
|
/>
|
|
696
752
|
)
|
|
697
753
|
})}
|
|
@@ -708,6 +764,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
708
764
|
tooltipData={tooltipData}
|
|
709
765
|
yMax={yMax}
|
|
710
766
|
xMax={xMax}
|
|
767
|
+
yAxisWidth={yAxisWidth}
|
|
711
768
|
/>
|
|
712
769
|
)}
|
|
713
770
|
{isNoDataAvailable && (
|
|
@@ -721,8 +778,22 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
721
778
|
)}
|
|
722
779
|
{showHoverLine && (
|
|
723
780
|
<>
|
|
724
|
-
<HoverLine
|
|
725
|
-
|
|
781
|
+
<HoverLine
|
|
782
|
+
xMax={xMax}
|
|
783
|
+
yMax={yMax}
|
|
784
|
+
point={point}
|
|
785
|
+
tooltipData={tooltipData}
|
|
786
|
+
orientation='horizontal'
|
|
787
|
+
yAxisWidth={yAxisWidth}
|
|
788
|
+
/>
|
|
789
|
+
<HoverLine
|
|
790
|
+
xMax={xMax}
|
|
791
|
+
yMax={yMax}
|
|
792
|
+
point={point}
|
|
793
|
+
tooltipData={tooltipData}
|
|
794
|
+
orientation='vertical'
|
|
795
|
+
yAxisWidth={yAxisWidth}
|
|
796
|
+
/>
|
|
726
797
|
</>
|
|
727
798
|
)}
|
|
728
799
|
<Group left={yAxisWidth}>
|
|
@@ -758,7 +829,6 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
758
829
|
suffixWidth={suffixWidth}
|
|
759
830
|
horizontalYAxisLabelSpace={horizontalYAxisLabelSpace}
|
|
760
831
|
categoryLabelSpace={categoryLabelSpace}
|
|
761
|
-
yLabelOffset={yLabelOffset}
|
|
762
832
|
/>
|
|
763
833
|
)}
|
|
764
834
|
{config.yAxis.type === 'categorical' && config.orientation === 'vertical' && (
|
|
@@ -819,10 +889,10 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
819
889
|
</svg>
|
|
820
890
|
{!isDraggingAnnotation &&
|
|
821
891
|
tooltipData &&
|
|
822
|
-
|
|
892
|
+
tooltipData.data?.length > 0 &&
|
|
823
893
|
tooltipOpen &&
|
|
824
894
|
showTooltip &&
|
|
825
|
-
!tooltipData?.data?.some(
|
|
895
|
+
!tooltipData?.data?.some(row => row?.value === undefined) &&
|
|
826
896
|
tooltipData.dataYPosition &&
|
|
827
897
|
tooltipData.dataXPosition &&
|
|
828
898
|
!config.tooltips.singleSeries && (
|
|
@@ -834,15 +904,22 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
834
904
|
<TooltipWithBounds
|
|
835
905
|
ref={tooltipRef}
|
|
836
906
|
key={Math.random()}
|
|
837
|
-
className={'tooltip
|
|
907
|
+
className={'tooltip cove-visualization'}
|
|
838
908
|
left={tooltipLeft}
|
|
839
909
|
top={tooltipTop}
|
|
840
910
|
>
|
|
841
911
|
<ul>
|
|
842
912
|
{typeof tooltipData === 'object' &&
|
|
843
|
-
|
|
844
|
-
.filter(
|
|
845
|
-
.map((
|
|
913
|
+
tooltipData.data
|
|
914
|
+
.filter(row => row && row.value !== undefined)
|
|
915
|
+
.map((row, index) => (
|
|
916
|
+
<TooltipListItem
|
|
917
|
+
row={row}
|
|
918
|
+
index={index}
|
|
919
|
+
key={index}
|
|
920
|
+
useMarkerColumn={tooltipData.useMarkerColumn}
|
|
921
|
+
/>
|
|
922
|
+
))}
|
|
846
923
|
</ul>
|
|
847
924
|
</TooltipWithBounds>
|
|
848
925
|
</>
|
|
@@ -10,7 +10,7 @@ import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
|
|
|
10
10
|
import { getTextWidth } from '@cdc/core/helpers/getTextWidth'
|
|
11
11
|
import { isMobileFontViewport } from '@cdc/core/helpers/viewports'
|
|
12
12
|
|
|
13
|
-
const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
13
|
+
const PairedBarChart = ({ width, height, originalWidth, yAxisWidth }) => {
|
|
14
14
|
const {
|
|
15
15
|
config,
|
|
16
16
|
colorScale,
|
|
@@ -93,7 +93,7 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
93
93
|
id='cdc-visualization__paired-bar-chart'
|
|
94
94
|
width={originalWidth}
|
|
95
95
|
height={height}
|
|
96
|
-
viewBox={`0 0 ${width +
|
|
96
|
+
viewBox={`0 0 ${width + yAxisWidth} ${height}`}
|
|
97
97
|
role='img'
|
|
98
98
|
tabIndex={0}
|
|
99
99
|
>
|