@cdc/chart 4.26.3 → 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.
Files changed (128) hide show
  1. package/CONFIG.md +169 -0
  2. package/README.md +42 -17
  3. package/dist/cdcchart.js +34725 -33730
  4. package/examples/feature/bar/additional-column-tooltip.json +3 -3
  5. package/examples/feature/deviation/planet-deviation-config.json +2 -2
  6. package/examples/feature/paired-bar/paired-bar-example.json +2 -2
  7. package/examples/feature/tests-case-rate/case-rate-example-config.json +2 -2
  8. package/examples/feature/tests-covid/covid-confidence-example-config.json +2 -2
  9. package/examples/feature/tests-covid/covid-example-config.json +2 -2
  10. package/examples/feature/tests-cutoff/cutoff-example-config.json +2 -2
  11. package/examples/feature/tests-non-numerics/planet-pie-example-config-nonnumeric.json +2 -2
  12. package/examples/metadata-variables.json +1 -1
  13. package/examples/minimal-example.json +24 -0
  14. package/examples/private/test2.json +35012 -0
  15. package/package.json +4 -4
  16. package/src/CdcChartComponent.tsx +9 -6
  17. package/src/_stories/{Chart.HTMLInDataTable.stories.tsx → Chart.HTMLInDataTable.smoke.stories.tsx} +10 -0
  18. package/src/_stories/Chart.Minimal.smoke.stories.tsx +25 -0
  19. package/src/_stories/{Chart.SmallMultiples.stories.tsx → Chart.SmallMultiples.smoke.stories.tsx} +17 -1
  20. package/src/_stories/{Chart.stories.tsx → Chart.smoke.stories.tsx} +12 -0
  21. package/src/_stories/{Chart.tooltip.stories.tsx → Chart.tooltip.smoke.stories.tsx} +68 -0
  22. package/src/_stories/ChartBar.Editor.stories.tsx +88 -85
  23. package/src/_stories/ChartEditor.Editor.stories.tsx +23 -0
  24. package/src/_stories/ChartLine.DashedDates.smoke.stories.tsx +23 -0
  25. package/src/_stories/_mock/line_chart_dashed_dates.json +276 -0
  26. package/src/_stories/_mock/paired-bar-abbr.json +1 -1
  27. package/src/_stories/_mock/paired-bar.json +1 -1
  28. package/src/components/Annotations/components/AnnotationDraggable.tsx +1 -1
  29. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +10 -2
  30. package/src/components/Axis/BottomAxis.tsx +1 -1
  31. package/src/components/Axis/LeftAxis.tsx +2 -4
  32. package/src/components/Axis/LeftAxisGridlines.tsx +1 -3
  33. package/src/components/BarChart/components/BarChart.Horizontal.tsx +9 -5
  34. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +9 -5
  35. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +9 -5
  36. package/src/components/BarChart/components/BarChart.Vertical.tsx +9 -6
  37. package/src/components/BarChart/components/BarChart.tsx +2 -6
  38. package/src/components/BarChart/helpers/useBarChart.ts +1 -1
  39. package/src/components/BoxPlot/BoxPlot.Vertical.tsx +3 -3
  40. package/src/components/EditorPanel/EditorPanel.tsx +633 -908
  41. package/src/components/EditorPanel/EditorPanelContext.ts +1 -1
  42. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +216 -165
  43. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +168 -116
  44. package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +154 -109
  45. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +3 -3
  46. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +12 -26
  47. package/src/components/EditorPanel/useEditorPermissions.ts +1 -10
  48. package/src/components/Forecasting/Forecasting.tsx +2 -2
  49. package/src/components/HorizonChart/HorizonChart.tsx +10 -2
  50. package/src/components/HoverLine/HoverLine.tsx +6 -8
  51. package/src/components/Legend/Legend.Component.tsx +4 -4
  52. package/src/components/Legend/LegendGroup/LegendGroup.styles.css +5 -0
  53. package/src/components/Legend/LegendGroup/LegendGroup.tsx +3 -1
  54. package/src/components/Legend/helpers/index.ts +0 -2
  55. package/src/components/LineChart/LineChartProps.ts +1 -0
  56. package/src/components/LineChart/components/LineChart.BumpCircle.tsx +3 -2
  57. package/src/components/LineChart/index.tsx +11 -4
  58. package/src/components/LinearChart/VisualizationRenderer.tsx +11 -1
  59. package/src/components/LinearChart/tests/LinearChart.test.tsx +147 -0
  60. package/src/components/LinearChart.tsx +98 -41
  61. package/src/components/PairedBarChart.jsx +2 -2
  62. package/src/components/PieChart/PieChart.tsx +11 -9
  63. package/src/components/Regions/components/Regions.tsx +30 -20
  64. package/src/components/ScatterPlot/ScatterPlot.jsx +19 -17
  65. package/src/components/SmallMultiples/SmallMultipleTile.tsx +1 -0
  66. package/src/components/Sparkline/components/SparkLine.tsx +1 -1
  67. package/src/components/WarmingStripes/WarmingStripes.tsx +5 -3
  68. package/src/data/initial-state.js +1 -0
  69. package/src/helpers/calculateLeftYAxisWidth.ts +193 -0
  70. package/src/helpers/tests/tooltipHelpers.test.ts +151 -0
  71. package/src/helpers/tooltipHelpers.ts +176 -0
  72. package/src/hooks/useHighlightedBars.ts +9 -16
  73. package/src/hooks/useProgrammaticTooltip.ts +16 -2
  74. package/src/hooks/useSmallMultipleSynchronization.ts +3 -4
  75. package/src/hooks/useTooltip.tsx +167 -38
  76. package/src/test/CdcChart.test.jsx +24 -0
  77. package/src/types/ChartConfig.ts +1 -0
  78. package/LICENSE +0 -201
  79. package/examples/chart-regression-2.json +0 -2360
  80. package/examples/feature/__data__/age-adjusted-rates.json +0 -1486
  81. package/examples/feature/__data__/city-temperature.json +0 -2198
  82. package/examples/feature/bar/Barchart_with_negative.json +0 -34
  83. package/examples/feature/boxplot/box-plot-data.json +0 -71
  84. package/examples/feature/boxplot/boxplot-data.json +0 -156
  85. package/examples/feature/combo/combochart-categories_are_numbers .json +0 -18
  86. package/examples/feature/forest-plot/log.json +0 -26
  87. package/examples/feature/tests-date-exclusions/date-exclusions-data.json +0 -162
  88. package/examples/region-issue.json +0 -2065
  89. package/examples/xaxis.json +0 -493
  90. /package/examples/{data → __data__}/data-with-metadata.json +0 -0
  91. /package/examples/feature/bar/{tall-data.json → __data__/tall-data.json} +0 -0
  92. /package/examples/feature/deviation/{planet-deviation-data.json → __data__/planet-deviation-data.json} +0 -0
  93. /package/examples/feature/paired-bar/{paired-bar-data.json → __data__/paired-bar-data.json} +0 -0
  94. /package/examples/feature/paired-bar/{paired-bar-formatted.json → __data__/paired-bar-formatted.json} +0 -0
  95. /package/examples/feature/tests-case-rate/{case-rate-example-data.json → __data__/case-rate-example-data.json} +0 -0
  96. /package/examples/feature/tests-covid/{covid-example-data-confidence.json → __data__/covid-example-data-confidence.json} +0 -0
  97. /package/examples/feature/tests-covid/{covid-example-data.json → __data__/covid-example-data.json} +0 -0
  98. /package/examples/feature/tests-cutoff/{cutoff-example-data.json → __data__/cutoff-example-data.json} +0 -0
  99. /package/examples/feature/tests-non-numerics/{planet-example-data-nonnumeric.json → __data__/planet-example-data-nonnumeric.json} +0 -0
  100. /package/src/_stories/{Chart.Anchors.stories.tsx → Chart.Anchors.smoke.stories.tsx} +0 -0
  101. /package/src/_stories/{Chart.BoxPlot.stories.tsx → Chart.BoxPlot.smoke.stories.tsx} +0 -0
  102. /package/src/_stories/{Chart.CI.stories.tsx → Chart.CI.smoke.stories.tsx} +0 -0
  103. /package/src/_stories/{Chart.Combo.stories.tsx → Chart.Combo.smoke.stories.tsx} +0 -0
  104. /package/src/_stories/{Chart.CustomColors.stories.tsx → Chart.CustomColors.smoke.stories.tsx} +0 -0
  105. /package/src/_stories/{Chart.Defaults.stories.tsx → Chart.Defaults.smoke.stories.tsx} +0 -0
  106. /package/src/_stories/{Chart.DynamicSeries.stories.tsx → Chart.DynamicSeries.smoke.stories.tsx} +0 -0
  107. /package/src/_stories/{Chart.Filters.stories.tsx → Chart.Filters.smoke.stories.tsx} +0 -0
  108. /package/src/_stories/{Chart.Forecast.stories.tsx → Chart.Forecast.smoke.stories.tsx} +0 -0
  109. /package/src/_stories/{Chart.Legend.Gradient.stories.tsx → Chart.Legend.Gradient.smoke.stories.tsx} +0 -0
  110. /package/src/_stories/{Chart.Patterns.stories.tsx → Chart.Patterns.smoke.stories.tsx} +0 -0
  111. /package/src/_stories/{Chart.PreserveDecimals.stories.tsx → Chart.PreserveDecimals.smoke.stories.tsx} +0 -0
  112. /package/src/_stories/{Chart.Regions.Categorical.stories.tsx → Chart.Regions.Categorical.smoke.stories.tsx} +0 -0
  113. /package/src/_stories/{Chart.Regions.DateScale.stories.tsx → Chart.Regions.DateScale.smoke.stories.tsx} +0 -0
  114. /package/src/_stories/{Chart.Regions.DateTimeScale.stories.tsx → Chart.Regions.DateTimeScale.smoke.stories.tsx} +0 -0
  115. /package/src/_stories/{Chart.ScatterPlot.stories.tsx → Chart.ScatterPlot.smoke.stories.tsx} +0 -0
  116. /package/src/_stories/{Chart.SmallestLeftAxisMax.stories.tsx → Chart.SmallestLeftAxisMax.smoke.stories.tsx} +0 -0
  117. /package/src/_stories/{ChartAnnotation.stories.tsx → ChartAnnotation.smoke.stories.tsx} +0 -0
  118. /package/src/_stories/{ChartAxisLabels.stories.tsx → ChartAxisLabels.smoke.stories.tsx} +0 -0
  119. /package/src/_stories/{ChartAxisTitles.stories.tsx → ChartAxisTitles.smoke.stories.tsx} +0 -0
  120. /package/src/_stories/{ChartBrush.Matrix.Continuous.stories.tsx → ChartBrush.Matrix.Continuous.smoke.stories.tsx} +0 -0
  121. /package/src/_stories/{ChartBrush.Matrix.Date.stories.tsx → ChartBrush.Matrix.Date.smoke.stories.tsx} +0 -0
  122. /package/src/_stories/{ChartBrush.Matrix.DateTime.stories.tsx → ChartBrush.Matrix.DateTime.smoke.stories.tsx} +0 -0
  123. /package/src/_stories/{ChartBrush.stories.tsx → ChartBrush.smoke.stories.tsx} +0 -0
  124. /package/src/_stories/{ChartLine.QuadrantAngles.stories.tsx → ChartLine.QuadrantAngles.smoke.stories.tsx} +0 -0
  125. /package/src/_stories/{ChartLine.Suppression.stories.tsx → ChartLine.Suppression.smoke.stories.tsx} +0 -0
  126. /package/src/_stories/{ChartLine.Symbols.stories.tsx → ChartLine.Symbols.smoke.stories.tsx} +0 -0
  127. /package/src/_stories/{ChartPrefixSuffix.stories.tsx → ChartPrefixSuffix.smoke.stories.tsx} +0 -0
  128. /package/src/_stories/{TechAdoptionWithLinks.stories.tsx → TechAdoptionWithLinks.smoke.stories.tsx} +0 -0
