@cdc/chart 4.24.12-2 → 4.25.1

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 (70) hide show
  1. package/dist/cdcchart.js +79411 -78816
  2. package/examples/feature/boxplot/boxplot.json +2 -157
  3. package/examples/feature/boxplot/testing.csv +23 -38
  4. package/examples/feature/tests-non-numerics/example-combo-bar-nonnumeric.json +394 -30
  5. package/examples/private/not-loading.json +360 -0
  6. package/index.html +7 -14
  7. package/package.json +2 -2
  8. package/src/CdcChart.tsx +92 -1512
  9. package/src/CdcChartComponent.tsx +1105 -0
  10. package/src/_stories/Chart.Anchors.stories.tsx +1 -1
  11. package/src/_stories/Chart.CustomColors.stories.tsx +1 -1
  12. package/src/_stories/Chart.DynamicSeries.stories.tsx +1 -1
  13. package/src/_stories/Chart.Legend.Gradient.stories.tsx +2 -2
  14. package/src/_stories/Chart.ScatterPlot.stories.tsx +19 -0
  15. package/src/_stories/Chart.tooltip.stories.tsx +1 -2
  16. package/src/_stories/ChartAnnotation.stories.tsx +1 -1
  17. package/src/_stories/ChartAxisLabels.stories.tsx +1 -1
  18. package/src/_stories/ChartAxisTitles.stories.tsx +1 -1
  19. package/src/_stories/ChartEditor.stories.tsx +1 -1
  20. package/src/_stories/ChartLine.Suppression.stories.tsx +1 -1
  21. package/src/_stories/ChartLine.Symbols.stories.tsx +18 -0
  22. package/src/_stories/ChartPrefixSuffix.stories.tsx +1 -1
  23. package/src/_stories/_mock/line_chart_symbols.json +437 -0
  24. package/src/_stories/_mock/scatterplot-image-download.json +1244 -0
  25. package/src/components/Annotations/components/AnnotationDraggable.tsx +3 -11
  26. package/src/components/Annotations/components/AnnotationDropdown.tsx +3 -3
  27. package/src/components/Axis/Categorical.Axis.tsx +3 -4
  28. package/src/components/BarChart/components/BarChart.Horizontal.tsx +14 -5
  29. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +10 -4
  30. package/src/components/BoxPlot/BoxPlot.tsx +34 -32
  31. package/src/components/BoxPlot/helpers/index.ts +108 -18
  32. package/src/components/DeviationBar.jsx +2 -6
  33. package/src/components/EditorPanel/EditorPanel.tsx +62 -6
  34. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +4 -0
  35. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +44 -7
  36. package/src/components/ForestPlot/ForestPlot.tsx +176 -26
  37. package/src/components/Legend/Legend.Component.tsx +29 -38
  38. package/src/components/Legend/Legend.Suppression.tsx +3 -5
  39. package/src/components/Legend/Legend.tsx +2 -2
  40. package/src/components/Legend/LegendLine.Shape.tsx +51 -0
  41. package/src/components/Legend/helpers/createFormatLabels.tsx +29 -26
  42. package/src/components/Legend/helpers/getLegendClasses.ts +20 -38
  43. package/src/components/Legend/helpers/index.ts +14 -7
  44. package/src/components/Legend/tests/getLegendClasses.test.ts +3 -20
  45. package/src/components/LineChart/components/LineChart.Circle.tsx +90 -88
  46. package/src/components/LineChart/index.tsx +4 -0
  47. package/src/components/LinearChart.tsx +54 -29
  48. package/src/components/PairedBarChart.jsx +2 -9
  49. package/src/components/ZoomBrush.tsx +5 -7
  50. package/src/data/initial-state.js +6 -3
  51. package/src/helpers/getBoxPlotConfig.ts +68 -0
  52. package/src/helpers/getColorScale.ts +28 -0
  53. package/src/helpers/getComboChartConfig.ts +42 -0
  54. package/src/helpers/getExcludedData.ts +37 -0
  55. package/src/helpers/getTopAxis.ts +7 -0
  56. package/src/hooks/useBarChart.ts +28 -9
  57. package/src/hooks/{useHighlightedBars.js → useHighlightedBars.ts} +2 -1
  58. package/src/hooks/useIntersectionObserver.ts +37 -0
  59. package/src/hooks/useMinMax.ts +4 -0
  60. package/src/hooks/useReduceData.ts +1 -1
  61. package/src/hooks/useTooltip.tsx +9 -1
  62. package/src/index.jsx +1 -0
  63. package/src/scss/DataTable.scss +0 -5
  64. package/src/scss/main.scss +30 -115
  65. package/src/types/ChartConfig.ts +6 -3
  66. package/src/types/ChartContext.ts +1 -3
  67. package/src/helpers/getQuartiles.ts +0 -27
  68. package/src/hooks/useColorScale.ts +0 -50
  69. package/src/hooks/useIntersectionObserver.jsx +0 -29
  70. package/src/hooks/useTopAxis.js +0 -6
