@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
package/src/hooks/useTooltip.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useContext } from 'react'
|
|
1
|
+
import { useContext, useRef } from 'react'
|
|
2
2
|
// Local imports
|
|
3
3
|
import parse from 'html-react-parser'
|
|
4
4
|
import ConfigContext from '../ConfigContext'
|
|
@@ -8,10 +8,12 @@ import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
|
8
8
|
// Third-party library imports
|
|
9
9
|
import { localPoint } from '@visx/event'
|
|
10
10
|
import { bisector } from 'd3-array'
|
|
11
|
-
import _ from 'lodash'
|
|
11
|
+
import _, { get } from 'lodash'
|
|
12
12
|
import { getHorizontalBarHeights } from '../components/BarChart/helpers/getBarHeights'
|
|
13
13
|
|
|
14
14
|
export const useTooltip = props => {
|
|
15
|
+
// Track the last X-axis value to prevent duplicate analytics events
|
|
16
|
+
const lastAnalyticsXValue = useRef<string | number | null>(null)
|
|
15
17
|
const {
|
|
16
18
|
tableData: data,
|
|
17
19
|
config,
|
|
@@ -23,7 +25,7 @@ export const useTooltip = props => {
|
|
|
23
25
|
setSharedFilter,
|
|
24
26
|
isDraggingAnnotation
|
|
25
27
|
} = useContext<ChartContext>(ConfigContext)
|
|
26
|
-
const { xScale, yScale, seriesScale, showTooltip, hideTooltip } = props
|
|
28
|
+
const { xScale, yScale, seriesScale, showTooltip, hideTooltip, interactionLabel = '' } = props
|
|
27
29
|
const { xAxis, visualizationType, orientation, yAxis, runtime } = config
|
|
28
30
|
|
|
29
31
|
const Y_AXIS_SIZE = Number(config.yAxis.size || 0)
|
|
@@ -84,6 +86,7 @@ export const useTooltip = props => {
|
|
|
84
86
|
|
|
85
87
|
const resolvedScaleValues = getResolvedScaleValues([x, y])
|
|
86
88
|
const singleSeriesValue = getYValueFromCoordinate(y, resolvedScaleValues)
|
|
89
|
+
|
|
87
90
|
const columnsWithTooltips = []
|
|
88
91
|
const tooltipItems = [] as any[][]
|
|
89
92
|
for (const [colKey, column] of Object.entries(config.columns)) {
|
|
@@ -154,6 +157,10 @@ export const useTooltip = props => {
|
|
|
154
157
|
return position
|
|
155
158
|
}
|
|
156
159
|
if (!config.tooltips.singleSeries || visualizationType === 'Line') {
|
|
160
|
+
// Collect analytics data for all series
|
|
161
|
+
const analyticsSeriesData: string[] = []
|
|
162
|
+
let xAxisValue: string | number | null = null
|
|
163
|
+
|
|
157
164
|
tooltipItems.push(
|
|
158
165
|
...getIncludedTooltipSeries()
|
|
159
166
|
?.filter(seriesKey => {
|
|
@@ -168,6 +175,7 @@ export const useTooltip = props => {
|
|
|
168
175
|
const seriesObjWithName = config.runtime.series.find(
|
|
169
176
|
series => series.dataKey === seriesKey && series.name !== undefined
|
|
170
177
|
)
|
|
178
|
+
|
|
171
179
|
if (
|
|
172
180
|
(value === null || value === undefined || value === '' || formattedValue === 'N/A') &&
|
|
173
181
|
config.general.hideNullValue
|
|
@@ -181,6 +189,29 @@ export const useTooltip = props => {
|
|
|
181
189
|
})
|
|
182
190
|
)
|
|
183
191
|
|
|
192
|
+
// Publish a single analytics event with all tooltip data
|
|
193
|
+
// Only publish if the X-axis value has changed (different from last hover)
|
|
194
|
+
if (analyticsSeriesData.length > 0 && xAxisValue !== lastAnalyticsXValue.current) {
|
|
195
|
+
lastAnalyticsXValue.current = xAxisValue
|
|
196
|
+
|
|
197
|
+
// Extract series names for the series field
|
|
198
|
+
const seriesNames = analyticsSeriesData.map(item => item.split(':')[0].trim()).join(', ')
|
|
199
|
+
|
|
200
|
+
const specifics = xAxisValue
|
|
201
|
+
? `series: ${seriesNames}, x: ${xAxisValue}, ${analyticsSeriesData.join(', ')}`
|
|
202
|
+
: `series: ${seriesNames}, ${analyticsSeriesData.join(', ')}`
|
|
203
|
+
|
|
204
|
+
publishAnalyticsEvent({
|
|
205
|
+
vizType: config?.type,
|
|
206
|
+
vizSubType: getVizSubType(config),
|
|
207
|
+
eventType: `chart_hover`,
|
|
208
|
+
eventAction: 'hover',
|
|
209
|
+
eventLabel: interactionLabel || 'unknown',
|
|
210
|
+
vizTitle: getVizTitle(config),
|
|
211
|
+
specifics
|
|
212
|
+
})
|
|
213
|
+
}
|
|
214
|
+
|
|
184
215
|
const runtimeSeries =
|
|
185
216
|
config.tooltips.singleSeries && visualizationType === 'Line'
|
|
186
217
|
? [_.find(config.runtime.series, d => d.dataKey === singleSeriesValue)]
|
|
@@ -239,6 +270,9 @@ export const useTooltip = props => {
|
|
|
239
270
|
* @returns {void} - The tooltip information is hidden
|
|
240
271
|
*/
|
|
241
272
|
const handleTooltipMouseOff = () => {
|
|
273
|
+
// Reset the analytics tracking when mouse leaves
|
|
274
|
+
lastAnalyticsXValue.current = null
|
|
275
|
+
|
|
242
276
|
if (config.visualizationType === 'Area Chart') {
|
|
243
277
|
setTimeout(() => {
|
|
244
278
|
hideTooltip()
|
|
@@ -571,18 +605,26 @@ export const useTooltip = props => {
|
|
|
571
605
|
|
|
572
606
|
// TOOLTIP BODY
|
|
573
607
|
// handle suppressed tooltip items
|
|
574
|
-
const
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
608
|
+
const shouldCheckSuppression = config.visualizationSubType !== 'stacked'
|
|
609
|
+
let suppressionEntry
|
|
610
|
+
if (shouldCheckSuppression && config.preliminaryData) {
|
|
611
|
+
suppressionEntry = config.preliminaryData.find(
|
|
612
|
+
pd =>
|
|
613
|
+
pd.label &&
|
|
614
|
+
pd.type === 'suppression' &&
|
|
615
|
+
pd.displayTooltip &&
|
|
616
|
+
value === pd.value &&
|
|
617
|
+
(!pd.column || key === pd.column)
|
|
618
|
+
)
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Remove suppressed items entirely if not showing symbols
|
|
622
|
+
if (suppressionEntry && !config.general.showSuppressedSymbol) {
|
|
623
|
+
return null
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
const { label, displayGray } = suppressionEntry || {}
|
|
627
|
+
|
|
586
628
|
let newValue = label || value
|
|
587
629
|
const style = displayGray ? { color: '#8b8b8a' } : {}
|
|
588
630
|
|
|
@@ -594,7 +636,7 @@ export const useTooltip = props => {
|
|
|
594
636
|
|
|
595
637
|
return (
|
|
596
638
|
<li style={style} className='tooltip-body mb-1'>
|
|
597
|
-
{parse(displayText)}
|
|
639
|
+
{displayText !== undefined ? parse(String(displayText)) : displayText}
|
|
598
640
|
</li>
|
|
599
641
|
)
|
|
600
642
|
}
|
package/src/index.jsx
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import ReactDOM from 'react-dom/client'
|
|
3
3
|
|
|
4
|
-
import './coreStyles_chart.scss'
|
|
5
4
|
import '@cdc/core/styles/cove-main.scss'
|
|
6
|
-
import 'react-tooltip/dist/react-tooltip.css'
|
|
7
5
|
|
|
8
6
|
import CdcChart from './CdcChart'
|
|
9
7
|
|
|
@@ -14,6 +12,11 @@ let domContainer = document.getElementsByClassName('react-container')[0]
|
|
|
14
12
|
|
|
15
13
|
ReactDOM.createRoot(domContainer).render(
|
|
16
14
|
<React.StrictMode>
|
|
17
|
-
<CdcChart
|
|
15
|
+
<CdcChart
|
|
16
|
+
interactionLabel={domContainer.attributes['data-config']?.value}
|
|
17
|
+
configUrl={domContainer.attributes['data-config'].value}
|
|
18
|
+
isEditor={isEditor}
|
|
19
|
+
isDebug={isDebug}
|
|
20
|
+
/>
|
|
18
21
|
</React.StrictMode>
|
|
19
22
|
)
|
package/src/scss/main.scss
CHANGED
|
@@ -741,3 +741,15 @@
|
|
|
741
741
|
.cdc-open-viz-module .debug {
|
|
742
742
|
border: 2px solid red;
|
|
743
743
|
}
|
|
744
|
+
|
|
745
|
+
// Pattern Legend Styles - using Bootstrap classes for layout, CSS for gaps only
|
|
746
|
+
.legend-patterns {
|
|
747
|
+
gap: var(--space-between-legend-item-rows);
|
|
748
|
+
margin-top: var(--space-between-legend-item-rows);
|
|
749
|
+
|
|
750
|
+
// When in row layout (top/bottom), override gap for proper row/column spacing
|
|
751
|
+
&.flex-row {
|
|
752
|
+
row-gap: var(--space-between-legend-item-rows);
|
|
753
|
+
column-gap: var(--space-between-legend-item-columns);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
@@ -25,7 +25,7 @@ export const getInitialState = (configObj: ChartConfig): ChartState => {
|
|
|
25
25
|
return {
|
|
26
26
|
isLoading: true,
|
|
27
27
|
config: defaults,
|
|
28
|
-
stateData:
|
|
28
|
+
stateData: configObj?.data || [],
|
|
29
29
|
colorScale: null,
|
|
30
30
|
excludedData: undefined,
|
|
31
31
|
filteredData: undefined,
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import { testStandaloneBuild } from '@cdc/core/helpers/tests/testStandaloneBuild.ts'
|
|
3
|
+
import { describe, it, expect } from 'vitest'
|
|
4
|
+
|
|
2
5
|
describe('Chart', () => {
|
|
3
|
-
it('
|
|
4
|
-
|
|
6
|
+
it('Can be built in isolation', async () => {
|
|
7
|
+
const pkgDir = path.join(__dirname, '..')
|
|
8
|
+
const result = testStandaloneBuild(pkgDir)
|
|
9
|
+
expect(result).toBe(true)
|
|
5
10
|
})
|
|
6
11
|
})
|
package/src/types/ChartConfig.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Axis } from '@cdc/core/types/Axis'
|
|
2
|
+
import { MarkupConfig } from '@cdc/core/types/MarkupVariable'
|
|
2
3
|
import { type ForestPlotConfigSettings } from './ForestPlot'
|
|
3
4
|
import { type Column } from '@cdc/core/types/Column'
|
|
4
5
|
import { type Series } from '@cdc/core/types/Series'
|
|
@@ -6,7 +7,17 @@ import { Runtime } from '@cdc/core/types/Runtime'
|
|
|
6
7
|
import { FilterBehavior } from '@cdc/core/types/FilterBehavior'
|
|
7
8
|
import { Table } from '@cdc/core/types/Table'
|
|
8
9
|
import { BoxPlot } from '@cdc/core/types/BoxPlot'
|
|
9
|
-
import { General } from '@cdc/core/types/General'
|
|
10
|
+
import { General as CoreGeneral } from '@cdc/core/types/General'
|
|
11
|
+
|
|
12
|
+
// Extend the core General type to include palette information for charts
|
|
13
|
+
export type General = CoreGeneral & {
|
|
14
|
+
palette?: {
|
|
15
|
+
name?: string
|
|
16
|
+
version?: string
|
|
17
|
+
isReversed?: boolean
|
|
18
|
+
customColors?: string[]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
10
21
|
import { type Link } from './../components/Sankey/types'
|
|
11
22
|
import { type DataDescription } from '@cdc/core/types/DataDescription'
|
|
12
23
|
import { type Legend as CoreLegend } from '@cdc/core/types/Legend'
|
|
@@ -96,6 +107,17 @@ export type Legend = CoreLegend & {
|
|
|
96
107
|
}
|
|
97
108
|
groupBy: string
|
|
98
109
|
separators?: string
|
|
110
|
+
patterns?: {
|
|
111
|
+
[key: string]: {
|
|
112
|
+
label?: string
|
|
113
|
+
color?: string
|
|
114
|
+
shape?: string
|
|
115
|
+
dataKey?: string
|
|
116
|
+
dataValue?: string
|
|
117
|
+
contrastCheck?: boolean
|
|
118
|
+
patternSize?: number
|
|
119
|
+
}
|
|
120
|
+
}
|
|
99
121
|
}
|
|
100
122
|
|
|
101
123
|
type Visual = {
|
|
@@ -125,7 +147,6 @@ export type AllChartsConfig = {
|
|
|
125
147
|
colorMatchLineSeriesLabels: boolean
|
|
126
148
|
columns: ChartColumns
|
|
127
149
|
confidenceKeys: ConfidenceInterval
|
|
128
|
-
customColors: string[]
|
|
129
150
|
data: Object[]
|
|
130
151
|
dataUrl: string
|
|
131
152
|
dataCutoff: number
|
|
@@ -225,12 +246,13 @@ export type AllChartsConfig = {
|
|
|
225
246
|
default: string
|
|
226
247
|
}
|
|
227
248
|
}
|
|
228
|
-
}
|
|
249
|
+
} & MarkupConfig
|
|
229
250
|
|
|
230
251
|
export type ForestPlotConfig = {
|
|
231
252
|
visualizationType: 'Forest Plot'
|
|
232
253
|
forestPlot: ForestPlotConfigSettings
|
|
233
|
-
} & AllChartsConfig
|
|
254
|
+
} & AllChartsConfig &
|
|
255
|
+
MarkupConfig
|
|
234
256
|
|
|
235
257
|
export type LineChartConfig = {
|
|
236
258
|
allowLineToBarGraph: boolean
|
|
@@ -238,7 +260,8 @@ export type LineChartConfig = {
|
|
|
238
260
|
isolatedDotsSameSize: boolean
|
|
239
261
|
lineDatapointStyle: 'hidden' | 'always show' | 'hover'
|
|
240
262
|
visualizationType: 'Line'
|
|
241
|
-
} & AllChartsConfig
|
|
263
|
+
} & AllChartsConfig &
|
|
264
|
+
MarkupConfig
|
|
242
265
|
|
|
243
266
|
export type SankeyLink = {
|
|
244
267
|
depth: number
|
|
@@ -279,6 +302,7 @@ export type SankeyChartConfig = {
|
|
|
279
302
|
}
|
|
280
303
|
]
|
|
281
304
|
visualizationType: 'Sankey'
|
|
282
|
-
} & AllChartsConfig
|
|
305
|
+
} & AllChartsConfig &
|
|
306
|
+
MarkupConfig
|
|
283
307
|
|
|
284
308
|
export type ChartConfig = SankeyChartConfig | LineChartConfig | ForestPlotConfig | AllChartsConfig
|
|
@@ -23,6 +23,7 @@ type SharedChartContext = {
|
|
|
23
23
|
handleDragStateChange: (isDragging: any) => void
|
|
24
24
|
highlight?: Function
|
|
25
25
|
handleShowAll?: Function
|
|
26
|
+
interactionLabel?: string
|
|
26
27
|
// whether or not the chart is viewed within the editor screen
|
|
27
28
|
isEditor?: boolean
|
|
28
29
|
// whether or not the user is dragging an annotation
|
package/vite.config.js
CHANGED
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config'
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
environment: 'jsdom',
|
|
6
|
+
globals: true,
|
|
7
|
+
setupFiles: ['../../vitest.setup.ts'],
|
|
8
|
+
exclude: [
|
|
9
|
+
'**/node_modules/**',
|
|
10
|
+
'**/dist/**',
|
|
11
|
+
'**/.storybook/**',
|
|
12
|
+
'**/*.stories.*',
|
|
13
|
+
'**/storybook-static/**'
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
})
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { cloneDeep } from 'lodash'
|
|
2
|
-
import { ChartConfig } from '../types/ChartConfig'
|
|
3
|
-
|
|
4
|
-
/* editConfigKeys
|
|
5
|
-
* Add edit or update config keys
|
|
6
|
-
* keyUpdates: { path: string[], value: any }[]
|
|
7
|
-
* path is the array of keys needed to reach the value to be updated
|
|
8
|
-
* value is the new value to be set
|
|
9
|
-
* if the key does not exist, it will be created
|
|
10
|
-
*/
|
|
11
|
-
export function editConfigKeys(config: ChartConfig, keyUpdates: { path: string[]; value: any }[]): ChartConfig {
|
|
12
|
-
const configDeepCopy = cloneDeep(config)
|
|
13
|
-
|
|
14
|
-
const newConfig = keyUpdates.reduce((acc, { path, value }) => {
|
|
15
|
-
const pathCopy = [...path]
|
|
16
|
-
const lastKey = pathCopy.pop()
|
|
17
|
-
const target = pathCopy.reduce((target, key) => {
|
|
18
|
-
if (!target[key]) {
|
|
19
|
-
target[key] = {}
|
|
20
|
-
}
|
|
21
|
-
return target[key]
|
|
22
|
-
}, acc)
|
|
23
|
-
target[lastKey] = value
|
|
24
|
-
return acc
|
|
25
|
-
}, configDeepCopy)
|
|
26
|
-
|
|
27
|
-
return newConfig
|
|
28
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import chroma from 'chroma-js'
|
|
2
|
-
|
|
3
|
-
export const generateColorsArray = (color = '#000000', special = false) => {
|
|
4
|
-
let colorObj = chroma(color)
|
|
5
|
-
let hoverColor = special ? colorObj.brighten(0.5).hex() : colorObj.saturate(1.3).hex()
|
|
6
|
-
|
|
7
|
-
return [color, hoverColor, colorObj.darken(0.3).hex()]
|
|
8
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { colorPalettesChart, twoColorPalette } from '@cdc/core/data/colorPalettes'
|
|
2
|
-
import { useEffect } from 'react'
|
|
3
|
-
|
|
4
|
-
export const useColorPalette = (config, updateConfig) => {
|
|
5
|
-
let twoColorPalettes = []
|
|
6
|
-
let sequential = []
|
|
7
|
-
let nonSequential = []
|
|
8
|
-
const accessibleColors = []
|
|
9
|
-
|
|
10
|
-
// Get two color palettes if visualization type is Paired Bar
|
|
11
|
-
if (config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') {
|
|
12
|
-
const isReversed = config.twoColor.isPaletteReversed
|
|
13
|
-
twoColorPalettes = Object.keys(twoColorPalette).filter(name =>
|
|
14
|
-
isReversed ? name.endsWith('reverse') : !name.endsWith('reverse')
|
|
15
|
-
)
|
|
16
|
-
} else {
|
|
17
|
-
// Get sequential and non-sequential palettes for other visualization types
|
|
18
|
-
const seqPalettes = []
|
|
19
|
-
const nonSeqPalettes = []
|
|
20
|
-
|
|
21
|
-
for (const paletteName in colorPalettesChart) {
|
|
22
|
-
const isSequential = paletteName.startsWith('sequential')
|
|
23
|
-
const isQualitative = paletteName.startsWith('qualitative')
|
|
24
|
-
const colorblindsafe = paletteName.startsWith('colorblindsafe')
|
|
25
|
-
const isReversed = paletteName.endsWith('reverse')
|
|
26
|
-
|
|
27
|
-
if (isSequential && ((!config.isPaletteReversed && !isReversed) || (config.isPaletteReversed && isReversed))) {
|
|
28
|
-
seqPalettes.push(paletteName)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (isQualitative && ((!config.isPaletteReversed && !isReversed) || (config.isPaletteReversed && isReversed))) {
|
|
32
|
-
nonSeqPalettes.push(paletteName)
|
|
33
|
-
}
|
|
34
|
-
if (colorblindsafe && ((!config.isPaletteReversed && !isReversed) || (config.isPaletteReversed && isReversed))) {
|
|
35
|
-
accessibleColors.push(paletteName)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
sequential = seqPalettes
|
|
40
|
-
nonSequential = nonSeqPalettes
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Update pairedBar.palette based on isPaletteReversed
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
let palette = ''
|
|
46
|
-
|
|
47
|
-
if (config.twoColor.isPaletteReversed && !config.twoColor.palette.endsWith('reverse')) {
|
|
48
|
-
palette = config.twoColor.palette + 'reverse'
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (!config.twoColor.isPaletteReversed && config.twoColor.palette.endsWith('reverse')) {
|
|
52
|
-
palette = config.twoColor.palette.slice(0, -7)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
updateConfig({ ...config, twoColor: { ...config.twoColor, palette: palette } })
|
|
56
|
-
}, [config.twoColor.isPaletteReversed])
|
|
57
|
-
|
|
58
|
-
// Update palette based on isPaletteReversed
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
let palette = ''
|
|
61
|
-
|
|
62
|
-
if (config.isPaletteReversed && !config.palette.endsWith('reverse')) {
|
|
63
|
-
palette = config.palette + 'reverse'
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (!config.isPaletteReversed && config.palette.endsWith('reverse')) {
|
|
67
|
-
palette = config.palette.slice(0, -7)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
updateConfig({ ...config, palette: palette })
|
|
71
|
-
}, [config.isPaletteReversed])
|
|
72
|
-
|
|
73
|
-
// Return all palettes
|
|
74
|
-
|
|
75
|
-
return { twoColorPalettes, sequential, nonSequential, accessibleColors }
|
|
76
|
-
}
|