@@ -9,6 +9,7 @@ import { updatePaletteNames } from '@cdc/core/helpers/updatePaletteNames'
9
9
  import { getColorPaletteVersion } from '@cdc/core/helpers/getColorPaletteVersion'
10
10
  import Icon from '@cdc/core/components/ui/Icon'
11
11
  import { CheckBox, Select, TextField } from '@cdc/core/components/EditorPanel/Inputs'
12
+ import Button from '@cdc/core/components/elements/Button'
12
13
  import { buildForecastPaletteOptions } from '../../../../helpers/buildForecastPaletteOptions'
13
14
  import { getSeriesColumnConfig, upsertSeriesColumnConfig } from '../../../../helpers/seriesColumnSettings'
14
15
 
@@ -20,7 +21,7 @@ import {
20
21
  AccordionItemPanel,
21
22
  AccordionItemButton
22
23
  } from 'react-accessible-accordion'
23
- import { Draggable, DragDropContext, Droppable } from '@hello-pangea/dnd'
24
+ import { Draggable } from '@hello-pangea/dnd'
24
25
  import Tooltip from '@cdc/core/components/ui/Tooltip'
25
26
 
26
27
  const SeriesContext = React.createContext({})
@@ -375,8 +376,8 @@ const SeriesDropdownConfidenceInterval = props => {
375
376
  )
