@sqlrooms/deck 0.29.0-rc.11 → 0.29.0-rc.13
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/README.md +193 -35
- package/dist/BlockMapSettings.d.ts.map +1 -1
- package/dist/BlockMapSettings.js +4 -16
- package/dist/BlockMapSettings.js.map +1 -1
- package/dist/DashboardMapSettings.d.ts.map +1 -1
- package/dist/DashboardMapSettings.js +7 -10
- package/dist/DashboardMapSettings.js.map +1 -1
- package/dist/DeckJsonMap.d.ts.map +1 -1
- package/dist/DeckJsonMap.js +75 -23
- package/dist/DeckJsonMap.js.map +1 -1
- package/dist/DeckJsonMapSpec.d.ts +41 -0
- package/dist/DeckJsonMapSpec.d.ts.map +1 -1
- package/dist/DeckJsonMapSpec.js +2 -0
- package/dist/DeckJsonMapSpec.js.map +1 -1
- package/dist/DeckMapBasemapSelect.d.ts +9 -0
- package/dist/DeckMapBasemapSelect.d.ts.map +1 -0
- package/dist/DeckMapBasemapSelect.js +20 -0
- package/dist/DeckMapBasemapSelect.js.map +1 -0
- package/dist/DeckMapDefaultStylesProvider.d.ts +13 -19
- package/dist/DeckMapDefaultStylesProvider.d.ts.map +1 -1
- package/dist/DeckMapDefaultStylesProvider.js +11 -18
- package/dist/DeckMapDefaultStylesProvider.js.map +1 -1
- package/dist/DeckMapSurface.d.ts +1 -1
- package/dist/DeckMapSurface.js +1 -1
- package/dist/DeckMapSurface.js.map +1 -1
- package/dist/DeckMapsSlice.d.ts +5 -0
- package/dist/DeckMapsSlice.d.ts.map +1 -1
- package/dist/DeckMapsSlice.js +6 -3
- package/dist/DeckMapsSlice.js.map +1 -1
- package/dist/MapSettings.d.ts +14 -0
- package/dist/MapSettings.d.ts.map +1 -1
- package/dist/MapSettings.js +548 -192
- package/dist/MapSettings.js.map +1 -1
- package/dist/MapSettingsControls.d.ts +8 -1
- package/dist/MapSettingsControls.d.ts.map +1 -1
- package/dist/MapSettingsControls.js +24 -2
- package/dist/MapSettingsControls.js.map +1 -1
- package/dist/ai.d.ts.map +1 -1
- package/dist/ai.js +20 -12
- package/dist/ai.js.map +1 -1
- package/dist/aiNormalize.d.ts.map +1 -1
- package/dist/aiNormalize.js +2 -1
- package/dist/aiNormalize.js.map +1 -1
- package/dist/basemap.d.ts +23 -0
- package/dist/basemap.d.ts.map +1 -0
- package/dist/basemap.js +23 -0
- package/dist/basemap.js.map +1 -0
- package/dist/block.d.ts +1 -1
- package/dist/block.d.ts.map +1 -1
- package/dist/block.js +13 -9
- package/dist/block.js.map +1 -1
- package/dist/createOrUpdateDeckMapResource.d.ts +6 -2
- package/dist/createOrUpdateDeckMapResource.d.ts.map +1 -1
- package/dist/createOrUpdateDeckMapResource.js +57 -4
- package/dist/createOrUpdateDeckMapResource.js.map +1 -1
- package/dist/datasets/PreparedDatasetStore.d.ts +3 -4
- package/dist/datasets/PreparedDatasetStore.d.ts.map +1 -1
- package/dist/datasets/PreparedDatasetStore.js +4 -8
- package/dist/datasets/PreparedDatasetStore.js.map +1 -1
- package/dist/datasets/helpers.d.ts +39 -2
- package/dist/datasets/helpers.d.ts.map +1 -1
- package/dist/datasets/helpers.js +86 -3
- package/dist/datasets/helpers.js.map +1 -1
- package/dist/datasets/usePreparedDatasetStates.d.ts.map +1 -1
- package/dist/datasets/usePreparedDatasetStates.js +12 -8
- package/dist/datasets/usePreparedDatasetStates.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/json/colorScaleFunction.d.ts +12 -4
- package/dist/json/colorScaleFunction.d.ts.map +1 -1
- package/dist/json/colorScaleFunction.js.map +1 -1
- package/dist/json/compileColorScale.d.ts +3 -2
- package/dist/json/compileColorScale.d.ts.map +1 -1
- package/dist/json/compileColorScale.js +16 -1
- package/dist/json/compileColorScale.js.map +1 -1
- package/dist/json/createDeckJsonConfiguration.d.ts.map +1 -1
- package/dist/json/createDeckJsonConfiguration.js +235 -175
- package/dist/json/createDeckJsonConfiguration.js.map +1 -1
- package/dist/json/defaultClasses.d.ts.map +1 -1
- package/dist/json/defaultClasses.js +3 -3
- package/dist/json/defaultClasses.js.map +1 -1
- package/dist/json/extractColorScaleLegends.d.ts.map +1 -1
- package/dist/json/extractColorScaleLegends.js +41 -26
- package/dist/json/extractColorScaleLegends.js.map +1 -1
- package/dist/json/heatmapDefaults.d.ts +17 -7
- package/dist/json/heatmapDefaults.d.ts.map +1 -1
- package/dist/json/heatmapDefaults.js +54 -12
- package/dist/json/heatmapDefaults.js.map +1 -1
- package/dist/json/layers/DeckHeatmapLayer.d.ts +32 -0
- package/dist/json/layers/DeckHeatmapLayer.d.ts.map +1 -0
- package/dist/json/layers/DeckHeatmapLayer.js +69 -0
- package/dist/json/layers/DeckHeatmapLayer.js.map +1 -0
- package/dist/json/layers/index.d.ts +1 -0
- package/dist/json/layers/index.d.ts.map +1 -1
- package/dist/json/layers/index.js +1 -0
- package/dist/json/layers/index.js.map +1 -1
- package/dist/json/rewriteGeoArrowAccessors.d.ts.map +1 -1
- package/dist/json/rewriteGeoArrowAccessors.js +13 -5
- package/dist/json/rewriteGeoArrowAccessors.js.map +1 -1
- package/dist/json/scaleFunction.d.ts +5 -8
- package/dist/json/scaleFunction.d.ts.map +1 -1
- package/dist/json/scaleFunction.js +30 -5
- package/dist/json/scaleFunction.js.map +1 -1
- package/dist/mapAiConfig.d.ts +6 -0
- package/dist/mapAiConfig.d.ts.map +1 -1
- package/dist/mapAiConfig.js +7 -0
- package/dist/mapAiConfig.js.map +1 -1
- package/dist/mapAiSharedInstructions.d.ts +1 -1
- package/dist/mapAiSharedInstructions.d.ts.map +1 -1
- package/dist/mapAiSharedInstructions.js +4 -3
- package/dist/mapAiSharedInstructions.js.map +1 -1
- package/dist/mapConfig.d.ts +6 -1
- package/dist/mapConfig.d.ts.map +1 -1
- package/dist/mapConfig.js +28 -3
- package/dist/mapConfig.js.map +1 -1
- package/dist/mapConfigUtils.d.ts +22 -0
- package/dist/mapConfigUtils.d.ts.map +1 -1
- package/dist/mapConfigUtils.js +152 -5
- package/dist/mapConfigUtils.js.map +1 -1
- package/dist/mapLayerConfigUtils.d.ts +55 -0
- package/dist/mapLayerConfigUtils.d.ts.map +1 -1
- package/dist/mapLayerConfigUtils.js +222 -11
- package/dist/mapLayerConfigUtils.js.map +1 -1
- package/dist/mapResourceAuthoring.d.ts +1 -1
- package/dist/mapResourceAuthoring.d.ts.map +1 -1
- package/dist/mapResourceAuthoring.js +14 -7
- package/dist/mapResourceAuthoring.js.map +1 -1
- package/dist/mapStyles.d.ts +16 -0
- package/dist/mapStyles.d.ts.map +1 -0
- package/dist/mapStyles.js +32 -0
- package/dist/mapStyles.js.map +1 -0
- package/dist/prepare/prepareDeckDataset.d.ts.map +1 -1
- package/dist/prepare/prepareDeckDataset.js +1 -0
- package/dist/prepare/prepareDeckDataset.js.map +1 -1
- package/dist/prepare/types.d.ts +3 -0
- package/dist/prepare/types.d.ts.map +1 -1
- package/dist/prepare/types.js.map +1 -1
- package/dist/prepare/wkbDecoder.d.ts.map +1 -1
- package/dist/prepare/wkbDecoder.js +62 -16
- package/dist/prepare/wkbDecoder.js.map +1 -1
- package/dist/prepare/wkbParser.d.ts +2 -0
- package/dist/prepare/wkbParser.d.ts.map +1 -1
- package/dist/prepare/wkbParser.js +1 -0
- package/dist/prepare/wkbParser.js.map +1 -1
- package/dist/protomapsStyles.d.ts +18 -0
- package/dist/protomapsStyles.d.ts.map +1 -0
- package/dist/protomapsStyles.js +38 -0
- package/dist/protomapsStyles.js.map +1 -0
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +11 -9
package/dist/MapSettings.js
CHANGED
|
@@ -1,43 +1,51 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useMemo, useState } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
3
3
|
import { getTableIdentity, resolveTableReference, } from '@sqlrooms/duckdb';
|
|
4
|
-
import { binnedNumericSchemes, categoricalSchemes, continuousDivergingSchemes, continuousSequentialSchemes, continuousSequentialInterpolators, parseColorString, } from '@sqlrooms/color-scales';
|
|
5
|
-
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Slider, ScrollArea, SettingsPanelHeader, Switch, } from '@sqlrooms/ui';
|
|
4
|
+
import { binnedNumericSchemes, categoricalSchemeColors, categoricalSchemes, continuousDivergingInterpolators, continuousDivergingSchemes, continuousSequentialSchemes, continuousSequentialInterpolators, parseColorString, } from '@sqlrooms/color-scales';
|
|
5
|
+
import { cn, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Slider, ScrollArea, SettingsPanelHeader, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Tooltip, TooltipContent, TooltipTrigger, } from '@sqlrooms/ui';
|
|
6
|
+
import { AlertTriangleIcon } from 'lucide-react';
|
|
7
|
+
import { DeckMapBasemapSelect } from './DeckMapBasemapSelect';
|
|
6
8
|
import { isDeckMapTableDatasetSource } from './mapConfig';
|
|
7
|
-
import { clearDeckMapLayerColorScale, createDeckMapLayerColorScale, DECK_MAP_COLOR_SCALE_TYPE_OPTIONS, DECK_MAP_LAYER_TYPE_OPTIONS, getDeckMapColorAccessorOptions, getDeckMapLayerDatasetId, getDeckMapLayerColorScale, getDeckMapLayerRecords,
|
|
8
|
-
import { DeckMapCodeViewerPanel, DeckMapCodeViewToggleButton, DeckMapColumnSelector as ColumnSelector, DeckMapColumnsProvider as ColumnsProvider, DeckMapSettingsField as Field, DeckMapTableSelector as DataTableSelector, } from './MapSettingsControls';
|
|
9
|
+
import { clearDeckMapLayerColorScale, createDeckMapLayerColorScale, DECK_MAP_COLOR_SCALE_TYPE_OPTIONS, DECK_MAP_DEFAULT_LAYER_COLOR, DECK_MAP_DEFAULT_STROKE_COLOR, DECK_MAP_LAYER_TYPE_OPTIONS, deckMapRgbaToHex, getDeckMapColorAccessorOptions, getDeckMapLayerDatasetId, getDeckMapLayerColorScale, getDeckMapLayerExtruded, getDeckMapLayerFlatColor, getDeckMapLayerRecords, setDeckMapLayerFlatColor, setDeckMapLayerGeometryColumn, setDeckMapLayerHexagonColumn, setDeckMapLayerArcColumns, setDeckMapLayerTimestampColumn, setDeckMapLayerType, setDeckMapLayerColumnRadius, updateDeckMapLayer, usesGeometryColumnSetting, usesH3ColumnSetting, usesArcColumnSetting, usesRadiusSetting, usesColumnRadiusSetting, usesTripsSettings, usesExtrusionSettings, usesStrokeSetting, usesStrokeExtrusionWarning, getDeckMapLayerStrokeDefault, getDeckMapColorScaleOpacity, getDeckMapLayerChannelOpacityPercent, detachDeckMapLayerOpacity, replaceDeckMapLayerColorScalesWithFlat, replaceDeckMapLayerColorScaleWithFlat, } from './mapLayerConfigUtils';
|
|
10
|
+
import { DeckMapCodeViewerPanel, DeckMapCodeViewToggleButton, DeckMapColumnSelector as ColumnSelector, DeckMapColumnsProvider as ColumnsProvider, DeckMapSettingsField as Field, DeckMapTableSelector as DataTableSelector, filterDeckMapColumns, isDeckMapCategoricalColorColumn, } from './MapSettingsControls';
|
|
9
11
|
import { regenerateMapConfigForTable } from './mapConfigUtils';
|
|
10
12
|
import { useDeckMapDatasetSchema } from './useDeckMapDatasetSchema';
|
|
11
|
-
|
|
13
|
+
import { detectHeatmapScheme, heatmapSchemeToColorRange, } from './json/heatmapDefaults';
|
|
12
14
|
const EMPTY_COLUMNS = [];
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
function getColorScaleColumnKind(type) {
|
|
16
|
+
return type === 'categorical' ? 'categorical' : 'quantitative';
|
|
17
|
+
}
|
|
18
|
+
/** Color-scale type matching the field's column kind. */
|
|
19
|
+
function resolveColorScaleTypeForField(columns, field, preferredType) {
|
|
20
|
+
if (!field)
|
|
21
|
+
return preferredType;
|
|
22
|
+
const column = columns.find((candidate) => candidate.name === field);
|
|
23
|
+
if (!column?.type)
|
|
24
|
+
return preferredType;
|
|
25
|
+
// String/boolean/binary fields only work with categorical scales.
|
|
26
|
+
if (isDeckMapCategoricalColorColumn(column)) {
|
|
27
|
+
return 'categorical';
|
|
19
28
|
}
|
|
20
|
-
return
|
|
29
|
+
return preferredType;
|
|
21
30
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (sampled.length === colorRange.length) {
|
|
28
|
-
const matches = sampled.every((color, idx) => {
|
|
29
|
-
const actual = colorRange[idx];
|
|
30
|
-
if (!Array.isArray(actual))
|
|
31
|
-
return false;
|
|
32
|
-
return (Math.abs(color[0] - actual[0]) < 2 &&
|
|
33
|
-
Math.abs(color[1] - actual[1]) < 2 &&
|
|
34
|
-
Math.abs(color[2] - actual[2]) < 2);
|
|
35
|
-
});
|
|
36
|
-
if (matches)
|
|
37
|
-
return scheme;
|
|
38
|
-
}
|
|
31
|
+
/** First selectable color-scale field for this type. */
|
|
32
|
+
function getDefaultColorScaleField(columns, type, preferred) {
|
|
33
|
+
const colorable = filterDeckMapColumns(columns, 'colorable');
|
|
34
|
+
if (preferred && colorable.some((column) => column.name === preferred)) {
|
|
35
|
+
return preferred;
|
|
39
36
|
}
|
|
40
|
-
|
|
37
|
+
const matchingKind = filterDeckMapColumns(colorable, getColorScaleColumnKind(type));
|
|
38
|
+
return matchingKind[0]?.name ?? colorable[0]?.name;
|
|
39
|
+
}
|
|
40
|
+
/** Pick field first, then coerce scale type to match that field. */
|
|
41
|
+
export function resolveColorScaleFieldAndType(columns, preferredType, preferredField) {
|
|
42
|
+
const field = getDefaultColorScaleField(columns, preferredType, preferredField);
|
|
43
|
+
if (!field)
|
|
44
|
+
return undefined;
|
|
45
|
+
return {
|
|
46
|
+
field,
|
|
47
|
+
type: resolveColorScaleTypeForField(columns, field, preferredType),
|
|
48
|
+
};
|
|
41
49
|
}
|
|
42
50
|
function getSchemeOptions(type) {
|
|
43
51
|
if (type === 'categorical') {
|
|
@@ -52,10 +60,296 @@ function getSchemeOptions(type) {
|
|
|
52
60
|
// Quantile/quantize/threshold: ColorBrewer only (Viridis → sequential).
|
|
53
61
|
return binnedNumericSchemes;
|
|
54
62
|
}
|
|
55
|
-
|
|
63
|
+
const SCHEME_PREVIEW_STEPS = 24;
|
|
64
|
+
/** Sample CSS colors for scheme dropdown previews. */
|
|
65
|
+
function getSchemePreviewColors(scheme, type) {
|
|
66
|
+
if (type === 'categorical') {
|
|
67
|
+
const colors = categoricalSchemeColors[scheme];
|
|
68
|
+
return colors ? [...colors] : [];
|
|
69
|
+
}
|
|
70
|
+
const interpolator = type === 'diverging'
|
|
71
|
+
? continuousDivergingInterpolators[scheme]
|
|
72
|
+
: (continuousSequentialInterpolators[scheme] ??
|
|
73
|
+
continuousDivergingInterpolators[scheme]);
|
|
74
|
+
if (!interpolator)
|
|
75
|
+
return [];
|
|
76
|
+
return Array.from({ length: SCHEME_PREVIEW_STEPS }, (_, i) => interpolator(i / (SCHEME_PREVIEW_STEPS - 1)));
|
|
77
|
+
}
|
|
78
|
+
/** Edge-to-edge CSS gradient for a scheme (no fringe gaps). */
|
|
79
|
+
function getSchemePreviewGradient(colors, type) {
|
|
80
|
+
if (colors.length === 0)
|
|
81
|
+
return undefined;
|
|
82
|
+
if (type === 'categorical') {
|
|
83
|
+
const stops = colors.flatMap((color, index) => {
|
|
84
|
+
const start = (index / colors.length) * 100;
|
|
85
|
+
const end = ((index + 1) / colors.length) * 100;
|
|
86
|
+
return [`${color} ${start}%`, `${color} ${end}%`];
|
|
87
|
+
});
|
|
88
|
+
return `linear-gradient(to right, ${stops.join(', ')})`;
|
|
89
|
+
}
|
|
90
|
+
return `linear-gradient(to right, ${colors.join(', ')})`;
|
|
91
|
+
}
|
|
92
|
+
const ColorSchemeOptionLabel = ({ scheme, type }) => {
|
|
93
|
+
const colors = getSchemePreviewColors(scheme, type);
|
|
94
|
+
const gradient = getSchemePreviewGradient(colors, type);
|
|
95
|
+
return (_jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-2", children: [gradient ? (_jsx("span", { "aria-hidden": true, className: "h-3 w-20 shrink-0 overflow-hidden rounded-sm", style: { backgroundImage: gradient } })) : null, _jsx("span", { className: "truncate", children: scheme })] }));
|
|
96
|
+
};
|
|
97
|
+
/** Compact color swatch; native picker is visually hidden. */
|
|
98
|
+
const ColorSwatchInput = ({ value, onChange, disabled, 'aria-label': ariaLabel }) => (_jsx("label", { className: cn('border-input relative h-5 w-9 shrink-0 overflow-hidden rounded-[3px] border', 'ring-offset-background focus-within:ring-ring focus-within:ring-1 focus-within:ring-offset-1', disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'), style: { backgroundColor: value }, children: _jsx("input", { type: "color", "aria-label": ariaLabel, value: value, disabled: disabled, className: "absolute inset-0 h-full w-full cursor-pointer opacity-0 disabled:cursor-not-allowed", onChange: (event) => onChange(event.target.value) }) }));
|
|
99
|
+
function opacityPercentToAlpha(percent) {
|
|
100
|
+
return Math.round((Math.max(0, Math.min(100, percent)) / 100) * 255);
|
|
101
|
+
}
|
|
102
|
+
function getLayerOpacityPercent(layer) {
|
|
103
|
+
const opacity = layer?.opacity;
|
|
104
|
+
if (typeof opacity === 'number' && Number.isFinite(opacity)) {
|
|
105
|
+
return Math.round(Math.max(0, Math.min(1, opacity)) * 100);
|
|
106
|
+
}
|
|
107
|
+
return 100;
|
|
108
|
+
}
|
|
109
|
+
const SettingsSliderField = ({ label, children }) => (_jsx(Field, { label: label, children: _jsx("div", { className: "pt-0.5", children: children }) }));
|
|
110
|
+
const AppearanceOpacitySlider = ({ valuePercent, onChange, disabled }) => (_jsx(SettingsSliderField, { label: `Opacity: ${valuePercent}%`, children: _jsx(Slider, { min: 0, max: 100, step: 1, value: [valuePercent], disabled: disabled, onValueChange: (values) => onChange(values[0] ?? valuePercent) }) }));
|
|
111
|
+
const AppearanceColorChannel = ({ accessor, layer, columns, mapConfig, layerIndex, applyConfig, lastColorScaleFieldsRef, readOnly, enabled, onEnabledChange, enableLabel = 'Enabled', defaultFlatColor = DECK_MAP_DEFAULT_LAYER_COLOR, widthPixels, onWidthChange, widthLabel = 'Width', radiusValue, onRadiusChange, radiusLabel = 'Radius', radiusUnit = '', radiusMin = 0.1, radiusMax = 50, radiusStep = 0.1, extrusionDisablesStroke = false, }) => {
|
|
112
|
+
const colorScale = getDeckMapLayerColorScale(layer, accessor);
|
|
113
|
+
const flatColor = getDeckMapLayerFlatColor(layer, accessor) ?? [
|
|
114
|
+
...defaultFlatColor,
|
|
115
|
+
];
|
|
116
|
+
const colorScaleType = colorScale?.type ?? 'sequential';
|
|
117
|
+
const schemeOptions = getSchemeOptions(colorScaleType);
|
|
118
|
+
// Don't read lastColorScaleFieldsRef during render (react-hooks/refs).
|
|
119
|
+
const defaultField = getDefaultColorScaleField(columns, colorScaleType);
|
|
120
|
+
const showControls = enabled !== false;
|
|
121
|
+
const opacityPercent = getDeckMapLayerChannelOpacityPercent(layer, accessor, flatColor[3] ?? 255);
|
|
122
|
+
const updateColorScale = (patch) => {
|
|
123
|
+
const preferredField = patch.field ??
|
|
124
|
+
colorScale?.field ??
|
|
125
|
+
lastColorScaleFieldsRef.current[accessor];
|
|
126
|
+
const resolved = resolveColorScaleFieldAndType(columns, patch.type ?? colorScale?.type ?? 'sequential', preferredField);
|
|
127
|
+
if (!resolved)
|
|
128
|
+
return;
|
|
129
|
+
const { field, type } = resolved;
|
|
130
|
+
lastColorScaleFieldsRef.current[accessor] = field;
|
|
131
|
+
const scheme = patch.scheme ??
|
|
132
|
+
(patch.type && patch.type !== colorScale?.type
|
|
133
|
+
? undefined
|
|
134
|
+
: type !== colorScale?.type
|
|
135
|
+
? undefined
|
|
136
|
+
: colorScale?.scheme);
|
|
137
|
+
applyConfig(updateDeckMapLayer(mapConfig, layerIndex, (nextLayer) => {
|
|
138
|
+
const detached = detachDeckMapLayerOpacity(nextLayer);
|
|
139
|
+
const existingScale = getDeckMapLayerColorScale(detached, accessor);
|
|
140
|
+
const currentFlat = getDeckMapLayerFlatColor(detached, accessor) ?? flatColor;
|
|
141
|
+
return {
|
|
142
|
+
...detached,
|
|
143
|
+
[accessor]: createDeckMapLayerColorScale({
|
|
144
|
+
field,
|
|
145
|
+
type,
|
|
146
|
+
scheme,
|
|
147
|
+
title: field,
|
|
148
|
+
opacity: existingScale
|
|
149
|
+
? getDeckMapColorScaleOpacity(existingScale)
|
|
150
|
+
: (currentFlat[3] ?? 255) / 255,
|
|
151
|
+
}),
|
|
152
|
+
};
|
|
153
|
+
}));
|
|
154
|
+
};
|
|
155
|
+
return (_jsxs("div", { className: "flex flex-col gap-2", children: [onEnabledChange ? (_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("span", { className: "flex items-center gap-1 text-xs font-medium", children: [enableLabel, extrusionDisablesStroke ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", className: "inline-flex", "aria-label": "no strokes with extrusion enabled", children: _jsx(AlertTriangleIcon, { className: "h-3.5 w-3.5 text-amber-500" }) }) }), _jsx(TooltipContent, { children: "no strokes with extrusion enabled" })] })) : null] }), _jsx(Switch, { checked: enabled !== false, onCheckedChange: onEnabledChange, "aria-label": enableLabel })] })) : null, showControls && onWidthChange && widthPixels !== undefined ? (_jsx(SettingsSliderField, { label: `${widthLabel}: ${Number(widthPixels.toFixed(1))}px`, children: _jsx(Slider, { min: 0.1, max: 20, step: 0.1, value: [widthPixels], onValueChange: (values) => onWidthChange(values[0] ?? 1) }) })) : null, showControls && onRadiusChange && radiusValue !== undefined ? (_jsx(SettingsSliderField, { label: `${radiusLabel}: ${radiusStep < 1 ? Number(radiusValue.toFixed(1)) : radiusValue}${radiusUnit}`, children: _jsx(Slider, { min: radiusMin, max: radiusMax, step: radiusStep, value: [radiusValue], onValueChange: (values) => onRadiusChange(values[0] ?? radiusValue) }) })) : null, showControls ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-xs font-medium", children: "Color scale" }), _jsx(Switch, { checked: Boolean(colorScale), disabled: readOnly || (!colorScale && !defaultField), "aria-label": "Color scale", onCheckedChange: (checked) => {
|
|
156
|
+
if (checked) {
|
|
157
|
+
updateColorScale({});
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (colorScale?.field) {
|
|
161
|
+
lastColorScaleFieldsRef.current[accessor] = colorScale.field;
|
|
162
|
+
}
|
|
163
|
+
applyConfig(clearDeckMapLayerColorScale(mapConfig, layerIndex, accessor));
|
|
164
|
+
} })] }), !colorScale ? (_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-xs font-medium", children: "Color" }), _jsx(ColorSwatchInput, { "aria-label": "Color", value: deckMapRgbaToHex(flatColor), disabled: readOnly, onChange: (hex) => {
|
|
165
|
+
const next = parseColorString(hex, flatColor[3] ?? 255);
|
|
166
|
+
applyConfig(setDeckMapLayerFlatColor(mapConfig, layerIndex, accessor, next));
|
|
167
|
+
} })] })) : null, colorScale ? (_jsxs("div", { className: "flex flex-col gap-2", children: [columns.length > 0 ? (_jsx(ColumnsProvider, { columns: columns, children: _jsx(Field, { label: "Field", required: true, children: _jsx(ColumnSelector.Colorable, { value: colorScale.field, onChange: (field) => updateColorScale({ field }), disabled: readOnly }) }) })) : null, _jsx(Field, { label: "Type", children: _jsxs(Select, { value: colorScaleType, onValueChange: (value) => updateColorScale({ type: value }), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: DECK_MAP_COLOR_SCALE_TYPE_OPTIONS.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] }) }), _jsx(Field, { label: "Scheme", children: _jsxs(Select, { value: colorScale.scheme, onValueChange: (value) => updateColorScale({ scheme: value }), children: [_jsx(SelectTrigger, { className: "w-full [&>span]:line-clamp-none", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: schemeOptions.map((scheme) => (_jsx(SelectItem, { value: scheme, children: _jsx(ColorSchemeOptionLabel, { scheme: scheme, type: colorScaleType }) }, scheme))) })] }) })] })) : null, _jsx(AppearanceOpacitySlider, { valuePercent: opacityPercent, disabled: readOnly, onChange: (percent) => {
|
|
168
|
+
applyConfig(updateDeckMapLayer(mapConfig, layerIndex, (nextLayer) => {
|
|
169
|
+
const detached = detachDeckMapLayerOpacity(nextLayer);
|
|
170
|
+
if (colorScale) {
|
|
171
|
+
const scale = getDeckMapLayerColorScale(detached, accessor) ??
|
|
172
|
+
colorScale;
|
|
173
|
+
return {
|
|
174
|
+
...detached,
|
|
175
|
+
[accessor]: {
|
|
176
|
+
...scale,
|
|
177
|
+
opacity: percent / 100,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
const current = getDeckMapLayerFlatColor(detached, accessor) ?? flatColor;
|
|
182
|
+
return {
|
|
183
|
+
...detached,
|
|
184
|
+
[accessor]: [
|
|
185
|
+
current[0],
|
|
186
|
+
current[1],
|
|
187
|
+
current[2],
|
|
188
|
+
opacityPercentToAlpha(percent),
|
|
189
|
+
],
|
|
190
|
+
};
|
|
191
|
+
}));
|
|
192
|
+
} })] })) : null] }));
|
|
193
|
+
};
|
|
194
|
+
/** Arc source/target colors; optional shared color scale. */
|
|
195
|
+
const AppearanceArcColorPanel = ({ layer, columns, mapConfig, layerIndex, applyConfig, lastColorScaleFieldsRef, readOnly, }) => {
|
|
196
|
+
const sourceScale = getDeckMapLayerColorScale(layer, 'getSourceColor');
|
|
197
|
+
const targetScale = getDeckMapLayerColorScale(layer, 'getTargetColor');
|
|
198
|
+
const colorScale = sourceScale ?? targetScale;
|
|
199
|
+
const colorScaleType = colorScale?.type ?? 'sequential';
|
|
200
|
+
const schemeOptions = getSchemeOptions(colorScaleType);
|
|
201
|
+
// Don't read lastColorScaleFieldsRef during render (react-hooks/refs).
|
|
202
|
+
const defaultField = getDefaultColorScaleField(columns, colorScaleType);
|
|
203
|
+
const sourceFlat = getDeckMapLayerFlatColor(layer, 'getSourceColor') ?? [
|
|
204
|
+
...DECK_MAP_DEFAULT_LAYER_COLOR,
|
|
205
|
+
];
|
|
206
|
+
const targetFlat = getDeckMapLayerFlatColor(layer, 'getTargetColor') ?? [
|
|
207
|
+
...DECK_MAP_DEFAULT_LAYER_COLOR,
|
|
208
|
+
];
|
|
209
|
+
const opacityPercent = Math.round((getDeckMapLayerChannelOpacityPercent(layer, 'getSourceColor', sourceFlat[3] ?? 255) +
|
|
210
|
+
getDeckMapLayerChannelOpacityPercent(layer, 'getTargetColor', targetFlat[3] ?? 255)) /
|
|
211
|
+
2);
|
|
212
|
+
const applySharedColorScale = (patch) => {
|
|
213
|
+
const preferredField = patch.field ??
|
|
214
|
+
colorScale?.field ??
|
|
215
|
+
lastColorScaleFieldsRef.current.getSourceColor ??
|
|
216
|
+
lastColorScaleFieldsRef.current.getTargetColor;
|
|
217
|
+
const resolved = resolveColorScaleFieldAndType(columns, patch.type ?? colorScale?.type ?? 'sequential', preferredField);
|
|
218
|
+
if (!resolved)
|
|
219
|
+
return;
|
|
220
|
+
const { field, type } = resolved;
|
|
221
|
+
lastColorScaleFieldsRef.current.getSourceColor = field;
|
|
222
|
+
lastColorScaleFieldsRef.current.getTargetColor = field;
|
|
223
|
+
const scheme = patch.scheme ??
|
|
224
|
+
(patch.type && patch.type !== colorScale?.type
|
|
225
|
+
? undefined
|
|
226
|
+
: type !== colorScale?.type
|
|
227
|
+
? undefined
|
|
228
|
+
: colorScale?.scheme);
|
|
229
|
+
applyConfig(updateDeckMapLayer(mapConfig, layerIndex, (nextLayer) => {
|
|
230
|
+
const detached = detachDeckMapLayerOpacity(nextLayer);
|
|
231
|
+
const existing = getDeckMapLayerColorScale(detached, 'getSourceColor') ??
|
|
232
|
+
getDeckMapLayerColorScale(detached, 'getTargetColor');
|
|
233
|
+
const source = getDeckMapLayerFlatColor(detached, 'getSourceColor') ?? sourceFlat;
|
|
234
|
+
const target = getDeckMapLayerFlatColor(detached, 'getTargetColor') ?? targetFlat;
|
|
235
|
+
const opacity = existing
|
|
236
|
+
? getDeckMapColorScaleOpacity(existing)
|
|
237
|
+
: Math.round(((source[3] ?? 255) + (target[3] ?? 255)) / 2) / 255;
|
|
238
|
+
const scale = createDeckMapLayerColorScale({
|
|
239
|
+
field,
|
|
240
|
+
type,
|
|
241
|
+
scheme,
|
|
242
|
+
title: field,
|
|
243
|
+
opacity,
|
|
244
|
+
});
|
|
245
|
+
return {
|
|
246
|
+
...detached,
|
|
247
|
+
getSourceColor: scale,
|
|
248
|
+
getTargetColor: scale,
|
|
249
|
+
};
|
|
250
|
+
}));
|
|
251
|
+
};
|
|
252
|
+
const setFlatColor = (accessor, color) => {
|
|
253
|
+
applyConfig(setDeckMapLayerFlatColor(mapConfig, layerIndex, accessor, color));
|
|
254
|
+
};
|
|
255
|
+
return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-xs font-medium", children: "Color scale" }), _jsx(Switch, { checked: Boolean(colorScale), disabled: readOnly || (!colorScale && !defaultField), "aria-label": "Color scale", onCheckedChange: (checked) => {
|
|
256
|
+
if (checked) {
|
|
257
|
+
applySharedColorScale({});
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (colorScale?.field) {
|
|
261
|
+
lastColorScaleFieldsRef.current.getSourceColor = colorScale.field;
|
|
262
|
+
lastColorScaleFieldsRef.current.getTargetColor = colorScale.field;
|
|
263
|
+
}
|
|
264
|
+
applyConfig(updateDeckMapLayer(mapConfig, layerIndex, (nextLayer) => {
|
|
265
|
+
const replacements = {};
|
|
266
|
+
if (getDeckMapLayerColorScale(nextLayer, 'getSourceColor')) {
|
|
267
|
+
replacements.getSourceColor = DECK_MAP_DEFAULT_LAYER_COLOR;
|
|
268
|
+
}
|
|
269
|
+
if (getDeckMapLayerColorScale(nextLayer, 'getTargetColor')) {
|
|
270
|
+
replacements.getTargetColor = DECK_MAP_DEFAULT_LAYER_COLOR;
|
|
271
|
+
}
|
|
272
|
+
return replaceDeckMapLayerColorScalesWithFlat(nextLayer, replacements);
|
|
273
|
+
}));
|
|
274
|
+
} })] }), !colorScale ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-xs font-medium", children: "Source color" }), _jsx(ColorSwatchInput, { "aria-label": "Source color", value: deckMapRgbaToHex(sourceFlat), disabled: readOnly, onChange: (hex) => {
|
|
275
|
+
const next = parseColorString(hex, sourceFlat[3] ?? 255);
|
|
276
|
+
setFlatColor('getSourceColor', next);
|
|
277
|
+
} })] }), _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-xs font-medium", children: "Target color" }), _jsx(ColorSwatchInput, { "aria-label": "Target color", value: deckMapRgbaToHex(targetFlat), disabled: readOnly, onChange: (hex) => {
|
|
278
|
+
const next = parseColorString(hex, targetFlat[3] ?? 255);
|
|
279
|
+
setFlatColor('getTargetColor', next);
|
|
280
|
+
} })] })] })) : (_jsxs("div", { className: "flex flex-col gap-2", children: [columns.length > 0 ? (_jsx(ColumnsProvider, { columns: columns, children: _jsx(Field, { label: "Field", required: true, children: _jsx(ColumnSelector.Colorable, { value: colorScale.field, onChange: (field) => applySharedColorScale({ field }), disabled: readOnly }) }) })) : null, _jsx(Field, { label: "Type", children: _jsxs(Select, { value: colorScaleType, onValueChange: (value) => applySharedColorScale({
|
|
281
|
+
type: value,
|
|
282
|
+
}), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: DECK_MAP_COLOR_SCALE_TYPE_OPTIONS.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] }) }), _jsx(Field, { label: "Scheme", children: _jsxs(Select, { value: colorScale.scheme, onValueChange: (value) => applySharedColorScale({ scheme: value }), children: [_jsx(SelectTrigger, { className: "w-full [&>span]:line-clamp-none", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: schemeOptions.map((scheme) => (_jsx(SelectItem, { value: scheme, children: _jsx(ColorSchemeOptionLabel, { scheme: scheme, type: colorScaleType }) }, scheme))) })] }) })] })), _jsx(AppearanceOpacitySlider, { valuePercent: opacityPercent, disabled: readOnly, onChange: (percent) => {
|
|
283
|
+
applyConfig(updateDeckMapLayer(mapConfig, layerIndex, (nextLayer) => {
|
|
284
|
+
const detached = detachDeckMapLayerOpacity(nextLayer);
|
|
285
|
+
if (colorScale) {
|
|
286
|
+
const scale = getDeckMapLayerColorScale(detached, 'getSourceColor') ??
|
|
287
|
+
getDeckMapLayerColorScale(detached, 'getTargetColor') ??
|
|
288
|
+
colorScale;
|
|
289
|
+
const nextScale = { ...scale, opacity: percent / 100 };
|
|
290
|
+
return {
|
|
291
|
+
...detached,
|
|
292
|
+
getSourceColor: nextScale,
|
|
293
|
+
getTargetColor: nextScale,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
const alpha = opacityPercentToAlpha(percent);
|
|
297
|
+
const source = getDeckMapLayerFlatColor(detached, 'getSourceColor') ??
|
|
298
|
+
sourceFlat;
|
|
299
|
+
const target = getDeckMapLayerFlatColor(detached, 'getTargetColor') ??
|
|
300
|
+
targetFlat;
|
|
301
|
+
return {
|
|
302
|
+
...detached,
|
|
303
|
+
getSourceColor: [source[0], source[1], source[2], alpha],
|
|
304
|
+
getTargetColor: [target[0], target[1], target[2], alpha],
|
|
305
|
+
};
|
|
306
|
+
}));
|
|
307
|
+
} })] }));
|
|
308
|
+
};
|
|
309
|
+
const AppearanceExtrusionPanel = ({ layer, columns, mapConfig, layerIndex, applyConfig, readOnly }) => {
|
|
310
|
+
const extruded = getDeckMapLayerExtruded(layer);
|
|
311
|
+
return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-xs font-medium", children: "Extruded" }), _jsx(Switch, { checked: extruded, onCheckedChange: (checked) => applyConfig(updateDeckMapLayer(mapConfig, layerIndex, (nextLayer) => ({
|
|
312
|
+
...nextLayer,
|
|
313
|
+
extruded: checked,
|
|
314
|
+
getElevation: checked
|
|
315
|
+
? (nextLayer.getElevation ?? 1)
|
|
316
|
+
: nextLayer.getElevation,
|
|
317
|
+
}))) })] }), extruded && columns.length > 0 ? (_jsx(ColumnsProvider, { columns: columns, children: _jsx(Field, { label: "Elevation column", children: _jsx(ColumnSelector.Numeric, { value: (() => {
|
|
318
|
+
const elev = layer?.getElevation;
|
|
319
|
+
if (elev &&
|
|
320
|
+
typeof elev === 'object' &&
|
|
321
|
+
'@@function' in elev) {
|
|
322
|
+
return elev.field;
|
|
323
|
+
}
|
|
324
|
+
if (typeof elev === 'string' && elev.startsWith('@@=')) {
|
|
325
|
+
return elev.slice(3);
|
|
326
|
+
}
|
|
327
|
+
return undefined;
|
|
328
|
+
})(), onChange: (elevationColumn) => applyConfig(updateDeckMapLayer(mapConfig, layerIndex, (nextLayer) => ({
|
|
329
|
+
...nextLayer,
|
|
330
|
+
getElevation: elevationColumn
|
|
331
|
+
? {
|
|
332
|
+
'@@function': 'scale',
|
|
333
|
+
field: elevationColumn,
|
|
334
|
+
type: 'linear',
|
|
335
|
+
domain: 'auto',
|
|
336
|
+
range: [0, 200],
|
|
337
|
+
}
|
|
338
|
+
: undefined,
|
|
339
|
+
elevationScale: nextLayer.elevationScale ?? 1,
|
|
340
|
+
}))), placeholder: "Select elevation column...", disabled: readOnly }) }) })) : null, extruded ? (_jsx(SettingsSliderField, { label: `Elevation scale: ${layer?.elevationScale ?? 1}x`, children: _jsx(Slider, { min: 0.01, max: 1000, step: 0.01, value: [layer?.elevationScale ?? 1], onValueChange: (values) => {
|
|
341
|
+
const value = values[0] ?? 1;
|
|
342
|
+
applyConfig(updateDeckMapLayer(mapConfig, layerIndex, (nextLayer) => ({
|
|
343
|
+
...nextLayer,
|
|
344
|
+
elevationScale: value,
|
|
345
|
+
})));
|
|
346
|
+
} }) })) : null] }));
|
|
347
|
+
};
|
|
348
|
+
export const DeckMapSettingsPanel = ({ title, selectedTable, config, tables, onClose, onTableChange, onTitleChange, onConfigChange, readOnly, customConfig = false, preferDatasetSource = false, }) => {
|
|
56
349
|
const [layerIndex, setLayerIndex] = useState(0);
|
|
57
|
-
const [
|
|
58
|
-
|
|
350
|
+
const [viewMode, setViewMode] = useState(customConfig ? 'code' : 'settings');
|
|
351
|
+
// Last color-scale field per accessor (restored when re-enabling a scale).
|
|
352
|
+
const lastColorScaleFieldsRef = useRef({});
|
|
59
353
|
const selectedDataTable = useMemo(() => selectedTable
|
|
60
354
|
? resolveTableReference(tables, selectedTable).table
|
|
61
355
|
: undefined, [selectedTable, tables]);
|
|
@@ -66,7 +360,7 @@ export const DeckMapSettingsPanel = ({ title, selectedTable, config, tables, onC
|
|
|
66
360
|
}, [onTableChange, readOnly]);
|
|
67
361
|
const mapConfig = config;
|
|
68
362
|
const serializedMapConfig = useMemo(() => JSON.stringify(config, null, 2), [config]);
|
|
69
|
-
const showCode = viewMode === 'code';
|
|
363
|
+
const showCode = customConfig || viewMode === 'code';
|
|
70
364
|
const layers = getDeckMapLayerRecords(mapConfig);
|
|
71
365
|
const activeLayerIndex = Math.min(layerIndex, Math.max(layers.length - 1, 0));
|
|
72
366
|
const activeLayer = layers[activeLayerIndex];
|
|
@@ -74,9 +368,7 @@ export const DeckMapSettingsPanel = ({ title, selectedTable, config, tables, onC
|
|
|
74
368
|
const activeLayerDataset = activeLayerDatasetId
|
|
75
369
|
? mapConfig.datasets?.[activeLayerDatasetId]
|
|
76
370
|
: undefined;
|
|
77
|
-
//
|
|
78
|
-
// output. Coordinate selectors edit the source transform, while render
|
|
79
|
-
// bindings such as geometry/color/elevation target output columns.
|
|
371
|
+
// Source table (coords/transform) vs compiled output columns (bindings).
|
|
80
372
|
const activeLayerDatasetSource = activeLayerDataset?.source;
|
|
81
373
|
const fallbackTableName = isDeckMapTableDatasetSource(activeLayerDatasetSource)
|
|
82
374
|
? activeLayerDatasetSource.tableName
|
|
@@ -84,7 +376,9 @@ export const DeckMapSettingsPanel = ({ title, selectedTable, config, tables, onC
|
|
|
84
376
|
const fallbackTable = useMemo(() => fallbackTableName
|
|
85
377
|
? resolveTableReference(tables, fallbackTableName).table
|
|
86
378
|
: undefined, [fallbackTableName, tables]);
|
|
87
|
-
const sourceDataTable =
|
|
379
|
+
const sourceDataTable = preferDatasetSource
|
|
380
|
+
? (fallbackTable ?? selectedDataTable)
|
|
381
|
+
: (selectedDataTable ?? fallbackTable);
|
|
88
382
|
const sourceColumns = sourceDataTable?.columns ?? EMPTY_COLUMNS;
|
|
89
383
|
const resolvedActiveLayerDatasetSource = useMemo(() => {
|
|
90
384
|
if (!activeLayerDatasetSource) {
|
|
@@ -96,14 +390,14 @@ export const DeckMapSettingsPanel = ({ title, selectedTable, config, tables, onC
|
|
|
96
390
|
return activeLayerDatasetSource;
|
|
97
391
|
}
|
|
98
392
|
return {
|
|
99
|
-
tableName: selectedDataTable
|
|
393
|
+
tableName: !preferDatasetSource && selectedDataTable
|
|
100
394
|
? getTableIdentity(selectedDataTable.table)
|
|
101
395
|
: activeLayerDatasetSource.tableName,
|
|
102
396
|
...(activeLayerDatasetSource.transformSql
|
|
103
397
|
? { transformSql: activeLayerDatasetSource.transformSql }
|
|
104
398
|
: {}),
|
|
105
399
|
};
|
|
106
|
-
}, [activeLayerDatasetSource, selectedDataTable]);
|
|
400
|
+
}, [activeLayerDatasetSource, preferDatasetSource, selectedDataTable]);
|
|
107
401
|
const datasetSchema = useDeckMapDatasetSchema({
|
|
108
402
|
source: resolvedActiveLayerDatasetSource,
|
|
109
403
|
sourceColumns,
|
|
@@ -118,181 +412,243 @@ export const DeckMapSettingsPanel = ({ title, selectedTable, config, tables, onC
|
|
|
118
412
|
const showColumnRadiusSetting = usesColumnRadiusSetting(activeLayer?.['@@type']);
|
|
119
413
|
const showTripsSettings = usesTripsSettings(activeLayer?.['@@type']);
|
|
120
414
|
const showExtrusionSettings = usesExtrusionSettings(activeLayer?.['@@type']);
|
|
415
|
+
const showStrokeSetting = usesStrokeSetting(activeLayer?.['@@type']);
|
|
416
|
+
const strokeEnabled = typeof activeLayer?.stroked === 'boolean'
|
|
417
|
+
? activeLayer.stroked
|
|
418
|
+
: getDeckMapLayerStrokeDefault(activeLayer?.['@@type'], {
|
|
419
|
+
extruded: getDeckMapLayerExtruded(activeLayer),
|
|
420
|
+
});
|
|
421
|
+
const strokeWidthPixels = activeLayer?.lineWidthUnits === 'pixels' &&
|
|
422
|
+
typeof activeLayer?.getLineWidth === 'number'
|
|
423
|
+
? activeLayer.getLineWidth
|
|
424
|
+
: (activeLayer?.lineWidthMinPixels ?? 1);
|
|
121
425
|
const colorAccessorOptions = getDeckMapColorAccessorOptions(activeLayer?.['@@type']);
|
|
122
|
-
const
|
|
123
|
-
|
|
426
|
+
const hasFillColor = colorAccessorOptions.some((option) => option.value === 'getFillColor');
|
|
427
|
+
const hasLineColor = colorAccessorOptions.some((option) => option.value === 'getLineColor');
|
|
428
|
+
const hasPathColor = colorAccessorOptions.some((option) => option.value === 'getColor');
|
|
429
|
+
const hasSourceColor = colorAccessorOptions.some((option) => option.value === 'getSourceColor');
|
|
430
|
+
const hasTargetColor = colorAccessorOptions.some((option) => option.value === 'getTargetColor');
|
|
431
|
+
const isPathLayer = activeLayer?.['@@type'] === 'GeoArrowPathLayer';
|
|
124
432
|
const isGeoJsonLayer = activeLayer?.['@@type'] === 'GeoJsonLayer';
|
|
433
|
+
// Keep unknown types visible if the layer already uses them.
|
|
434
|
+
const activeLayerType = typeof activeLayer?.['@@type'] === 'string'
|
|
435
|
+
? activeLayer['@@type']
|
|
436
|
+
: undefined;
|
|
437
|
+
const layerTypeOptions = activeLayerType &&
|
|
438
|
+
!DECK_MAP_LAYER_TYPE_OPTIONS.some((option) => option.value === activeLayerType)
|
|
439
|
+
? [
|
|
440
|
+
...DECK_MAP_LAYER_TYPE_OPTIONS,
|
|
441
|
+
{ value: activeLayerType, label: activeLayerType },
|
|
442
|
+
]
|
|
443
|
+
: DECK_MAP_LAYER_TYPE_OPTIONS;
|
|
444
|
+
// GeoJsonLayer uses pointRadius* / getPointRadius; scatterplot uses radius* / getRadius.
|
|
125
445
|
const pointRadiusPixels = isGeoJsonLayer
|
|
126
|
-
?
|
|
446
|
+
? activeLayer?.pointRadiusUnits === 'pixels' &&
|
|
447
|
+
typeof activeLayer?.getPointRadius === 'number'
|
|
127
448
|
? activeLayer.getPointRadius
|
|
128
449
|
: (activeLayer?.pointRadiusMinPixels ?? 2)
|
|
129
450
|
: activeLayer?.radiusUnits === 'pixels' &&
|
|
130
451
|
typeof activeLayer?.getRadius === 'number'
|
|
131
452
|
? activeLayer.getRadius
|
|
132
453
|
: (activeLayer?.radiusMinPixels ?? 2);
|
|
133
|
-
const colorScale = effectiveColorAccessor
|
|
134
|
-
? getDeckMapLayerColorScale(activeLayer, effectiveColorAccessor)
|
|
135
|
-
: undefined;
|
|
136
|
-
const colorScaleType = colorScale?.type ?? 'sequential';
|
|
137
|
-
const schemeOptions = getSchemeOptions(colorScaleType);
|
|
138
454
|
const isHeatmapLayer = activeLayer?.['@@type'] === 'GeoArrowHeatmapLayer';
|
|
139
|
-
const
|
|
455
|
+
const showAppearanceCard = isHeatmapLayer || colorAccessorOptions.length > 0;
|
|
456
|
+
const lineWidthPixels = activeLayer?.widthUnits === 'pixels' &&
|
|
457
|
+
typeof activeLayer?.getWidth === 'number'
|
|
458
|
+
? activeLayer.getWidth
|
|
459
|
+
: (activeLayer?.widthMinPixels ??
|
|
460
|
+
(showTripsSettings ? 3 : 1));
|
|
140
461
|
const applyConfig = useCallback((nextConfig) => {
|
|
141
462
|
if (readOnly)
|
|
142
463
|
return;
|
|
143
464
|
onConfigChange(nextConfig);
|
|
144
465
|
}, [onConfigChange, readOnly]);
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (!
|
|
466
|
+
// Drop point/heatmap radius leftovers on Column layers (pixels vs meters).
|
|
467
|
+
useEffect(() => {
|
|
468
|
+
if (!showColumnRadiusSetting || !activeLayer || readOnly)
|
|
148
469
|
return;
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
470
|
+
const needsHeal = activeLayer.radiusUnits === 'pixels' ||
|
|
471
|
+
activeLayer.getRadius !== undefined ||
|
|
472
|
+
activeLayer.radiusMinPixels !== undefined ||
|
|
473
|
+
activeLayer.radiusMaxPixels !== undefined ||
|
|
474
|
+
activeLayer.radiusPixels !== undefined;
|
|
475
|
+
if (!needsHeal)
|
|
476
|
+
return;
|
|
477
|
+
const radius = typeof activeLayer.radius === 'number' &&
|
|
478
|
+
Number.isFinite(activeLayer.radius) &&
|
|
479
|
+
activeLayer.radius > 0
|
|
480
|
+
? activeLayer.radius
|
|
481
|
+
: 50;
|
|
482
|
+
applyConfig(setDeckMapLayerColumnRadius(mapConfig, activeLayerIndex, radius));
|
|
483
|
+
}, [
|
|
484
|
+
activeLayer,
|
|
485
|
+
activeLayerIndex,
|
|
486
|
+
applyConfig,
|
|
487
|
+
mapConfig,
|
|
488
|
+
readOnly,
|
|
489
|
+
showColumnRadiusSetting,
|
|
490
|
+
]);
|
|
491
|
+
// Fix path/arc/trips where widthMaxPixels < widthMinPixels (clamps the slider).
|
|
492
|
+
useEffect(() => {
|
|
493
|
+
const isLineWidthLayer = showTripsSettings ||
|
|
494
|
+
activeLayer?.['@@type'] === 'GeoArrowPathLayer' ||
|
|
495
|
+
showArcColumnSetting;
|
|
496
|
+
if (!isLineWidthLayer || !activeLayer || readOnly)
|
|
497
|
+
return;
|
|
498
|
+
const min = typeof activeLayer.widthMinPixels === 'number'
|
|
499
|
+
? activeLayer.widthMinPixels
|
|
500
|
+
: undefined;
|
|
501
|
+
const max = typeof activeLayer.widthMaxPixels === 'number'
|
|
502
|
+
? activeLayer.widthMaxPixels
|
|
503
|
+
: undefined;
|
|
504
|
+
if (min === undefined || max === undefined || max >= min)
|
|
505
|
+
return;
|
|
506
|
+
applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
507
|
+
...layer,
|
|
508
|
+
widthMinPixels: Math.min(min, max),
|
|
509
|
+
widthMaxPixels: Math.max(min, max),
|
|
159
510
|
})));
|
|
511
|
+
}, [
|
|
512
|
+
activeLayer,
|
|
513
|
+
activeLayerIndex,
|
|
514
|
+
applyConfig,
|
|
515
|
+
mapConfig,
|
|
516
|
+
readOnly,
|
|
517
|
+
showArcColumnSetting,
|
|
518
|
+
showTripsSettings,
|
|
519
|
+
]);
|
|
520
|
+
const setStrokeWidth = (value) => {
|
|
521
|
+
applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => {
|
|
522
|
+
const nextLayer = {
|
|
523
|
+
...layer,
|
|
524
|
+
lineWidthUnits: 'pixels',
|
|
525
|
+
lineWidthMinPixels: value,
|
|
526
|
+
lineWidthMaxPixels: value,
|
|
527
|
+
};
|
|
528
|
+
if (typeof layer.getLineWidth !== 'string') {
|
|
529
|
+
nextLayer.getLineWidth = value;
|
|
530
|
+
}
|
|
531
|
+
return nextLayer;
|
|
532
|
+
}));
|
|
533
|
+
};
|
|
534
|
+
const setLineWidth = (value) => {
|
|
535
|
+
applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => {
|
|
536
|
+
const nextLayer = {
|
|
537
|
+
...layer,
|
|
538
|
+
widthUnits: 'pixels',
|
|
539
|
+
widthMinPixels: value,
|
|
540
|
+
widthMaxPixels: value,
|
|
541
|
+
};
|
|
542
|
+
if (typeof layer.getWidth !== 'string') {
|
|
543
|
+
nextLayer.getWidth = value;
|
|
544
|
+
}
|
|
545
|
+
return nextLayer;
|
|
546
|
+
}));
|
|
160
547
|
};
|
|
161
|
-
|
|
548
|
+
const setPointRadius = (value) => {
|
|
549
|
+
applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => {
|
|
550
|
+
if (layer['@@type'] === 'GeoJsonLayer') {
|
|
551
|
+
const nextLayer = {
|
|
552
|
+
...layer,
|
|
553
|
+
pointRadiusUnits: 'pixels',
|
|
554
|
+
pointRadiusMinPixels: value,
|
|
555
|
+
pointRadiusMaxPixels: value,
|
|
556
|
+
};
|
|
557
|
+
if (typeof layer.getPointRadius !== 'string') {
|
|
558
|
+
nextLayer.getPointRadius = value;
|
|
559
|
+
}
|
|
560
|
+
return nextLayer;
|
|
561
|
+
}
|
|
562
|
+
const nextLayer = {
|
|
563
|
+
...layer,
|
|
564
|
+
radiusUnits: 'pixels',
|
|
565
|
+
radiusMinPixels: value,
|
|
566
|
+
radiusMaxPixels: value,
|
|
567
|
+
};
|
|
568
|
+
if (typeof layer.getRadius !== 'string') {
|
|
569
|
+
nextLayer.getRadius = value;
|
|
570
|
+
}
|
|
571
|
+
return nextLayer;
|
|
572
|
+
}));
|
|
573
|
+
};
|
|
574
|
+
const setColumnRadius = (value) => {
|
|
575
|
+
applyConfig(setDeckMapLayerColumnRadius(mapConfig, activeLayerIndex, value));
|
|
576
|
+
};
|
|
577
|
+
const fillRadiusProps = showRadiusSetting
|
|
578
|
+
? {
|
|
579
|
+
radiusValue: pointRadiusPixels,
|
|
580
|
+
onRadiusChange: setPointRadius,
|
|
581
|
+
radiusLabel: 'Point radius',
|
|
582
|
+
radiusUnit: 'px',
|
|
583
|
+
radiusMin: 0.1,
|
|
584
|
+
radiusMax: 50,
|
|
585
|
+
radiusStep: 0.1,
|
|
586
|
+
}
|
|
587
|
+
: showColumnRadiusSetting
|
|
588
|
+
? {
|
|
589
|
+
radiusValue: activeLayer?.radius ?? 50,
|
|
590
|
+
onRadiusChange: setColumnRadius,
|
|
591
|
+
radiusLabel: 'Column radius',
|
|
592
|
+
radiusUnit: 'm',
|
|
593
|
+
radiusMin: 1,
|
|
594
|
+
radiusMax: 10000,
|
|
595
|
+
radiusStep: 1,
|
|
596
|
+
}
|
|
597
|
+
: {};
|
|
598
|
+
return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [_jsx(SettingsPanelHeader, { title: "Map settings", className: "shrink-0 p-2", actions: customConfig ? undefined : (_jsx(DeckMapCodeViewToggleButton, { label: showCode ? 'Show settings' : 'View code', selected: showCode, onClick: () => setViewMode((currentViewMode) => currentViewMode === 'code' ? 'settings' : 'code') })), onClose: onClose, closeLabel: "Close map settings" }), _jsxs("div", { className: "flex shrink-0 flex-col gap-2 px-2 pb-2", children: [_jsx(Field, { label: "Title", children: _jsx("input", { value: title, onChange: (e) => onTitleChange(e.target.value), placeholder: "Map title", disabled: readOnly, className: "border-input placeholder:text-muted-foreground focus-visible:ring-ring h-8 w-full rounded-md border bg-transparent px-3 py-2 text-xs font-medium shadow-sm outline-hidden transition-colors focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50" }) }), _jsx(DeckMapBasemapSelect, { config: config, onConfigChange: onConfigChange, readOnly: readOnly })] }), showCode ? (_jsx(DeckMapCodeViewerPanel, { value: serializedMapConfig, copyTooltipLabel: "Copy map config" })) : (_jsx(ScrollArea, { className: "min-h-0 flex-1 [&_[data-radix-scroll-area-viewport]>div]:!block", children: _jsxs("div", { className: "flex flex-col gap-2 p-2 pt-0", children: [_jsx(Field, { label: "Dataset", required: true, children: _jsx(DataTableSelector, { onChange: handleTableChange, tables: tables, value: sourceDataTable, disabled: readOnly }) }), layers.length > 0 && (_jsxs("div", { className: "flex flex-col gap-3", children: [layers.length > 1 && (_jsx(Field, { label: "Layer", children: _jsxs(Select, { value: String(activeLayerIndex), onValueChange: (value) => setLayerIndex(Number(value)), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: layers.map((layer, index) => (_jsx(SelectItem, { value: String(index), children: String(layer.id ?? `Layer ${index + 1}`) }, index))) })] }) })), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-medium", children: "Visible" }), _jsx(Switch, { checked: activeLayer?.visible !== false, onCheckedChange: (checked) => applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
162
599
|
...layer,
|
|
163
600
|
visible: checked,
|
|
164
601
|
}))) })] }), _jsx(Field, { label: "Layer type", children: _jsxs(Select, { value: typeof activeLayer?.['@@type'] === 'string'
|
|
165
602
|
? activeLayer['@@type']
|
|
166
|
-
: undefined, onValueChange: (value) => applyConfig(setDeckMapLayerType(mapConfig, activeLayerIndex, value)), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: "Select layer type" }) }), _jsx(SelectContent, { children:
|
|
603
|
+
: undefined, onValueChange: (value) => applyConfig(setDeckMapLayerType(mapConfig, activeLayerIndex, value)), children: [_jsx(SelectTrigger, { className: "w-full text-xs", children: _jsx(SelectValue, { placeholder: "Select layer type" }) }), _jsx(SelectContent, { children: layerTypeOptions.map((option) => (_jsx(SelectItem, { value: option.value, className: "text-xs", children: option.label }, option.value))) })] }) }), (datasetSchema.isLoading || datasetSchemaErrorMessage) && (_jsx("div", { className: "text-muted-foreground rounded-md border px-2 py-1.5 text-xs", children: datasetSchema.isLoading
|
|
167
604
|
? 'Inspecting dataset schema...'
|
|
168
|
-
: `Dataset schema unavailable: ${datasetSchemaErrorMessage}` })),
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
605
|
+
: `Dataset schema unavailable: ${datasetSchemaErrorMessage}` })), showAppearanceCard && (_jsx(Field, { label: "Appearance", children: _jsx("div", { className: "flex flex-col gap-2 rounded-md border p-2", children: isHeatmapLayer ? (_jsxs(_Fragment, { children: [_jsx(SettingsSliderField, { label: `Radius: ${activeLayer?.radiusPixels ?? 30}px`, children: _jsx(Slider, { min: 1, max: 100, step: 1, value: [
|
|
606
|
+
activeLayer?.radiusPixels ?? 30,
|
|
607
|
+
], onValueChange: (values) => {
|
|
608
|
+
const value = values[0] ?? 30;
|
|
609
|
+
applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
610
|
+
...layer,
|
|
611
|
+
radiusPixels: value,
|
|
612
|
+
})));
|
|
613
|
+
} }) }), _jsxs(Select, { value: detectHeatmapScheme(activeLayer?.colorRange), onValueChange: (value) => applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
174
614
|
...layer,
|
|
175
|
-
|
|
176
|
-
})))
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
? {
|
|
213
|
-
...layer,
|
|
214
|
-
pointRadiusUnits: 'pixels',
|
|
215
|
-
pointRadiusMinPixels: value,
|
|
216
|
-
pointRadiusMaxPixels: Math.max(value, layer.pointRadiusMaxPixels ?? value),
|
|
217
|
-
getPointRadius: value,
|
|
218
|
-
}
|
|
219
|
-
: {
|
|
220
|
-
...layer,
|
|
221
|
-
radiusMinPixels: value,
|
|
222
|
-
radiusMaxPixels: Math.max(value, layer.radiusMaxPixels ?? value),
|
|
223
|
-
};
|
|
224
|
-
if (layer['@@type'] !== 'GeoJsonLayer' &&
|
|
225
|
-
layer.radiusUnits === 'pixels' &&
|
|
226
|
-
typeof layer.getRadius !== 'string') {
|
|
227
|
-
nextLayer.getRadius = value;
|
|
228
|
-
}
|
|
229
|
-
return nextLayer;
|
|
230
|
-
}));
|
|
231
|
-
} }) }) })), showColumnRadiusSetting && (_jsx(Field, { label: `Column radius: ${activeLayer?.radius ?? 50}m`, children: _jsx("div", { className: "pt-0.5", children: _jsx(Slider, { min: 1, max: 10000, step: 1, value: [activeLayer?.radius ?? 50], onValueChange: (values) => {
|
|
232
|
-
const value = values[0] ?? 50;
|
|
233
|
-
applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
234
|
-
...layer,
|
|
235
|
-
radius: value,
|
|
236
|
-
})));
|
|
237
|
-
} }) }) })), outputColumns.length > 0 && showGeometryColumnSetting && (_jsx(ColumnsProvider, { columns: outputColumns, children: _jsx(Field, { label: "Geometry column", required: true, children: _jsx(ColumnSelector, { value: activeLayerDataset?.geometryColumn, onChange: (geometryColumn) => applyConfig(setDeckMapLayerGeometryColumn(mapConfig, activeLayerIndex, geometryColumn)), placeholder: "Select geometry column...", disabled: readOnly }) }) })), outputColumns.length > 0 && showH3ColumnSetting && (_jsx(ColumnsProvider, { columns: outputColumns, children: _jsx(Field, { label: "H3 column", required: true, children: _jsx(ColumnSelector, { value: activeLayer?._sqlroomsBinding
|
|
238
|
-
?.hexagonColumn, onChange: (hexagonColumn) => applyConfig(setDeckMapLayerHexagonColumn(mapConfig, activeLayerIndex, hexagonColumn)), placeholder: "Select H3 index column...", disabled: readOnly }) }) })), outputColumns.length > 0 && showArcColumnSetting && (_jsxs(ColumnsProvider, { columns: outputColumns, children: [_jsx(Field, { label: "Source geometry", required: true, children: _jsx(ColumnSelector, { value: activeLayer?._sqlroomsBinding
|
|
239
|
-
?.sourceGeometryColumn, onChange: (sourceGeometryColumn) => applyConfig(setDeckMapLayerArcColumns(mapConfig, activeLayerIndex, {
|
|
240
|
-
sourceGeometryColumn,
|
|
241
|
-
})), placeholder: "Select source geometry...", disabled: readOnly }) }), _jsx(Field, { label: "Target geometry", required: true, children: _jsx(ColumnSelector, { value: activeLayer?._sqlroomsBinding
|
|
242
|
-
?.targetGeometryColumn, onChange: (targetGeometryColumn) => applyConfig(setDeckMapLayerArcColumns(mapConfig, activeLayerIndex, {
|
|
243
|
-
targetGeometryColumn,
|
|
244
|
-
})), placeholder: "Select target geometry...", disabled: readOnly }) })] })), showArcColumnSetting && (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-medium", children: "Flat lines" }), _jsx(Switch, { checked: activeLayer?.getHeight === 0, onCheckedChange: (checked) => applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
245
|
-
...layer,
|
|
246
|
-
getHeight: checked ? 0 : undefined,
|
|
247
|
-
}))) })] })), showArcColumnSetting && (_jsx(Field, { label: `Line width: ${activeLayer?.widthMinPixels ?? 1}px`, children: _jsx(Slider, { min: 1, max: 20, step: 1, value: [
|
|
248
|
-
activeLayer?.widthMinPixels ?? 1,
|
|
249
|
-
], onValueChange: (values) => {
|
|
250
|
-
const value = values[0] ?? 1;
|
|
251
|
-
applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
252
|
-
...layer,
|
|
253
|
-
widthMinPixels: value,
|
|
254
|
-
})));
|
|
255
|
-
} }) })), showExtrusionSettings && (_jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-xs font-medium", children: "Extrusion" }), _jsx(Switch, { checked: Boolean(activeLayer?.extruded), onCheckedChange: (checked) => applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
256
|
-
...layer,
|
|
257
|
-
extruded: checked,
|
|
258
|
-
getElevation: checked
|
|
259
|
-
? (layer.getElevation ?? 1)
|
|
260
|
-
: layer.getElevation,
|
|
261
|
-
}))) })] }), Boolean(activeLayer?.extruded) &&
|
|
262
|
-
dataOutputColumns.length > 0 && (_jsx(ColumnsProvider, { columns: dataOutputColumns, children: _jsx(Field, { label: "Elevation column", children: _jsx(ColumnSelector.Numeric, { value: (() => {
|
|
263
|
-
const elev = activeLayer?.getElevation;
|
|
264
|
-
if (elev &&
|
|
265
|
-
typeof elev === 'object' &&
|
|
266
|
-
'@@function' in elev) {
|
|
267
|
-
return elev.field;
|
|
268
|
-
}
|
|
269
|
-
if (typeof elev === 'string' &&
|
|
270
|
-
elev.startsWith('@@=')) {
|
|
271
|
-
return elev.slice(3);
|
|
272
|
-
}
|
|
273
|
-
return undefined;
|
|
274
|
-
})(), onChange: (elevationColumn) => applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
275
|
-
...layer,
|
|
276
|
-
getElevation: elevationColumn
|
|
277
|
-
? {
|
|
278
|
-
'@@function': 'scale',
|
|
279
|
-
field: elevationColumn,
|
|
280
|
-
type: 'linear',
|
|
281
|
-
domain: 'auto',
|
|
282
|
-
range: [0, 200],
|
|
283
|
-
}
|
|
284
|
-
: undefined,
|
|
285
|
-
elevationScale: layer.elevationScale ?? 1,
|
|
286
|
-
}))), placeholder: "Select elevation column...", disabled: readOnly }) }) })), Boolean(activeLayer?.extruded) && (_jsx(Field, { label: `Elevation scale: ${activeLayer?.elevationScale ?? 1}x`, children: _jsx("div", { className: "pt-1.5", children: _jsx(Slider, { min: 0.01, max: 100, step: 0.01, value: [
|
|
287
|
-
activeLayer?.elevationScale ??
|
|
288
|
-
1,
|
|
289
|
-
], onValueChange: (values) => {
|
|
290
|
-
const value = values[0] ?? 1;
|
|
291
|
-
applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
292
|
-
...layer,
|
|
293
|
-
elevationScale: value,
|
|
294
|
-
})));
|
|
295
|
-
} }) }) }))] })), sourceDataTable &&
|
|
615
|
+
colorRange: heatmapSchemeToColorRange(value),
|
|
616
|
+
}))), children: [_jsx(SelectTrigger, { className: "w-full [&>span]:line-clamp-none", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: continuousSequentialSchemes.map((scheme) => (_jsx(SelectItem, { value: scheme, children: _jsx(ColorSchemeOptionLabel, { scheme: scheme, type: "sequential" }) }, scheme))) })] }), _jsx(AppearanceOpacitySlider, { valuePercent: getLayerOpacityPercent(activeLayer), disabled: readOnly, onChange: (percent) => {
|
|
617
|
+
applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
618
|
+
...layer,
|
|
619
|
+
opacity: percent / 100,
|
|
620
|
+
})));
|
|
621
|
+
} })] })) : (_jsxs(_Fragment, { children: [(showTripsSettings ||
|
|
622
|
+
isPathLayer ||
|
|
623
|
+
showArcColumnSetting) && (_jsx(SettingsSliderField, { label: `${showTripsSettings ? 'Trip width' : 'Line width'}: ${lineWidthPixels}px`, children: _jsx(Slider, { min: 1, max: 20, step: 1, value: [lineWidthPixels], onValueChange: (values) => setLineWidth(values[0] ?? lineWidthPixels) }) })), showArcColumnSetting ? (_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-xs font-medium", children: "Flat lines" }), _jsx(Switch, { checked: activeLayer?.getHeight === 0, onCheckedChange: (checked) => applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
624
|
+
...layer,
|
|
625
|
+
getHeight: checked ? 0 : undefined,
|
|
626
|
+
}))) })] })) : null, showTripsSettings ? (_jsx(SettingsSliderField, { label: `Trail length: ${Math.round((activeLayer?._trailLengthFactor ?? 0.4) * 100)}%`, children: _jsx(Slider, { min: 5, max: 100, step: 5, value: [
|
|
627
|
+
Math.round((activeLayer?._trailLengthFactor ?? 0.4) * 100),
|
|
628
|
+
], onValueChange: (values) => {
|
|
629
|
+
const value = (values[0] ?? 40) / 100;
|
|
630
|
+
applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => ({
|
|
631
|
+
...layer,
|
|
632
|
+
_trailLengthFactor: value,
|
|
633
|
+
})));
|
|
634
|
+
} }) })) : null, hasFillColor && hasLineColor && showStrokeSetting ? (_jsxs(Tabs, { defaultValue: "fill", className: "w-full", children: [_jsxs(TabsList, { className: `grid h-8 w-full ${showExtrusionSettings ? 'grid-cols-3' : 'grid-cols-2'}`, children: [_jsx(TabsTrigger, { value: "fill", className: "text-xs", children: "Fill" }), _jsx(TabsTrigger, { value: "stroke", className: "text-xs", children: "Stroke" }), showExtrusionSettings ? (_jsx(TabsTrigger, { value: "extrusion", className: "text-xs", children: "Extrusion" })) : null] }), _jsx(TabsContent, { value: "fill", className: "mt-2", children: _jsx(AppearanceColorChannel, { accessor: "getFillColor", layer: activeLayer, columns: dataOutputColumns, mapConfig: mapConfig, layerIndex: activeLayerIndex, applyConfig: applyConfig, lastColorScaleFieldsRef: lastColorScaleFieldsRef, readOnly: readOnly, ...fillRadiusProps }) }), _jsx(TabsContent, { value: "stroke", className: "mt-2", children: _jsx(AppearanceColorChannel, { accessor: "getLineColor", layer: activeLayer, columns: dataOutputColumns, mapConfig: mapConfig, layerIndex: activeLayerIndex, applyConfig: applyConfig, lastColorScaleFieldsRef: lastColorScaleFieldsRef, readOnly: readOnly, enabled: strokeEnabled, onEnabledChange: (checked) => applyConfig(updateDeckMapLayer(mapConfig, activeLayerIndex, (layer) => {
|
|
635
|
+
if (checked) {
|
|
636
|
+
return { ...layer, stroked: true };
|
|
637
|
+
}
|
|
638
|
+
// Clear stroke color scale when stroke is off.
|
|
639
|
+
const next = {
|
|
640
|
+
...layer,
|
|
641
|
+
stroked: false,
|
|
642
|
+
};
|
|
643
|
+
if (getDeckMapLayerColorScale(next, 'getLineColor')) {
|
|
644
|
+
return replaceDeckMapLayerColorScaleWithFlat(next, 'getLineColor', DECK_MAP_DEFAULT_STROKE_COLOR);
|
|
645
|
+
}
|
|
646
|
+
return next;
|
|
647
|
+
})), enableLabel: "Stroke", defaultFlatColor: DECK_MAP_DEFAULT_STROKE_COLOR, widthPixels: strokeWidthPixels, onWidthChange: setStrokeWidth, widthLabel: "Stroke width", extrusionDisablesStroke: usesStrokeExtrusionWarning(activeLayer?.['@@type']) && getDeckMapLayerExtruded(activeLayer) }) }), showExtrusionSettings ? (_jsx(TabsContent, { value: "extrusion", className: "mt-2", children: _jsx(AppearanceExtrusionPanel, { layer: activeLayer, columns: dataOutputColumns, mapConfig: mapConfig, layerIndex: activeLayerIndex, applyConfig: applyConfig, readOnly: readOnly }) })) : null] }, `appearance-fill-stroke${showExtrusionSettings ? '-extrusion' : ''}`)) : hasFillColor && showExtrusionSettings ? (_jsxs(Tabs, { defaultValue: "fill", className: "w-full", children: [_jsxs(TabsList, { className: "grid h-8 w-full grid-cols-2", children: [_jsx(TabsTrigger, { value: "fill", className: "text-xs", children: "Fill" }), _jsx(TabsTrigger, { value: "extrusion", className: "text-xs", children: "Extrusion" })] }), _jsx(TabsContent, { value: "fill", className: "mt-2", children: _jsx(AppearanceColorChannel, { accessor: "getFillColor", layer: activeLayer, columns: dataOutputColumns, mapConfig: mapConfig, layerIndex: activeLayerIndex, applyConfig: applyConfig, lastColorScaleFieldsRef: lastColorScaleFieldsRef, readOnly: readOnly, ...fillRadiusProps }) }), _jsx(TabsContent, { value: "extrusion", className: "mt-2", children: _jsx(AppearanceExtrusionPanel, { layer: activeLayer, columns: dataOutputColumns, mapConfig: mapConfig, layerIndex: activeLayerIndex, applyConfig: applyConfig, readOnly: readOnly }) })] }, "appearance-fill-extrusion")) : hasFillColor ? (_jsx(AppearanceColorChannel, { accessor: "getFillColor", layer: activeLayer, columns: dataOutputColumns, mapConfig: mapConfig, layerIndex: activeLayerIndex, applyConfig: applyConfig, lastColorScaleFieldsRef: lastColorScaleFieldsRef, readOnly: readOnly, ...fillRadiusProps })) : null, hasSourceColor && hasTargetColor ? (_jsx(AppearanceArcColorPanel, { layer: activeLayer, columns: dataOutputColumns, mapConfig: mapConfig, layerIndex: activeLayerIndex, applyConfig: applyConfig, lastColorScaleFieldsRef: lastColorScaleFieldsRef, readOnly: readOnly })) : null, hasPathColor ? (_jsx(AppearanceColorChannel, { accessor: "getColor", layer: activeLayer, columns: dataOutputColumns, mapConfig: mapConfig, layerIndex: activeLayerIndex, applyConfig: applyConfig, lastColorScaleFieldsRef: lastColorScaleFieldsRef, readOnly: readOnly })) : null] })) }) })), outputColumns.length > 0 && showGeometryColumnSetting && (_jsx(ColumnsProvider, { columns: outputColumns, children: _jsx(Field, { label: "Geometry column", required: true, children: _jsx(ColumnSelector, { value: activeLayerDataset?.geometryColumn, onChange: (geometryColumn) => applyConfig(setDeckMapLayerGeometryColumn(mapConfig, activeLayerIndex, geometryColumn)), placeholder: "Select geometry column...", disabled: readOnly }) }) })), outputColumns.length > 0 && showTripsSettings && (_jsx(ColumnsProvider, { columns: outputColumns, children: _jsx(Field, { label: "Timestamp column", required: true, children: _jsx(ColumnSelector, { value: activeLayer?._sqlroomsBinding?.timestampColumn, onChange: (timestampColumn) => applyConfig(setDeckMapLayerTimestampColumn(mapConfig, activeLayerIndex, timestampColumn)), placeholder: "Select timestamp column...", disabled: readOnly }) }) })), outputColumns.length > 0 && showH3ColumnSetting && (_jsx(ColumnsProvider, { columns: outputColumns, children: _jsx(Field, { label: "H3 column", required: true, children: _jsx(ColumnSelector, { value: activeLayer?._sqlroomsBinding?.hexagonColumn, onChange: (hexagonColumn) => applyConfig(setDeckMapLayerHexagonColumn(mapConfig, activeLayerIndex, hexagonColumn)), placeholder: "Select H3 index column...", disabled: readOnly }) }) })), outputColumns.length > 0 && showArcColumnSetting && (_jsxs(ColumnsProvider, { columns: outputColumns, children: [_jsx(Field, { label: "Source geometry", required: true, children: _jsx(ColumnSelector, { value: activeLayer?._sqlroomsBinding?.sourceGeometryColumn, onChange: (sourceGeometryColumn) => applyConfig(setDeckMapLayerArcColumns(mapConfig, activeLayerIndex, {
|
|
648
|
+
sourceGeometryColumn,
|
|
649
|
+
})), placeholder: "Select source geometry...", disabled: readOnly }) }), _jsx(Field, { label: "Target geometry", required: true, children: _jsx(ColumnSelector, { value: activeLayer?._sqlroomsBinding?.targetGeometryColumn, onChange: (targetGeometryColumn) => applyConfig(setDeckMapLayerArcColumns(mapConfig, activeLayerIndex, {
|
|
650
|
+
targetGeometryColumn,
|
|
651
|
+
})), placeholder: "Select target geometry...", disabled: readOnly }) })] }))] })), sourceDataTable &&
|
|
296
652
|
!showGeometryColumnSetting &&
|
|
297
653
|
!showH3ColumnSetting &&
|
|
298
654
|
!showArcColumnSetting && (_jsxs(ColumnsProvider, { columns: sourceColumns, children: [_jsx(Field, { label: "Latitude column", required: true, children: _jsx(ColumnSelector.Numeric, { value: mapConfig.fitToData?.latitudeColumn, onChange: (latitudeColumn) => {
|