@@ -1,8 +1,10 @@
1
1
  import React, { useContext, useEffect, useState } from 'react'
2
2
  import ConfigContext from '../ConfigContext'
3
3
  import { formatNumber as formatColNumber } from '@cdc/core/helpers/cove/number'
4
+ import { appFontSize } from '@cdc/core/helpers/cove/fontSettings'
4
5
  export const useBarChart = () => {
5
- const { config, colorPalettes, tableData, updateConfig, parseDate, formatDate, setSeriesHighlight, seriesHighlight } = useContext(ConfigContext)
6
+ const { config, colorPalettes, tableData, updateConfig, parseDate, formatDate, setSeriesHighlight, seriesHighlight } =
7
+ useContext(ConfigContext)
6
8
  const { orientation } = config
7
9
  const [hoveredBar, setHoveredBar] = useState(null)
8
10
 
@@ -17,12 +19,22 @@ export const useBarChart = () => {
17
19
  const isRounded = config.barStyle === 'rounded'
18
20
  const isStacked = config.visualizationSubType === 'stacked'
19
21
  const tipRounding = config.tipRounding
20
- const radius = config.roundingStyle === 'standard' ? '8px' : config.roundingStyle === 'shallow' ? '5px' : config.roundingStyle === 'finger' ? '15px' : '0px'
22
+ const radius =
23
+ config.roundingStyle === 'standard'
24
+ ? '8px'
25
+ : config.roundingStyle === 'shallow'
26
+ ? '5px'
27
+ : config.roundingStyle === 'finger'
28
+ ? '15px'
29
+ : '0px'
21
30
  const stackCount = config.runtime.seriesKeys.length
22
- const fontSize = { small: 16, medium: 18, large: 20 }
23
31
  const hasMultipleSeries = Object.keys(config.runtime.seriesLabels).length > 1
24
- const isBarAndLegendIsolate = config.visualizationType === 'Bar' && config.legend.behavior === 'isolate' && config.legend.axisAlign
25
- const barStackedSeriesKeys = isBarAndLegendIsolate && seriesHighlight?.length ? seriesHighlight : config.runtime.barSeriesKeys || config.runtime.seriesKeys
32
+ const isBarAndLegendIsolate =
33
+ config.visualizationType === 'Bar' && config.legend.behavior === 'isolate' && config.legend.axisAlign
34
+ const barStackedSeriesKeys =
35
+ isBarAndLegendIsolate && seriesHighlight?.length
36
+ ? seriesHighlight
37
+ : config.runtime.barSeriesKeys || config.runtime.seriesKeys
26
38
 
27
39
  useEffect(() => {
28
40
  if (orientation === 'horizontal' && !config.yAxis.labelPlacement) {
@@ -68,7 +80,9 @@ export const useBarChart = () => {
68
80
  style = isHorizontal ? { borderRadius: `0 ${radius} ${radius} 0` } : { borderRadius: `${radius} ${radius} 0 0` }
69
81
  }
70
82
  if (!isStacked && index === -1) {
71
- style = isHorizontal ? { borderRadius: `${radius} 0 0 ${radius} ` } : { borderRadius: ` 0 0 ${radius} ${radius}` }
83
+ style = isHorizontal
84
+ ? { borderRadius: `${radius} 0 0 ${radius} ` }
85
+ : { borderRadius: ` 0 0 ${radius} ${radius}` }
72
86
  }
73
87
  if (tipRounding === 'full' && isStacked && index === 0 && stackCount > 1) {
74
88
  style = isHorizontal ? { borderRadius: `${radius} 0 0 ${radius}` } : { borderRadius: `0 0 ${radius} ${radius}` }
@@ -126,7 +140,7 @@ export const useBarChart = () => {
126
140
  barHeight = heights.stacked
127
141
  }
128
142
 
129
- const labelHeight = isLabelBelowBar ? fontSize[config.fontSize] * 1.2 : 0
143
+ const labelHeight = isLabelBelowBar ? appFontSize * 1.2 : 0
130
144
  let barSpace = Number(config.barSpace)
131
145
 
132
146
  // calculate height of container based height, space and fontSize of labels
@@ -191,7 +205,13 @@ export const useBarChart = () => {
191
205
  addColCommas: config.columns[colKeys].commas
192
206
  }
193
207
 
194
- const formattedValue = formatColNumber(closestVal[config.columns[colKeys].name], 'left', true, config, formattingParams)
208
+ const formattedValue = formatColNumber(
209
+ closestVal[config.columns[colKeys].name],
210
+ 'left',
211
+ true,
212
+ config,
213
+ formattingParams
214
+ )
195
215
  if (config.columns[colKeys].tooltips) {
196
216
  columnsWithTooltips.push([config.columns[colKeys].label, formattedValue])
197
217
  }
@@ -225,7 +245,6 @@ export const useBarChart = () => {
225
245
  radius,
226
246
  stackCount,
227
247
  barStackedSeriesKeys,
228
- fontSize,
229
248
  hasMultipleSeries,
230
249
  applyRadius,
231
250
  updateBars,
@@ -1,7 +1,8 @@
1
1
  import React, { useContext } from 'react'
2
2
  import ConfigContext from '../ConfigContext'
3
+ import { ChartConfig } from '../types/ChartConfig'
3
4
 
4
- export const useHighlightedBars = (config, updateConfig) => {
5
+ export const useHighlightedBars = (config: ChartConfig, updateConfig: (config) => void) => {
5
6
  const { formatDate, parseDate } = useContext(ConfigContext)
6
7
 
7
8
  let highlightedSeries = [] // only allow single series for highlights
@@ -0,0 +1,37 @@
1
+ import { useEffect, useState, MutableRefObject } from 'react'
2
+
3
+ interface IntersectionObserverOptions {
4
+ threshold?: number | number[]
5
+ root?: Element | null
6
+ rootMargin?: string
7
+ freezeOnceVisible?: boolean
8
+ }
9
+
10
+ export default function useIntersectionObserver(
11
+ elementRef: MutableRefObject<Element | null>,
12
+ { threshold = 0, root = null, rootMargin = '0%', freezeOnceVisible = false }: IntersectionObserverOptions
13
+ ) {
14
+ const [entry, setEntry] = useState<IntersectionObserverEntry | undefined>()
15
+
16
+ const frozen = entry?.isIntersecting && freezeOnceVisible
17
+
18
+ const updateEntry = ([entry]: IntersectionObserverEntry[]) => {
19
+ setEntry(entry)
20
+ }
21
+
22
+ useEffect(() => {
23
+ const node = elementRef?.current
24
+ const hasIOSupport = !!window.IntersectionObserver
25
+
26
+ if (!hasIOSupport || frozen || !node) return
27
+
28
+ const observerParams = { threshold, root, rootMargin }
29
+ const observer = new IntersectionObserver(updateEntry, observerParams)
30
+
31
+ observer.observe(node)
32
+
33
+ return () => observer.disconnect()
34
+ }, [elementRef, threshold, root, rootMargin, frozen])
35
+
36
+ return entry
37
+ }
@@ -240,6 +240,10 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
240
240
  min = 0
241
241
  }
242
242
 
243
+ if (config.visualizationType === 'Scatter Plot') {
244
+ max = max * 1.1
245
+ }
246
+
243
247
  return { min, max, leftMax, rightMax }
244
248
  }
245
249
  export default useMinMax
@@ -11,7 +11,7 @@ function useReduceData(config, data) {
11
11
  }
12
12
  const getMaxValueFromData = () => {
13
13
  let max = Math.max(
14
- ...data.map(d =>
14
+ ...data?.map(d =>
15
15
  Math.max(
16
16
  ...config.runtime.seriesKeys.map(key => {
17
17
  const seriesKey = getSeriesKey(key)
@@ -143,11 +143,19 @@ export const useTooltip = props => {
143
143
  })
144
144
 
145
145
  if (visualizationType === 'Pie') {
146
+ const roundTo = Number(config.dataFormat.roundTo) || 0
147
+
148
+ const degrees = ((arc.endAngle - arc.startAngle) * 180) / Math.PI
149
+
150
+ // Calculate the percentage of the full circle (360 degrees)
151
+ const percentageOfCircle = (degrees / 360) * 100
152
+ const roundedPercentage = percentageOfCircle.toFixed(roundTo)
153
+
146
154
  tooltipItems.push(
147
155
  // ignore
148
156
  [config.xAxis.dataKey, pieChartData],
149
157
  [config.runtime.yAxis.dataKey, formatNumber(arc?.data[config.runtime.yAxis.dataKey])],
150
- ['Percent', `${Math.round((((arc?.endAngle - arc?.startAngle) * 180) / Math.PI / 360) * 100) + '%'}`]
158
+ ['Percent', `${roundedPercentage + '%'}`]
151
159
  )
152
160
  }
153
161
 
package/src/index.jsx CHANGED
@@ -4,6 +4,7 @@ import ReactDOM from 'react-dom/client'
4
4
  import CdcChart from './CdcChart'
5
5
  import './coreStyles_chart.scss'
6
6
 
7
+ import '@cdc/core/styles/cove-main.scss'
7
8
  import 'react-tooltip/dist/react-tooltip.css'
8
9
 
9
10
  let isEditor = window.location.href.includes('editor=true')
@@ -1,14 +1,9 @@
1
1
  .data-table-container {
2
- margin: 20px 0 0;
3
-
4
2
  &.brush-active {
5
3
  margin: 80px 0 0;
6
4
  }
7
5
 
8
6
  width: 100%;
9
- &.download-link-above {
10
- margin: 0;
11
- }
12
7
  }
13
8
 
14
9
  .data-table-container {
@@ -50,13 +50,6 @@
50
50
  overflow-y: auto;
51
51
  }
52
52
 
53
- .d-flex {
54
- display: flex;
55
- }
56
- .flex-column-reverse {
57
- flex-direction: column-reverse;
58
- }
59
-
60
53
  .cdc-open-viz-module.type-dashboard {
61
54
  .cdc-open-viz-module.type-chart.isEditor {
62
55
  .cdc-chart-inner-container {
@@ -153,34 +146,39 @@
153
146
  .legend-container {
154
147
  background: #fff;
155
148
  width: 100%;
156
- padding: 15px;
157
149
  vertical-align: top;
158
150
  text-align: left;
159
- border: 1px solid var(--lightGray);
151
+ border: 1px solid var(--cool-gray-10);
152
+ border-radius: 6px;
160
153
  position: relative;
161
154
 
155
+ h3 {
156
+ font-size: var(--legend-title-font-size);
157
+ }
158
+
159
+ p {
160
+ font-size: var(--legend-description-font-size);
161
+ }
162
+
163
+ tspan,
164
+ div {
165
+ font-size: var(--legend-item-font-size);
166
+ }
167
+
162
168
  &.border-0 {
163
169
  border: 1px solid transparent;
164
170
  padding: 0;
165
171
  }
166
172
 
167
173
  &__inner {
174
+ display: flex;
175
+ flex-direction: column;
176
+ row-gap: var(--space-between-legend-item-rows);
177
+ column-gap: var(--space-between-legend-item-columns);
168
178
  &.double-column,
169
179
  &.single-row {
170
180
  display: grid;
171
181
  grid-template-columns: 1fr 1fr;
172
- grid-column-gap: 1.5em;
173
- }
174
-
175
- &.vertical-sorted {
176
- display: block;
177
-
178
- @include breakpoint(sm) {
179
- column-count: 2;
180
- column-width: 100%;
181
- }
182
- column-gap: 1.5em;
183
- column-fill: balance;
184
182
  }
185
183
 
186
184
  &.single-row {
@@ -192,13 +190,16 @@
192
190
  flex-basis: auto;
193
191
  }
194
192
  }
193
+
194
+ &.double-column.reverse-items div.legend-item:last-child {
195
+ margin-bottom: 0.2rem !important;
196
+ }
195
197
  }
196
198
 
197
199
  .legend-item {
198
200
  text-align: left;
199
201
  user-select: none;
200
- white-space: nowrap;
201
-
202
+ line-height: var(--legend-item-font-size);
202
203
  .visx-legend-label {
203
204
  word-wrap: break-word;
204
205
  white-space: pre-wrap;
@@ -212,27 +213,9 @@
212
213
 
213
214
  .legend-item > .legend-item {
214
215
  display: inline-block;
215
- margin-right: 0.5rem;
216
216
  flex: 0 0 auto;
217
217
  }
218
218
 
219
- h3 {
220
- font-size: 1.3rem;
221
- }
222
-
223
- h3,
224
- p {
225
- margin-bottom: 0.4em;
226
- }
227
-
228
- & div.legend-item {
229
- margin-bottom: 0.2em !important;
230
-
231
- &:last-child {
232
- margin: 0 !important;
233
- }
234
- }
235
-
236
219
  .legend-item {
237
220
  cursor: pointer;
238
221
  transition: 0.2s all;
@@ -241,6 +224,11 @@
241
224
  opacity: 0.5;
242
225
  transition: 0.2s all;
243
226
  }
227
+ &.highlighted {
228
+ outline: 1px solid #005ea2;
229
+ outline-offset: 5px;
230
+ border-radius: 1px;
231
+ }
244
232
  }
245
233
 
246
234
  &__outer {
@@ -261,10 +249,6 @@
261
249
  }
262
250
  }
263
251
 
264
- .legend-container__inner.flex-column-reverse div.legend-item:last-child {
265
- margin-bottom: 0.2rem !important;
266
- }
267
-
268
252
  .dynamic-legend-list {
269
253
  // overide traditional legend item that uses !important
270
254
  .legend-item {
@@ -297,7 +281,6 @@
297
281
  align-items: center;
298
282
  font-size: 1em;
299
283
  vertical-align: middle;
300
- margin-bottom: 0.5em;
301
284
 
302
285
  & > span {
303
286
  display: flex;
@@ -305,7 +288,7 @@
305
288
  align-items: center;
306
289
  white-space: nowrap;
307
290
  font-size: 1em;
308
- margin-right: 8px;
291
+ margin-right: 9px;
309
292
  max-height: 1px;
310
293
  }
311
294
 
@@ -483,32 +466,6 @@
483
466
  }
484
467
  }
485
468
 
486
- @include breakpointClass(xs) {
487
- &.font-small {
488
- font-size: 0.8em;
489
-
490
- .chart-container > svg {
491
- font-size: 12px;
492
- }
493
- }
494
-
495
- &.font-medium {
496
- font-size: 0.9em;
497
-
498
- .chart-container > svg {
499
- font-size: 14px;
500
- }
501
- }
502
-
503
- &.font-large {
504
- font-size: 1em;
505
-
506
- .chart-container > svg {
507
- font-size: 16px;
508
- }
509
- }
510
- }
511
-
512
469
  @include breakpointClass(sm) {
513
470
  .chart-container {
514
471
  .no-wrap {
@@ -547,48 +504,6 @@
547
504
  }
548
505
  }
549
506
  }
550
-
551
- &.font-small {
552
- font-size: 0.9em;
553
-
554
- .chart-container > svg {
555
- font-size: 14px;
556
- }
557
- }
558
-
559
- &.font-large {
560
- font-size: 1.1em;
561
-
562
- .chart-container > svg {
563
- font-size: 18px;
564
- }
565
- }
566
- }
567
-
568
- @include breakpointClass(lg) {
569
- &.font-small {
570
- font-size: 1em;
571
-
572
- .chart-container > svg {
573
- font-size: 16px;
574
- }
575
- }
576
-
577
- &.font-medium {
578
- font-size: 1.1em;
579
-
580
- .chart-container > svg {
581
- font-size: 18px;
582
- }
583
- }
584
-
585
- &.font-large {
586
- font-size: 1.2em;
587
-
588
- .chart-container > svg {
589
- font-size: 20px;
590
- }
591
- }
592
507
  }
593
508
 
594
509
  [tabindex]:focus-visible {
@@ -14,6 +14,7 @@ import { ConfidenceInterval } from '@cdc/core/types/ConfidenceInterval'
14
14
  import { Region } from '@cdc/core/types/Region'
15
15
  import { VizFilter } from '@cdc/core/types/VizFilter'
16
16
  import { type Annotation } from '@cdc/core/types/Annotation'
17
+ import { Version } from '@cdc/core/types/Version'
17
18
 
18
19
  export type ViewportSize = 'xxs' | 'xs' | 'sm' | 'md' | 'lg'
19
20
  export type ChartColumns = Record<string, Column>
@@ -79,10 +80,11 @@ type Exclusions = {
79
80
 
80
81
  export type Legend = CoreLegend & {
81
82
  seriesHighlight: string[]
83
+
82
84
  hideSuppressionLink: boolean
83
85
  style: 'circles' | 'boxes' | 'gradient' | 'lines'
84
86
  subStyle: 'linear blocks' | 'smooth'
85
-
87
+ hasShape: boolean
86
88
  tickRotation: string
87
89
  hideBorder: {
88
90
  side: boolean
@@ -98,6 +100,8 @@ type Visual = {
98
100
  hideBackgroundColor?: boolean
99
101
  verticalHoverLine?: boolean
100
102
  horizontalHoverLine?: boolean
103
+ lineDatapointSymbol: 'none' | 'standard'
104
+ maximumShapeAmount: 7
101
105
  }
102
106
 
103
107
  export type AllChartsConfig = {
@@ -131,7 +135,6 @@ export type AllChartsConfig = {
131
135
  exclusions: Exclusions
132
136
  filters: VizFilter[]
133
137
  filterBehavior: FilterBehavior
134
- fontSize: 'small' | 'medium' | 'large'
135
138
  footnotes: string
136
139
  forestPlot: ForestPlotConfigSettings
137
140
  formattedData: Object[] & { urlFiltered: boolean }
@@ -184,7 +187,7 @@ export type AllChartsConfig = {
184
187
  twoColor: { palette: string }
185
188
  type: 'chart' | 'dashboard'
186
189
  uid: string | number
187
- version: string
190
+ version: Version
188
191
  visual: Visual
189
192
  visualizationType: VisualizationType
190
193
  visualizationSubType: string
@@ -23,9 +23,7 @@ type SharedChartContext = {
23
23
  handleChartAriaLabels: (config: any) => string
24
24
  handleDragStateChange: (isDragging: any) => void
25
25
  highlight?: Function
26
- highlightReset?: Function
27
- // whether or not the legend is appearing below the chart
28
- isLegendBottom?: boolean
26
+ handleShowAll?: Function
29
27
  // whether or not the chart is viewed within the editor screen
30
28
  isEditor?: boolean
31
29
  // whether or not the user is dragging an annotation
@@ -1,27 +0,0 @@
1
- /**
2
- * Calculates the first quartile (q1) and third quartile (q3) from an array of integers or decimals.
3
- *
4
- * @param {Array} arr - The array of integers or decimals.
5
- * @returns {Object} An object containing the q1 and q3 values.
6
- */
7
- import _ from 'lodash'
8
-
9
- export const getQuartiles = (values: number[]): { q1: number; q3: number } => {
10
- const sortedData: number[] = _.sortBy(values)
11
-
12
- const quantile = (sortedData: number[], q: number): number => {
13
- const position: number = (sortedData.length - 1) * q
14
- const base: number = Math.floor(position)
15
- const rest: number = position - base
16
- if (sortedData[base + 1] !== undefined) {
17
- return sortedData[base] + rest * (sortedData[base + 1] - sortedData[base])
18
- } else {
19
- return sortedData[base]
20
- }
21
- }
22
-
23
- const q1: number = quantile(sortedData, 0.25)
24
- const q3: number = quantile(sortedData, 0.75)
25
-
26
- return { q1, q3 }
27
- }
@@ -1,50 +0,0 @@
1
- import { colorPalettesChart as colorPalettes, twoColorPalette } from '@cdc/core/data/colorPalettes'
2
- import { scaleOrdinal } from '@visx/scale'
3
- import { useContext } from 'react'
4
- import ConfigContext from '../ConfigContext'
5
-
6
- const useColorScale = () => {
7
- const { config, data } = useContext(ConfigContext)
8
- const { visualizationSubType, visualizationType, series, legend } = config
9
-
10
- const generatePalette = colorsCount => {
11
- if (!series?.length) return []
12
- const isSpecialType = ['Paired Bar', 'Deviation Bar'].includes(visualizationType)
13
- const chosenPalette = isSpecialType ? config.twoColor.palette : config.palette
14
- const allPalettes = { ...colorPalettes, ...twoColorPalette }
15
- let palette = config.customColors || allPalettes[chosenPalette]
16
- while (colorsCount > palette.length) palette = palette.concat(palette)
17
- return palette.slice(0, colorsCount)
18
- }
19
-
20
- let colorScale = scaleOrdinal({
21
- domain: config?.runtime?.seriesLabelsAll,
22
- range: generatePalette(series.length)
23
- })
24
-
25
- if (visualizationType === 'Deviation Bar') {
26
- const { targetLabel } = config.xAxis
27
- colorScale = scaleOrdinal({
28
- domain: [`Below ${targetLabel}`, `Above ${targetLabel}`],
29
- range: generatePalette(2)
30
- })
31
- }
32
- if (visualizationType === 'Bar' && visualizationSubType === 'regular' && series?.length === 1 && legend?.colorCode) {
33
- const set = new Set(data?.map(d => d[legend.colorCode]))
34
- colorScale = scaleOrdinal({
35
- domain: [...set],
36
- range: generatePalette([...set].length)
37
- })
38
- }
39
- if (config.series.some(s => s.name)) {
40
- const set = new Set(series.map(d => d.name || d.dataKey))
41
- colorScale = colorScale = scaleOrdinal({
42
- domain: [...set],
43
- range: generatePalette(series.length)
44
- })
45
- }
46
-
47
- return { colorScale }
48
- }
49
-
50
- export default useColorScale
@@ -1,29 +0,0 @@
1
- import { useEffect, useState } from 'react'
2
-
3
- export default function useIntersectionObserver(elementRef, { threshold = 0, root = null, rootMargin = '0%', freezeOnceVisible = false }) {
4
- const [entry, setEntry] = useState()
5
-
6
- const frozen = entry?.isIntersecting && freezeOnceVisible
7
-
8
- const updateEntry = ([entry]) => {
9
- setEntry(entry)
10
- }
11
-
12
- useEffect(() => {
13
- setTimeout(() => {
14
- const node = elementRef?.current
15
- const hasIOSupport = !!window.IntersectionObserver
16
-
17
- if (!hasIOSupport || frozen || !node) return
18
-
19
- const observerParams = { threshold, root, rootMargin }
20
- const observer = new IntersectionObserver(updateEntry, observerParams)
21
-
22
- observer.observe(node)
23
-
24
- return () => observer.disconnect()
25
- }, 500)
26
- }, [elementRef, threshold, root, rootMargin, frozen])
27
-
28
- return entry
29
- }
@@ -1,6 +0,0 @@
1
- export default function useTopAxis(config) {
2
- // When to show top axis
3
- const hasTopAxis = config.visualizationType === 'Bar' || config.visualizationType === 'Combo' || config.visualizationType === 'Line'
4
-
5
- return { hasTopAxis }
6
- }