@cdc/chart 4.25.8 → 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 +37524 -35243
- 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 +1 -2
- package/src/CdcChartComponent.tsx +174 -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 +159 -20
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +138 -5
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +215 -73
- package/src/components/BarChart/components/BarChart.Vertical.tsx +153 -21
- 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/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.PatternSettings.tsx +414 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +28 -20
- 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 +106 -13
- package/src/components/Legend/helpers/createFormatLabels.tsx +230 -171
- package/src/components/LegendWrapper.tsx +1 -1
- package/src/components/LineChart/components/LineChart.Circle.tsx +2 -2
- package/src/components/LineChart/index.tsx +2 -2
- package/src/components/LinearChart.tsx +22 -5
- 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 -293
- 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 +57 -15
- package/src/index.jsx +0 -2
- 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'
|
|
@@ -18,6 +19,7 @@ import LegendLineShape from './LegendLine.Shape'
|
|
|
18
19
|
import LegendGroup from './LegendGroup'
|
|
19
20
|
import { getSeriesWithData } from '../../helpers/dataHelpers'
|
|
20
21
|
import { publishAnalyticsEvent } from '@cdc/core/helpers/metrics/helpers'
|
|
22
|
+
import { getVizTitle, getVizSubType } from '@cdc/core/helpers/metrics/utils'
|
|
21
23
|
|
|
22
24
|
const LEGEND_PADDING = 36
|
|
23
25
|
|
|
@@ -36,7 +38,6 @@ export interface LegendProps {
|
|
|
36
38
|
interactionLabel: string
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
/* eslint-disable jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */
|
|
40
41
|
const Legend: React.FC<LegendProps> = forwardRef(
|
|
41
42
|
(
|
|
42
43
|
{
|
|
@@ -72,6 +73,7 @@ const Legend: React.FC<LegendProps> = forwardRef(
|
|
|
72
73
|
|
|
73
74
|
const { HighLightedBarUtils } = useHighlightedBars(config)
|
|
74
75
|
let highLightedLegendItems = HighLightedBarUtils.findDuplicates(config.highlightedBarValues)
|
|
76
|
+
|
|
75
77
|
if (!legend) return null
|
|
76
78
|
return (
|
|
77
79
|
<aside
|
|
@@ -140,23 +142,34 @@ const Legend: React.FC<LegendProps> = forwardRef(
|
|
|
140
142
|
onKeyDown={e => {
|
|
141
143
|
if (e.key === 'Enter') {
|
|
142
144
|
e.preventDefault()
|
|
143
|
-
publishAnalyticsEvent(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
+
})
|
|
149
156
|
highlight(label)
|
|
150
157
|
}
|
|
151
158
|
}}
|
|
152
159
|
onClick={e => {
|
|
153
160
|
e.preventDefault()
|
|
154
|
-
publishAnalyticsEvent(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
'
|
|
159
|
-
|
|
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
|
+
})
|
|
160
173
|
highlight(label)
|
|
161
174
|
}}
|
|
162
175
|
role='button'
|
|
@@ -221,6 +234,86 @@ const Legend: React.FC<LegendProps> = forwardRef(
|
|
|
221
234
|
</div>
|
|
222
235
|
|
|
223
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
|
+
)}
|
|
224
317
|
</>
|
|
225
318
|
)
|
|
226
319
|
}}
|
|
@@ -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
|
|
@@ -105,7 +105,7 @@ const LineChartCircle = (props: LineChartCircleProps) => {
|
|
|
105
105
|
<g
|
|
106
106
|
transform={transformShape(pointData[config.xAxis.dataKey], pointData[filtered?.dataKey])}
|
|
107
107
|
className={`visx-glyph-group${displayArea ? '' : '-hidden'}`}
|
|
108
|
-
data-
|
|
108
|
+
data-seriesindex={seriesIndex}
|
|
109
109
|
>
|
|
110
110
|
<Shape
|
|
111
111
|
fillOpacity={mode === 'ALWAYS_SHOW_POINTS' ? 1 : 0}
|
|
@@ -142,7 +142,7 @@ const LineChartCircle = (props: LineChartCircleProps) => {
|
|
|
142
142
|
<g
|
|
143
143
|
transform={transformShape(pointData[config.xAxis?.dataKey], pointData[filtered?.dataKey])}
|
|
144
144
|
className={`visx-glyph-group${displayArea ? '' : '-hidden'}`}
|
|
145
|
-
data-
|
|
145
|
+
data-seriesindex={seriesIndex}
|
|
146
146
|
>
|
|
147
147
|
<Shape size={dotSize} stroke={color} fill={color} />
|
|
148
148
|
</g>
|
|
@@ -228,10 +228,10 @@ const LineChart = (props: LineChartProps) => {
|
|
|
228
228
|
/>
|
|
229
229
|
|
|
230
230
|
{suppressedSegments.map((segment, index) => {
|
|
231
|
-
return Object.entries(segment.data).map(([key, value]) => {
|
|
231
|
+
return Object.entries(segment.data).map(([key, value], entryIndex) => {
|
|
232
232
|
return (
|
|
233
233
|
<LinePath
|
|
234
|
-
key={index}
|
|
234
|
+
key={`${index}-${key}-${entryIndex}`}
|
|
235
235
|
data={value}
|
|
236
236
|
x={d => xPos(d)}
|
|
237
237
|
y={d =>
|