376
377
  })}
377
378
  </Accordion>
378
- <button
379
- className='btn btn-primary full-width'
379
+ <Button
380
+ variant='editor-primary'
380
381
  onClick={e => {
381
382
  e.preventDefault()
382
383
  let copiedIndex = null
@@ -397,7 +398,7 @@ const SeriesDropdownConfidenceInterval = props => {
397
398
  }}
398
399
  >
399
400
  Add Confidence Interval Group
400
- </button>
401
+ </Button>
401
402
  </fieldset>
402
403
  </div>
403
404
  )
@@ -652,7 +653,7 @@ const SeriesButtonRemove = props => {
652
653
  }
653
654
  }
654
655
 
655
- const handleRemoveSeries = (e, series, index) => {
656
+ const handleRemoveSeries = (e, series) => {
656
657
  e.preventDefault()
657
658
  removeSeries(series.dataKey)
658
659
  }
@@ -660,9 +661,9 @@ const SeriesButtonRemove = props => {
660
661
  return (
661
662
  config.series &&
662
663
  config.series.length > 1 && (
663
- <button className='series-list__remove' onClick={e => handleRemoveSeries(e, series, index)}>
664
+ <Button variant='danger' size='sm' className='grouped-list__remove' onClick={e => handleRemoveSeries(e, series)}>
664
665
  Remove
665
- </button>
666
+ </Button>
666
667
  )
667
668
  )
668
669
  }
@@ -710,11 +711,13 @@ const SeriesItem = props => {
710
711
  >
711
712
  <Icon display='move' size={15} style={{ cursor: 'default' }} />
712
713
  {series.dataKey}
713
- <Series.Button.Remove series={series} index={i} />
714
714
  </AccordionItemButton>
715
715
  </AccordionItemHeading>
716
716
  {chartsWithOptions.includes(config.visualizationType) && (
717
717
  <AccordionItemPanel>
718
+ <div className='series-item__panel-actions'>
719
+ <Series.Button.Remove series={series} index={i} />
720
+ </div>
718
721
  <Series.Input.Name series={series} index={i} />
719
722
  <Series.Input.ColumnSettings series={series} index={i} />
720
723
  {showDynamicCategory && (
@@ -773,22 +776,6 @@ const SeriesItem = props => {
773
776
  )
774
777
  }
775
778
 
776
- const SeriesList = props => {
777
- const { series, getItemStyle, sortableItemStyles, chartsWithOptions } = props
778
- return series.map((series, i) => {
779
- return (
780
- <SeriesItem
781
- getItemStyle={getItemStyle}
782
- sortableItemStyles={sortableItemStyles}
783
- chartsWithOptions={chartsWithOptions}
784
- series={series}
785
- index={i}
786
- key={`series-list-${i}`}
787
- />
788
- )
789
- })
790
- }
791
-
792
779
  const Series = {
793
780
  Wrapper: SeriesWrapper,
794
781
  Dropdown: {
@@ -811,8 +798,7 @@ const Series = {
811
798
  Button: {
812
799
  Remove: SeriesButtonRemove
813
800
  },
814
- Item: SeriesItem,
815
- List: SeriesList
801
+ Item: SeriesItem
816
802
  }
817
803
 
818
804
  export default Series
@@ -274,16 +274,7 @@ export const useEditorPermissions = () => {
274
274
  }
275
275
 
276
276
  const visSupportsRegions = () => {
277
- const disabledCharts = [
278
- 'Forest Plot',
279
- 'Horizon Chart',
280
- 'Pie',
281
- 'Paired Bar',
282
- 'Radar',
283
- 'Spark Line',
284
- 'Sankey',
285
- 'Warming Stripes'
286
- ]
277
+ const disabledCharts = ['Forest Plot', 'Pie', 'Paired Bar', 'Radar', 'Spark Line', 'Sankey', 'Warming Stripes']
287
278
  if (disabledCharts.includes(visualizationType)) return false
288
279
  return true
289
280
  }
@@ -110,7 +110,7 @@ const prepareForecastData = (
110
110
  return segments.length > 0 ? segments : [sortedData]
111
111
  }
112
112
 
113
- const Forecasting = ({ xScale, yScale, height, width, handleTooltipMouseOver, handleTooltipMouseOff }) => {
113
+ const Forecasting = ({ xScale, yScale, height, width, yAxisWidth, handleTooltipMouseOver, handleTooltipMouseOff }) => {
114
114
  const { transformedData: data, rawData, config, seriesHighlight, parseDate } = useContext(ConfigContext)
115
115
  const { xAxis, yAxis, legend, runtime } = config
116
116
  const DEBUG = false
@@ -143,7 +143,7 @@ const Forecasting = ({ xScale, yScale, height, width, handleTooltipMouseOver, ha
143
143
  return (
144
144
  data && (
145
145
  <ErrorBoundary component='ForecastingChart'>
146
- <Group className='forecasting-items' key='forecasting-items-wrapper' left={Number(yAxis.size)}>
146
+ <Group className='forecasting-items' key='forecasting-items-wrapper' left={yAxisWidth}>
147
147
  {runtime.forecastingSeriesKeys?.map((group, index) => {
148
148
  if (!group || !group.stages) return false
149
149
  return group.stages.map((stage, stageIndex) => {
@@ -23,13 +23,21 @@ type HorizonChartProps = {
23
23
  yScale: any
24
24
  xMax: number
25
25
  yMax: number
26
+ yAxisWidth: number
26
27
  handleTooltipMouseOver: (e: any, additionalData?: any) => void
27
28
  handleTooltipMouseOff: () => void
28
29
  tooltipData?: any
29
30
  showTooltip?: boolean
30
31
  }
31
32
 
32
- const HorizonChart = ({ xScale, xMax, yMax, handleTooltipMouseOver, handleTooltipMouseOff }: HorizonChartProps) => {
33
+ const HorizonChart = ({
34
+ xScale,
35
+ xMax,
36
+ yMax,
37
+ yAxisWidth,
38
+ handleTooltipMouseOver,
39
+ handleTooltipMouseOff
40
+ }: HorizonChartProps) => {
33
41
  // Get data and config from context
34
42
  const { transformedData: data, config, colorScale, rawData, parseDate } = useContext(ConfigContext)
35
43
 
@@ -94,7 +102,7 @@ const HorizonChart = ({ xScale, xMax, yMax, handleTooltipMouseOver, handleToolti
94
102
 
95
103
  return (
96
104
  <ErrorBoundary component='HorizonChart'>
97
- <Group className='horizon-chart' key='horizon-wrapper' left={Number(config.yAxis.size)} height={Number(yMax)}>
105
+ <Group className='horizon-chart' key='horizon-wrapper' left={yAxisWidth} height={Number(yMax)}>
98
106
  {seriesKeys.map((seriesKey, index) => {
99
107
  const rowY = getRowY(index)
100
108
  return (
@@ -9,9 +9,10 @@ type HoverLineProps = {
9
9
  yMax?: number
10
10
  point: { x: number; y: number }
11
11
  orientation: 'horizontal' | 'vertical'
12
+ yAxisWidth: number
12
13
  }
13
14
 
14
- const HoverLine: React.FC<HoverLineProps> = ({ tooltipData, xMax, yMax, point, orientation }) => {
15
+ const HoverLine: React.FC<HoverLineProps> = ({ tooltipData, xMax, yMax, point, orientation, yAxisWidth }) => {
15
16
  const { config } = useContext(ConfigContext)
16
17
  const { verticalHoverLine, horizontalHoverLine } = config.visual
17
18
  const { visualizationType } = config
@@ -23,8 +24,9 @@ const HoverLine: React.FC<HoverLineProps> = ({ tooltipData, xMax, yMax, point, o
23
24
  const showHorizontalHoverLine = horizontalHoverLine || (horizontalHoverLine && isScatterPlot)
24
25
 
25
26
  const getX = () => {
26
- if (point.x > xMax + Number(config.yAxis.size)) return xMax
27
- if (point.x < config.yAxis.size) return config.yAxis.size
27
+ if (point.x < yAxisWidth) return yAxisWidth
28
+ if (xMax === undefined) return point.x
29
+ if (point.x > xMax + yAxisWidth) return xMax + yAxisWidth
28
30
  return point.x
29
31
  }
30
32
 
@@ -52,11 +54,7 @@ const HoverLine: React.FC<HoverLineProps> = ({ tooltipData, xMax, yMax, point, o
52
54
  if (isHorizontal) {
53
55
  return (
54
56
  showHorizontalHoverLine && (
55
- <Group
56
- key={`tooltipLine-horizontal${point.y}${point.x}`}
57
- className='horizontal-tooltip-line'
58
- left={config.yAxis.size ? config.yAxis.size : 0}
59
- >
57
+ <Group key={`tooltipLine-horizontal${point.y}${point.x}`} className='horizontal-tooltip-line' left={yAxisWidth}>
60
58
  <Line
61
59
  from={{ x: 0, y: getY() }}
62
60
  to={{ x: xMax, y: getY() }}
@@ -117,8 +117,8 @@ const Legend: React.FC<LegendProps> = forwardRef(
117
117
  >
118
118
  {(legend.label || legend.description) && (
119
119
  <div className={legend.description ? 'mb-3' : 'mb-2'}>
120
- {legend.label && <h3 className='fw-bold'>{parse(legend.label)}</h3>}
121
- {legend.description && <p className='mt-2'>{parse(legend.description)}</p>}
120
+ {legend.label && <h3 className='fw-bold cove-prose'>{parse(legend.label)}</h3>}
121
+ {legend.description && <p className='mt-2 cove-prose'>{parse(legend.description)}</p>}
122
122
  </div>
123
123
  )}
124
124
  <LegendGradient
@@ -242,7 +242,7 @@ const Legend: React.FC<LegendProps> = forwardRef(
242
242
  </>
243
243
  )}
244
244
  </>
245
- <LegendLabel align='left' className='m-0'>
245
+ <LegendLabel align='left' className='m-0 cove-prose'>
246
246
  {parse(label.text)}
247
247
  </LegendLabel>
248
248
  </LegendItem>
@@ -361,7 +361,7 @@ const Legend: React.FC<LegendProps> = forwardRef(
361
361
  />
362
362
  </svg>
363
363
  </span>
364
- <LegendLabel align='left' className='m-0'>
364
+ <LegendLabel align='left' className='m-0 cove-prose'>
365
365
  {parse(String((pattern as any)?.label || key))}
366
366
  </LegendLabel>
367
367
  </LegendItem>
@@ -17,6 +17,11 @@
17
17
  }
18
18
  }
19
19
 
20
+ .legend-group-grid {
21
+ display: flex;
22
+ flex-wrap: wrap;
23
+ }
24
+
20
25
  .legend-group.top,
21
26
  .legend-group.bottom {
22
27
  grid-gap: 10px;
@@ -32,7 +32,7 @@ const LegendGroup = ({ formatLabels }) => {
32
32
 
33
33
  const groups: string[] = getSubGroups(data, config.legend.groupBy)
34
34
 
35
- const classNames = ['legend-group', 'container', config.legend.position, currentViewport, 'row']
35
+ const classNames = ['legend-group', 'legend-group-grid', 'container', config.legend.position, currentViewport]
36
36
 
37
37
  const gridCol =
38
38
  currentViewport === 'xs'
@@ -47,6 +47,8 @@ const LegendGroup = ({ formatLabels }) => {
47
47
 
48
48
  let classNameItem = ['legend-group group-item', isSigleCol]
49
49
 
50
+ if (groups.length === 0) return null
51
+
50
52
  return (
51
53
  <div className={classNames.join(' ')}>
52
54
  {groups.map(group => {
@@ -40,8 +40,6 @@ export const getMarginBottom = (isLegendBottom, config) => {
40
40
 
41
41
  if (isLegendTop) marginBottom = 27
42
42
 
43
- if (isLegendTop && config.yAxis?.inlineLabel) marginBottom += 9
44
-
45
43
  if (isLegendBottom) marginBottom += 9
46
44
 
47
45
  if (hasSuppression) marginBottom += 40
@@ -8,6 +8,7 @@ export type LineChartProps = {
8
8
  getYAxisData: Function
9
9
  xMax: number
10
10
  yMax: number
11
+ yAxisWidth: number
11
12
  handleTooltipMouseOver: Function
12
13
  handleTooltipMouseOff: Function
13
14
  showTooltip: boolean
@@ -10,10 +10,11 @@ type LineChartBumpCircleProp = {
10
10
  xScale: any
11
11
  yScale: any
12
12
  parseDate: any
13
+ yAxisWidth: number
13
14
  }
14
15
 
15
16
  const LineChartBumpCircle = (props: LineChartBumpCircleProp) => {
16
- const { config, xScale, yScale, parseDate } = props
17
+ const { config, xScale, yScale, parseDate, yAxisWidth } = props
17
18
 
18
19
  // get xScale and yScale...
19
20
  if (!config?.runtime?.series) return
@@ -55,7 +56,7 @@ const LineChartBumpCircle = (props: LineChartBumpCircleProp) => {
55
56
  let axis_dataKey = d[config.xAxis.dataKey]
56
57
  return (
57
58
  <React.Fragment key={`bump-circle-${series_dataKey}-${dataIndex}`}>
58
- <Group left={Number(config.runtime.yAxis.size)}>
59
+ <Group left={yAxisWidth}>
59
60
  {series_dataKey && (
60
61
  <>
61
62
  <circle
@@ -36,6 +36,7 @@ const LineChart = (props: LineChartProps) => {
36
36
  xScale,
37
37
  yMax,
38
38
  yScale,
39
+ yAxisWidth,
39
40
  } = props
40
41
 
41
42
  // prettier-ignore
@@ -55,7 +56,7 @@ const LineChart = (props: LineChartProps) => {
55
56
 
56
57
  return (
57
58
  <ErrorBoundary component='LineChart'>
58
- <Group left={Number(config.runtime.yAxis.size)} className='line-chart-group'>
59
+ <Group left={yAxisWidth} className='line-chart-group'>
59
60
  {/* left - expects a number not a string */}
60
61
  {(config.runtime.lineSeriesKeys || config.runtime.seriesKeys).map((seriesKey, index) => {
61
62
  const seriesData = config.runtime.series.find(item => item.dataKey === seriesKey)
@@ -264,7 +265,7 @@ const LineChart = (props: LineChartProps) => {
264
265
  }
265
266
  styles={createStyles({
266
267
  preliminaryData: config.preliminaryData,
267
- data: tableData,
268
+ data: _data,
268
269
  stroke: colorScale(config.runtime.seriesLabels[seriesKey]),
269
270
  strokeWidth: seriesData.weight || 2,
270
271
  handleLineType,
@@ -496,7 +497,7 @@ const LineChart = (props: LineChartProps) => {
496
497
  </Text>
497
498
  )}
498
499
  </Group>
499
- <Group left={Number(config.runtime.yAxis.size)} className='glyph-tooltip-group'>
500
+ <Group left={yAxisWidth} className='glyph-tooltip-group'>
500
501
  <Group key={`tooltip-group`} display={'block'}>
501
502
  {/* tooltips */}
502
503
  <Bar
@@ -543,7 +544,13 @@ const LineChart = (props: LineChartProps) => {
543
544
  </Group>
544
545
  </Group>
545
546
  {config.visualizationType === 'Bump Chart' && (
546
- <LineChartBumpCircle config={config} xScale={xScale} yScale={yScale} />
547
+ <LineChartBumpCircle
548
+ config={config}
549
+ xScale={xScale}
550
+ yScale={yScale}
551
+ parseDate={parseDate}
552
+ yAxisWidth={yAxisWidth}
553
+ />
547
554
  )}
548
555
  </ErrorBoundary>
549
556
  )
@@ -76,13 +76,16 @@ const VisualizationRenderer: React.FC<VisualizationRendererProps> = ({
76
76
  )}
77
77
 
78
78
  {/* Paired Bar Chart */}
79
- {visualizationType === 'Paired Bar' && <PairedBarChart originalWidth={parentWidth} width={xMax} height={yMax} />}
79
+ {visualizationType === 'Paired Bar' && (
80
+ <PairedBarChart originalWidth={parentWidth} width={xMax} height={yMax} yAxisWidth={yAxisWidth} />
81
+ )}
80
82
 
81
83
  {/* Scatter Plot */}
82
84
  {visualizationType === 'Scatter Plot' && (
83
85
  <ScatterPlot
84
86
  xScale={xScale}
85
87
  yScale={yScale}
88
+ yAxisWidth={yAxisWidth}
86
89
  getXAxisData={getXAxisData}
87
90
  getYAxisData={getYAxisData}
88
91
  xMax={xMax}
@@ -102,6 +105,7 @@ const VisualizationRenderer: React.FC<VisualizationRendererProps> = ({
102
105
  yScale={yScale}
103
106
  xMax={xMax}
104
107
  yMax={yMax}
108
+ yAxisWidth={yAxisWidth}
105
109
  synchronizedXValue={synchronizedXValue}
106
110
  showTooltip={showTooltip}
107
111
  handleTooltipMouseOff={handleTooltipMouseOff}
@@ -115,6 +119,7 @@ const VisualizationRenderer: React.FC<VisualizationRendererProps> = ({
115
119
  yScale={yScale}
116
120
  xMax={xMax}
117
121
  yMax={yMax}
122
+ yAxisWidth={yAxisWidth}
118
123
  handleTooltipMouseOver={handleTooltipMouseOver}
119
124
  handleTooltipMouseOff={handleTooltipMouseOff}
120
125
  tooltipData={tooltipData}
@@ -132,6 +137,7 @@ const VisualizationRenderer: React.FC<VisualizationRendererProps> = ({
132
137
  max={max}
133
138
  xScale={xScale}
134
139
  yScale={yScale}
140
+ yAxisWidth={yAxisWidth}
135
141
  />
136
142
  )}
137
143
 
@@ -156,6 +162,7 @@ const VisualizationRenderer: React.FC<VisualizationRendererProps> = ({
156
162
  yScale={yScale}
157
163
  yMax={yMax}
158
164
  xMax={xMax}
165
+ yAxisWidth={yAxisWidth}
159
166
  chartRef={svgRef}
160
167
  width={xMax}
161
168
  height={yMax}
@@ -193,6 +200,7 @@ const VisualizationRenderer: React.FC<VisualizationRendererProps> = ({
193
200
  <LineChart
194
201
  xScale={xScale}
195
202
  yScale={yScale}
203
+ yAxisWidth={yAxisWidth}
196
204
  getXAxisData={getXAxisData}
197
205
  getYAxisData={getYAxisData}
198
206
  xMax={xMax}
@@ -211,6 +219,7 @@ const VisualizationRenderer: React.FC<VisualizationRendererProps> = ({
211
219
  <LineChart
212
220
  xScale={xScale}
213
221
  yScale={yScale}
222
+ yAxisWidth={yAxisWidth}
214
223
  getXAxisData={getXAxisData}
215
224
  getYAxisData={getYAxisData}
216
225
  xMax={xMax}
@@ -229,6 +238,7 @@ const VisualizationRenderer: React.FC<VisualizationRendererProps> = ({
229
238
  tooltipData={tooltipData}
230
239
  xScale={xScale}
231
240
  yScale={yScale}
241
+ yAxisWidth={yAxisWidth}
232
242
  width={xMax}
233
243
  height={yMax}
234
244
  xScaleNoPadding={xScaleNoPadding}
@@ -67,6 +67,11 @@ const renderLinearChart = (
67
67
  )
68
68
  }
69
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
+
70
75
  describe('LinearChart', () => {
71
76
  describe('rendering', () => {
72
77
  it('renders without crashing', () => {
@@ -258,6 +263,148 @@ describe('LinearChart', () => {
258
263
  // The axis line should be hidden, but grid lines may still render
259
264
  expect(container.querySelector('svg')).toBeTruthy()
260
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
+ })
261
408
  })
262
409
 
263
410
  describe('SVG dimensions', () => {