@cdc/chart 4.25.7 → 4.25.10
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/.claude/settings.local.json +9 -0
- package/dist/cdcchart.js +39551 -37016
- package/examples/feature/__data__/planet-example-data.json +0 -30
- package/examples/grouped-bar-test.json +400 -0
- package/examples/private/d.json +382 -0
- package/examples/private/example-2.json +49784 -0
- package/examples/private/f2.json +1 -0
- package/examples/private/f4.json +1577 -0
- package/examples/private/forecast.json +1180 -0
- package/examples/private/lollipop.json +468 -0
- package/examples/private/new.json +48756 -0
- package/examples/private/pie-chart-legend.json +904 -0
- package/examples/suppressed_tooltip.json +480 -0
- package/index.html +10 -22
- package/package.json +25 -7
- package/src/CdcChart.tsx +10 -4
- package/src/CdcChartComponent.tsx +188 -32
- package/src/_stories/Chart.Anchors.stories.tsx +2 -2
- package/src/_stories/Chart.BoxPlot.stories.tsx +1 -1
- package/src/_stories/Chart.CI.stories.tsx +1 -1
- package/src/_stories/Chart.CustomColors.stories.tsx +1 -1
- package/src/_stories/Chart.DynamicSeries.stories.tsx +2 -2
- package/src/_stories/Chart.Filters.stories.tsx +2 -2
- package/src/_stories/Chart.Legend.Gradient.stories.tsx +2 -2
- package/src/_stories/Chart.Patterns.stories.tsx +19 -0
- package/src/_stories/Chart.ScatterPlot.stories.tsx +1 -1
- package/src/_stories/Chart.stories.tsx +8 -5
- package/src/_stories/Chart.tooltip.stories.tsx +1 -1
- package/src/_stories/ChartAnnotation.stories.tsx +1 -1
- package/src/_stories/ChartAxisLabels.stories.tsx +2 -2
- package/src/_stories/ChartAxisTitles.stories.tsx +2 -2
- package/src/_stories/ChartEditor.stories.tsx +60 -60
- package/src/_stories/ChartLine.Suppression.stories.tsx +1 -1
- package/src/_stories/ChartLine.Symbols.stories.tsx +1 -1
- package/src/_stories/ChartPrefixSuffix.stories.tsx +2 -2
- package/src/_stories/_mock/stacked-pattern-test.json +520 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +1 -0
- package/src/components/Annotations/components/AnnotationDropdown.tsx +1 -1
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +170 -25
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +139 -6
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +215 -73
- package/src/components/BarChart/components/BarChart.Vertical.tsx +172 -23
- package/src/components/BarChart/helpers/index.ts +43 -4
- package/src/components/BarChart/helpers/lollipopColors.ts +27 -0
- package/src/components/BarChart/helpers/useBarChart.ts +25 -3
- package/src/components/BoxPlot/BoxPlot.Vertical.tsx +2 -1
- package/src/components/Brush/BrushChart.tsx +65 -10
- package/src/components/Brush/BrushController.tsx +37 -5
- package/src/components/Brush/types.tsx +8 -0
- package/src/components/DeviationBar.jsx +9 -6
- package/src/components/EditorPanel/EditorPanel.tsx +364 -39
- package/src/components/EditorPanel/EditorPanelContext.ts +3 -0
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +2 -2
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +414 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +30 -54
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +115 -120
- package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
- package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +0 -8
- package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +49 -48
- package/src/components/Forecasting/Forecasting.tsx +36 -6
- package/src/components/ForestPlot/ForestPlot.tsx +11 -7
- package/src/components/ForestPlot/ForestPlotProps.ts +1 -1
- package/src/components/Legend/Legend.Component.tsx +110 -2
- package/src/components/Legend/Legend.tsx +3 -1
- package/src/components/Legend/helpers/createFormatLabels.tsx +230 -171
- package/src/components/LegendWrapper.tsx +1 -1
- package/src/components/LineChart/components/LineChart.BumpCircle.tsx +27 -26
- package/src/components/LineChart/components/LineChart.Circle.tsx +2 -2
- package/src/components/LineChart/index.tsx +2 -2
- package/src/components/LinearChart.tsx +26 -9
- package/src/components/PairedBarChart.jsx +6 -4
- package/src/components/PieChart/PieChart.tsx +170 -54
- package/src/components/Sankey/components/Sankey.tsx +7 -1
- package/src/components/ScatterPlot/ScatterPlot.jsx +32 -4
- package/src/data/initial-state.js +315 -292
- package/src/helpers/buildForecastPaletteMappings.ts +112 -0
- package/src/helpers/buildForecastPaletteOptions.ts +109 -0
- package/src/helpers/getColorScale.ts +72 -8
- package/src/helpers/getNewRuntime.ts +1 -1
- package/src/helpers/getTransformedData.ts +1 -1
- package/src/hooks/useChartHoverAnalytics.tsx +44 -0
- package/src/hooks/useReduceData.ts +105 -70
- package/src/hooks/useTooltip.tsx +58 -16
- package/src/index.jsx +6 -3
- package/src/scss/main.scss +12 -0
- package/src/store/chart.reducer.ts +1 -1
- package/src/test/CdcChart.test.jsx +8 -3
- package/src/types/ChartConfig.ts +30 -6
- package/src/types/ChartContext.ts +1 -0
- package/vite.config.js +1 -1
- package/vitest.config.ts +16 -0
- package/src/coreStyles_chart.scss +0 -3
- package/src/helpers/configHelpers.ts +0 -28
- package/src/helpers/generateColorsArray.ts +0 -8
- package/src/hooks/useColorPalette.js +0 -76
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import parse from 'html-react-parser'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import { LegendOrdinal, LegendItem, LegendLabel } from '@visx/legend'
|
|
4
|
+
import { PatternLines, PatternCircles, PatternWaves } from '@visx/pattern'
|
|
4
5
|
import LegendShape from '@cdc/core/components/LegendShape'
|
|
5
6
|
import Button from '@cdc/core/components/elements/Button'
|
|
6
7
|
import { getLegendClasses } from './helpers/getLegendClasses'
|
|
@@ -17,6 +18,8 @@ import { isLegendWrapViewport } from '@cdc/core/helpers/viewports'
|
|
|
17
18
|
import LegendLineShape from './LegendLine.Shape'
|
|
18
19
|
import LegendGroup from './LegendGroup'
|
|
19
20
|
import { getSeriesWithData } from '../../helpers/dataHelpers'
|
|
21
|
+
import { publishAnalyticsEvent } from '@cdc/core/helpers/metrics/helpers'
|
|
22
|
+
import { getVizTitle, getVizSubType } from '@cdc/core/helpers/metrics/utils'
|
|
20
23
|
|
|
21
24
|
const LEGEND_PADDING = 36
|
|
22
25
|
|
|
@@ -32,9 +35,9 @@ export interface LegendProps {
|
|
|
32
35
|
skipId: string
|
|
33
36
|
dimensions: DimensionsType // for responsive width legend
|
|
34
37
|
transformedData: any
|
|
38
|
+
interactionLabel: string
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
/* eslint-disable jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */
|
|
38
41
|
const Legend: React.FC<LegendProps> = forwardRef(
|
|
39
42
|
(
|
|
40
43
|
{
|
|
@@ -47,7 +50,8 @@ const Legend: React.FC<LegendProps> = forwardRef(
|
|
|
47
50
|
formatLabels,
|
|
48
51
|
skipId = 'legend',
|
|
49
52
|
dimensions,
|
|
50
|
-
transformedData: data
|
|
53
|
+
transformedData: data,
|
|
54
|
+
interactionLabel = ''
|
|
51
55
|
},
|
|
52
56
|
ref
|
|
53
57
|
) => {
|
|
@@ -69,6 +73,7 @@ const Legend: React.FC<LegendProps> = forwardRef(
|
|
|
69
73
|
|
|
70
74
|
const { HighLightedBarUtils } = useHighlightedBars(config)
|
|
71
75
|
let highLightedLegendItems = HighLightedBarUtils.findDuplicates(config.highlightedBarValues)
|
|
76
|
+
|
|
72
77
|
if (!legend) return null
|
|
73
78
|
return (
|
|
74
79
|
<aside
|
|
@@ -137,11 +142,34 @@ const Legend: React.FC<LegendProps> = forwardRef(
|
|
|
137
142
|
onKeyDown={e => {
|
|
138
143
|
if (e.key === 'Enter') {
|
|
139
144
|
e.preventDefault()
|
|
145
|
+
publishAnalyticsEvent({
|
|
146
|
+
vizType: config?.type,
|
|
147
|
+
vizSubType: getVizSubType(config),
|
|
148
|
+
vizTitle: getVizTitle(config),
|
|
149
|
+
eventType: `chart_legend_item_toggled` as any,
|
|
150
|
+
eventAction: 'keydown',
|
|
151
|
+
eventLabel: interactionLabel,
|
|
152
|
+
specifics: config.visualizationType === 'Bar'
|
|
153
|
+
? `label: ${label.text}, orientation: ${config.orientation === 'horizontal' ? 'horizontal' : 'vertical'}, mode: ${legend.behavior}`
|
|
154
|
+
: `label: ${label.text}, mode: ${legend.behavior}`,
|
|
155
|
+
})
|
|
140
156
|
highlight(label)
|
|
141
157
|
}
|
|
142
158
|
}}
|
|
143
159
|
onClick={e => {
|
|
144
160
|
e.preventDefault()
|
|
161
|
+
publishAnalyticsEvent({
|
|
162
|
+
vizType: config?.type,
|
|
163
|
+
vizSubType: getVizSubType(config),
|
|
164
|
+
eventType: `chart_legend_item_toggled` as any,
|
|
165
|
+
eventAction: 'click',
|
|
166
|
+
eventLabel: interactionLabel,
|
|
167
|
+
specifics: config.visualizationType === 'Bar'
|
|
168
|
+
? `label: ${label.text}, orientation: ${config.orientation === 'horizontal' ? 'horizontal' : 'vertical'}, mode: ${legend.behavior}`
|
|
169
|
+
: `label: ${label.text}, mode: ${legend.behavior}`,
|
|
170
|
+
|
|
171
|
+
vizTitle: getVizTitle(config)
|
|
172
|
+
})
|
|
145
173
|
highlight(label)
|
|
146
174
|
}}
|
|
147
175
|
role='button'
|
|
@@ -206,6 +234,86 @@ const Legend: React.FC<LegendProps> = forwardRef(
|
|
|
206
234
|
</div>
|
|
207
235
|
|
|
208
236
|
<LegendSuppression config={config} isLegendBottom={isLegendBottom} />
|
|
237
|
+
|
|
238
|
+
{/* Pattern Legend Items */}
|
|
239
|
+
{config.legend.patterns && Object.keys(config.legend.patterns).length > 0 && (
|
|
240
|
+
<div
|
|
241
|
+
className={`legend-patterns d-flex ${['top', 'bottom'].includes(config.legend.position) ? 'flex-row flex-wrap' : 'flex-column'
|
|
242
|
+
}`}
|
|
243
|
+
>
|
|
244
|
+
{Object.entries(config.legend.patterns).map(([key, pattern]) => {
|
|
245
|
+
const patternId = `legend-pattern-${key}`
|
|
246
|
+
const size = config.legend.patternSize || 8
|
|
247
|
+
const legendSize = 16
|
|
248
|
+
const pColor = (pattern as any)?.color || '#666666'
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
<LegendItem
|
|
252
|
+
key={patternId}
|
|
253
|
+
className='legend-item legend-item--pattern d-flex align-items-center'
|
|
254
|
+
tabIndex={0}
|
|
255
|
+
role='button'
|
|
256
|
+
>
|
|
257
|
+
<span className='me-2'>
|
|
258
|
+
<svg width={legendSize} height={legendSize}>
|
|
259
|
+
<defs>
|
|
260
|
+
{pattern.shape === 'circles' && (
|
|
261
|
+
<PatternCircles
|
|
262
|
+
id={patternId}
|
|
263
|
+
height={size}
|
|
264
|
+
width={size}
|
|
265
|
+
fill={pColor}
|
|
266
|
+
radius={1.25}
|
|
267
|
+
/>
|
|
268
|
+
)}
|
|
269
|
+
{pattern.shape === 'lines' && (
|
|
270
|
+
<PatternLines
|
|
271
|
+
id={patternId}
|
|
272
|
+
height={size}
|
|
273
|
+
width={size}
|
|
274
|
+
stroke={pColor}
|
|
275
|
+
strokeWidth={0.75}
|
|
276
|
+
orientation={['horizontal']}
|
|
277
|
+
/>
|
|
278
|
+
)}
|
|
279
|
+
{pattern.shape === 'diagonalLines' && (
|
|
280
|
+
<PatternLines
|
|
281
|
+
id={patternId}
|
|
282
|
+
height={size}
|
|
283
|
+
width={size}
|
|
284
|
+
stroke={pColor}
|
|
285
|
+
strokeWidth={0.75}
|
|
286
|
+
orientation={['diagonalRightToLeft']}
|
|
287
|
+
/>
|
|
288
|
+
)}
|
|
289
|
+
{pattern.shape === 'waves' && (
|
|
290
|
+
<PatternWaves
|
|
291
|
+
id={patternId}
|
|
292
|
+
height={size}
|
|
293
|
+
width={size}
|
|
294
|
+
fill={pColor}
|
|
295
|
+
strokeWidth={0.25}
|
|
296
|
+
/>
|
|
297
|
+
)}
|
|
298
|
+
</defs>
|
|
299
|
+
<circle
|
|
300
|
+
fill={`url(#${patternId})`}
|
|
301
|
+
r={legendSize / 2}
|
|
302
|
+
cx={legendSize / 2}
|
|
303
|
+
cy={legendSize / 2}
|
|
304
|
+
stroke='#0000004d'
|
|
305
|
+
strokeWidth={1}
|
|
306
|
+
/>
|
|
307
|
+
</svg>
|
|
308
|
+
</span>
|
|
309
|
+
<LegendLabel align='left' className='m-0'>
|
|
310
|
+
{parse(String((pattern as any)?.label || key))}
|
|
311
|
+
</LegendLabel>
|
|
312
|
+
</LegendItem>
|
|
313
|
+
)
|
|
314
|
+
})}
|
|
315
|
+
</div>
|
|
316
|
+
)}
|
|
209
317
|
</>
|
|
210
318
|
)
|
|
211
319
|
}}
|
|
@@ -21,7 +21,8 @@ const Legend = forwardRef((props, ref) => {
|
|
|
21
21
|
transformedData
|
|
22
22
|
} = useContext(ConfigContext)
|
|
23
23
|
if (!config.legend) return null
|
|
24
|
-
// create fn to reverse labels while legend is Bottom. Legend-right , legend-left works by default
|
|
24
|
+
// create fn to reverse labels while legend is Bottom. Legend-right , legend-left works by default
|
|
25
|
+
const { interactionLabel } = props
|
|
25
26
|
|
|
26
27
|
const createLegendLabels = createFormatLabels(config, tableData, data, colorScale)
|
|
27
28
|
|
|
@@ -40,6 +41,7 @@ const Legend = forwardRef((props, ref) => {
|
|
|
40
41
|
handleShowAll={handleShowAll}
|
|
41
42
|
currentViewport={currentViewport}
|
|
42
43
|
formatLabels={createLegendLabels}
|
|
44
|
+
interactionLabel={interactionLabel}
|
|
43
45
|
/>
|
|
44
46
|
</Fragment>
|
|
45
47
|
)
|
|
@@ -1,171 +1,230 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return labels
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
1
|
+
import {
|
|
2
|
+
colorPalettesChart as colorPalettes,
|
|
3
|
+
colorPalettesChartV2,
|
|
4
|
+
sequentialPalettes,
|
|
5
|
+
twoColorPalette
|
|
6
|
+
} from '@cdc/core/data/colorPalettes'
|
|
7
|
+
import { getCurrentPaletteName, getFallbackColorPalette, migratePaletteWithMap } from '@cdc/core/helpers/palettes/utils'
|
|
8
|
+
import { chartPaletteMigrationMap } from '@cdc/core/helpers/palettes/migratePaletteName'
|
|
9
|
+
import { getPaletteAccessor } from '@cdc/core/helpers/getPaletteAccessor'
|
|
10
|
+
import { getColorPaletteVersion } from '@cdc/core/helpers/getColorPaletteVersion'
|
|
11
|
+
import { isV1Palette } from '@cdc/core/helpers/palettes/utils'
|
|
12
|
+
import { v2ColorDistribution } from '@cdc/core/helpers/palettes/colorDistributions'
|
|
13
|
+
import { updatePaletteNames } from '@cdc/core/helpers/updatePaletteNames'
|
|
14
|
+
import { buildForecastPaletteMappings } from '../../../helpers/buildForecastPaletteMappings'
|
|
15
|
+
import { FaStar } from 'react-icons/fa'
|
|
16
|
+
import { Label } from '../../../types/Label'
|
|
17
|
+
import { ColorScale, TransformedData } from '../../../types/ChartContext'
|
|
18
|
+
import { ChartConfig } from '../../../types/ChartConfig'
|
|
19
|
+
import _ from 'lodash'
|
|
20
|
+
|
|
21
|
+
export const createFormatLabels =
|
|
22
|
+
(config: ChartConfig, tableData: Object[], data: TransformedData[], colorScale: ColorScale) =>
|
|
23
|
+
(defaultLabels: Label[]): Label[] => {
|
|
24
|
+
const { visualizationType, visualizationSubType, series, runtime, legend } = config
|
|
25
|
+
const sortVertical = labels =>
|
|
26
|
+
legend.verticalSorted
|
|
27
|
+
? _.sortBy(_.cloneDeep(labels), label => {
|
|
28
|
+
const match = label.datum?.match(/-?\d+(\.\d+)?/)
|
|
29
|
+
return match ? parseFloat(match[0]) : Number.MAX_SAFE_INTEGER
|
|
30
|
+
})
|
|
31
|
+
: labels
|
|
32
|
+
const reverseLabels = labels => {
|
|
33
|
+
if (config.series.some(series => series.dynamicCategory)) {
|
|
34
|
+
return orderDynamicLabels(labels)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return config.legend.reverseLabelOrder ? sortVertical(labels).reverse() : sortVertical(labels)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const orderDynamicLabels = labels => {
|
|
41
|
+
// Handle different ordering configurations
|
|
42
|
+
switch (config.legend.order) {
|
|
43
|
+
case 'dataColumn':
|
|
44
|
+
return labels
|
|
45
|
+
case 'asc':
|
|
46
|
+
case 'desc':
|
|
47
|
+
return labels.sort((a, b) => {
|
|
48
|
+
const valA = a.datum || a.text
|
|
49
|
+
const valB = b.datum || b.text
|
|
50
|
+
const numA = parseFloat(valA)
|
|
51
|
+
const numB = parseFloat(valB)
|
|
52
|
+
if (!isNaN(numA) && !isNaN(numB)) {
|
|
53
|
+
return config.legend.order === 'asc' ? numA - numB : numB - numA
|
|
54
|
+
} else {
|
|
55
|
+
return config.legend.order === 'asc' ? valA.localeCompare(valB) : valB.localeCompare(valA)
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
default:
|
|
60
|
+
return labels // Default case to handle any unexpected config.legend.order values
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const colorCode = config.legend?.colorCode
|
|
64
|
+
if (visualizationType === 'Deviation Bar') {
|
|
65
|
+
let versionName = isV1Palette(config) ? 'v1' : 'v2'
|
|
66
|
+
const [belowColor, aboveColor] = twoColorPalette?.[versionName]?.[config.twoColor.palette] || [
|
|
67
|
+
'#1D6ABF',
|
|
68
|
+
'#935586'
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
const labelBelow = {
|
|
72
|
+
datum: 'X',
|
|
73
|
+
index: 0,
|
|
74
|
+
text: `Below ${config.xAxis.targetLabel}`,
|
|
75
|
+
value: belowColor
|
|
76
|
+
}
|
|
77
|
+
const labelAbove = {
|
|
78
|
+
datum: 'X',
|
|
79
|
+
index: 1,
|
|
80
|
+
text: `Above ${config.xAxis.targetLabel}`,
|
|
81
|
+
value: aboveColor
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return reverseLabels([labelBelow, labelAbove])
|
|
85
|
+
}
|
|
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
|
+
|
|
115
|
+
tableData.forEach(d => set.add(d[colorCode]))
|
|
116
|
+
|
|
117
|
+
// create labels with unique values
|
|
118
|
+
const uniqueLabels = Array.from(set).map((val, i) => {
|
|
119
|
+
const newLabel = {
|
|
120
|
+
datum: val,
|
|
121
|
+
index: i,
|
|
122
|
+
text: val,
|
|
123
|
+
value: palette?.[i]
|
|
124
|
+
}
|
|
125
|
+
return newLabel
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
return reverseLabels(uniqueLabels)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// get forecasting items inside of combo
|
|
132
|
+
if (runtime?.forecastingSeriesKeys?.length > 0) {
|
|
133
|
+
let seriesLabels = []
|
|
134
|
+
|
|
135
|
+
// Create palette lookup map - use version-specific palettes
|
|
136
|
+
// Forecasting charts use sequentialPalettes for v1, sequential-only palettes for v2
|
|
137
|
+
const paletteVersion = getColorPaletteVersion(config)
|
|
138
|
+
|
|
139
|
+
let forecastPalettes
|
|
140
|
+
if (paletteVersion === 1) {
|
|
141
|
+
// V1: Use original sequential palettes
|
|
142
|
+
forecastPalettes = sequentialPalettes
|
|
143
|
+
} else {
|
|
144
|
+
// V2: Only use sequential palettes (filter out divergent and qualitative)
|
|
145
|
+
const allV2Palettes = colorPalettesChartV2
|
|
146
|
+
forecastPalettes = {}
|
|
147
|
+
Object.keys(allV2Palettes).forEach(key => {
|
|
148
|
+
if (key.startsWith('sequential')) {
|
|
149
|
+
forecastPalettes[key] = allV2Palettes[key]
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const processedPalettes = updatePaletteNames(forecastPalettes)
|
|
155
|
+
const forecastingPalettes = buildForecastPaletteMappings(processedPalettes, paletteVersion)
|
|
156
|
+
|
|
157
|
+
//store unique values to Set by colorCode
|
|
158
|
+
// loop through each stage/group/area on the chart and create a label
|
|
159
|
+
config.runtime?.forecastingSeriesKeys?.map((outerGroup, index) => {
|
|
160
|
+
return outerGroup?.stages?.map((stage, index) => {
|
|
161
|
+
const palette = forecastingPalettes[stage.color] || false
|
|
162
|
+
let colorValue = palette?.[2] || '#ccc'
|
|
163
|
+
|
|
164
|
+
const newLabel = {
|
|
165
|
+
datum: stage.key,
|
|
166
|
+
index: index,
|
|
167
|
+
text: stage.key,
|
|
168
|
+
value: colorValue
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
seriesLabels.push(newLabel)
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
// loop through bars for now to meet requirements.
|
|
176
|
+
config.runtime.barSeriesKeys &&
|
|
177
|
+
config.runtime.barSeriesKeys.forEach((bar, index) => {
|
|
178
|
+
const currentPaletteName = getCurrentPaletteName(config) || getFallbackColorPalette(config)
|
|
179
|
+
const migratedPaletteName = migratePaletteWithMap(currentPaletteName, chartPaletteMigrationMap, true)
|
|
180
|
+
const palette = getPaletteAccessor(colorPalettes, config, migratedPaletteName)
|
|
181
|
+
let colorValue = palette?.[index] || '#ccc'
|
|
182
|
+
|
|
183
|
+
const newLabel = {
|
|
184
|
+
datum: bar,
|
|
185
|
+
index: index,
|
|
186
|
+
text: bar,
|
|
187
|
+
value: colorValue
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
seriesLabels.push(newLabel)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
return reverseLabels(seriesLabels)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (config.series.some(item => item.name)) {
|
|
197
|
+
const uniqueLabels = Array.from(new Set(config.series.map(d => d.name || d.dataKey))).map((val, i) => ({
|
|
198
|
+
datum: val,
|
|
199
|
+
index: i,
|
|
200
|
+
text: val,
|
|
201
|
+
value: colorScale(val)
|
|
202
|
+
}))
|
|
203
|
+
return reverseLabels(uniqueLabels)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (
|
|
207
|
+
(config.visualizationType === 'Bar' || config.visualizationType === 'Combo') &&
|
|
208
|
+
config.visualizationSubType === 'regular' &&
|
|
209
|
+
config.suppressedData
|
|
210
|
+
) {
|
|
211
|
+
const lastIndex = defaultLabels.length - 1
|
|
212
|
+
let newLabels = []
|
|
213
|
+
|
|
214
|
+
config.suppressedData?.forEach(({ label, icon }, index) => {
|
|
215
|
+
if (label && icon) {
|
|
216
|
+
const newLabel = {
|
|
217
|
+
datum: label,
|
|
218
|
+
index: lastIndex + index,
|
|
219
|
+
text: label,
|
|
220
|
+
icon: <FaStar color='#000' size={15} />
|
|
221
|
+
}
|
|
222
|
+
newLabels.push(newLabel)
|
|
223
|
+
}
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
return [...defaultLabels, ...newLabels]
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return reverseLabels(defaultLabels)
|
|
230
|
+
}
|
|
@@ -22,7 +22,7 @@ const LegendWrapper: React.FC<LegendWrapperProps> = props => {
|
|
|
22
22
|
return classes.join(' ')
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
return <div className={getLegendWrappingClasses()}>{
|
|
25
|
+
return <div className={getLegendWrappingClasses()}>{children}</div>
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export default LegendWrapper
|