@cdc/chart 4.24.10 → 4.24.12-2

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 (94) hide show
  1. package/dist/cdcchart.js +35019 -34301
  2. package/examples/feature/boxplot/boxplot-data.json +88 -22
  3. package/examples/feature/boxplot/boxplot.json +540 -16
  4. package/examples/feature/boxplot/testing.csv +7 -7
  5. package/examples/feature/sankey/sankey-example-data.json +126 -14
  6. package/examples/feature/tests-date-exclusions/date-exclusions-config.json +372 -12
  7. package/examples/private/DEV-8850-2.json +493 -0
  8. package/examples/private/DEV-9822.json +574 -0
  9. package/examples/private/DEV-9840.json +553 -0
  10. package/examples/private/DEV-9850-3.json +461 -0
  11. package/examples/private/chart.json +1084 -0
  12. package/examples/private/ci_formatted.json +202 -0
  13. package/examples/private/ci_issue.json +3016 -0
  14. package/examples/private/completed.json +634 -0
  15. package/examples/private/dem-data-long.csv +20 -0
  16. package/examples/private/dem-data-long.json +36 -0
  17. package/examples/private/demographic_data.csv +157 -0
  18. package/examples/private/demographic_data.json +2654 -0
  19. package/examples/private/demographic_dynamic.json +443 -0
  20. package/examples/private/demographic_standard.json +560 -0
  21. package/examples/private/ehdi.json +29939 -0
  22. package/examples/private/test.json +493 -0
  23. package/index.html +10 -7
  24. package/package.json +2 -2
  25. package/src/CdcChart.tsx +132 -152
  26. package/src/_stories/Chart.Anchors.stories.tsx +31 -0
  27. package/src/_stories/Chart.CustomColors.stories.tsx +19 -0
  28. package/src/_stories/Chart.DynamicSeries.stories.tsx +34 -0
  29. package/src/_stories/Chart.Legend.Gradient.stories.tsx +42 -1
  30. package/src/_stories/Chart.stories.tsx +37 -6
  31. package/src/_stories/ChartAxisLabels.stories.tsx +4 -1
  32. package/src/_stories/ChartEditor.stories.tsx +27 -0
  33. package/src/_stories/ChartLine.Suppression.stories.tsx +25 -0
  34. package/src/_stories/ChartPrefixSuffix.stories.tsx +8 -0
  35. package/{examples/feature/area/area-chart-date-city-temperature.json → src/_stories/_mock/area_chart_stacked.json} +125 -27
  36. package/src/_stories/_mock/boxplot_multiseries.json +647 -0
  37. package/src/_stories/_mock/dynamic_series_bar_config.json +723 -0
  38. package/src/_stories/_mock/dynamic_series_config.json +979 -0
  39. package/src/_stories/_mock/line_chart_dynamic_ci.json +493 -0
  40. package/src/_stories/_mock/line_chart_non_dynamic_ci.json +522 -0
  41. package/{examples/feature/scatterplot/scatterplot.json → src/_stories/_mock/scatterplot_mock.json} +62 -92
  42. package/src/_stories/_mock/short_dates.json +288 -0
  43. package/src/_stories/_mock/suppression_mock.json +1549 -0
  44. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +15 -3
  45. package/src/components/Axis/Categorical.Axis.tsx +2 -2
  46. package/src/components/BarChart/components/BarChart.Horizontal.tsx +46 -37
  47. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +43 -9
  48. package/src/components/BarChart/components/BarChart.Vertical.tsx +53 -47
  49. package/src/components/BarChart/helpers/getBarData.ts +28 -0
  50. package/src/components/BarChart/helpers/index.ts +1 -2
  51. package/src/components/BarChart/helpers/tests/getBarData.test.ts +74 -0
  52. package/src/components/BoxPlot/BoxPlot.tsx +131 -0
  53. package/src/components/BoxPlot/helpers/index.ts +54 -0
  54. package/src/components/BrushChart.tsx +23 -26
  55. package/src/components/EditorPanel/EditorPanel.tsx +117 -139
  56. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +3 -3
  57. package/src/components/EditorPanel/components/Panels/Panel.BoxPlot.tsx +51 -6
  58. package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +40 -9
  59. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +3 -3
  60. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +122 -56
  61. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +1 -2
  62. package/src/components/EditorPanel/useEditorPermissions.ts +20 -2
  63. package/src/components/Legend/Legend.Component.tsx +11 -12
  64. package/src/components/Legend/Legend.tsx +16 -16
  65. package/src/components/Legend/helpers/getLegendClasses.ts +59 -0
  66. package/src/components/Legend/helpers/index.ts +2 -1
  67. package/src/components/Legend/tests/getLegendClasses.test.ts +115 -0
  68. package/src/components/LineChart/components/LineChart.Circle.tsx +1 -1
  69. package/src/components/LineChart/helpers.ts +49 -43
  70. package/src/components/LineChart/index.tsx +135 -83
  71. package/src/components/LinearChart.tsx +196 -181
  72. package/src/components/PieChart/PieChart.tsx +7 -1
  73. package/src/components/Sankey/components/ColumnList.tsx +19 -0
  74. package/src/components/Sankey/components/Sankey.tsx +479 -0
  75. package/src/components/Sankey/helpers/getSankeyTooltip.tsx +33 -0
  76. package/src/components/Sankey/index.tsx +1 -492
  77. package/src/components/Sankey/sankey.scss +22 -21
  78. package/src/components/Sankey/types/index.ts +1 -1
  79. package/src/components/Sankey/useSankeyAlert.tsx +60 -0
  80. package/src/components/ScatterPlot/ScatterPlot.jsx +20 -4
  81. package/src/data/initial-state.js +7 -12
  82. package/src/helpers/countNumOfTicks.ts +57 -0
  83. package/src/helpers/getQuartiles.ts +15 -18
  84. package/src/hooks/useMinMax.ts +44 -16
  85. package/src/hooks/useReduceData.ts +43 -10
  86. package/src/hooks/useScales.ts +90 -35
  87. package/src/hooks/useTooltip.tsx +59 -50
  88. package/src/scss/DataTable.scss +5 -0
  89. package/src/scss/main.scss +6 -20
  90. package/src/types/ChartConfig.ts +6 -19
  91. package/src/types/ChartContext.ts +4 -1
  92. package/src/types/ForestPlot.ts +8 -0
  93. package/src/components/BoxPlot/BoxPlot.jsx +0 -111
  94. package/src/hooks/useLegendClasses.ts +0 -72
