@cdc/chart 4.25.8 → 4.25.11
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-1a1724a1.es.js → cdcchart-dgT_1dIT.es.js} +136 -151
- package/dist/cdcchart.js +44236 -40355
- package/examples/feature/__data__/planet-example-data.json +0 -30
- package/examples/feature/boxplot/valid-boxplot.csv +38 -17
- package/examples/grouped-bar-test.json +400 -0
- package/examples/private/DEV-11825.json +573 -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/na.json +913 -0
- package/examples/private/new.json +48756 -0
- package/examples/private/pie-chart-legend.json +904 -0
- package/examples/private/test-data.csv +28 -0
- package/examples/suppressed_tooltip.json +480 -0
- package/index.html +2 -133
- package/package.json +25 -7
- package/src/CdcChart.tsx +9 -13
- package/src/CdcChartComponent.tsx +403 -92
- 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.Combo.stories.tsx +18 -0
- 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.Forecast.stories.tsx +36 -0
- package/src/_stories/Chart.HTMLInDataTable.stories.tsx +520 -0
- package/src/_stories/Chart.Legend.Gradient.stories.tsx +2 -2
- package/src/_stories/Chart.Patterns.stories.tsx +20 -0
- package/src/_stories/Chart.PreserveDecimals.stories.tsx +220 -0
- package/src/_stories/Chart.ScatterPlot.stories.tsx +1 -1
- package/src/_stories/Chart.SmallMultiples.stories.tsx +47 -0
- package/src/_stories/Chart.stories.tsx +8 -5
- package/src/_stories/Chart.tooltip.stories.tsx +1 -1
- package/src/_stories/ChartAnnotation.stories.tsx +7 -4
- package/src/_stories/ChartAxisLabels.stories.tsx +2 -2
- package/src/_stories/ChartAxisTitles.stories.tsx +2 -2
- package/src/_stories/ChartBar.Editor.stories.tsx +3580 -0
- package/src/_stories/ChartEditor.Editor.stories.tsx +658 -0
- package/src/_stories/ChartEditor.stories.tsx +59 -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/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/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/_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/Annotations/components/findNearestDatum.ts +6 -41
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +10 -6
- package/src/components/AreaChart/index.tsx +1 -2
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +161 -22
- 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 +155 -22
- 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/BoxPlot/helpers/index.ts +3 -3
- package/src/components/Brush/BrushChart.tsx +1 -1
- package/src/components/DeviationBar.jsx +9 -6
- package/src/components/EditorPanel/EditorPanel.tsx +563 -229
- package/src/components/EditorPanel/EditorPanelContext.ts +3 -0
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +96 -111
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +19 -1
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +461 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +80 -67
- package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +422 -0
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +188 -139
- package/src/components/EditorPanel/components/Panels/index.tsx +5 -1
- package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +0 -8
- package/src/components/EditorPanel/editor-panel.scss +0 -20
- package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +49 -48
- package/src/components/EditorPanel/useEditorPermissions.ts +7 -15
- package/src/components/Forecasting/Forecasting.tsx +175 -27
- package/src/components/ForestPlot/ForestPlot.tsx +11 -7
- package/src/components/ForestPlot/ForestPlotProps.ts +1 -1
- package/src/components/Legend/Legend.Component.tsx +114 -14
- package/src/components/Legend/helpers/createFormatLabels.tsx +230 -171
- package/src/components/Legend/helpers/getLegendClasses.ts +0 -1
- package/src/components/LegendWrapper.tsx +1 -1
- package/src/components/LineChart/LineChartProps.ts +0 -3
- package/src/components/LineChart/components/LineChart.Circle.tsx +2 -2
- package/src/components/LineChart/helpers.ts +1 -1
- package/src/components/LineChart/index.tsx +38 -15
- package/src/components/LinearChart.tsx +96 -84
- package/src/components/PairedBarChart.jsx +6 -4
- package/src/components/PieChart/PieChart.tsx +170 -54
- package/src/components/Regions/components/Regions.tsx +3 -24
- package/src/components/Sankey/components/Sankey.tsx +7 -1
- package/src/components/Sankey/types/index.ts +1 -1
- package/src/components/ScatterPlot/ScatterPlot.jsx +32 -4
- package/src/components/SmallMultiples/SmallMultipleTile.tsx +198 -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/data/initial-state.js +327 -293
- package/src/helpers/buildForecastPaletteMappings.ts +112 -0
- package/src/helpers/buildForecastPaletteOptions.ts +71 -0
- package/src/helpers/getColorScale.ts +82 -8
- package/src/{hooks/useMinMax.ts → helpers/getMinMax.ts} +14 -7
- package/src/helpers/getNewRuntime.ts +1 -1
- package/src/helpers/getTransformedData.ts +1 -1
- package/src/helpers/getYAxisAutoPadding.ts +53 -0
- package/src/helpers/smallMultiplesHelpers.ts +529 -0
- package/src/hooks/useChartHoverAnalytics.tsx +44 -0
- package/src/hooks/useProgrammaticTooltip.ts +96 -0
- package/src/hooks/useReduceData.ts +105 -70
- package/src/hooks/useScales.ts +88 -34
- package/src/hooks/useSmallMultipleSynchronization.ts +59 -0
- package/src/hooks/useTooltip.tsx +116 -29
- package/src/index.jsx +0 -2
- package/src/scss/main.scss +13 -80
- package/src/store/chart.actions.ts +2 -0
- package/src/store/chart.reducer.ts +5 -1
- package/src/test/CdcChart.test.jsx +8 -3
- package/src/types/ChartConfig.ts +53 -11
- package/src/types/ChartContext.ts +4 -0
- package/vite.config.js +1 -1
- package/vitest.config.ts +16 -0
- package/src/_stories/_mock/pie_data.json +0 -218
- package/src/components/AreaChart/components/AreaChart.jsx +0 -109
- package/src/coreStyles_chart.scss +0 -3
- package/src/helpers/configHelpers.ts +0 -28
- package/src/helpers/generateColorsArray.ts +0 -8
- package/src/helpers/sort.ts +0 -7
- package/src/hooks/useActiveElement.js +0 -19
- package/src/hooks/useChartClasses.js +0 -41
- package/src/hooks/useColorPalette.js +0 -76
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback, memo, useContext } from 'react'
|
|
2
|
-
import { DragDropContext, Droppable } from '@hello-pangea/dnd'
|
|
2
|
+
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
|
|
3
3
|
import chroma from 'chroma-js'
|
|
4
4
|
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
5
5
|
import {
|
|
@@ -23,9 +23,11 @@ import { Select, TextField, CheckBox } from '@cdc/core/components/EditorPanel/In
|
|
|
23
23
|
import MultiSelect from '@cdc/core/components/MultiSelect'
|
|
24
24
|
import { viewports } from '@cdc/core/helpers/getViewport'
|
|
25
25
|
import { approvedCurveTypes } from '@cdc/core/helpers/lineChartHelpers'
|
|
26
|
+
import PanelMarkup from '@cdc/core/components/EditorPanel/components/PanelMarkup'
|
|
26
27
|
|
|
27
28
|
// chart components
|
|
28
29
|
import Panels from './components/Panels'
|
|
30
|
+
import PaletteConversionModal from '@cdc/core/components/PaletteConversionModal'
|
|
29
31
|
|
|
30
32
|
// cdc additional
|
|
31
33
|
import { useEditorPermissions } from './useEditorPermissions'
|
|
@@ -34,20 +36,25 @@ import ConfigContext from '../../ConfigContext'
|
|
|
34
36
|
import useReduceData from '../../hooks/useReduceData'
|
|
35
37
|
import useRightAxis from '../../hooks/useRightAxis'
|
|
36
38
|
import WarningImage from '../../images/warning.svg'
|
|
37
|
-
import
|
|
39
|
+
import getMinMax from '../../helpers/getMinMax'
|
|
38
40
|
|
|
39
41
|
import { type ChartContext } from '../../types/ChartContext'
|
|
40
42
|
import { type ChartConfig } from '../../types/ChartConfig'
|
|
41
43
|
|
|
44
|
+
import '@cdc/core/components/EditorPanel/EditorPanel.styles.css'
|
|
42
45
|
import './editor-panel.scss'
|
|
43
46
|
import { Anchor } from '@cdc/core/types/Axis'
|
|
44
47
|
import EditorPanelContext from './EditorPanelContext'
|
|
45
48
|
import _ from 'lodash'
|
|
46
49
|
import { adjustedSymbols as symbolCodes } from '@cdc/core/helpers/footnoteSymbols'
|
|
47
50
|
import { updateFieldRankByValue } from './helpers/updateFieldRankByValue'
|
|
51
|
+
import cloneConfig from '@cdc/core/helpers/cloneConfig'
|
|
48
52
|
import FootnotesEditor from '@cdc/core/components/EditorPanel/FootnotesEditor'
|
|
49
53
|
import { Datasets } from '@cdc/core/types/DataSet'
|
|
50
54
|
import { updateFieldFactory } from '@cdc/core/helpers/updateFieldFactory'
|
|
55
|
+
import { paletteMigrationMap, twoColorPaletteMigrationMap } from '@cdc/core/helpers/palettes/migratePaletteName'
|
|
56
|
+
import { isV1Palette, migratePaletteWithMap } from '@cdc/core/helpers/palettes/utils'
|
|
57
|
+
import { USE_V2_MIGRATION } from '@cdc/core/helpers/constants'
|
|
51
58
|
|
|
52
59
|
interface PreliminaryProps {
|
|
53
60
|
config: ChartConfig
|
|
@@ -627,8 +634,16 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
627
634
|
} = useContext<ChartContext>(ConfigContext)
|
|
628
635
|
|
|
629
636
|
const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
|
|
630
|
-
const properties = {
|
|
631
|
-
|
|
637
|
+
const properties = {
|
|
638
|
+
data,
|
|
639
|
+
tableData: data,
|
|
640
|
+
config,
|
|
641
|
+
minValue,
|
|
642
|
+
maxValue,
|
|
643
|
+
existPositiveValue,
|
|
644
|
+
isAllLine
|
|
645
|
+
}
|
|
646
|
+
const { leftMax, rightMax } = getMinMax(properties)
|
|
632
647
|
|
|
633
648
|
const {
|
|
634
649
|
visHasAnchors,
|
|
@@ -825,6 +840,14 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
825
840
|
|
|
826
841
|
const [displayPanel, setDisplayPanel] = useState(true)
|
|
827
842
|
const [displayViewportOverrides, setDisplayViewportOverrides] = useState(false)
|
|
843
|
+
const [showConversionModal, setShowConversionModal] = useState(false)
|
|
844
|
+
const [pendingPaletteSelection, setPendingPaletteSelection] = useState<{
|
|
845
|
+
palette: string
|
|
846
|
+
action: () => void
|
|
847
|
+
seriesIndex?: number
|
|
848
|
+
stageIndex?: number
|
|
849
|
+
type?: 'general' | 'twoColor' | 'forecast'
|
|
850
|
+
} | null>(null)
|
|
828
851
|
|
|
829
852
|
const setLollipopShape = shape => {
|
|
830
853
|
updateConfig({
|
|
@@ -892,8 +915,36 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
892
915
|
|
|
893
916
|
const getColumns = (filter = true) => {
|
|
894
917
|
let columns = {}
|
|
895
|
-
|
|
896
|
-
|
|
918
|
+
|
|
919
|
+
// Try multiple data sources in order of preference
|
|
920
|
+
let dataToUse = []
|
|
921
|
+
|
|
922
|
+
if (unfilteredData && unfilteredData.length > 0) {
|
|
923
|
+
// First preference: unfilteredData from context
|
|
924
|
+
dataToUse = unfilteredData
|
|
925
|
+
} else if (isDashboard && datasets && config.dataKey && datasets[config.dataKey]?.data?.length > 0) {
|
|
926
|
+
// Second preference: data from datasets in dashboard mode
|
|
927
|
+
dataToUse = datasets[config.dataKey].data
|
|
928
|
+
} else if (rawData && rawData.length > 0) {
|
|
929
|
+
// Third preference: rawData from context
|
|
930
|
+
dataToUse = rawData
|
|
931
|
+
} else if (data && data.length > 0) {
|
|
932
|
+
// Fourth preference: transformedData from context
|
|
933
|
+
dataToUse = data
|
|
934
|
+
} else if (config.data && config.data.length > 0) {
|
|
935
|
+
// Fifth preference: data directly from config
|
|
936
|
+
dataToUse = config.data
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// If we still don't have data, return empty array
|
|
940
|
+
if (!dataToUse || dataToUse.length === 0) {
|
|
941
|
+
return []
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
dataToUse.forEach(row => {
|
|
945
|
+
if (row && typeof row === 'object') {
|
|
946
|
+
Object.keys(row).forEach(columnName => (columns[columnName] = true))
|
|
947
|
+
}
|
|
897
948
|
})
|
|
898
949
|
|
|
899
950
|
if (filter) {
|
|
@@ -975,18 +1026,18 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
975
1026
|
|
|
976
1027
|
// prettier-ignore
|
|
977
1028
|
const {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1029
|
+
highlightedBarValues,
|
|
1030
|
+
highlightedSeriesValues,
|
|
1031
|
+
handleUpdateHighlightedBar,
|
|
1032
|
+
handleAddNewHighlightedBar,
|
|
1033
|
+
handleRemoveHighlightedBar,
|
|
1034
|
+
handleUpdateHighlightedBarColor,
|
|
1035
|
+
handleHighlightedBarLegendLabel,
|
|
1036
|
+
handleUpdateHighlightedBorderWidth
|
|
1037
|
+
} = useHighlightedBars(config, updateConfig)
|
|
987
1038
|
|
|
988
1039
|
const convertStateToConfig = () => {
|
|
989
|
-
let strippedState =
|
|
1040
|
+
let strippedState = cloneConfig(config)
|
|
990
1041
|
if (false === missingRequiredSections(config)) {
|
|
991
1042
|
delete strippedState.newViz
|
|
992
1043
|
}
|
|
@@ -1093,6 +1144,289 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
1093
1144
|
const section = config.orientation === 'horizontal' ? 'xAxis' : 'yAxis'
|
|
1094
1145
|
const [warningMsg, setWarningMsg] = useState({ maxMsg: '', minMsg: '', rightMaxMessage: '', minMsgRight: '' })
|
|
1095
1146
|
|
|
1147
|
+
// Palette migration functions
|
|
1148
|
+
const handlePaletteSelection = (palette: string) => {
|
|
1149
|
+
try {
|
|
1150
|
+
// Check if config exists and has basic structure
|
|
1151
|
+
if (!config) {
|
|
1152
|
+
console.error('COVE: Config is undefined in handlePaletteSelection')
|
|
1153
|
+
return
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
// Check if it's a v1 palette configuration
|
|
1157
|
+
const isV1PaletteConfig = isV1Palette(config)
|
|
1158
|
+
|
|
1159
|
+
const executeSelection = () => {
|
|
1160
|
+
const _newConfig = cloneConfig(config)
|
|
1161
|
+
if (!_newConfig.general.palette) {
|
|
1162
|
+
_newConfig.general.palette = {}
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// If v2 migration is disabled, use the original palette name and keep v1 version
|
|
1166
|
+
if (!USE_V2_MIGRATION) {
|
|
1167
|
+
_newConfig.general.palette.name = palette
|
|
1168
|
+
_newConfig.general.palette.version = '1.0'
|
|
1169
|
+
} else {
|
|
1170
|
+
// V2 migration logic
|
|
1171
|
+
const migratedName = palette ? migratePaletteWithMap(palette, paletteMigrationMap, false) : undefined
|
|
1172
|
+
_newConfig.general.palette.name = migratedName
|
|
1173
|
+
if (isV1PaletteConfig) {
|
|
1174
|
+
_newConfig.general.palette.version = '2.0'
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
updateConfig(_newConfig)
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
if (isV1PaletteConfig) {
|
|
1181
|
+
setPendingPaletteSelection({ palette, action: executeSelection, type: 'general' })
|
|
1182
|
+
setShowConversionModal(true)
|
|
1183
|
+
} else {
|
|
1184
|
+
executeSelection()
|
|
1185
|
+
}
|
|
1186
|
+
} catch (error) {
|
|
1187
|
+
console.error('COVE: Error in handlePaletteSelection:', error)
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
// Two-color palette migration function
|
|
1192
|
+
const handleTwoColorPaletteSelection = (palette: string) => {
|
|
1193
|
+
try {
|
|
1194
|
+
// Check if config exists and has basic structure
|
|
1195
|
+
if (!config) {
|
|
1196
|
+
console.error('COVE: Config is undefined in handleTwoColorPaletteSelection')
|
|
1197
|
+
return
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
// Check if it's a v1 palette configuration
|
|
1201
|
+
const isV1PaletteConfig = isV1Palette(config)
|
|
1202
|
+
|
|
1203
|
+
const executeSelection = () => {
|
|
1204
|
+
const _newConfig = cloneConfig(config)
|
|
1205
|
+
if (!_newConfig.twoColor) {
|
|
1206
|
+
_newConfig.twoColor = { palette: '', isPaletteReversed: false }
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
// If v2 migration is disabled, use the original palette name and keep v1 version
|
|
1210
|
+
if (!USE_V2_MIGRATION) {
|
|
1211
|
+
_newConfig.twoColor.palette = palette
|
|
1212
|
+
if (!_newConfig.general) {
|
|
1213
|
+
_newConfig.general = {}
|
|
1214
|
+
}
|
|
1215
|
+
if (!_newConfig.general.palette) {
|
|
1216
|
+
_newConfig.general.palette = {}
|
|
1217
|
+
}
|
|
1218
|
+
_newConfig.general.palette.version = '1.0'
|
|
1219
|
+
} else {
|
|
1220
|
+
// V2 migration logic
|
|
1221
|
+
const migratedPaletteName = isV1PaletteConfig
|
|
1222
|
+
? migratePaletteWithMap(palette, twoColorPaletteMigrationMap, false)
|
|
1223
|
+
: palette
|
|
1224
|
+
|
|
1225
|
+
_newConfig.twoColor.palette = migratedPaletteName
|
|
1226
|
+
|
|
1227
|
+
if (isV1PaletteConfig) {
|
|
1228
|
+
if (!_newConfig.general) {
|
|
1229
|
+
_newConfig.general = {}
|
|
1230
|
+
}
|
|
1231
|
+
if (!_newConfig.general.palette) {
|
|
1232
|
+
_newConfig.general.palette = {}
|
|
1233
|
+
}
|
|
1234
|
+
_newConfig.general.palette.version = '2.0'
|
|
1235
|
+
|
|
1236
|
+
// Create backup for rollback functionality (consistent with standard format)
|
|
1237
|
+
if (!_newConfig.general.palette.backups) {
|
|
1238
|
+
_newConfig.general.palette.backups = []
|
|
1239
|
+
}
|
|
1240
|
+
_newConfig.general.palette.backups.push({
|
|
1241
|
+
name: config.twoColor?.palette || palette,
|
|
1242
|
+
version: '1.0',
|
|
1243
|
+
isReversed: false,
|
|
1244
|
+
type: 'twoColor'
|
|
1245
|
+
})
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
updateConfig(_newConfig)
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
if (isV1PaletteConfig) {
|
|
1252
|
+
setPendingPaletteSelection({ palette, action: executeSelection, type: 'twoColor' })
|
|
1253
|
+
setShowConversionModal(true)
|
|
1254
|
+
} else {
|
|
1255
|
+
executeSelection()
|
|
1256
|
+
}
|
|
1257
|
+
} catch (error) {
|
|
1258
|
+
console.error('COVE: Error in handleTwoColorPaletteSelection:', error)
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// Forecast palette selection - includes v1/v2 migration modal logic
|
|
1263
|
+
const handleForecastPaletteSelection = (palette: string, seriesIndex: number, stageIndex: number) => {
|
|
1264
|
+
try {
|
|
1265
|
+
if (!config) {
|
|
1266
|
+
console.error('COVE: Config is undefined in handleForecastPaletteSelection')
|
|
1267
|
+
return
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
// Check if it's a v1 palette configuration
|
|
1271
|
+
const isV1PaletteConfig = isV1Palette(config)
|
|
1272
|
+
|
|
1273
|
+
const executeSelection = () => {
|
|
1274
|
+
const copyOfSeries = [...config.series]
|
|
1275
|
+
const copyOfStages = [...(copyOfSeries[seriesIndex].stages || [])]
|
|
1276
|
+
copyOfStages[stageIndex] = { ...copyOfStages[stageIndex], color: palette }
|
|
1277
|
+
copyOfSeries[seriesIndex] = { ...copyOfSeries[seriesIndex], stages: copyOfStages }
|
|
1278
|
+
|
|
1279
|
+
const _newConfig = cloneConfig(config)
|
|
1280
|
+
_newConfig.series = copyOfSeries
|
|
1281
|
+
|
|
1282
|
+
// If this is the first v2 palette selection, upgrade to v2
|
|
1283
|
+
if (isV1PaletteConfig && USE_V2_MIGRATION) {
|
|
1284
|
+
if (!_newConfig.general) {
|
|
1285
|
+
_newConfig.general = {}
|
|
1286
|
+
}
|
|
1287
|
+
if (!_newConfig.general.palette) {
|
|
1288
|
+
_newConfig.general.palette = {}
|
|
1289
|
+
}
|
|
1290
|
+
_newConfig.general.palette.version = '2.0'
|
|
1291
|
+
|
|
1292
|
+
// Forecast-specific migration map for v1 → v2 palette names (all lowercase-hyphen format)
|
|
1293
|
+
const forecastPaletteMigrationMap: Record<string, string> = {
|
|
1294
|
+
// Sequential Blue variants → sequential-blue
|
|
1295
|
+
'sequential-blue': 'sequential-blue',
|
|
1296
|
+
'sequential-blue-two': 'sequential-blue',
|
|
1297
|
+
'sequential-blue-three': 'sequential-blue',
|
|
1298
|
+
'sequential-blue-2-(mpx)': 'sequential-blue',
|
|
1299
|
+
'sequential-blue-2-mpx': 'sequential-blue',
|
|
1300
|
+
// Sequential Orange variants → sequential-orange
|
|
1301
|
+
'sequential-orange': 'sequential-orange',
|
|
1302
|
+
'sequential-orange-two': 'sequential-orange',
|
|
1303
|
+
'sequential-orange-(mpx)': 'sequential-orange',
|
|
1304
|
+
'sequential-orange-mpx': 'sequential-orange',
|
|
1305
|
+
// Other sequential palettes (no variants, just normalize)
|
|
1306
|
+
'sequential-green': 'sequential-green',
|
|
1307
|
+
'sequential-purple': 'sequential-purple',
|
|
1308
|
+
'sequential-teal': 'sequential-teal',
|
|
1309
|
+
// Reverse variants - Sequential Blue
|
|
1310
|
+
'sequential-bluereverse': 'sequential-bluereverse',
|
|
1311
|
+
'sequential-blue-reverse': 'sequential-bluereverse',
|
|
1312
|
+
'sequential-blue-tworeverse': 'sequential-bluereverse',
|
|
1313
|
+
'sequential-blue-two-reverse': 'sequential-bluereverse',
|
|
1314
|
+
'sequential-blue-threereverse': 'sequential-bluereverse',
|
|
1315
|
+
'sequential-blue-three-reverse': 'sequential-bluereverse',
|
|
1316
|
+
'sequential-blue-2-(mpx)reverse': 'sequential-bluereverse',
|
|
1317
|
+
'sequential-blue-2-(mpx)-reverse': 'sequential-bluereverse',
|
|
1318
|
+
'sequential-blue-2-mpxreverse': 'sequential-bluereverse',
|
|
1319
|
+
'sequential-blue-2-mpx-reverse': 'sequential-bluereverse',
|
|
1320
|
+
// Reverse variants - Sequential Orange
|
|
1321
|
+
'sequential-orangereverse': 'sequential-orangereverse',
|
|
1322
|
+
'sequential-orange-reverse': 'sequential-orangereverse',
|
|
1323
|
+
'sequential-orange-tworeverse': 'sequential-orangereverse',
|
|
1324
|
+
'sequential-orange-two-reverse': 'sequential-orangereverse',
|
|
1325
|
+
'sequential-orange-(mpx)reverse': 'sequential-orangereverse',
|
|
1326
|
+
'sequential-orange-(mpx)-reverse': 'sequential-orangereverse',
|
|
1327
|
+
'sequential-orange-mpxreverse': 'sequential-orangereverse',
|
|
1328
|
+
'sequential-orange-mpx-reverse': 'sequential-orangereverse',
|
|
1329
|
+
// Reverse variants - Other sequential palettes
|
|
1330
|
+
'sequential-greenreverse': 'sequential-greenreverse',
|
|
1331
|
+
'sequential-green-reverse': 'sequential-greenreverse',
|
|
1332
|
+
'sequential-purplereverse': 'sequential-purplereverse',
|
|
1333
|
+
'sequential-purple-reverse': 'sequential-purplereverse',
|
|
1334
|
+
'sequential-tealreverse': 'sequential-tealreverse',
|
|
1335
|
+
'sequential-teal-reverse': 'sequential-tealreverse'
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
// Migrate and normalize all forecast stage colors to v2 format
|
|
1339
|
+
_newConfig.series.forEach((series: any) => {
|
|
1340
|
+
if (series.type === 'Forecasting' && series.stages) {
|
|
1341
|
+
series.stages.forEach((stage: any) => {
|
|
1342
|
+
if (stage.color) {
|
|
1343
|
+
// First, try to migrate using the map
|
|
1344
|
+
const migrated = forecastPaletteMigrationMap[stage.color] || stage.color
|
|
1345
|
+
// Then normalize to lowercase with hyphens
|
|
1346
|
+
stage.color = migrated.toLowerCase().replace(/ /g, '-').replace(/_/g, '-')
|
|
1347
|
+
}
|
|
1348
|
+
})
|
|
1349
|
+
}
|
|
1350
|
+
})
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
updateConfig(_newConfig)
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
if (isV1PaletteConfig) {
|
|
1357
|
+
setPendingPaletteSelection({ palette, action: executeSelection, type: 'forecast', seriesIndex, stageIndex })
|
|
1358
|
+
setShowConversionModal(true)
|
|
1359
|
+
} else {
|
|
1360
|
+
executeSelection()
|
|
1361
|
+
}
|
|
1362
|
+
} catch (error) {
|
|
1363
|
+
console.error('COVE: Error in handleForecastPaletteSelection:', error)
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
// Modal handlers
|
|
1368
|
+
const handleConversionConfirm = () => {
|
|
1369
|
+
if (pendingPaletteSelection) {
|
|
1370
|
+
pendingPaletteSelection.action()
|
|
1371
|
+
}
|
|
1372
|
+
setShowConversionModal(false)
|
|
1373
|
+
setPendingPaletteSelection(null)
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
const handleConversionCancel = () => {
|
|
1377
|
+
// Don't update config - just close modal and discard pending selection
|
|
1378
|
+
setShowConversionModal(false)
|
|
1379
|
+
setPendingPaletteSelection(null)
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
const handleReturnToV1 = () => {
|
|
1383
|
+
if (pendingPaletteSelection) {
|
|
1384
|
+
const _newConfig = cloneConfig(config)
|
|
1385
|
+
const { palette, type } = pendingPaletteSelection
|
|
1386
|
+
|
|
1387
|
+
// Handle based on palette type
|
|
1388
|
+
if (type === 'forecast') {
|
|
1389
|
+
// Forecast palette selection
|
|
1390
|
+
const { seriesIndex, stageIndex } = pendingPaletteSelection
|
|
1391
|
+
if (seriesIndex !== undefined && stageIndex !== undefined) {
|
|
1392
|
+
const copyOfSeries = [..._newConfig.series]
|
|
1393
|
+
const copyOfStages = [...copyOfSeries[seriesIndex].stages]
|
|
1394
|
+
copyOfStages[stageIndex] = { ...copyOfStages[stageIndex], color: palette }
|
|
1395
|
+
copyOfSeries[seriesIndex] = { ...copyOfSeries[seriesIndex], stages: copyOfStages }
|
|
1396
|
+
_newConfig.series = copyOfSeries
|
|
1397
|
+
}
|
|
1398
|
+
} else if (type === 'twoColor') {
|
|
1399
|
+
// Two-color palette selection
|
|
1400
|
+
if (!_newConfig.twoColor) {
|
|
1401
|
+
_newConfig.twoColor = { palette: '', isPaletteReversed: false }
|
|
1402
|
+
}
|
|
1403
|
+
_newConfig.twoColor.palette = palette
|
|
1404
|
+
} else {
|
|
1405
|
+
// General palette selection (type === 'general' or undefined for backwards compatibility)
|
|
1406
|
+
if (!_newConfig.general) {
|
|
1407
|
+
_newConfig.general = {}
|
|
1408
|
+
}
|
|
1409
|
+
if (!_newConfig.general.palette) {
|
|
1410
|
+
_newConfig.general.palette = {}
|
|
1411
|
+
}
|
|
1412
|
+
_newConfig.general.palette.name = palette
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
// Set version to V1
|
|
1416
|
+
if (!_newConfig.general) {
|
|
1417
|
+
_newConfig.general = {}
|
|
1418
|
+
}
|
|
1419
|
+
if (!_newConfig.general.palette) {
|
|
1420
|
+
_newConfig.general.palette = {}
|
|
1421
|
+
}
|
|
1422
|
+
_newConfig.general.palette.version = '1.0'
|
|
1423
|
+
|
|
1424
|
+
updateConfig(_newConfig)
|
|
1425
|
+
}
|
|
1426
|
+
setShowConversionModal(false)
|
|
1427
|
+
setPendingPaletteSelection(null)
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1096
1430
|
const validateMaxValue = () => {
|
|
1097
1431
|
const enteredValue = config[section].max
|
|
1098
1432
|
const enteredRightMax = config[section].rightMax
|
|
@@ -1232,18 +1566,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
1232
1566
|
)
|
|
1233
1567
|
}
|
|
1234
1568
|
})
|
|
1235
|
-
|
|
1236
|
-
let columnsByKey = {}
|
|
1237
|
-
config.data.forEach(datum => {
|
|
1238
|
-
Object.keys(datum).forEach(key => {
|
|
1239
|
-
columnsByKey[key] = columnsByKey[key] || []
|
|
1240
|
-
const value = typeof datum[key] === 'number' ? datum[key].toString() : datum[key]
|
|
1241
|
-
|
|
1242
|
-
if (columnsByKey[key].indexOf(value) === -1) {
|
|
1243
|
-
columnsByKey[key].push(value)
|
|
1244
|
-
}
|
|
1245
|
-
})
|
|
1246
|
-
})
|
|
1247
1569
|
}
|
|
1248
1570
|
|
|
1249
1571
|
// for pie charts
|
|
@@ -1261,18 +1583,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
1261
1583
|
)
|
|
1262
1584
|
}
|
|
1263
1585
|
})
|
|
1264
|
-
|
|
1265
|
-
let columnsByKey = {}
|
|
1266
|
-
data.forEach(datum => {
|
|
1267
|
-
Object.keys(datum).forEach(key => {
|
|
1268
|
-
columnsByKey[key] = columnsByKey[key] || []
|
|
1269
|
-
const value = typeof datum[key] === 'number' ? datum[key].toString() : datum[key]
|
|
1270
|
-
|
|
1271
|
-
if (columnsByKey[key].indexOf(value) === -1) {
|
|
1272
|
-
columnsByKey[key].push(value)
|
|
1273
|
-
}
|
|
1274
|
-
})
|
|
1275
|
-
})
|
|
1276
1586
|
}
|
|
1277
1587
|
|
|
1278
1588
|
const removeAdditionalColumn = columnName => {
|
|
@@ -1379,11 +1689,14 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
1379
1689
|
handleHighlightedBarLegendLabel,
|
|
1380
1690
|
handleUpdateHighlightedBar,
|
|
1381
1691
|
handleRemoveHighlightedBar,
|
|
1382
|
-
isPaletteReversed: config.
|
|
1692
|
+
isPaletteReversed: config.general?.palette?.isReversed,
|
|
1383
1693
|
highlightedSeriesValues,
|
|
1384
1694
|
handleUpdateHighlightedBorderWidth,
|
|
1385
1695
|
handleUpdateHighlightedBarColor,
|
|
1386
|
-
setLollipopShape
|
|
1696
|
+
setLollipopShape,
|
|
1697
|
+
handlePaletteSelection,
|
|
1698
|
+
handleTwoColorPaletteSelection,
|
|
1699
|
+
handleForecastPaletteSelection
|
|
1387
1700
|
}
|
|
1388
1701
|
if (isLoading) {
|
|
1389
1702
|
return <></>
|
|
@@ -1478,20 +1791,25 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
1478
1791
|
options={getColumns()}
|
|
1479
1792
|
/>
|
|
1480
1793
|
{config.series && config.series.length !== 0 && (
|
|
1481
|
-
<Panels.Series.Wrapper
|
|
1794
|
+
<Panels.Series.Wrapper
|
|
1795
|
+
getColumns={getColumns}
|
|
1796
|
+
handleForecastPaletteSelection={handleForecastPaletteSelection}
|
|
1797
|
+
>
|
|
1482
1798
|
<fieldset>
|
|
1483
|
-
<legend className='edit-label
|
|
1484
|
-
|
|
1485
|
-
<Tooltip
|
|
1486
|
-
<
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
<
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1799
|
+
<legend className='edit-label d-flex align-items-center'>
|
|
1800
|
+
Displaying
|
|
1801
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1802
|
+
<Tooltip.Target>
|
|
1803
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1804
|
+
</Tooltip.Target>
|
|
1805
|
+
<Tooltip.Content>
|
|
1806
|
+
<p>
|
|
1807
|
+
A data series is a set of related data points plotted in a chart and typically
|
|
1808
|
+
represented in the chart legend.
|
|
1809
|
+
</p>
|
|
1810
|
+
</Tooltip.Content>
|
|
1811
|
+
</Tooltip>
|
|
1812
|
+
</legend>
|
|
1495
1813
|
</fieldset>
|
|
1496
1814
|
|
|
1497
1815
|
<DragDropContext
|
|
@@ -1606,9 +1924,30 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
1606
1924
|
)}
|
|
1607
1925
|
{config.visualizationType !== 'Pie' && (
|
|
1608
1926
|
<>
|
|
1609
|
-
<
|
|
1610
|
-
|
|
1611
|
-
|
|
1927
|
+
<Select
|
|
1928
|
+
label='Axis Type'
|
|
1929
|
+
value={config.yAxis.type}
|
|
1930
|
+
options={[
|
|
1931
|
+
{ value: 'linear', label: 'Numeric (Linear Scale)' },
|
|
1932
|
+
...(config.visualizationSubType !== 'stacked'
|
|
1933
|
+
? [{ value: 'logarithmic', label: 'Numeric (Logarithmic Scale)' }]
|
|
1934
|
+
: []),
|
|
1935
|
+
...(config.orientation !== 'horizontal'
|
|
1936
|
+
? [{ value: 'categorical', label: 'Categorical' }]
|
|
1937
|
+
: [])
|
|
1938
|
+
]}
|
|
1939
|
+
section='yAxis'
|
|
1940
|
+
fieldName='type'
|
|
1941
|
+
updateField={(_section, _subsection, _fieldName, value) => {
|
|
1942
|
+
updateConfig({
|
|
1943
|
+
...config,
|
|
1944
|
+
yAxis: {
|
|
1945
|
+
...config.yAxis,
|
|
1946
|
+
type: value
|
|
1947
|
+
}
|
|
1948
|
+
})
|
|
1949
|
+
}}
|
|
1950
|
+
tooltip={
|
|
1612
1951
|
<Tooltip style={{ textTransform: 'none', display: 'inline-block' }}>
|
|
1613
1952
|
<Tooltip.Target>
|
|
1614
1953
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
@@ -1618,26 +1957,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
1618
1957
|
exponential data, or 'Categorical' for discrete categories.
|
|
1619
1958
|
</Tooltip.Content>
|
|
1620
1959
|
</Tooltip>
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
value={config.yAxis.type}
|
|
1624
|
-
onChange={e =>
|
|
1625
|
-
updateConfig({
|
|
1626
|
-
...config,
|
|
1627
|
-
yAxis: {
|
|
1628
|
-
...config.yAxis,
|
|
1629
|
-
type: e.target.value
|
|
1630
|
-
}
|
|
1631
|
-
})
|
|
1632
|
-
}
|
|
1633
|
-
>
|
|
1634
|
-
<option value='linear'>Numeric (Linear Scale)</option>
|
|
1635
|
-
{config.visualizationSubType !== 'stacked' && (
|
|
1636
|
-
<option value='logarithmic'>Numeric (Logarithmic Scale)</option>
|
|
1637
|
-
)}
|
|
1638
|
-
{config.orientation !== 'horizontal' && <option value='categorical'>Categorical</option>}
|
|
1639
|
-
</select>
|
|
1640
|
-
</label>
|
|
1960
|
+
}
|
|
1961
|
+
/>
|
|
1641
1962
|
<CategoricalAxis
|
|
1642
1963
|
config={config}
|
|
1643
1964
|
updateConfig={updateConfig}
|
|
@@ -1683,25 +2004,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
1683
2004
|
</Tooltip>
|
|
1684
2005
|
}
|
|
1685
2006
|
/>
|
|
1686
|
-
<TextField
|
|
1687
|
-
display={!visHasCategoricalAxis()}
|
|
1688
|
-
value={config.yAxis.inlineLabel}
|
|
1689
|
-
section='yAxis'
|
|
1690
|
-
fieldName='inlineLabel'
|
|
1691
|
-
label='Inline Label'
|
|
1692
|
-
updateField={updateFieldDeprecated}
|
|
1693
|
-
maxLength={35}
|
|
1694
|
-
tooltip={
|
|
1695
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1696
|
-
<Tooltip.Target>
|
|
1697
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1698
|
-
</Tooltip.Target>
|
|
1699
|
-
<Tooltip.Content>
|
|
1700
|
-
<p>35 character limit</p>
|
|
1701
|
-
</Tooltip.Content>
|
|
1702
|
-
</Tooltip>
|
|
1703
|
-
}
|
|
1704
|
-
/>
|
|
1705
2007
|
{config.runtime.seriesKeys &&
|
|
1706
2008
|
config.runtime.seriesKeys.length === 1 &&
|
|
1707
2009
|
!['Box Plot', 'Deviation Bar', 'Forest Plot'].includes(config.visualizationType) && (
|
|
@@ -1940,6 +2242,30 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
1940
2242
|
updateField={updateFieldDeprecated}
|
|
1941
2243
|
min={0}
|
|
1942
2244
|
/>{' '}
|
|
2245
|
+
<CheckBox
|
|
2246
|
+
value={config.dataFormat.preserveOriginalDecimals}
|
|
2247
|
+
section='dataFormat'
|
|
2248
|
+
fieldName='preserveOriginalDecimals'
|
|
2249
|
+
label='Preserve Original Decimal Places'
|
|
2250
|
+
updateField={updateFieldDeprecated}
|
|
2251
|
+
tooltip={
|
|
2252
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2253
|
+
<Tooltip.Target>
|
|
2254
|
+
<Icon
|
|
2255
|
+
display='question'
|
|
2256
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2257
|
+
/>
|
|
2258
|
+
</Tooltip.Target>
|
|
2259
|
+
<Tooltip.Content>
|
|
2260
|
+
<p>
|
|
2261
|
+
When enabled, numbers will display with their original decimal places from the data source,
|
|
2262
|
+
bypassing the "Round to decimal point" setting above. This is useful when you have mixed
|
|
2263
|
+
data (e.g., whole numbers in one column and percentages with decimals in another).
|
|
2264
|
+
</p>
|
|
2265
|
+
</Tooltip.Content>
|
|
2266
|
+
</Tooltip>
|
|
2267
|
+
}
|
|
2268
|
+
/>
|
|
1943
2269
|
<div className='two-col-inputs'>
|
|
1944
2270
|
<TextField
|
|
1945
2271
|
value={config.dataFormat.prefix}
|
|
@@ -2203,28 +2529,25 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
2203
2529
|
/>
|
|
2204
2530
|
</label>
|
|
2205
2531
|
|
|
2206
|
-
<
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
yAxis
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
))}
|
|
2226
|
-
</select>
|
|
2227
|
-
</label>
|
|
2532
|
+
<Select
|
|
2533
|
+
value={config.yAxis.anchors[index].lineStyle || ''}
|
|
2534
|
+
label='Anchor Line Style'
|
|
2535
|
+
onChange={e => {
|
|
2536
|
+
const copiedAnchors = [...config.yAxis.anchors]
|
|
2537
|
+
copiedAnchors[index].lineStyle = e.target.value
|
|
2538
|
+
updateConfig({
|
|
2539
|
+
...config,
|
|
2540
|
+
yAxis: {
|
|
2541
|
+
...config.yAxis,
|
|
2542
|
+
anchors: copiedAnchors
|
|
2543
|
+
}
|
|
2544
|
+
})
|
|
2545
|
+
}}
|
|
2546
|
+
options={[
|
|
2547
|
+
{ value: '', label: 'Select' },
|
|
2548
|
+
...lineOptions.map(line => ({ value: line.value, label: line.value }))
|
|
2549
|
+
]}
|
|
2550
|
+
/>
|
|
2228
2551
|
</AccordionItemPanel>
|
|
2229
2552
|
</AccordionItem>
|
|
2230
2553
|
))}
|
|
@@ -2328,28 +2651,25 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
2328
2651
|
/>
|
|
2329
2652
|
</label>
|
|
2330
2653
|
|
|
2331
|
-
<
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
xAxis
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
))}
|
|
2351
|
-
</select>
|
|
2352
|
-
</label>
|
|
2654
|
+
<Select
|
|
2655
|
+
value={config.xAxis.anchors[index].lineStyle || ''}
|
|
2656
|
+
label='Anchor Line Style'
|
|
2657
|
+
onChange={e => {
|
|
2658
|
+
const copiedAnchors = [...config.xAxis.anchors]
|
|
2659
|
+
copiedAnchors[index].lineStyle = e.target.value
|
|
2660
|
+
updateConfig({
|
|
2661
|
+
...config,
|
|
2662
|
+
xAxis: {
|
|
2663
|
+
...config.xAxis,
|
|
2664
|
+
anchors: copiedAnchors
|
|
2665
|
+
}
|
|
2666
|
+
})
|
|
2667
|
+
}}
|
|
2668
|
+
options={[
|
|
2669
|
+
{ value: '', label: 'Select' },
|
|
2670
|
+
...lineOptions.map(line => ({ value: line.value, label: line.value }))
|
|
2671
|
+
]}
|
|
2672
|
+
/>
|
|
2353
2673
|
</AccordionItemPanel>
|
|
2354
2674
|
</AccordionItem>
|
|
2355
2675
|
))}
|
|
@@ -2555,9 +2875,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
2555
2875
|
<>
|
|
2556
2876
|
{config.visualizationType !== 'Forest Plot' && (
|
|
2557
2877
|
<>
|
|
2558
|
-
<
|
|
2559
|
-
|
|
2560
|
-
|
|
2878
|
+
<Select
|
|
2879
|
+
label='Data Scaling Type'
|
|
2880
|
+
tooltip={
|
|
2561
2881
|
<Tooltip style={{ textTransform: 'none', display: 'inline-block' }}>
|
|
2562
2882
|
<Tooltip.Target>
|
|
2563
2883
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
@@ -2567,31 +2887,32 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
2567
2887
|
time-series data.
|
|
2568
2888
|
</Tooltip.Content>
|
|
2569
2889
|
</Tooltip>
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2890
|
+
}
|
|
2891
|
+
value={config.xAxis.type}
|
|
2892
|
+
options={[
|
|
2893
|
+
...(!['Bump Chart', 'Forecasting'].includes(config.visualizationType)
|
|
2894
|
+
? [{ label: 'Categorical (Linear Scale)', value: 'categorical' }]
|
|
2895
|
+
: []),
|
|
2896
|
+
...(!['Bump Chart'].includes(config.visualizationType)
|
|
2897
|
+
? [{ label: 'Date (Linear Scale)', value: 'date' }]
|
|
2898
|
+
: []),
|
|
2899
|
+
{ label: 'Date (Date Time Scale)', value: 'date-time' },
|
|
2900
|
+
...(config.visualizationType === 'Scatter Plot'
|
|
2901
|
+
? [{ label: 'Continuous', value: 'continuous' }]
|
|
2902
|
+
: [])
|
|
2903
|
+
]}
|
|
2904
|
+
section='xAxis'
|
|
2905
|
+
fieldName='type'
|
|
2906
|
+
updateField={(_section, _subsection, _fieldName, value) => {
|
|
2907
|
+
updateConfig({
|
|
2908
|
+
...config,
|
|
2909
|
+
xAxis: {
|
|
2910
|
+
...config.xAxis,
|
|
2911
|
+
type: value
|
|
2912
|
+
}
|
|
2913
|
+
})
|
|
2914
|
+
}}
|
|
2915
|
+
/>
|
|
2595
2916
|
<CheckBox
|
|
2596
2917
|
value={config.xAxis.manual}
|
|
2597
2918
|
section='xAxis'
|
|
@@ -2772,7 +3093,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
2772
3093
|
</>
|
|
2773
3094
|
)}
|
|
2774
3095
|
|
|
2775
|
-
{(isDateScale(config.xAxis) ||
|
|
3096
|
+
{(isDateScale(config.xAxis) ||
|
|
3097
|
+
config?.visualizationType === 'Bump Chart' ||
|
|
3098
|
+
config?.visualizationType === 'Forecasting') && (
|
|
2776
3099
|
<>
|
|
2777
3100
|
<p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>
|
|
2778
3101
|
Format how charts should parse and display your dates using{' '}
|
|
@@ -3306,21 +3629,19 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
3306
3629
|
Remove
|
|
3307
3630
|
</button>
|
|
3308
3631
|
<p>Highlighted Bar {i + 1}</p>
|
|
3309
|
-
<
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
</select>
|
|
3323
|
-
</label>
|
|
3632
|
+
<Select
|
|
3633
|
+
value={config.highlightedBarValues[i].value}
|
|
3634
|
+
label='Value'
|
|
3635
|
+
onChange={e => handleUpdateHighlightedBar(e, i)}
|
|
3636
|
+
options={[
|
|
3637
|
+
{ value: '', label: '- Select Value -' },
|
|
3638
|
+
...(highlightedSeriesValues
|
|
3639
|
+
? [...new Set(highlightedSeriesValues)]
|
|
3640
|
+
.sort()
|
|
3641
|
+
.map(option => ({ value: option, label: option }))
|
|
3642
|
+
: [])
|
|
3643
|
+
]}
|
|
3644
|
+
/>
|
|
3324
3645
|
<label>
|
|
3325
3646
|
<span className='edit-label column-heading'>Color</span>
|
|
3326
3647
|
<input
|
|
@@ -3524,28 +3845,25 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
3524
3845
|
/>
|
|
3525
3846
|
</label>
|
|
3526
3847
|
|
|
3527
|
-
<
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
xAxis
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
))}
|
|
3547
|
-
</select>
|
|
3548
|
-
</label>
|
|
3848
|
+
<Select
|
|
3849
|
+
value={config.xAxis.anchors[index].lineStyle || ''}
|
|
3850
|
+
label='Anchor Line Style'
|
|
3851
|
+
onChange={e => {
|
|
3852
|
+
const copiedAnchors = [...config.xAxis.anchors]
|
|
3853
|
+
copiedAnchors[index].lineStyle = e.target.value
|
|
3854
|
+
updateConfig({
|
|
3855
|
+
...config,
|
|
3856
|
+
xAxis: {
|
|
3857
|
+
...config.xAxis,
|
|
3858
|
+
anchors: copiedAnchors
|
|
3859
|
+
}
|
|
3860
|
+
})
|
|
3861
|
+
}}
|
|
3862
|
+
options={[
|
|
3863
|
+
{ value: '', label: 'Select' },
|
|
3864
|
+
...lineOptions.map(line => ({ value: line.value, label: line.value }))
|
|
3865
|
+
]}
|
|
3866
|
+
/>
|
|
3549
3867
|
</AccordionItemPanel>
|
|
3550
3868
|
</AccordionItem>
|
|
3551
3869
|
))}
|
|
@@ -3653,28 +3971,25 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
3653
3971
|
/>
|
|
3654
3972
|
</label>
|
|
3655
3973
|
|
|
3656
|
-
<
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
yAxis
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
))}
|
|
3676
|
-
</select>
|
|
3677
|
-
</label>
|
|
3974
|
+
<Select
|
|
3975
|
+
value={config.yAxis.anchors[index].lineStyle || ''}
|
|
3976
|
+
label='Anchor Line Style'
|
|
3977
|
+
onChange={e => {
|
|
3978
|
+
const copiedAnchors = [...config.yAxis.anchors]
|
|
3979
|
+
copiedAnchors[index].lineStyle = e.target.value
|
|
3980
|
+
updateConfig({
|
|
3981
|
+
...config,
|
|
3982
|
+
yAxis: {
|
|
3983
|
+
...config.yAxis,
|
|
3984
|
+
anchors: copiedAnchors
|
|
3985
|
+
}
|
|
3986
|
+
})
|
|
3987
|
+
}}
|
|
3988
|
+
options={[
|
|
3989
|
+
{ value: '', label: 'Select' },
|
|
3990
|
+
...lineOptions.map(line => ({ value: line.value, label: line.value }))
|
|
3991
|
+
]}
|
|
3992
|
+
/>
|
|
3678
3993
|
</AccordionItemPanel>
|
|
3679
3994
|
</AccordionItem>
|
|
3680
3995
|
))}
|
|
@@ -4126,6 +4441,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
4126
4441
|
</>
|
|
4127
4442
|
)}
|
|
4128
4443
|
<Panels.Visual name='Visual' />
|
|
4444
|
+
<Panels.PatternSettings name='PatternSettings' />
|
|
4129
4445
|
{/* Spark Line has no data table */}
|
|
4130
4446
|
{config.visualizationType !== 'Spark Line' && (
|
|
4131
4447
|
<AccordionItem>
|
|
@@ -4145,11 +4461,29 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
|
|
|
4145
4461
|
)}
|
|
4146
4462
|
<Panels.Annotate name='Text Annotations' />
|
|
4147
4463
|
{/* {(config.visualizationType === 'Bar' || config.visualizationType === 'Line') && <Panels.DateHighlighting name='Date Highlighting' />} */}
|
|
4464
|
+
<PanelMarkup
|
|
4465
|
+
name='Markup Variables'
|
|
4466
|
+
markupVariables={config.markupVariables || []}
|
|
4467
|
+
data={rawData}
|
|
4468
|
+
enableMarkupVariables={config.enableMarkupVariables || false}
|
|
4469
|
+
onMarkupVariablesChange={variables => updateField(null, null, 'markupVariables', variables)}
|
|
4470
|
+
onToggleEnable={enabled => updateField(null, null, 'enableMarkupVariables', enabled)}
|
|
4471
|
+
/>
|
|
4472
|
+
<Panels.SmallMultiples name='Small Multiples' />
|
|
4148
4473
|
</Accordion>
|
|
4149
4474
|
{config.type !== 'Spark Line' && (
|
|
4150
4475
|
<AdvancedEditor loadConfig={updateConfig} config={config} convertStateToConfig={convertStateToConfig} />
|
|
4151
4476
|
)}
|
|
4152
4477
|
</Layout.Sidebar>
|
|
4478
|
+
|
|
4479
|
+
{showConversionModal && (
|
|
4480
|
+
<PaletteConversionModal
|
|
4481
|
+
onConfirm={handleConversionConfirm}
|
|
4482
|
+
onCancel={handleConversionCancel}
|
|
4483
|
+
onReturnToV1={handleReturnToV1}
|
|
4484
|
+
paletteName={pendingPaletteSelection?.palette}
|
|
4485
|
+
/>
|
|
4486
|
+
)}
|
|
4153
4487
|
</ErrorBoundary>
|
|
4154
4488
|
</EditorPanelContext.Provider>
|
|
4155
4489
|
)
|