@cdc/chart 4.25.10 → 4.26.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.
- package/dist/{cdcchart-1a1724a1.es.js → cdcchart-dgT_1dIT.es.js} +136 -151
- package/dist/cdcchart.js +44003 -43518
- package/examples/feature/__data__/planet-example-data.json +1 -1
- package/examples/feature/boxplot/valid-boxplot.csv +38 -17
- package/examples/feature/pie/planet-pie-example-config.json +48 -2
- package/examples/private/DEV-11825.json +573 -0
- package/examples/private/DEV-12100.json +1303 -0
- package/examples/private/cat-y.json +1235 -0
- package/examples/private/data-points.json +228 -0
- package/examples/private/height.json +3915 -0
- package/examples/private/links.json +569 -0
- package/examples/private/na.json +913 -0
- package/examples/private/quadrant.txt +30 -0
- package/examples/private/test-data.csv +28 -0
- package/examples/private/test-forecast.json +5510 -0
- package/examples/private/warming-stripe-test.json +2578 -0
- package/examples/private/warming-stripes.json +4763 -0
- package/examples/tech-adoption-with-links.json +560 -0
- package/index.html +16 -140
- package/package.json +6 -5
- package/preview.html +1616 -0
- package/src/CdcChart.tsx +8 -11
- package/src/CdcChartComponent.tsx +329 -124
- package/src/_stories/Chart.Combo.stories.tsx +18 -0
- package/src/_stories/Chart.Forecast.stories.tsx +36 -0
- package/src/_stories/Chart.HTMLInDataTable.stories.tsx +520 -0
- package/src/_stories/Chart.Patterns.stories.tsx +2 -1
- package/src/_stories/Chart.PreserveDecimals.stories.tsx +220 -0
- package/src/_stories/Chart.Regions.Categorical.stories.tsx +148 -0
- package/src/_stories/Chart.Regions.DateScale.stories.tsx +197 -0
- package/src/_stories/Chart.Regions.DateTimeScale.stories.tsx +297 -0
- package/src/_stories/Chart.SmallMultiples.stories.tsx +47 -0
- package/src/_stories/Chart.stories.tsx +8 -0
- package/src/_stories/ChartAnnotation.stories.tsx +6 -3
- package/src/_stories/ChartBar.Editor.stories.tsx +3585 -0
- package/src/_stories/ChartBrush.Editor.stories.tsx +295 -0
- package/src/_stories/ChartBrush.stories.tsx +50 -0
- package/src/_stories/ChartEditor.Editor.stories.tsx +656 -0
- package/src/_stories/ChartEditor.stories.tsx +1 -2
- package/src/_stories/TechAdoptionWithLinks.stories.tsx +27 -0
- package/src/_stories/_mock/brush_enabled.json +326 -0
- package/src/_stories/_mock/brush_mock.json +2 -69
- package/src/_stories/_mock/combo.json +451 -0
- package/src/_stories/_mock/editor-test-configs.json +376 -0
- package/src/_stories/_mock/editor-test-datasets.json +477 -0
- package/src/_stories/_mock/editor-tests/bar-chart-editor-test.json +255 -0
- package/src/_stories/_mock/editor-tests/bar-chart-general-test.json +267 -0
- package/src/_stories/_mock/editor-tests/bar-chart-test.json +237 -0
- package/src/_stories/_mock/forecast_combo_with_gaps.json +913 -0
- package/src/_stories/_mock/horizontal-bars-dynamic-y-axis.json +413 -0
- package/src/_stories/_mock/pie_config.json +257 -62
- package/src/_stories/_mock/small_multiples/small_multiples_bars.json +1944 -0
- package/src/_stories/_mock/small_multiples/small_multiples_big_data_bars.json +1114 -0
- package/src/_stories/_mock/small_multiples/small_multiples_lines.json +2646 -0
- package/src/_stories/_mock/small_multiples/small_multiples_lines_colors.json +1305 -0
- package/src/_stories/_mock/small_multiples/small_multiples_stacked_bars.json +1936 -0
- package/src/components/Annotations/components/findNearestDatum.ts +6 -41
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +10 -7
- package/src/components/AreaChart/index.tsx +1 -2
- package/src/components/Axis/Categorical.Axis.tsx +6 -7
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +181 -27
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +3 -1
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +1 -0
- package/src/components/BarChart/components/BarChart.Vertical.tsx +8 -9
- package/src/components/BarChart/components/context.tsx +1 -0
- package/src/components/BarChart/helpers/useBarChart.ts +14 -2
- package/src/components/BoxPlot/helpers/index.ts +3 -3
- package/src/components/Brush/BrushSelector.tsx +1258 -0
- package/src/components/Brush/MiniChartPreview.tsx +283 -0
- package/src/components/DeviationBar.jsx +9 -7
- package/src/components/EditorPanel/EditorPanel.tsx +2720 -2586
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +96 -111
- package/src/components/EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx +56 -34
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +76 -31
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +104 -55
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +54 -49
- package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +427 -0
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +96 -48
- package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
- package/src/components/EditorPanel/editor-panel.scss +0 -20
- package/src/components/EditorPanel/useEditorPermissions.ts +36 -31
- package/src/components/Forecasting/Forecasting.tsx +139 -21
- package/src/components/Legend/Legend.Component.tsx +16 -9
- package/src/components/Legend/Legend.tsx +3 -2
- package/src/components/Legend/helpers/createFormatLabels.tsx +325 -176
- package/src/components/Legend/helpers/getLegendClasses.ts +0 -1
- package/src/components/Legend/helpers/index.ts +10 -6
- package/src/components/LineChart/LineChartProps.ts +0 -3
- package/src/components/LineChart/helpers.ts +1 -1
- package/src/components/LineChart/index.tsx +36 -13
- package/src/components/LinearChart.tsx +559 -499
- package/src/components/PairedBarChart.jsx +20 -3
- package/src/components/Regions/components/Regions.tsx +366 -144
- package/src/components/Sankey/types/index.ts +1 -1
- package/src/components/ScatterPlot/ScatterPlot.jsx +2 -2
- package/src/components/SmallMultiples/SmallMultipleTile.tsx +202 -0
- package/src/components/SmallMultiples/SmallMultiples.css +32 -0
- package/src/components/SmallMultiples/SmallMultiples.tsx +271 -0
- package/src/components/SmallMultiples/index.ts +2 -0
- package/src/components/WarmingStripes/WarmingStripes.tsx +160 -0
- package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +35 -0
- package/src/components/WarmingStripes/WarmingStripesGradientLegend.tsx +104 -0
- package/src/components/WarmingStripes/index.tsx +3 -0
- package/src/data/initial-state.js +16 -2
- package/src/helpers/buildForecastPaletteOptions.ts +0 -38
- package/src/helpers/calculateHorizontalBarCategoryLabelWidth.ts +57 -0
- package/src/helpers/getColorScale.ts +10 -0
- package/src/{hooks/useMinMax.ts → helpers/getMinMax.ts} +26 -14
- package/src/helpers/getYAxisAutoPadding.ts +53 -0
- package/src/helpers/sizeHelpers.ts +0 -20
- package/src/helpers/smallMultiplesHelpers.ts +529 -0
- package/src/hooks/useChartHoverAnalytics.tsx +10 -9
- package/src/hooks/useProgrammaticTooltip.ts +96 -0
- package/src/hooks/useScales.ts +98 -34
- package/src/hooks/useSmallMultipleSynchronization.ts +59 -0
- package/src/hooks/useTooltip.tsx +91 -25
- package/src/scss/DataTable.scss +0 -4
- package/src/scss/main.scss +18 -83
- package/src/store/chart.actions.ts +2 -0
- package/src/store/chart.reducer.ts +4 -0
- package/src/test/CdcChart.test.jsx +1 -1
- package/src/types/ChartConfig.ts +27 -6
- package/src/types/ChartContext.ts +3 -0
- package/src/types/Label.ts +1 -0
- package/src/utils/analyticsTracking.ts +19 -0
- package/LICENSE +0 -201
- package/src/_stories/_mock/pie_data.json +0 -218
- package/src/components/AreaChart/components/AreaChart.jsx +0 -109
- package/src/components/Brush/BrushChart.tsx +0 -128
- package/src/components/Brush/BrushController.tsx +0 -71
- package/src/components/Brush/types.tsx +0 -8
- package/src/components/BrushChart.tsx +0 -223
- package/src/helpers/sort.ts +0 -7
- package/src/hooks/useActiveElement.js +0 -19
- package/src/hooks/useChartClasses.js +0 -41
|
@@ -5,226 +5,375 @@ import {
|
|
|
5
5
|
twoColorPalette
|
|
6
6
|
} from '@cdc/core/data/colorPalettes'
|
|
7
7
|
import { getCurrentPaletteName, getFallbackColorPalette, migratePaletteWithMap } from '@cdc/core/helpers/palettes/utils'
|
|
8
|
-
import { chartPaletteMigrationMap } from '@cdc/core/helpers/palettes/migratePaletteName'
|
|
8
|
+
import { chartPaletteMigrationMap, paletteMigrationMap } from '@cdc/core/helpers/palettes/migratePaletteName'
|
|
9
9
|
import { getPaletteAccessor } from '@cdc/core/helpers/getPaletteAccessor'
|
|
10
10
|
import { getColorPaletteVersion } from '@cdc/core/helpers/getColorPaletteVersion'
|
|
11
11
|
import { isV1Palette } from '@cdc/core/helpers/palettes/utils'
|
|
12
12
|
import { v2ColorDistribution } from '@cdc/core/helpers/palettes/colorDistributions'
|
|
13
13
|
import { updatePaletteNames } from '@cdc/core/helpers/updatePaletteNames'
|
|
14
14
|
import { buildForecastPaletteMappings } from '../../../helpers/buildForecastPaletteMappings'
|
|
15
|
+
import { getFullColorPalette } from '../../../helpers/smallMultiplesHelpers'
|
|
15
16
|
import { FaStar } from 'react-icons/fa'
|
|
16
17
|
import { Label } from '../../../types/Label'
|
|
17
18
|
import { ColorScale, TransformedData } from '../../../types/ChartContext'
|
|
18
19
|
import { ChartConfig } from '../../../types/ChartConfig'
|
|
19
20
|
import _ from 'lodash'
|
|
21
|
+
import { scaleSequential } from 'd3-scale'
|
|
22
|
+
import { interpolateRgbBasis } from 'd3-interpolate'
|
|
23
|
+
import { filterChartColorPalettes } from '@cdc/core/helpers/filterColorPalettes'
|
|
20
24
|
|
|
21
25
|
export const createFormatLabels =
|
|
22
|
-
(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
: labels
|
|
32
|
-
const reverseLabels = labels => {
|
|
33
|
-
if (config.series.some(series => series.dynamicCategory)) {
|
|
34
|
-
return orderDynamicLabels(labels)
|
|
35
|
-
}
|
|
26
|
+
(
|
|
27
|
+
config: ChartConfig,
|
|
28
|
+
tableData: Object[],
|
|
29
|
+
data: TransformedData[],
|
|
30
|
+
colorScale: ColorScale,
|
|
31
|
+
formatNumber: (value: any, axis: string) => string
|
|
32
|
+
) =>
|
|
33
|
+
(defaultLabels: Label[]): Label[] => {
|
|
34
|
+
const { visualizationType, visualizationSubType, series, runtime, legend } = config
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
// Handle small multiples legend adjustments
|
|
37
|
+
// by-series + same: all tiles use same color, legend should show one color
|
|
38
|
+
if (config.smallMultiples?.mode === 'by-series' && config.smallMultiples?.colorMode === 'same') {
|
|
39
|
+
const baseColor = colorScale?.range()?.[0]
|
|
40
|
+
return defaultLabels.map((label, i) => ({
|
|
41
|
+
...label,
|
|
42
|
+
value: baseColor
|
|
43
|
+
}))
|
|
44
|
+
}
|
|
39
45
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
46
|
+
// by-column + different: each tile gets different color, legend should show tile values with their colors
|
|
47
|
+
if (config.smallMultiples?.mode === 'by-column' && config.smallMultiples?.colorMode === 'different') {
|
|
48
|
+
const tileColumn = config.smallMultiples.tileColumn
|
|
49
|
+
const tileValues = Array.from(new Set(data.map(d => d[tileColumn])))
|
|
50
|
+
.filter(Boolean)
|
|
51
|
+
.sort()
|
|
52
|
+
const tilePalette = getFullColorPalette(config, tileValues.length)
|
|
53
|
+
|
|
54
|
+
return tileValues.map((value, index) => ({
|
|
55
|
+
datum: value,
|
|
56
|
+
index,
|
|
57
|
+
text: config.smallMultiples.tileTitles?.[value] || String(value),
|
|
58
|
+
value: tilePalette[index]
|
|
59
|
+
}))
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Handle Warming Stripes legend
|
|
63
|
+
if (visualizationType === 'Warming Stripes') {
|
|
64
|
+
const valueKey = runtime.seriesKeys?.[0]
|
|
65
|
+
if (!valueKey || !data || data.length === 0) {
|
|
66
|
+
return []
|
|
62
67
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
|
|
69
|
+
// Calculate min and max values
|
|
70
|
+
const values = data.map(d => Number(d[valueKey])).filter(v => !isNaN(v))
|
|
71
|
+
const minValue = Math.min(...values)
|
|
72
|
+
const maxValue = Math.max(...values)
|
|
73
|
+
|
|
74
|
+
// Get the color palette from config (same logic as WarmingStripes component)
|
|
75
|
+
const colorPalettesFiltered = filterChartColorPalettes(config)
|
|
76
|
+
const configPalette = config.general?.palette?.name
|
|
77
|
+
const migratedPaletteName = configPalette ? configPalette : getFallbackColorPalette(config)
|
|
78
|
+
|
|
79
|
+
const isReversedPalette = migratedPaletteName?.endsWith('reverse')
|
|
80
|
+
const basePaletteName = isReversedPalette ? migratedPaletteName.slice(0, -7) : migratedPaletteName
|
|
81
|
+
|
|
82
|
+
let palette =
|
|
83
|
+
colorPalettesFiltered[migratePaletteWithMap(basePaletteName, paletteMigrationMap, false)] ||
|
|
84
|
+
colorPalettesFiltered[basePaletteName] ||
|
|
85
|
+
colorPalettesFiltered[configPalette]
|
|
86
|
+
|
|
87
|
+
if (!palette || palette.length < 2) {
|
|
88
|
+
palette = [
|
|
89
|
+
'#053061',
|
|
90
|
+
'#2166ac',
|
|
91
|
+
'#4393c3',
|
|
92
|
+
'#92c5de',
|
|
93
|
+
'#d1e5f0',
|
|
94
|
+
'#f7f7f7',
|
|
95
|
+
'#fddbc7',
|
|
96
|
+
'#f4a582',
|
|
97
|
+
'#d6604d',
|
|
98
|
+
'#b2182b',
|
|
99
|
+
'#67001f'
|
|
69
100
|
]
|
|
101
|
+
}
|
|
70
102
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
103
|
+
const shouldReverse = config.general?.palette?.isReversed || isReversedPalette
|
|
104
|
+
const finalPalette = shouldReverse ? [...palette].reverse() : palette
|
|
105
|
+
const warmingColorScale = scaleSequential(interpolateRgbBasis(finalPalette)).domain([minValue, maxValue])
|
|
106
|
+
|
|
107
|
+
// For gradient style, create smooth gradient with min/max labels only
|
|
108
|
+
if (legend?.style === 'gradient') {
|
|
109
|
+
// Create many color stops for smooth gradient (these are used for the gradient fill)
|
|
110
|
+
const numColorStops = 20
|
|
111
|
+
const colorStops = []
|
|
112
|
+
for (let i = 0; i < numColorStops; i++) {
|
|
113
|
+
const t = i / (numColorStops - 1)
|
|
114
|
+
const value = minValue + t * (maxValue - minValue)
|
|
115
|
+
colorStops.push(warmingColorScale(value))
|
|
76
116
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
117
|
+
|
|
118
|
+
// Create multiple stops for proper spacing, but only show labels at first and last
|
|
119
|
+
// This ensures the first label appears at the left edge and last at the right edge
|
|
120
|
+
const numPositions = 5 // Number of tick positions for spacing
|
|
121
|
+
const labels = []
|
|
122
|
+
for (let i = 0; i < numPositions; i++) {
|
|
123
|
+
const t = i / (numPositions - 1)
|
|
124
|
+
const value = minValue + t * (maxValue - minValue)
|
|
125
|
+
const isFirstOrLast = i === 0 || i === numPositions - 1
|
|
126
|
+
|
|
127
|
+
labels.push({
|
|
128
|
+
datum: String(value),
|
|
129
|
+
index: i,
|
|
130
|
+
text: isFirstOrLast ? formatNumber(value, 'left') : '',
|
|
131
|
+
value: colorStops[Math.floor(t * (numColorStops - 1))],
|
|
132
|
+
colors: colorStops
|
|
133
|
+
})
|
|
82
134
|
}
|
|
83
135
|
|
|
84
|
-
return
|
|
136
|
+
return labels
|
|
85
137
|
}
|
|
86
|
-
if (visualizationType === 'Bar' && visualizationSubType === 'regular' && colorCode && series?.length === 1) {
|
|
87
|
-
const currentPaletteName = getCurrentPaletteName(config) || getFallbackColorPalette(config)
|
|
88
|
-
const paletteName = migratePaletteWithMap(currentPaletteName, chartPaletteMigrationMap, true)
|
|
89
|
-
let palette = getPaletteAccessor(colorPalettes, config, paletteName)
|
|
90
|
-
|
|
91
|
-
const numberOfKeys = data.length
|
|
92
|
-
|
|
93
|
-
// Check if we should use v2 distribution logic for better contrast
|
|
94
|
-
const version = getColorPaletteVersion(config)
|
|
95
|
-
const isSequentialOrDivergent =
|
|
96
|
-
paletteName && (paletteName.includes('sequential') || paletteName.includes('divergent'))
|
|
97
|
-
const isPairedBarOrDeviation = ['Paired Bar', 'Deviation Bar'].includes(config.visualizationType)
|
|
98
|
-
const useV2Distribution =
|
|
99
|
-
version === 2 && isSequentialOrDivergent && palette.length === 9 && numberOfKeys <= 9 && !isPairedBarOrDeviation
|
|
100
|
-
|
|
101
|
-
if (useV2Distribution && v2ColorDistribution[numberOfKeys]) {
|
|
102
|
-
// Use strategic color distribution for v2 sequential palettes
|
|
103
|
-
const distributionIndices = v2ColorDistribution[numberOfKeys]
|
|
104
|
-
palette = distributionIndices.map(index => palette[index])
|
|
105
|
-
} else {
|
|
106
|
-
// Use existing logic for v1 palettes and other cases
|
|
107
|
-
while (tableData.length > palette?.length) {
|
|
108
|
-
palette = palette.concat(palette)
|
|
109
|
-
}
|
|
110
|
-
palette = palette?.slice(0, data.length)
|
|
111
|
-
}
|
|
112
|
-
//store unique values to Set by colorCode
|
|
113
|
-
const set = new Set()
|
|
114
138
|
|
|
115
|
-
|
|
139
|
+
// For interval style, create ranges
|
|
140
|
+
const numIntervals = legend?.warmingStripesIntervals || 5
|
|
141
|
+
const range = maxValue - minValue
|
|
142
|
+
const intervalSize = range / numIntervals
|
|
116
143
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
144
|
+
const intervalLabels = []
|
|
145
|
+
|
|
146
|
+
for (let i = 0; i < numIntervals; i++) {
|
|
147
|
+
// Calculate interval boundaries
|
|
148
|
+
// Each interval after the first starts at the exact boundary point
|
|
149
|
+
const start = minValue + i * intervalSize
|
|
150
|
+
const end = i === numIntervals - 1 ? maxValue : minValue + (i + 1) * intervalSize
|
|
151
|
+
const midPoint = (start + end) / 2
|
|
152
|
+
|
|
153
|
+
// For display, show the actual start for first interval
|
|
154
|
+
// For subsequent intervals, format the boundary point
|
|
155
|
+
const displayStart = start
|
|
156
|
+
const displayEnd = i === numIntervals - 1 ? end : end
|
|
157
|
+
|
|
158
|
+
intervalLabels.push({
|
|
159
|
+
datum: String(midPoint),
|
|
160
|
+
index: i,
|
|
161
|
+
text:
|
|
162
|
+
i === 0
|
|
163
|
+
? `${formatNumber(displayStart, 'left')} - < ${formatNumber(displayEnd, 'left')}`
|
|
164
|
+
: i === numIntervals - 1
|
|
165
|
+
? `${formatNumber(displayStart, 'left')} - ${formatNumber(displayEnd, 'left')}`
|
|
166
|
+
: `${formatNumber(displayStart, 'left')} - < ${formatNumber(displayEnd, 'left')}`,
|
|
167
|
+
value: warmingColorScale(midPoint)
|
|
126
168
|
})
|
|
169
|
+
}
|
|
127
170
|
|
|
128
|
-
|
|
171
|
+
return intervalLabels
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const sortVertical = labels =>
|
|
175
|
+
legend.verticalSorted
|
|
176
|
+
? _.sortBy(_.cloneDeep(labels), label => {
|
|
177
|
+
const match = label.datum?.match(/-?\d+(\.\d+)?/)
|
|
178
|
+
return match ? parseFloat(match[0]) : Number.MAX_SAFE_INTEGER
|
|
179
|
+
})
|
|
180
|
+
: labels
|
|
181
|
+
const reverseLabels = labels => {
|
|
182
|
+
if (config.series.some(series => series.dynamicCategory)) {
|
|
183
|
+
return orderDynamicLabels(labels)
|
|
129
184
|
}
|
|
130
185
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
186
|
+
return config.legend.reverseLabelOrder ? sortVertical(labels).reverse() : sortVertical(labels)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const orderDynamicLabels = labels => {
|
|
190
|
+
// Handle different ordering configurations
|
|
191
|
+
switch (config.legend.order) {
|
|
192
|
+
case 'dataColumn':
|
|
193
|
+
return labels
|
|
194
|
+
case 'asc':
|
|
195
|
+
case 'desc':
|
|
196
|
+
return labels.sort((a, b) => {
|
|
197
|
+
const valA = a.datum || a.text
|
|
198
|
+
const valB = b.datum || b.text
|
|
199
|
+
const numA = parseFloat(valA)
|
|
200
|
+
const numB = parseFloat(valB)
|
|
201
|
+
if (!isNaN(numA) && !isNaN(numB)) {
|
|
202
|
+
return config.legend.order === 'asc' ? numA - numB : numB - numA
|
|
203
|
+
} else {
|
|
204
|
+
return config.legend.order === 'asc' ? valA.localeCompare(valB) : valB.localeCompare(valA)
|
|
150
205
|
}
|
|
151
206
|
})
|
|
152
|
-
}
|
|
153
207
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
datum: stage.key,
|
|
166
|
-
index: index,
|
|
167
|
-
text: stage.key,
|
|
168
|
-
value: colorValue
|
|
169
|
-
}
|
|
208
|
+
default:
|
|
209
|
+
return labels // Default case to handle any unexpected config.legend.order values
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const colorCode = config.legend?.colorCode
|
|
213
|
+
if (visualizationType === 'Deviation Bar') {
|
|
214
|
+
let versionName = isV1Palette(config) ? 'v1' : 'v2'
|
|
215
|
+
const [belowColor, aboveColor] = twoColorPalette?.[versionName]?.[config.twoColor.palette] || [
|
|
216
|
+
'#1D6ABF',
|
|
217
|
+
'#935586'
|
|
218
|
+
]
|
|
170
219
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
220
|
+
const labelBelow = {
|
|
221
|
+
datum: 'X',
|
|
222
|
+
index: 0,
|
|
223
|
+
text: `Below ${config.xAxis.targetLabel}`,
|
|
224
|
+
value: belowColor
|
|
225
|
+
}
|
|
226
|
+
const labelAbove = {
|
|
227
|
+
datum: 'X',
|
|
228
|
+
index: 1,
|
|
229
|
+
text: `Above ${config.xAxis.targetLabel}`,
|
|
230
|
+
value: aboveColor
|
|
231
|
+
}
|
|
174
232
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
let colorValue = palette?.[index] || '#ccc'
|
|
182
|
-
|
|
183
|
-
const newLabel = {
|
|
184
|
-
datum: bar,
|
|
185
|
-
index: index,
|
|
186
|
-
text: bar,
|
|
187
|
-
value: colorValue
|
|
188
|
-
}
|
|
233
|
+
return reverseLabels([labelBelow, labelAbove])
|
|
234
|
+
}
|
|
235
|
+
if (visualizationType === 'Bar' && visualizationSubType === 'regular' && colorCode && series?.length === 1) {
|
|
236
|
+
const currentPaletteName = getCurrentPaletteName(config) || getFallbackColorPalette(config)
|
|
237
|
+
const paletteName = migratePaletteWithMap(currentPaletteName, chartPaletteMigrationMap, true)
|
|
238
|
+
let palette = getPaletteAccessor(colorPalettes, config, paletteName)
|
|
189
239
|
|
|
190
|
-
|
|
191
|
-
})
|
|
240
|
+
const numberOfKeys = data.length
|
|
192
241
|
|
|
193
|
-
|
|
242
|
+
// Check if we should use v2 distribution logic for better contrast
|
|
243
|
+
const version = getColorPaletteVersion(config)
|
|
244
|
+
const isSequentialOrDivergent =
|
|
245
|
+
paletteName && (paletteName.includes('sequential') || paletteName.includes('divergent'))
|
|
246
|
+
const isPairedBarOrDeviation = ['Paired Bar', 'Deviation Bar'].includes(config.visualizationType)
|
|
247
|
+
const useV2Distribution =
|
|
248
|
+
version === 2 && isSequentialOrDivergent && palette.length === 9 && numberOfKeys <= 9 && !isPairedBarOrDeviation
|
|
249
|
+
|
|
250
|
+
if (useV2Distribution && v2ColorDistribution[numberOfKeys]) {
|
|
251
|
+
// Use strategic color distribution for v2 sequential palettes
|
|
252
|
+
const distributionIndices = v2ColorDistribution[numberOfKeys]
|
|
253
|
+
palette = distributionIndices.map(index => palette[index])
|
|
254
|
+
} else {
|
|
255
|
+
// Use existing logic for v1 palettes and other cases
|
|
256
|
+
while (tableData.length > palette?.length) {
|
|
257
|
+
palette = palette.concat(palette)
|
|
258
|
+
}
|
|
259
|
+
palette = palette?.slice(0, data.length)
|
|
194
260
|
}
|
|
261
|
+
//store unique values to Set by colorCode
|
|
262
|
+
const set = new Set()
|
|
195
263
|
|
|
196
|
-
|
|
197
|
-
|
|
264
|
+
tableData.forEach(d => set.add(d[colorCode]))
|
|
265
|
+
|
|
266
|
+
// create labels with unique values
|
|
267
|
+
const uniqueLabels = Array.from(set).map((val, i) => {
|
|
268
|
+
const newLabel = {
|
|
198
269
|
datum: val,
|
|
199
270
|
index: i,
|
|
200
271
|
text: val,
|
|
201
|
-
value:
|
|
202
|
-
}
|
|
203
|
-
return
|
|
272
|
+
value: palette?.[i]
|
|
273
|
+
}
|
|
274
|
+
return newLabel
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
return reverseLabels(uniqueLabels)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// get forecasting items inside of combo
|
|
281
|
+
if (runtime?.forecastingSeriesKeys?.length > 0) {
|
|
282
|
+
let seriesLabels = []
|
|
283
|
+
|
|
284
|
+
// Create palette lookup map - use version-specific palettes
|
|
285
|
+
// Forecasting charts use sequentialPalettes for v1, sequential-only palettes for v2
|
|
286
|
+
const paletteVersion = getColorPaletteVersion(config)
|
|
287
|
+
|
|
288
|
+
let forecastPalettes
|
|
289
|
+
if (paletteVersion === 1) {
|
|
290
|
+
// V1: Use original sequential palettes
|
|
291
|
+
forecastPalettes = sequentialPalettes
|
|
292
|
+
} else {
|
|
293
|
+
// V2: Only use sequential palettes (filter out divergent and qualitative)
|
|
294
|
+
const allV2Palettes = colorPalettesChartV2
|
|
295
|
+
forecastPalettes = {}
|
|
296
|
+
Object.keys(allV2Palettes).forEach(key => {
|
|
297
|
+
if (key.startsWith('sequential')) {
|
|
298
|
+
forecastPalettes[key] = allV2Palettes[key]
|
|
299
|
+
}
|
|
300
|
+
})
|
|
204
301
|
}
|
|
205
302
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
newLabels.push(newLabel)
|
|
303
|
+
const processedPalettes = updatePaletteNames(forecastPalettes)
|
|
304
|
+
const forecastingPalettes = buildForecastPaletteMappings(processedPalettes, paletteVersion)
|
|
305
|
+
|
|
306
|
+
//store unique values to Set by colorCode
|
|
307
|
+
// loop through each stage/group/area on the chart and create a label
|
|
308
|
+
config.runtime?.forecastingSeriesKeys?.map((outerGroup, index) => {
|
|
309
|
+
return outerGroup?.stages?.map((stage, index) => {
|
|
310
|
+
const palette = forecastingPalettes[stage.color] || false
|
|
311
|
+
let colorValue = palette?.[2] || '#ccc'
|
|
312
|
+
|
|
313
|
+
const newLabel = {
|
|
314
|
+
datum: stage.key,
|
|
315
|
+
index: index,
|
|
316
|
+
text: stage.key,
|
|
317
|
+
value: colorValue
|
|
223
318
|
}
|
|
319
|
+
|
|
320
|
+
seriesLabels.push(newLabel)
|
|
224
321
|
})
|
|
322
|
+
})
|
|
225
323
|
|
|
226
|
-
|
|
227
|
-
|
|
324
|
+
// loop through bars for now to meet requirements.
|
|
325
|
+
config.runtime.barSeriesKeys &&
|
|
326
|
+
config.runtime.barSeriesKeys.forEach((bar, index) => {
|
|
327
|
+
const currentPaletteName = getCurrentPaletteName(config) || getFallbackColorPalette(config)
|
|
328
|
+
const migratedPaletteName = migratePaletteWithMap(currentPaletteName, chartPaletteMigrationMap, true)
|
|
329
|
+
const palette = getPaletteAccessor(colorPalettes, config, migratedPaletteName)
|
|
330
|
+
let colorValue = palette?.[index] || '#ccc'
|
|
331
|
+
|
|
332
|
+
const newLabel = {
|
|
333
|
+
datum: bar,
|
|
334
|
+
index: index,
|
|
335
|
+
text: bar,
|
|
336
|
+
value: colorValue
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
seriesLabels.push(newLabel)
|
|
340
|
+
})
|
|
228
341
|
|
|
229
|
-
return reverseLabels(
|
|
342
|
+
return reverseLabels(seriesLabels)
|
|
230
343
|
}
|
|
344
|
+
|
|
345
|
+
if (config.series.some(item => item.name)) {
|
|
346
|
+
const uniqueLabels = Array.from(new Set(config.series.map(d => d.name || d.dataKey))).map((val, i) => ({
|
|
347
|
+
datum: val,
|
|
348
|
+
index: i,
|
|
349
|
+
text: val,
|
|
350
|
+
value: colorScale(val)
|
|
351
|
+
}))
|
|
352
|
+
return reverseLabels(uniqueLabels)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (
|
|
356
|
+
(config.visualizationType === 'Bar' || config.visualizationType === 'Combo') &&
|
|
357
|
+
config.visualizationSubType === 'regular' &&
|
|
358
|
+
config.suppressedData
|
|
359
|
+
) {
|
|
360
|
+
const lastIndex = defaultLabels.length - 1
|
|
361
|
+
let newLabels = []
|
|
362
|
+
|
|
363
|
+
config.suppressedData?.forEach(({ label, icon }, index) => {
|
|
364
|
+
if (label && icon) {
|
|
365
|
+
const newLabel = {
|
|
366
|
+
datum: label,
|
|
367
|
+
index: lastIndex + index,
|
|
368
|
+
text: label,
|
|
369
|
+
icon: <FaStar color='#000' size={15} />
|
|
370
|
+
}
|
|
371
|
+
newLabels.push(newLabel)
|
|
372
|
+
}
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
return [...defaultLabels, ...newLabels]
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return reverseLabels(defaultLabels)
|
|
379
|
+
}
|
|
@@ -2,6 +2,15 @@ export const getGradientConfig = (config, formatLabels, colorScale) => {
|
|
|
2
2
|
const defaultValue = [{ datum: '', index: 0, text: '', value: '' }]
|
|
3
3
|
|
|
4
4
|
const formatted = formatLabels(defaultValue)
|
|
5
|
+
|
|
6
|
+
// For Warming Stripes, always use the formatted labels which contain the gradient stops
|
|
7
|
+
if (config.visualizationType === 'Warming Stripes' && config.legend.style === 'gradient') {
|
|
8
|
+
// Extract the colors array from the first item (all items have the same color stops)
|
|
9
|
+
const colors = formatted[0]?.colors || formatted.map(label => label?.value).filter(Boolean)
|
|
10
|
+
const labels = formatted.map(label => label?.text || label?.datum)
|
|
11
|
+
return { colors, labels }
|
|
12
|
+
}
|
|
13
|
+
|
|
5
14
|
const colors = config.legend.colorCode ? formatted.map(label => label?.value) : colorScale?.range() ?? []
|
|
6
15
|
const labels = config.legend.colorCode
|
|
7
16
|
? formatted.map(label => label?.text || label?.datum)
|
|
@@ -19,12 +28,7 @@ export const getMarginTop = (isLegendBottom, config) => {
|
|
|
19
28
|
if (!isLegendBottom) {
|
|
20
29
|
return '0px'
|
|
21
30
|
}
|
|
22
|
-
|
|
23
|
-
const additiolMargin = 25
|
|
24
|
-
return `${DEFAULT_MARGIN_TOP + config.brush?.height + additiolMargin}px`
|
|
25
|
-
} else {
|
|
26
|
-
return `${DEFAULT_MARGIN_TOP}px`
|
|
27
|
-
}
|
|
31
|
+
return `${DEFAULT_MARGIN_TOP}px`
|
|
28
32
|
}
|
|
29
33
|
export const getMarginBottom = (isLegendBottom, config) => {
|
|
30
34
|
const isLegendTop = config.legend?.position === 'top' && !config.legend.hide
|