@@ -7,6 +7,7 @@ import { isDateScale } from '@cdc/core/helpers/cove/date'
7
7
  // Third-party library imports
8
8
  import { localPoint } from '@visx/event'
9
9
  import { bisector } from 'd3-array'
10
+ import _ from 'lodash'
10
11
 
11
12
  export const useTooltip = props => {
12
13
  const {
@@ -56,11 +57,9 @@ export const useTooltip = props => {
56
57
  const getFormattedValue = (seriesKey, value, config, getAxisPosition) => {
57
58
  // handle case where data is missing
58
59
  const showMissingDataValue = config.general.showMissingDataLabel && (!value || value === 'null')
59
- let formattedValue = seriesKey === config.xAxis.dataKey ? value : formatNumber(value, getAxisPosition(seriesKey))
60
+ const formattedValue = seriesKey === config.xAxis.dataKey ? value : formatNumber(value, getAxisPosition(seriesKey))
60
61
 
61
- formattedValue = showMissingDataValue ? 'N/A' : formattedValue
62
-
63
- return formattedValue
62
+ return showMissingDataValue ? 'N/A' : formattedValue
64
63
  }
65
64
 
66
65
  const getTooltipInformation = (tooltipDataArray, eventSvgCoords) => {
@@ -101,37 +100,9 @@ export const useTooltip = props => {
101
100
 
102
101
  const closestXScaleValue = getXValueFromCoordinate(x - Number(config.yAxis.size || 0))
103
102
 
104
- const includedSeries =
105
- visualizationType !== 'Pie'
106
- ? config.runtime.series.filter(series => series.tooltip === true).map(item => item.dataKey)
107
- : config.runtime.series.map(item => item.dataKey)
108
- includedSeries.push(config.xAxis.dataKey)
109
- if (config.visualizationType === 'Forecasting') {
110
- config.runtime.series.map(s => {
111
- s.confidenceIntervals.map(c => {
112
- if (c.showInTooltip) {
113
- includedSeries.push(c.high)
114
- includedSeries.push(c.low)
115
- }
116
- })
117
- })
118
- }
119
- function getColumnNames(columns) {
120
- let names = []
121
- for (let key in columns) {
122
- if (columns.hasOwnProperty(key)) {
123
- names.push(columns[key].name)
124
- }
125
- }
126
- return names
127
- }
128
- includedSeries.push(...getColumnNames(config.columns))
129
- includedSeries.push(...getColumnNames(config.columns))
130
-
131
- const yScaleValues = getYScaleValues(closestXScaleValue, includedSeries)
132
103
  const xScaleValues = data.filter(d => d[xAxis.dataKey] === getClosestYValue(y))
133
104
 
134
- const resolvedScaleValues = orientation === 'vertical' ? yScaleValues : xScaleValues
105
+ const resolvedScaleValues = orientation === 'vertical' ? getYScaleValues(closestXScaleValue) : xScaleValues
135
106
 
136
107
  const getAxisPosition = seriesKey => {
137
108
  const seriesObj = config.runtime.series.filter(s => s.dataKey === seriesKey)[0]
@@ -187,12 +158,12 @@ export const useTooltip = props => {
187
158
  if (visualizationType !== 'Pie' && visualizationType !== 'Forest Plot' && !config.tooltips.singleSeries) {
188
159
  tooltipItems.push(
189
160
  ...getIncludedTooltipSeries()
190
- ?.filter(
191
- seriesKey =>
192
- config.runtime.series?.find(item => item.dataKey === seriesKey && item?.tooltip) ||
193
- config.xAxis?.dataKey == seriesKey ||
194
- visualizationType === 'Forecasting'
195
- )
161
+ ?.filter(seriesKey => {
162
+ const series = config.runtime.series?.find(
163
+ s => s.dataKey === seriesKey && s?.tooltip && !s.dynamicCategory
164
+ )
165
+ return series || config.xAxis?.dataKey == seriesKey || visualizationType === 'Forecasting'
166
+ })
196
167
  ?.flatMap(seriesKey => {
197
168
  const value = resolvedScaleValues[0]?.[seriesKey]
198
169
  const formattedValue = getFormattedValue(seriesKey, value, config, getAxisPosition)
@@ -206,6 +177,17 @@ export const useTooltip = props => {
206
177
  }
207
178
  })
208
179
  )
180
+
181
+ config.runtime.series?.forEach(series => {
182
+ if (series?.dynamicCategory) {
183
+ const seriesKey = series.dataKey
184
+ const resolvedScaleValue = resolvedScaleValues.find(v => v[series.dynamicCategory] === seriesKey)
185
+ if (!resolvedScaleValue) return
186
+ const value = resolvedScaleValue[series.originalDataKey]
187
+ const formattedValue = getFormattedValue(seriesKey, value, config, getAxisPosition)
188
+ tooltipItems.push([seriesKey, formattedValue, getAxisPosition(seriesKey)])
189
+ }
190
+ })
209
191
  }
210
192
 
211
193
  // handle tooltip for single hovered series
@@ -376,25 +358,48 @@ export const useTooltip = props => {
376
358
  /**
377
359
  * Provides an array of objects with the closest y series data items
378
360
  * @param {String} closestXScaleValue
379
- * @param {Array} includedSeries
380
361
  * @returns an array of objects with the closest y series data items
381
362
  */
382
- const getYScaleValues = (closestXScaleValue, includedSeries) => {
383
- try {
384
- let dataToSearch
363
+ const getYScaleValues = closestXScaleValue => {
364
+ const runtimeSeries = config.runtime.series.filter(
365
+ series => visualizationType === 'Pie' || (series.tooltip === true && !series.dynamicCategory)
366
+ )
367
+ const includedSeries = runtimeSeries.map(item => item.dataKey)
368
+ includedSeries.push(config.xAxis.dataKey)
369
+ // get dynamic category series
370
+ const dynamicDataCategories = _.uniq(
371
+ config.runtime.series.flatMap(series => {
372
+ if (series.dynamicCategory) {
373
+ return [series.dynamicCategory, series.originalDataKey]
374
+ }
375
+ })
376
+ )
377
+ includedSeries.push(...dynamicDataCategories)
385
378
 
386
- if (xAxis.type === 'categorical') {
387
- dataToSearch = data.filter(d => d[xAxis.dataKey] === closestXScaleValue)
388
- } else {
389
- dataToSearch = data.filter(d => d[xAxis.dataKey] === closestXScaleValue)
390
- }
379
+ if (config.visualizationType === 'Forecasting') {
380
+ config.runtime.series.map(s => {
381
+ s.confidenceIntervals.map(c => {
382
+ if (c.showInTooltip) {
383
+ includedSeries.push(c.high)
384
+ includedSeries.push(c.low)
385
+ }
386
+ })
387
+ })
388
+ }
389
+
390
+ const colNames = Object.values(config.columns).map(column => column.name)
391
+ // @ Murad why are we adding them twice?
392
+ includedSeries.push(...colNames, ...colNames)
393
+
394
+ try {
395
+ const dataToSearch = data.filter(d => d[xAxis.dataKey] === closestXScaleValue)
391
396
  // Return an empty array if no matching data is found.
392
397
  if (!dataToSearch || dataToSearch.length === 0) {
393
398
  return []
394
399
  }
395
400
 
396
401
  const yScaleValues = dataToSearch.map(object => {
397
- return Object.fromEntries(Object.entries(object).filter(([key, value]) => includedSeries.includes(key)))
402
+ return _.pick(object, includedSeries)
398
403
  })
399
404
  return yScaleValues
400
405
  } catch (error) {
@@ -548,9 +553,13 @@ export const useTooltip = props => {
548
553
  (!pd.column || key === pd.column)
549
554
  )) ||
550
555
  {}
551
- const newValue = label || value
556
+ let newValue = label || value
552
557
  const style = displayGray ? { color: '#8b8b8a' } : {}
553
558
 
559
+ if (index == 1 && config.dataFormat.onlyShowTopPrefixSuffix) {
560
+ newValue = `${config.dataFormat.prefix}${newValue}${config.dataFormat.suffix}`
561
+ }
562
+
554
563
  return <li style={style} className='tooltip-body'>{`${getSeriesNameFromLabel(key)}: ${newValue}`}</li>
555
564
  }
556
565
 
@@ -1,5 +1,10 @@
1
1
  .data-table-container {
2
2
  margin: 20px 0 0;
3
+
4
+ &.brush-active {
5
+ margin: 80px 0 0;
6
+ }
7
+
3
8
  width: 100%;
4
9
  &.download-link-above {
5
10
  margin: 0;
@@ -120,23 +120,6 @@
120
120
  }
121
121
  }
122
122
 
123
- .btn {
124
- background: #005eaa;
125
- color: #fff !important;
126
- border: 0;
127
- padding: 0.4em 0.8em;
128
- display: block;
129
- border-radius: 5px;
130
- transition: 0.1s all;
131
- cursor: pointer;
132
-
133
- &[disabled] {
134
- opacity: 0.5;
135
- z-index: -1;
136
- position: relative;
137
- }
138
- }
139
-
140
123
  .warning-icon {
141
124
  position: relative;
142
125
  top: 2px;
@@ -157,7 +140,7 @@
157
140
  .subtext--responsive-ticks,
158
141
  .section-subtext {
159
142
  &--brush-active {
160
- margin-top: 2.5em;
143
+ margin-top: 3em !important;
161
144
  }
162
145
  }
163
146
 
@@ -176,7 +159,7 @@
176
159
  border: 1px solid var(--lightGray);
177
160
  position: relative;
178
161
 
179
- &.no-border {
162
+ &.border-0 {
180
163
  border: 1px solid transparent;
181
164
  padding: 0;
182
165
  }
@@ -213,7 +196,6 @@
213
196
 
214
197
  .legend-item {
215
198
  text-align: left;
216
- align-items: flex-start !important;
217
199
  user-select: none;
218
200
  white-space: nowrap;
219
201
 
@@ -279,6 +261,10 @@
279
261
  }
280
262
  }
281
263
 
264
+ .legend-container__inner.flex-column-reverse div.legend-item:last-child {
265
+ margin-bottom: 0.2rem !important;
266
+ }
267
+
282
268
  .dynamic-legend-list {
283
269
  // overide traditional legend item that uses !important
284
270
  .legend-item {
@@ -8,6 +8,8 @@ import { Table } from '@cdc/core/types/Table'
8
8
  import { BoxPlot } from '@cdc/core/types/BoxPlot'
9
9
  import { General } from '@cdc/core/types/General'
10
10
  import { type Link } from './../components/Sankey/types'
11
+ import { type DataDescription } from '@cdc/core/types/DataDescription'
12
+ import { type Legend as CoreLegend } from '@cdc/core/types/Legend'
11
13
  import { ConfidenceInterval } from '@cdc/core/types/ConfidenceInterval'
12
14
  import { Region } from '@cdc/core/types/Region'
13
15
  import { VizFilter } from '@cdc/core/types/VizFilter'
@@ -75,27 +77,12 @@ type Exclusions = {
75
77
  dateEnd: string
76
78
  }
77
79
 
78
- export type Legend = {
80
+ export type Legend = CoreLegend & {
79
81
  seriesHighlight: string[]
80
- additionalCategories: string[]
81
- // general legend onClick behavior
82
- behavior: 'highlight' | 'isolate' | string
83
- axisAlign: boolean
84
- colorCode: string
85
- description: string
86
- // show or hide the legend
87
- hide: boolean
88
- highlightOnHover: boolean
89
- label: string
90
- position: 'left' | 'bottom' | 'top' | 'right'
91
- reverseLabelOrder: boolean
92
- singleRow: boolean
93
- type: string
94
- verticalSorted: boolean
95
82
  hideSuppressionLink: boolean
96
83
  style: 'circles' | 'boxes' | 'gradient' | 'lines'
97
84
  subStyle: 'linear blocks' | 'smooth'
98
- hideSuppressedLabels: boolean
85
+
99
86
  tickRotation: string
100
87
  hideBorder: {
101
88
  side: boolean
@@ -136,7 +123,7 @@ export type AllChartsConfig = {
136
123
  data: Object[]
137
124
  dataUrl: string
138
125
  dataCutoff: number
139
- dataDescription: string
126
+ dataDescription: Partial<DataDescription>
140
127
  dataFormat: DataFormat
141
128
  dataKey: string
142
129
  description: string
@@ -166,7 +153,7 @@ export type AllChartsConfig = {
166
153
  lollipopColorStyle: 'regular' | 'two-tone'
167
154
  lollipopShape: string
168
155
  lollipopSize: 'small' | 'medium' | 'large'
169
- newViz: Object
156
+ newViz: boolean
170
157
  orientation: ChartOrientation
171
158
  palette: string
172
159
  pieType?: string
@@ -1,6 +1,5 @@
1
1
  import { type ChartConfig } from './ChartConfig'
2
2
  import { PickD3Scale } from '@visx/scale'
3
- import { type SharedFilter } from '@cdc/dashboard/src/types/SharedFilter'
4
3
  import { type Annotation } from '@cdc/core/types/Annotation'
5
4
  import { DimensionsType } from '@cdc/core/types/Dimensions'
6
5
  import { type DashboardConfig } from '@cdc/dashboard/src/types/DashboardConfig'
@@ -70,7 +69,11 @@ export type ChartContext =
70
69
  formatTooltipsDate: Function
71
70
  formatNumber?: Function
72
71
  handleLineType?: Function
72
+ // 508 compliance: tabbing handler for charts
73
+ handleChartTabbing?: (chartConfig: ChartConfig, legendId: string) => string
73
74
  isNumber?: boolean
75
+ // 508 compliance: tabbing id for legends
76
+ legendId: string
74
77
  // url param added to allow various console logs and chart helpers
75
78
  isDebug?: boolean
76
79
  parseDate?: Function
@@ -50,4 +50,12 @@ export type ForestPlotConfigSettings = {
50
50
  // labels under chart
51
51
  leftLabel: string
52
52
  rightLabel: string
53
+ /** rightWidthOffsetMobile */
54
+ rightWidthOffsetMobile: number
55
+ /** leftWidthOffsetMobile */
56
+ leftWidthOffsetMobile: number
57
+ regression: {
58
+ showDiamond: boolean
59
+ description: boolean
60
+ }
53
61
  }
@@ -1,111 +0,0 @@
1
- import React, { useContext, useEffect } from 'react'
2
- import { BoxPlot } from '@visx/stats'
3
- import { Group } from '@visx/group'
4
- import ConfigContext from '../../ConfigContext'
5
- import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
6
- import { colorPalettesChart } from '@cdc/core/data/colorPalettes'
7
-
8
- const CoveBoxPlot = ({ xScale, yScale }) => {
9
- const { config, setConfig } = useContext(ConfigContext)
10
- const { boxplot } = config
11
-
12
- useEffect(() => {
13
- if (config.legend.hide === false) {
14
- setConfig({
15
- ...config,
16
- legend: {
17
- ...config.legend,
18
- hide: true
19
- }
20
- })
21
- }
22
- }, []) // eslint-disable-line
23
-
24
- // tooltips
25
- const tooltip_id = `cdc-open-viz-tooltip-${config.runtime.uniqueId}`
26
- const handleTooltip = d => {
27
- return `
28
- <strong>${d.columnCategory}</strong></br>
29
- ${boxplot.labels.q1}: ${d.columnFirstQuartile}<br/>
30
- ${boxplot.labels.q3}: ${d.columnThirdQuartile}<br/>
31
- ${boxplot.labels.iqr}: ${d.columnIqr}<br/>
32
- ${boxplot.labels.median}: ${d.columnMedian}
33
- `
34
- }
35
-
36
- // accessors & constants
37
- const max = d => Number(d.columnMax)
38
- const min = d => Number(d.columnMin)
39
- const median = d => Number(d.columnMedian)
40
- const thirdQuartile = d => Number(d.columnThirdQuartile)
41
- const firstQuartile = d => Number(d.columnFirstQuartile)
42
- const fillOpacity = 0.5
43
- const boxWidth = xScale.bandwidth()
44
- const constrainedWidth = Math.min(40, boxWidth)
45
- const color_0 = colorPalettesChart[config?.palette][0] ? colorPalettesChart[config?.palette][0] : '#000'
46
-
47
- return (
48
- <ErrorBoundary component='BoxPlot'>
49
- <Group className='boxplot' key={`boxplot-group`}>
50
- {boxplot.plots.map((d, i) => {
51
- const offset = boxWidth - constrainedWidth
52
- const radius = 4
53
- return (
54
- <Group key={`boxplotplot-${i}`}>
55
- {boxplot.plotNonOutlierValues &&
56
- d.nonOutlierValues.map((value, index) => {
57
- return <circle cx={xScale(d.columnCategory) + Number(config.yAxis.size) + boxWidth / 2} cy={yScale(value)} r={radius} fill={'#ccc'} style={{ opacity: 1, fillOpacity: 1, stroke: 'black' }} key={`boxplot-${i}--circle-${index}`} />
58
- })}
59
- <BoxPlot
60
- data-left={xScale(d.columnCategory) + config.yAxis.size + offset / 2 + 0.5}
61
- key={`box-plot-${i}`}
62
- min={min(d)}
63
- max={max(d)}
64
- left={Number(xScale(d.columnCategory)) + Number(config.yAxis.size) + offset / 2 + 0.5}
65
- firstQuartile={firstQuartile(d)}
66
- thirdQuartile={thirdQuartile(d)}
67
- median={median(d)}
68
- boxWidth={constrainedWidth}
69
- fill={color_0}
70
- fillOpacity={fillOpacity}
71
- stroke='black'
72
- valueScale={yScale}
73
- outliers={boxplot.plotOutlierValues ? d.columnOutliers : []}
74
- outlierProps={{
75
- style: {
76
- fill: `${color_0}`,
77
- opacity: 1
78
- }
79
- }}
80
- medianProps={{
81
- style: {
82
- stroke: 'black'
83
- }
84
- }}
85
- boxProps={{
86
- style: {
87
- stroke: 'black',
88
- strokeWidth: boxplot.borders === 'true' ? 1 : 0
89
- }
90
- }}
91
- maxProps={{
92
- style: {
93
- stroke: 'black'
94
- }
95
- }}
96
- container
97
- containerProps={{
98
- 'data-tooltip-html': handleTooltip(d),
99
- 'data-tooltip-id': tooltip_id,
100
- tabIndex: -1
101
- }}
102
- />
103
- </Group>
104
- )
105
- })}
106
- </Group>
107
- </ErrorBoundary>
108
- )
109
- }
110
-
111
- export default CoveBoxPlot
@@ -1,72 +0,0 @@
1
- type ConfigType = {
2
- legend: {
3
- position: 'left' | 'bottom' | 'top' | 'right'
4
- singleRow?: boolean
5
- reverseLabelOrder?: boolean
6
- verticalSorted?: boolean
7
- hideBorder: {
8
- side?: boolean
9
- topBottom?: boolean
10
- }
11
- }
12
- }
13
-
14
- const useLegendClasses = (config: ConfigType) => {
15
- const containerClasses = ['legend-container']
16
- const innerClasses = ['legend-container__inner']
17
-
18
- // Handle legend positioning
19
- switch (config.legend.position) {
20
- case 'left':
21
- containerClasses.push('left')
22
- break
23
- case 'right':
24
- containerClasses.push('right')
25
- break
26
- case 'bottom':
27
- containerClasses.push('bottom')
28
- innerClasses.push('double-column', 'bottom')
29
- break
30
- case 'top':
31
- containerClasses.push('top')
32
- innerClasses.push('double-column', 'top')
33
- break
34
- }
35
-
36
- // Handle single row configuration for 'bottom' and 'top' positions
37
- if (['bottom', 'top'].includes(config.legend.position) && config.legend.singleRow) {
38
- innerClasses.push('single-row')
39
- }
40
-
41
- // Reverse label order
42
- if (config.legend.reverseLabelOrder) {
43
- innerClasses.push('d-flex', 'flex-column-reverse')
44
- }
45
-
46
- // Vertical sorting for 'bottom' and 'top' positions
47
- if (['bottom', 'top'].includes(config.legend.position) && config.legend.verticalSorted) {
48
- innerClasses.push('vertical-sorted')
49
- }
50
-
51
- // Configure border classes
52
- if (
53
- config.legend.hideBorder.side &&
54
- (['right', 'left'].includes(config.legend.position) || !config.legend.position)
55
- ) {
56
- containerClasses.push('no-border')
57
- }
58
-
59
- if (config.legend.hideBorder.topBottom && ['top', 'bottom'].includes(config.legend.position)) {
60
- containerClasses.push('no-border')
61
- }
62
-
63
- if (config.legend.hideBorder.topBottom && ['top'].includes(config.legend.position)) {
64
- containerClasses.push('p-0')
65
- }
66
-
67
- return {
68
- containerClasses,
69
- innerClasses
70
- }
71
- }
72
- export default useLegendClasses