@sqlrooms/deck 0.29.0-rc.5 → 0.29.0-rc.6
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 +24 -2
- package/dist/DeckJsonMap.d.ts +1 -1
- package/dist/DeckJsonMap.d.ts.map +1 -1
- package/dist/DeckJsonMap.js +16 -11
- package/dist/DeckJsonMap.js.map +1 -1
- package/dist/LatitudeSelector.d.ts +11 -0
- package/dist/LatitudeSelector.d.ts.map +1 -0
- package/dist/LatitudeSelector.js +25 -0
- package/dist/LatitudeSelector.js.map +1 -0
- package/dist/LongitudeSelector.d.ts +11 -0
- package/dist/LongitudeSelector.d.ts.map +1 -0
- package/dist/LongitudeSelector.js +27 -0
- package/dist/LongitudeSelector.js.map +1 -0
- package/dist/MapSettings.d.ts +10 -0
- package/dist/MapSettings.d.ts.map +1 -0
- package/dist/MapSettings.js +96 -0
- package/dist/MapSettings.js.map +1 -0
- package/dist/ai.d.ts +168 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +232 -0
- package/dist/ai.js.map +1 -0
- package/dist/dashboard.d.ts.map +1 -1
- package/dist/dashboard.js +72 -105
- package/dist/dashboard.js.map +1 -1
- package/dist/dashboardConfig.d.ts +22 -6
- package/dist/dashboardConfig.d.ts.map +1 -1
- package/dist/dashboardConfig.js +2 -5
- package/dist/dashboardConfig.js.map +1 -1
- package/dist/dashboardIntegration.d.ts +3 -0
- package/dist/dashboardIntegration.d.ts.map +1 -0
- package/dist/dashboardIntegration.js +16 -0
- package/dist/dashboardIntegration.js.map +1 -0
- package/dist/datasets/PreparedDatasetStore.js +2 -1
- package/dist/datasets/PreparedDatasetStore.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/json/colorScaleFunction.d.ts +1 -1
- package/dist/json/colorScaleFunction.d.ts.map +1 -1
- package/dist/json/colorScaleFunction.js +7 -1
- package/dist/json/colorScaleFunction.js.map +1 -1
- package/dist/json/extractColorScaleLegends.d.ts.map +1 -1
- package/dist/json/extractColorScaleLegends.js +0 -1
- package/dist/json/extractColorScaleLegends.js.map +1 -1
- package/dist/json/layerCompatibility.d.ts.map +1 -1
- package/dist/json/layerCompatibility.js +2 -0
- package/dist/json/layerCompatibility.js.map +1 -1
- package/dist/mapConfigUtils.d.ts +62 -0
- package/dist/mapConfigUtils.d.ts.map +1 -0
- package/dist/mapConfigUtils.js +233 -0
- package/dist/mapConfigUtils.js.map +1 -0
- package/dist/mapDataPolicy.d.ts +4 -0
- package/dist/mapDataPolicy.d.ts.map +1 -0
- package/dist/mapDataPolicy.js +25 -0
- package/dist/mapDataPolicy.js.map +1 -0
- package/dist/mapLayerConfigUtils.d.ts +38 -0
- package/dist/mapLayerConfigUtils.d.ts.map +1 -0
- package/dist/mapLayerConfigUtils.js +185 -0
- package/dist/mapLayerConfigUtils.js.map +1 -0
- package/dist/prepare/wkbDecoder.d.ts.map +1 -1
- package/dist/prepare/wkbDecoder.js +266 -67
- package/dist/prepare/wkbDecoder.js.map +1 -1
- package/dist/prepare/wkbParser.d.ts +19 -0
- package/dist/prepare/wkbParser.d.ts.map +1 -0
- package/dist/prepare/wkbParser.js +115 -0
- package/dist/prepare/wkbParser.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +8 -6
- package/dist/useDeckLayersReadyRedraw.d.ts +0 -13
- package/dist/useDeckLayersReadyRedraw.d.ts.map +0 -1
- package/dist/useDeckLayersReadyRedraw.js +0 -35
- package/dist/useDeckLayersReadyRedraw.js.map +0 -1
package/README.md
CHANGED
|
@@ -204,6 +204,7 @@ payload in React.
|
|
|
204
204
|
|
|
205
205
|
- `spec`: a JSON-like deck.gl spec object or JSON string
|
|
206
206
|
- `datasets`: a dataset registry keyed by dataset id
|
|
207
|
+
- `interleaved`: when true, deck layers insert into MapLibre's layer stack (requires WebGL2). Default: `false`
|
|
207
208
|
- `deckProps`: runtime-only deck props such as `getTooltip`, `onHover`, `onClick`
|
|
208
209
|
- `mapProps`: runtime-only MapLibre props
|
|
209
210
|
- `showLegends`: whether SQLRooms-generated color legends should render
|
|
@@ -211,6 +212,15 @@ payload in React.
|
|
|
211
212
|
`spec` stays serializable; callbacks and runtime behavior belong in `deckProps`
|
|
212
213
|
or `mapProps`.
|
|
213
214
|
|
|
215
|
+
By default, MapLibre is the root and deck.gl renders in a separate overlay
|
|
216
|
+
canvas via `MapboxOverlay`. MapLibre controls and attribution remain accessible.
|
|
217
|
+
Set `interleaved` to `true` to insert deck layers into MapLibre's layer stack
|
|
218
|
+
(e.g. render points under map labels). This requires WebGL2 (MapLibre GL v3+).
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
<DeckJsonMap spec={spec} datasets={datasets} interleaved />
|
|
222
|
+
```
|
|
223
|
+
|
|
214
224
|
### Dataset Registry
|
|
215
225
|
|
|
216
226
|
Each SQLRooms-managed layer binds to exactly one dataset through
|
|
@@ -259,6 +269,17 @@ For in-memory Arrow datasets, `arrowTable` may be temporarily `undefined` while
|
|
|
259
269
|
data is still loading. `DeckJsonMap` will keep rendering the basemap and treat
|
|
260
270
|
that dataset as loading until a table is provided.
|
|
261
271
|
|
|
272
|
+
Use `onDatasetStatesChange` when the surrounding UI needs dataset loading,
|
|
273
|
+
ready, or error state:
|
|
274
|
+
|
|
275
|
+
```tsx
|
|
276
|
+
<DeckJsonMap
|
|
277
|
+
spec={spec}
|
|
278
|
+
datasets={datasets}
|
|
279
|
+
onDatasetStatesChange={(states) => setDatasetStates(states)}
|
|
280
|
+
/>
|
|
281
|
+
```
|
|
282
|
+
|
|
262
283
|
## SQLRooms Layer Bindings
|
|
263
284
|
|
|
264
285
|
SQLRooms-specific layer metadata lives under `_sqlroomsBinding`:
|
|
@@ -403,9 +424,10 @@ The current curated layer set is:
|
|
|
403
424
|
- `GeoJsonLayer`
|
|
404
425
|
|
|
405
426
|
GeoArrow-native geometry columns are the efficient path. WKB/WKT geometry falls
|
|
406
|
-
back to decoding and GeoJSON-binary preparation, with
|
|
427
|
+
back to decoding and GeoJSON-binary preparation, with promotion available
|
|
407
428
|
for point-focused GeoArrow layers such as `GeoArrowScatterplotLayer`,
|
|
408
|
-
`GeoArrowHeatmapLayer`, and `GeoArrowColumnLayer
|
|
429
|
+
`GeoArrowHeatmapLayer`, and `GeoArrowColumnLayer`, plus polygon promotion for
|
|
430
|
+
`GeoArrowPolygonLayer` and `GeoArrowSolidPolygonLayer`.
|
|
409
431
|
|
|
410
432
|
The GeoArrow layer implementations themselves come from
|
|
411
433
|
[`@geoarrow/deck.gl-layers`](https://github.com/geoarrow/deck.gl-layers).
|
package/dist/DeckJsonMap.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
2
2
|
import type { DeckJsonMapProps } from './types';
|
|
3
|
-
export declare function DeckJsonMap({ spec, datasets, mapStyle, deckProps, mapProps, showLegends, className, children, }: DeckJsonMapProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
export declare function DeckJsonMap({ spec, datasets, mapStyle, interleaved, deckProps, mapProps, showLegends, className, children, onDatasetStatesChange, }: DeckJsonMapProps): import("react/jsx-runtime").JSX.Element;
|
|
4
4
|
//# sourceMappingURL=DeckJsonMap.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeckJsonMap.d.ts","sourceRoot":"","sources":["../src/DeckJsonMap.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DeckJsonMap.d.ts","sourceRoot":"","sources":["../src/DeckJsonMap.tsx"],"names":[],"mappings":"AAIA,OAAO,kCAAkC,CAAC;AAW1C,OAAO,KAAK,EAAC,gBAAgB,EAA2B,MAAM,SAAS,CAAC;AAoIxE,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,WAAmB,EACnB,SAAS,EACT,QAAQ,EACR,WAAkB,EAClB,SAAS,EACT,QAAQ,EACR,qBAAqB,GACtB,EAAE,gBAAgB,2CAwIlB"}
|
package/dist/DeckJsonMap.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { JSONConverter } from '@deck.gl/json';
|
|
3
|
-
import
|
|
3
|
+
import { MapboxOverlay } from '@deck.gl/mapbox';
|
|
4
4
|
import { ColorScaleLegend } from '@sqlrooms/color-scales';
|
|
5
5
|
import { cn, useTheme } from '@sqlrooms/ui';
|
|
6
6
|
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
7
7
|
import { useEffect, useMemo, useRef } from 'react';
|
|
8
|
-
import Map from 'react-map-gl/maplibre';
|
|
8
|
+
import Map, { useControl } from 'react-map-gl/maplibre';
|
|
9
9
|
import { DeckJsonMapSpec } from './DeckJsonMapSpec';
|
|
10
10
|
import { normalizeDatasets } from './datasets/normalizeDatasets';
|
|
11
11
|
import { usePreparedDatasetStates } from './datasets/usePreparedDatasetStates';
|
|
@@ -13,7 +13,6 @@ import { createDeckJsonConfiguration } from './json/createDeckJsonConfiguration'
|
|
|
13
13
|
import { extractColorScaleLegends } from './json/extractColorScaleLegends';
|
|
14
14
|
import { getLayerCompatibility } from './json/layerCompatibility';
|
|
15
15
|
import { resolveDatasetId } from './json/layerConfig';
|
|
16
|
-
import { useDeckLayersReadyRedraw } from './useDeckLayersReadyRedraw';
|
|
17
16
|
const DEFAULT_MAP_STYLES = {
|
|
18
17
|
light: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
|
|
19
18
|
dark: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',
|
|
@@ -93,10 +92,16 @@ function renderDatasetErrorOverlay(datasetStates) {
|
|
|
93
92
|
}
|
|
94
93
|
return (_jsx("div", { className: "pointer-events-none absolute inset-x-4 top-4 z-10 space-y-2", children: failedDatasets.map(([datasetId, state]) => (_jsx("div", { className: "rounded-md border border-red-200 bg-red-50/95 px-3 py-2 text-sm text-red-700 shadow-sm", children: `Dataset "${datasetId}" failed: ${state.error.message}` }, datasetId))) }));
|
|
95
94
|
}
|
|
96
|
-
|
|
95
|
+
function DeckOverlayControl({ interleaved, ...deckProps }) {
|
|
96
|
+
const overlay = useControl(() => new MapboxOverlay({ interleaved }));
|
|
97
|
+
overlay.setProps(deckProps);
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
export function DeckJsonMap({ spec, datasets, mapStyle, interleaved = false, deckProps, mapProps, showLegends = true, className, children, onDatasetStatesChange, }) {
|
|
97
101
|
const normalizedDatasets = useMemo(() => normalizeDatasets(datasets), [datasets]);
|
|
98
102
|
const datasetIds = useMemo(() => Object.keys(normalizedDatasets), [normalizedDatasets]);
|
|
99
103
|
const datasetStates = usePreparedDatasetStates(normalizedDatasets);
|
|
104
|
+
const onDatasetStatesChangeRef = useRef(onDatasetStatesChange);
|
|
100
105
|
const { spec: parsedSpec, error: specError } = useMemo(() => parseSpec(spec), [spec]);
|
|
101
106
|
const availableSpec = useMemo(() => parsedSpec
|
|
102
107
|
? filterUnavailableLayers(parsedSpec, datasetIds, datasetStates)
|
|
@@ -130,6 +135,12 @@ export function DeckJsonMap({ spec, datasets, mapStyle, deckProps, mapProps, sho
|
|
|
130
135
|
console.error(convertedDeckPropsResult.error);
|
|
131
136
|
}
|
|
132
137
|
}, [convertedDeckPropsResult.error]);
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
onDatasetStatesChangeRef.current = onDatasetStatesChange;
|
|
140
|
+
}, [onDatasetStatesChange]);
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
onDatasetStatesChangeRef.current?.(datasetStates);
|
|
143
|
+
}, [datasetStates]);
|
|
133
144
|
const fallbackDeckProps = useMemo(() => extractFallbackDeckProps(availableSpec), [availableSpec]);
|
|
134
145
|
const convertedDeckProps = (convertedDeckPropsResult.props ??
|
|
135
146
|
fallbackDeckProps ??
|
|
@@ -137,17 +148,11 @@ export function DeckJsonMap({ spec, datasets, mapStyle, deckProps, mapProps, sho
|
|
|
137
148
|
const extraDeckProps = (deckProps ?? {});
|
|
138
149
|
const extraMapProps = (mapProps ?? {});
|
|
139
150
|
const hasRenderingError = Boolean(convertedDeckPropsResult.error);
|
|
140
|
-
const deckRef = useRef(null);
|
|
141
151
|
const mergedLayers = hasRenderingError
|
|
142
152
|
? []
|
|
143
153
|
: (deckProps?.layers ??
|
|
144
154
|
convertedDeckProps.layers ??
|
|
145
155
|
[]);
|
|
146
|
-
useDeckLayersReadyRedraw({
|
|
147
|
-
deckRef,
|
|
148
|
-
hasRenderingError,
|
|
149
|
-
layers: mergedLayers,
|
|
150
|
-
});
|
|
151
156
|
const mergedDeckProps = {
|
|
152
157
|
...convertedDeckProps,
|
|
153
158
|
...extraDeckProps,
|
|
@@ -165,6 +170,6 @@ export function DeckJsonMap({ spec, datasets, mapStyle, deckProps, mapProps, sho
|
|
|
165
170
|
datasetStates,
|
|
166
171
|
})
|
|
167
172
|
: [], [availableSpec, datasetIds, datasetStates, showLegends]);
|
|
168
|
-
return (_jsxs("div", { className: cn('relative h-full w-full', className), children: [hasRenderingError ? (_jsx("div", { className: "absolute inset-0 z-10 flex items-center justify-center p-4", children: _jsx("div", { className: "max-w-sm rounded-md border border-red-200 bg-red-50/95 p-4 text-sm text-red-700 shadow-sm", children: `Map couldn't be rendered. Check the console for details.` }) })) : null,
|
|
173
|
+
return (_jsxs("div", { className: cn('relative h-full w-full', className), children: [hasRenderingError ? (_jsx("div", { className: "absolute inset-0 z-10 flex items-center justify-center p-4", children: _jsx("div", { className: "max-w-sm rounded-md border border-red-200 bg-red-50/95 p-4 text-sm text-red-700 shadow-sm", children: `Map couldn't be rendered. Check the console for details.` }) })) : null, _jsxs(Map, { ...mergedMapProps, style: { width: '100%', height: '100%', ...mapProps?.style }, children: [_jsx(DeckOverlayControl, { interleaved: interleaved, ...mergedDeckProps }), children] }), renderDatasetErrorOverlay(datasetStates), !hasRenderingError && showLegends ? (_jsx("div", { className: "pointer-events-none absolute bottom-2 left-2 z-10 max-w-56", children: _jsx(ColorScaleLegend, { legends: legends }) })) : null] }));
|
|
169
174
|
}
|
|
170
175
|
//# sourceMappingURL=DeckJsonMap.js.map
|
package/dist/DeckJsonMap.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeckJsonMap.js","sourceRoot":"","sources":["../src/DeckJsonMap.tsx"],"names":[],"mappings":"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","sourcesContent":["import {JSONConverter} from '@deck.gl/json';\nimport type {DeckGLRef} from '@deck.gl/react';\nimport DeckGL from '@deck.gl/react';\nimport {ColorScaleLegend} from '@sqlrooms/color-scales';\nimport {cn, ResolvedTheme, useTheme} from '@sqlrooms/ui';\nimport 'maplibre-gl/dist/maplibre-gl.css';\nimport {useEffect, useMemo, useRef} from 'react';\nimport Map from 'react-map-gl/maplibre';\nimport {ZodError} from 'zod';\nimport {DeckJsonMapSpec} from './DeckJsonMapSpec';\nimport {normalizeDatasets} from './datasets/normalizeDatasets';\nimport {usePreparedDatasetStates} from './datasets/usePreparedDatasetStates';\nimport {createDeckJsonConfiguration} from './json/createDeckJsonConfiguration';\nimport {extractColorScaleLegends} from './json/extractColorScaleLegends';\nimport {getLayerCompatibility} from './json/layerCompatibility';\nimport {resolveDatasetId} from './json/layerConfig';\nimport type {DeckJsonMapProps, PreparedDeckDatasetState} from './types';\nimport {useDeckLayersReadyRedraw} from './useDeckLayersReadyRedraw';\n\nconst DEFAULT_MAP_STYLES: Record<ResolvedTheme, string> = {\n light: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',\n dark: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',\n};\n\nfunction parseSpec(spec: DeckJsonMapProps['spec']) {\n try {\n const parsedValue = typeof spec === 'string' ? JSON.parse(spec) : spec;\n const validatedSpec = DeckJsonMapSpec.safeParse(parsedValue);\n if (!validatedSpec.success) {\n return {\n spec: null,\n error: new Error(formatSpecValidationError(validatedSpec.error)),\n };\n }\n\n return {\n spec: validatedSpec.data,\n error: null,\n };\n } catch (error) {\n return {\n spec: null,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n}\n\nfunction formatSpecValidationError(error: ZodError) {\n const issues = error.issues.map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join('.') : 'spec';\n return `${path}: ${issue.message}`;\n });\n\n return `Invalid DeckJsonMap spec. ${issues.join('; ')}`;\n}\n\nfunction extractFallbackDeckProps(spec: Record<string, unknown> | null) {\n if (!spec) {\n return {};\n }\n\n const fallbackProps: Record<string, unknown> = {};\n for (const key of ['initialViewState', 'viewState', 'controller']) {\n if (key in spec) {\n fallbackProps[key] = spec[key];\n }\n }\n\n return fallbackProps;\n}\n\nfunction filterUnavailableLayers(\n spec: Record<string, unknown>,\n datasetIds: string[],\n datasetStates: Record<string, PreparedDeckDatasetState>,\n) {\n const layers = Array.isArray(spec.layers) ? spec.layers : [];\n const filteredLayers = layers.filter((layer) => {\n if (!layer || typeof layer !== 'object') {\n return true;\n }\n\n const layerProps = layer as Record<string, unknown>;\n const layerName = String(layerProps['@@type'] ?? '');\n const compatibility = getLayerCompatibility(layerName);\n if (!compatibility) {\n return true;\n }\n\n const datasetId = resolveDatasetId(layerProps, datasetIds);\n if (!datasetId) {\n return true;\n }\n\n const datasetState = datasetStates[datasetId];\n if (!datasetState) {\n return false;\n }\n\n return datasetState.status === 'ready';\n });\n\n return {\n ...spec,\n layers: filteredLayers,\n };\n}\n\nfunction renderDatasetErrorOverlay(\n datasetStates: Record<string, PreparedDeckDatasetState>,\n) {\n const failedDatasets = Object.entries(datasetStates).filter(\n (\n entry,\n ): entry is [\n string,\n Extract<PreparedDeckDatasetState, {status: 'error'}>,\n ] => entry[1].status === 'error',\n );\n\n if (!failedDatasets.length) {\n return null;\n }\n\n return (\n <div className=\"pointer-events-none absolute inset-x-4 top-4 z-10 space-y-2\">\n {failedDatasets.map(([datasetId, state]) => (\n <div\n key={datasetId}\n className=\"rounded-md border border-red-200 bg-red-50/95 px-3 py-2 text-sm text-red-700 shadow-sm\"\n >\n {`Dataset \"${datasetId}\" failed: ${state.error.message}`}\n </div>\n ))}\n </div>\n );\n}\n\nexport function DeckJsonMap({\n spec,\n datasets,\n mapStyle,\n deckProps,\n mapProps,\n showLegends = true,\n className,\n children,\n}: DeckJsonMapProps) {\n const normalizedDatasets = useMemo(\n () => normalizeDatasets(datasets),\n [datasets],\n );\n const datasetIds = useMemo(\n () => Object.keys(normalizedDatasets),\n [normalizedDatasets],\n );\n const datasetStates = usePreparedDatasetStates(normalizedDatasets);\n\n const {spec: parsedSpec, error: specError} = useMemo(\n () => parseSpec(spec),\n [spec],\n );\n\n const availableSpec = useMemo(\n () =>\n parsedSpec\n ? filterUnavailableLayers(parsedSpec, datasetIds, datasetStates)\n : null,\n [parsedSpec, datasetIds, datasetStates],\n );\n\n const converter = useMemo(\n () =>\n new JSONConverter({\n configuration: createDeckJsonConfiguration({\n datasetStates,\n datasetIds,\n }),\n onJSONChange: () => {},\n }),\n [datasetIds, datasetStates],\n );\n\n const convertedDeckPropsResult = useMemo(() => {\n if (!availableSpec) {\n return {props: null, error: specError};\n }\n\n try {\n return {\n props: converter.convert(availableSpec) as Record<string, unknown>,\n error: null,\n };\n } catch (error) {\n return {\n props: null,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n }, [availableSpec, converter, specError]);\n\n useEffect(() => {\n if (convertedDeckPropsResult.error) {\n console.error(convertedDeckPropsResult.error);\n }\n }, [convertedDeckPropsResult.error]);\n\n const fallbackDeckProps = useMemo(\n () => extractFallbackDeckProps(availableSpec),\n [availableSpec],\n );\n const convertedDeckProps = (convertedDeckPropsResult.props ??\n fallbackDeckProps ??\n {}) as Record<string, unknown>;\n const extraDeckProps = (deckProps ?? {}) as Record<string, unknown>;\n const extraMapProps = (mapProps ?? {}) as Record<string, unknown>;\n const hasRenderingError = Boolean(convertedDeckPropsResult.error);\n const deckRef = useRef<DeckGLRef>(null);\n const mergedLayers = hasRenderingError\n ? []\n : (deckProps?.layers ??\n (convertedDeckProps.layers as unknown[] | undefined) ??\n []);\n useDeckLayersReadyRedraw({\n deckRef,\n hasRenderingError,\n layers: mergedLayers,\n });\n\n const mergedDeckProps = {\n ...convertedDeckProps,\n ...extraDeckProps,\n layers: mergedLayers,\n };\n\n const {resolvedTheme} = useTheme();\n\n const mergedMapProps = {\n ...extraMapProps,\n mapStyle:\n mapStyle ?? mapProps?.mapStyle ?? DEFAULT_MAP_STYLES[resolvedTheme],\n };\n const legends = useMemo(\n () =>\n showLegends\n ? extractColorScaleLegends({\n spec: availableSpec,\n datasetIds,\n datasetStates,\n })\n : [],\n [availableSpec, datasetIds, datasetStates, showLegends],\n );\n\n return (\n <div className={cn('relative h-full w-full', className)}>\n {hasRenderingError ? (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center p-4\">\n <div className=\"max-w-sm rounded-md border border-red-200 bg-red-50/95 p-4 text-sm text-red-700 shadow-sm\">\n {`Map couldn't be rendered. Check the console for details.`}\n </div>\n </div>\n ) : null}\n\n <DeckGL ref={deckRef} {...(mergedDeckProps as object)}>\n <Map {...(mergedMapProps as object)}>{children}</Map>\n </DeckGL>\n\n {renderDatasetErrorOverlay(datasetStates)}\n {!hasRenderingError && showLegends ? (\n <div className=\"pointer-events-none absolute bottom-2 left-2 z-10 max-w-56\">\n <ColorScaleLegend legends={legends} />\n </div>\n ) : null}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"DeckJsonMap.js","sourceRoot":"","sources":["../src/DeckJsonMap.tsx"],"names":[],"mappings":"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","sourcesContent":["import {JSONConverter} from '@deck.gl/json';\nimport {MapboxOverlay} from '@deck.gl/mapbox';\nimport {ColorScaleLegend} from '@sqlrooms/color-scales';\nimport {cn, ResolvedTheme, useTheme} from '@sqlrooms/ui';\nimport 'maplibre-gl/dist/maplibre-gl.css';\nimport {useEffect, useMemo, useRef} from 'react';\nimport Map, {useControl} from 'react-map-gl/maplibre';\nimport {ZodError} from 'zod';\nimport {DeckJsonMapSpec} from './DeckJsonMapSpec';\nimport {normalizeDatasets} from './datasets/normalizeDatasets';\nimport {usePreparedDatasetStates} from './datasets/usePreparedDatasetStates';\nimport {createDeckJsonConfiguration} from './json/createDeckJsonConfiguration';\nimport {extractColorScaleLegends} from './json/extractColorScaleLegends';\nimport {getLayerCompatibility} from './json/layerCompatibility';\nimport {resolveDatasetId} from './json/layerConfig';\nimport type {DeckJsonMapProps, PreparedDeckDatasetState} from './types';\n\nconst DEFAULT_MAP_STYLES: Record<ResolvedTheme, string> = {\n light: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',\n dark: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',\n};\n\nfunction parseSpec(spec: DeckJsonMapProps['spec']) {\n try {\n const parsedValue = typeof spec === 'string' ? JSON.parse(spec) : spec;\n const validatedSpec = DeckJsonMapSpec.safeParse(parsedValue);\n if (!validatedSpec.success) {\n return {\n spec: null,\n error: new Error(formatSpecValidationError(validatedSpec.error)),\n };\n }\n\n return {\n spec: validatedSpec.data,\n error: null,\n };\n } catch (error) {\n return {\n spec: null,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n}\n\nfunction formatSpecValidationError(error: ZodError) {\n const issues = error.issues.map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join('.') : 'spec';\n return `${path}: ${issue.message}`;\n });\n\n return `Invalid DeckJsonMap spec. ${issues.join('; ')}`;\n}\n\nfunction extractFallbackDeckProps(spec: Record<string, unknown> | null) {\n if (!spec) {\n return {};\n }\n\n const fallbackProps: Record<string, unknown> = {};\n for (const key of ['initialViewState', 'viewState', 'controller']) {\n if (key in spec) {\n fallbackProps[key] = spec[key];\n }\n }\n\n return fallbackProps;\n}\n\nfunction filterUnavailableLayers(\n spec: Record<string, unknown>,\n datasetIds: string[],\n datasetStates: Record<string, PreparedDeckDatasetState>,\n) {\n const layers = Array.isArray(spec.layers) ? spec.layers : [];\n const filteredLayers = layers.filter((layer) => {\n if (!layer || typeof layer !== 'object') {\n return true;\n }\n\n const layerProps = layer as Record<string, unknown>;\n const layerName = String(layerProps['@@type'] ?? '');\n const compatibility = getLayerCompatibility(layerName);\n if (!compatibility) {\n return true;\n }\n\n const datasetId = resolveDatasetId(layerProps, datasetIds);\n if (!datasetId) {\n return true;\n }\n\n const datasetState = datasetStates[datasetId];\n if (!datasetState) {\n return false;\n }\n\n return datasetState.status === 'ready';\n });\n\n return {\n ...spec,\n layers: filteredLayers,\n };\n}\n\nfunction renderDatasetErrorOverlay(\n datasetStates: Record<string, PreparedDeckDatasetState>,\n) {\n const failedDatasets = Object.entries(datasetStates).filter(\n (\n entry,\n ): entry is [\n string,\n Extract<PreparedDeckDatasetState, {status: 'error'}>,\n ] => entry[1].status === 'error',\n );\n\n if (!failedDatasets.length) {\n return null;\n }\n\n return (\n <div className=\"pointer-events-none absolute inset-x-4 top-4 z-10 space-y-2\">\n {failedDatasets.map(([datasetId, state]) => (\n <div\n key={datasetId}\n className=\"rounded-md border border-red-200 bg-red-50/95 px-3 py-2 text-sm text-red-700 shadow-sm\"\n >\n {`Dataset \"${datasetId}\" failed: ${state.error.message}`}\n </div>\n ))}\n </div>\n );\n}\n\nfunction DeckOverlayControl({\n interleaved,\n ...deckProps\n}: {interleaved: boolean} & Record<string, unknown>) {\n const overlay = useControl<MapboxOverlay>(\n () => new MapboxOverlay({interleaved}),\n );\n overlay.setProps(deckProps);\n return null;\n}\n\nexport function DeckJsonMap({\n spec,\n datasets,\n mapStyle,\n interleaved = false,\n deckProps,\n mapProps,\n showLegends = true,\n className,\n children,\n onDatasetStatesChange,\n}: DeckJsonMapProps) {\n const normalizedDatasets = useMemo(\n () => normalizeDatasets(datasets),\n [datasets],\n );\n const datasetIds = useMemo(\n () => Object.keys(normalizedDatasets),\n [normalizedDatasets],\n );\n const datasetStates = usePreparedDatasetStates(normalizedDatasets);\n const onDatasetStatesChangeRef = useRef(onDatasetStatesChange);\n\n const {spec: parsedSpec, error: specError} = useMemo(\n () => parseSpec(spec),\n [spec],\n );\n\n const availableSpec = useMemo(\n () =>\n parsedSpec\n ? filterUnavailableLayers(parsedSpec, datasetIds, datasetStates)\n : null,\n [parsedSpec, datasetIds, datasetStates],\n );\n\n const converter = useMemo(\n () =>\n new JSONConverter({\n configuration: createDeckJsonConfiguration({\n datasetStates,\n datasetIds,\n }),\n onJSONChange: () => {},\n }),\n [datasetIds, datasetStates],\n );\n\n const convertedDeckPropsResult = useMemo(() => {\n if (!availableSpec) {\n return {props: null, error: specError};\n }\n\n try {\n return {\n props: converter.convert(availableSpec) as Record<string, unknown>,\n error: null,\n };\n } catch (error) {\n return {\n props: null,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n }, [availableSpec, converter, specError]);\n\n useEffect(() => {\n if (convertedDeckPropsResult.error) {\n console.error(convertedDeckPropsResult.error);\n }\n }, [convertedDeckPropsResult.error]);\n\n useEffect(() => {\n onDatasetStatesChangeRef.current = onDatasetStatesChange;\n }, [onDatasetStatesChange]);\n\n useEffect(() => {\n onDatasetStatesChangeRef.current?.(datasetStates);\n }, [datasetStates]);\n\n const fallbackDeckProps = useMemo(\n () => extractFallbackDeckProps(availableSpec),\n [availableSpec],\n );\n const convertedDeckProps = (convertedDeckPropsResult.props ??\n fallbackDeckProps ??\n {}) as Record<string, unknown>;\n const extraDeckProps = (deckProps ?? {}) as Record<string, unknown>;\n const extraMapProps = (mapProps ?? {}) as Record<string, unknown>;\n const hasRenderingError = Boolean(convertedDeckPropsResult.error);\n const mergedLayers = hasRenderingError\n ? []\n : (deckProps?.layers ??\n (convertedDeckProps.layers as unknown[] | undefined) ??\n []);\n\n const mergedDeckProps = {\n ...convertedDeckProps,\n ...extraDeckProps,\n layers: mergedLayers,\n };\n\n const {resolvedTheme} = useTheme();\n\n const mergedMapProps = {\n ...extraMapProps,\n mapStyle:\n mapStyle ?? mapProps?.mapStyle ?? DEFAULT_MAP_STYLES[resolvedTheme],\n };\n const legends = useMemo(\n () =>\n showLegends\n ? extractColorScaleLegends({\n spec: availableSpec,\n datasetIds,\n datasetStates,\n })\n : [],\n [availableSpec, datasetIds, datasetStates, showLegends],\n );\n\n return (\n <div className={cn('relative h-full w-full', className)}>\n {hasRenderingError ? (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center p-4\">\n <div className=\"max-w-sm rounded-md border border-red-200 bg-red-50/95 p-4 text-sm text-red-700 shadow-sm\">\n {`Map couldn't be rendered. Check the console for details.`}\n </div>\n </div>\n ) : null}\n\n <Map\n {...(mergedMapProps as object)}\n style={{width: '100%', height: '100%', ...mapProps?.style}}\n >\n <DeckOverlayControl interleaved={interleaved} {...mergedDeckProps} />\n {children}\n </Map>\n\n {renderDatasetErrorOverlay(datasetStates)}\n {!hasRenderingError && showLegends ? (\n <div className=\"pointer-events-none absolute bottom-2 left-2 z-10 max-w-56\">\n <ColorScaleLegend legends={legends} />\n </div>\n ) : null}\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import type { MosaicDashboardPanelConfigType } from '@sqlrooms/mosaic';
|
|
3
|
+
import type { DataTable } from '@sqlrooms/duckdb';
|
|
4
|
+
interface LatitudeSelectorProps {
|
|
5
|
+
dashboardId: string;
|
|
6
|
+
panel: MosaicDashboardPanelConfigType;
|
|
7
|
+
currentTable: DataTable;
|
|
8
|
+
}
|
|
9
|
+
export declare const LatitudeSelector: FC<LatitudeSelectorProps>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=LatitudeSelector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LatitudeSelector.d.ts","sourceRoot":"","sources":["../src/LatitudeSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,EAAE,EAAc,MAAM,OAAO,CAAC;AAEtC,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAC;AAIhD,UAAU,qBAAqB;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,8BAA8B,CAAC;IACtC,YAAY,EAAE,SAAS,CAAC;CACzB;AAED,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CA0CtD,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { useStoreWithMosaicDashboard, ColumnSelector } from '@sqlrooms/mosaic';
|
|
4
|
+
import { regenerateMapConfigForTable } from './mapConfigUtils';
|
|
5
|
+
export const LatitudeSelector = ({ dashboardId, panel, currentTable, }) => {
|
|
6
|
+
const updatePanel = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.updatePanel);
|
|
7
|
+
const mapConfig = panel.config;
|
|
8
|
+
const currentLongitudeColumn = mapConfig?.fitToData?.longitudeColumn;
|
|
9
|
+
const currentLatitudeColumn = mapConfig?.fitToData?.latitudeColumn;
|
|
10
|
+
const handleChange = useCallback((latitudeColumn) => {
|
|
11
|
+
const newConfig = regenerateMapConfigForTable(panel, currentTable, currentLongitudeColumn, latitudeColumn);
|
|
12
|
+
updatePanel(dashboardId, panel.id, {
|
|
13
|
+
config: { ...newConfig, settingsOpen: mapConfig?.settingsOpen },
|
|
14
|
+
});
|
|
15
|
+
}, [
|
|
16
|
+
currentLongitudeColumn,
|
|
17
|
+
panel,
|
|
18
|
+
currentTable,
|
|
19
|
+
updatePanel,
|
|
20
|
+
dashboardId,
|
|
21
|
+
mapConfig?.settingsOpen,
|
|
22
|
+
]);
|
|
23
|
+
return (_jsx(ColumnSelector.Numeric, { value: currentLatitudeColumn, onChange: handleChange }));
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=LatitudeSelector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LatitudeSelector.js","sourceRoot":"","sources":["../src/LatitudeSelector.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAK,WAAW,EAAC,MAAM,OAAO,CAAC;AACtC,OAAO,EAAC,2BAA2B,EAAE,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAG7E,OAAO,EAAC,2BAA2B,EAAC,MAAM,kBAAkB,CAAC;AAS7D,MAAM,CAAC,MAAM,gBAAgB,GAA8B,CAAC,EAC1D,WAAW,EACX,KAAK,EACL,YAAY,GACb,EAAE,EAAE;IACH,MAAM,WAAW,GAAG,2BAA2B,CAC7C,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,WAAW,CAC7C,CAAC;IAEF,MAAM,SAAS,GAAG,KAAK,CAAC,MAAqC,CAAC;IAC9D,MAAM,sBAAsB,GAAG,SAAS,EAAE,SAAS,EAAE,eAAe,CAAC;IACrE,MAAM,qBAAqB,GAAG,SAAS,EAAE,SAAS,EAAE,cAAc,CAAC;IAEnE,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,cAAsB,EAAE,EAAE;QACzB,MAAM,SAAS,GAAG,2BAA2B,CAC3C,KAAK,EACL,YAAY,EACZ,sBAAsB,EACtB,cAAc,CACf,CAAC;QAEF,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,EAAE;YACjC,MAAM,EAAE,EAAC,GAAG,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAQ;SACrE,CAAC,CAAC;IACL,CAAC,EACD;QACE,sBAAsB;QACtB,KAAK;QACL,YAAY;QACZ,WAAW;QACX,WAAW;QACX,SAAS,EAAE,YAAY;KACxB,CACF,CAAC;IAEF,OAAO,CACL,KAAC,cAAc,CAAC,OAAO,IACrB,KAAK,EAAE,qBAAqB,EAC5B,QAAQ,EAAE,YAAY,GACtB,CACH,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {FC, useCallback} from 'react';\nimport {useStoreWithMosaicDashboard, ColumnSelector} from '@sqlrooms/mosaic';\nimport type {MosaicDashboardPanelConfigType} from '@sqlrooms/mosaic';\nimport type {DataTable} from '@sqlrooms/duckdb';\nimport {regenerateMapConfigForTable} from './mapConfigUtils';\nimport {DeckMapDashboardPanelConfig} from './dashboardConfig';\n\ninterface LatitudeSelectorProps {\n dashboardId: string;\n panel: MosaicDashboardPanelConfigType;\n currentTable: DataTable;\n}\n\nexport const LatitudeSelector: FC<LatitudeSelectorProps> = ({\n dashboardId,\n panel,\n currentTable,\n}) => {\n const updatePanel = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.updatePanel,\n );\n\n const mapConfig = panel.config as DeckMapDashboardPanelConfig;\n const currentLongitudeColumn = mapConfig?.fitToData?.longitudeColumn;\n const currentLatitudeColumn = mapConfig?.fitToData?.latitudeColumn;\n\n const handleChange = useCallback(\n (latitudeColumn: string) => {\n const newConfig = regenerateMapConfigForTable(\n panel,\n currentTable,\n currentLongitudeColumn,\n latitudeColumn,\n );\n\n updatePanel(dashboardId, panel.id, {\n config: {...newConfig, settingsOpen: mapConfig?.settingsOpen} as any,\n });\n },\n [\n currentLongitudeColumn,\n panel,\n currentTable,\n updatePanel,\n dashboardId,\n mapConfig?.settingsOpen,\n ],\n );\n\n return (\n <ColumnSelector.Numeric\n value={currentLatitudeColumn}\n onChange={handleChange}\n />\n );\n};\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import type { MosaicDashboardPanelConfigType } from '@sqlrooms/mosaic';
|
|
3
|
+
import type { DataTable } from '@sqlrooms/duckdb';
|
|
4
|
+
interface LongitudeSelectorProps {
|
|
5
|
+
dashboardId: string;
|
|
6
|
+
panel: MosaicDashboardPanelConfigType;
|
|
7
|
+
currentTable: DataTable;
|
|
8
|
+
}
|
|
9
|
+
export declare const LongitudeSelector: FC<LongitudeSelectorProps>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=LongitudeSelector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LongitudeSelector.d.ts","sourceRoot":"","sources":["../src/LongitudeSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,EAAE,EAAc,MAAM,OAAO,CAAC;AAEtC,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAC;AAIhD,UAAU,sBAAsB;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,8BAA8B,CAAC;IACtC,YAAY,EAAE,SAAS,CAAC;CACzB;AAED,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CA4CxD,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { useStoreWithMosaicDashboard, ColumnSelector } from '@sqlrooms/mosaic';
|
|
4
|
+
import { regenerateMapConfigForTable } from './mapConfigUtils';
|
|
5
|
+
export const LongitudeSelector = ({ dashboardId, panel, currentTable, }) => {
|
|
6
|
+
const updatePanel = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.updatePanel);
|
|
7
|
+
const mapConfig = panel.config;
|
|
8
|
+
const currentLongitudeColumn = mapConfig?.fitToData?.longitudeColumn;
|
|
9
|
+
const currentLatitudeColumn = mapConfig?.fitToData?.latitudeColumn;
|
|
10
|
+
const handleChange = useCallback((longitudeColumn) => {
|
|
11
|
+
if (!currentLatitudeColumn)
|
|
12
|
+
return;
|
|
13
|
+
const newConfig = regenerateMapConfigForTable(panel, currentTable, longitudeColumn, currentLatitudeColumn);
|
|
14
|
+
updatePanel(dashboardId, panel.id, {
|
|
15
|
+
config: { ...newConfig, settingsOpen: mapConfig?.settingsOpen },
|
|
16
|
+
});
|
|
17
|
+
}, [
|
|
18
|
+
currentLatitudeColumn,
|
|
19
|
+
panel,
|
|
20
|
+
currentTable,
|
|
21
|
+
updatePanel,
|
|
22
|
+
dashboardId,
|
|
23
|
+
mapConfig?.settingsOpen,
|
|
24
|
+
]);
|
|
25
|
+
return (_jsx(ColumnSelector.Numeric, { value: currentLongitudeColumn, onChange: handleChange }));
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=LongitudeSelector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LongitudeSelector.js","sourceRoot":"","sources":["../src/LongitudeSelector.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAK,WAAW,EAAC,MAAM,OAAO,CAAC;AACtC,OAAO,EAAC,2BAA2B,EAAE,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAG7E,OAAO,EAAC,2BAA2B,EAAC,MAAM,kBAAkB,CAAC;AAS7D,MAAM,CAAC,MAAM,iBAAiB,GAA+B,CAAC,EAC5D,WAAW,EACX,KAAK,EACL,YAAY,GACb,EAAE,EAAE;IACH,MAAM,WAAW,GAAG,2BAA2B,CAC7C,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,WAAW,CAC7C,CAAC;IAEF,MAAM,SAAS,GAAG,KAAK,CAAC,MAAqC,CAAC;IAC9D,MAAM,sBAAsB,GAAG,SAAS,EAAE,SAAS,EAAE,eAAe,CAAC;IACrE,MAAM,qBAAqB,GAAG,SAAS,EAAE,SAAS,EAAE,cAAc,CAAC;IAEnE,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,eAAuB,EAAE,EAAE;QAC1B,IAAI,CAAC,qBAAqB;YAAE,OAAO;QAEnC,MAAM,SAAS,GAAG,2BAA2B,CAC3C,KAAK,EACL,YAAY,EACZ,eAAe,EACf,qBAAqB,CACtB,CAAC;QAEF,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,EAAE;YACjC,MAAM,EAAE,EAAC,GAAG,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAQ;SACrE,CAAC,CAAC;IACL,CAAC,EACD;QACE,qBAAqB;QACrB,KAAK;QACL,YAAY;QACZ,WAAW;QACX,WAAW;QACX,SAAS,EAAE,YAAY;KACxB,CACF,CAAC;IAEF,OAAO,CACL,KAAC,cAAc,CAAC,OAAO,IACrB,KAAK,EAAE,sBAAsB,EAC7B,QAAQ,EAAE,YAAY,GACtB,CACH,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {FC, useCallback} from 'react';\nimport {useStoreWithMosaicDashboard, ColumnSelector} from '@sqlrooms/mosaic';\nimport type {MosaicDashboardPanelConfigType} from '@sqlrooms/mosaic';\nimport type {DataTable} from '@sqlrooms/duckdb';\nimport {regenerateMapConfigForTable} from './mapConfigUtils';\nimport {DeckMapDashboardPanelConfig} from './dashboardConfig';\n\ninterface LongitudeSelectorProps {\n dashboardId: string;\n panel: MosaicDashboardPanelConfigType;\n currentTable: DataTable;\n}\n\nexport const LongitudeSelector: FC<LongitudeSelectorProps> = ({\n dashboardId,\n panel,\n currentTable,\n}) => {\n const updatePanel = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.updatePanel,\n );\n\n const mapConfig = panel.config as DeckMapDashboardPanelConfig;\n const currentLongitudeColumn = mapConfig?.fitToData?.longitudeColumn;\n const currentLatitudeColumn = mapConfig?.fitToData?.latitudeColumn;\n\n const handleChange = useCallback(\n (longitudeColumn: string) => {\n if (!currentLatitudeColumn) return;\n\n const newConfig = regenerateMapConfigForTable(\n panel,\n currentTable,\n longitudeColumn,\n currentLatitudeColumn,\n );\n\n updatePanel(dashboardId, panel.id, {\n config: {...newConfig, settingsOpen: mapConfig?.settingsOpen} as any,\n });\n },\n [\n currentLatitudeColumn,\n panel,\n currentTable,\n updatePanel,\n dashboardId,\n mapConfig?.settingsOpen,\n ],\n );\n\n return (\n <ColumnSelector.Numeric\n value={currentLongitudeColumn}\n onChange={handleChange}\n />\n );\n};\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import type { MosaicDashboardPanelConfigType } from '@sqlrooms/mosaic';
|
|
3
|
+
interface MapSettingsPanelProps {
|
|
4
|
+
dashboardId: string;
|
|
5
|
+
panel: MosaicDashboardPanelConfigType;
|
|
6
|
+
onClose?: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare const MapSettingsPanel: FC<MapSettingsPanelProps>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=MapSettings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MapSettings.d.ts","sourceRoot":"","sources":["../src/MapSettings.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,EAAE,EAAiC,MAAM,OAAO,CAAC;AAOzD,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,kBAAkB,CAAC;AAwCrE,UAAU,qBAAqB;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,8BAA8B,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAeD,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CAuUtD,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
3
|
+
import { Field, ColumnSelector, ColumnsProvider, useStoreWithMosaicDashboard, } from '@sqlrooms/mosaic';
|
|
4
|
+
import { useStoreWithDuckDb } from '@sqlrooms/duckdb';
|
|
5
|
+
import { binnedNumericSchemes, categoricalSchemes, continuousDivergingSchemes, continuousSequentialSchemes, } from '@sqlrooms/color-scales';
|
|
6
|
+
import { Button, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, } from '@sqlrooms/ui';
|
|
7
|
+
import { XIcon } from 'lucide-react';
|
|
8
|
+
import { LatitudeSelector } from './LatitudeSelector';
|
|
9
|
+
import { LongitudeSelector } from './LongitudeSelector';
|
|
10
|
+
import { DEFAULT_DECK_MAP_MAX_DATA_POINTS } from './dashboardConfig';
|
|
11
|
+
import { clearDeckMapLayerColorScale, createDeckMapLayerColorScale, DECK_MAP_COLOR_SCALE_TYPE_OPTIONS, DECK_MAP_LAYER_TYPE_OPTIONS, getDeckMapColorAccessorOptions, getDeckMapLayerDatasetId, getDeckMapLayerColorScale, getDeckMapLayerRecords, setDeckMapLayerColorScale, setDeckMapLayerGeometryColumn, setDeckMapLayerType, usesGeometryColumnSetting, } from './mapLayerConfigUtils';
|
|
12
|
+
function getSchemeOptions(type) {
|
|
13
|
+
if (type === 'categorical') {
|
|
14
|
+
return categoricalSchemes;
|
|
15
|
+
}
|
|
16
|
+
if (type === 'diverging') {
|
|
17
|
+
return continuousDivergingSchemes;
|
|
18
|
+
}
|
|
19
|
+
if (type === 'sequential') {
|
|
20
|
+
return continuousSequentialSchemes;
|
|
21
|
+
}
|
|
22
|
+
return binnedNumericSchemes;
|
|
23
|
+
}
|
|
24
|
+
export const MapSettingsPanel = ({ dashboardId, panel, onClose, }) => {
|
|
25
|
+
const [layerIndex, setLayerIndex] = useState(0);
|
|
26
|
+
const [colorAccessor, setColorAccessor] = useState('getFillColor');
|
|
27
|
+
const tables = useStoreWithDuckDb((state) => state.db.tables);
|
|
28
|
+
const tableName = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.config.dashboardsById[dashboardId]?.selectedTable);
|
|
29
|
+
const updatePanel = useStoreWithMosaicDashboard((state) => state.mosaicDashboard.updatePanel);
|
|
30
|
+
const currentTable = useMemo(() => tables.find((t) => t.table.table === tableName), [tables, tableName]);
|
|
31
|
+
const mapConfig = panel.config;
|
|
32
|
+
const layers = getDeckMapLayerRecords(mapConfig);
|
|
33
|
+
const activeLayerIndex = Math.min(layerIndex, Math.max(layers.length - 1, 0));
|
|
34
|
+
const activeLayer = layers[activeLayerIndex];
|
|
35
|
+
const activeLayerDatasetId = getDeckMapLayerDatasetId(activeLayer);
|
|
36
|
+
const activeLayerDataset = activeLayerDatasetId
|
|
37
|
+
? mapConfig.datasets?.[activeLayerDatasetId]
|
|
38
|
+
: undefined;
|
|
39
|
+
const showGeometryColumnSetting = usesGeometryColumnSetting(activeLayer?.['@@type']);
|
|
40
|
+
const colorAccessorOptions = getDeckMapColorAccessorOptions(activeLayer?.['@@type']);
|
|
41
|
+
const effectiveColorAccessor = colorAccessorOptions.find((option) => option.value === colorAccessor)
|
|
42
|
+
?.value ?? colorAccessorOptions[0]?.value;
|
|
43
|
+
const colorScale = effectiveColorAccessor
|
|
44
|
+
? getDeckMapLayerColorScale(activeLayer, effectiveColorAccessor)
|
|
45
|
+
: undefined;
|
|
46
|
+
const colorScaleType = colorScale?.type ?? 'sequential';
|
|
47
|
+
const schemeOptions = getSchemeOptions(colorScaleType);
|
|
48
|
+
const firstColumnName = currentTable?.columns[0]?.name;
|
|
49
|
+
const maxRows = mapConfig.dataPolicy?.maxRows ?? DEFAULT_DECK_MAP_MAX_DATA_POINTS;
|
|
50
|
+
const applyConfig = useCallback((config) => {
|
|
51
|
+
updatePanel(dashboardId, panel.id, {
|
|
52
|
+
config: { ...config, settingsOpen: mapConfig.settingsOpen },
|
|
53
|
+
});
|
|
54
|
+
}, [dashboardId, mapConfig.settingsOpen, panel.id, updatePanel]);
|
|
55
|
+
const updateColorScale = (patch) => {
|
|
56
|
+
const field = patch.field ?? colorScale?.field ?? firstColumnName;
|
|
57
|
+
if (!field || !effectiveColorAccessor)
|
|
58
|
+
return;
|
|
59
|
+
const type = patch.type ?? colorScale?.type ?? 'sequential';
|
|
60
|
+
const scheme = patch.scheme ??
|
|
61
|
+
(patch.type && patch.type !== colorScale?.type
|
|
62
|
+
? undefined
|
|
63
|
+
: colorScale?.scheme);
|
|
64
|
+
applyConfig(setDeckMapLayerColorScale(mapConfig, activeLayerIndex, effectiveColorAccessor, createDeckMapLayerColorScale({
|
|
65
|
+
field,
|
|
66
|
+
type,
|
|
67
|
+
scheme,
|
|
68
|
+
title: field,
|
|
69
|
+
})));
|
|
70
|
+
};
|
|
71
|
+
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex items-center justify-between border-b px-3 py-1.5 text-xs font-medium", children: [_jsx("div", { className: "flex items-center", children: "Map settings" }), onClose && (_jsx(Button, { variant: "ghost", size: "icon", className: "h-5 w-5", onClick: onClose, "aria-label": "Close", children: _jsx(XIcon, { className: "h-3.5 w-3.5" }) }))] }), _jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-2", children: [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))) })] }) })), _jsx(Field, { label: "Layer type", children: _jsxs(Select, { value: typeof activeLayer?.['@@type'] === 'string'
|
|
72
|
+
? activeLayer['@@type']
|
|
73
|
+
: undefined, onValueChange: (value) => applyConfig(setDeckMapLayerType(mapConfig, activeLayerIndex, value)), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, { placeholder: "Select layer type" }) }), _jsx(SelectContent, { children: DECK_MAP_LAYER_TYPE_OPTIONS.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] }) }), _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: "Color scale" }), _jsx(Switch, { checked: Boolean(colorScale), onCheckedChange: (checked) => {
|
|
74
|
+
if (!effectiveColorAccessor)
|
|
75
|
+
return;
|
|
76
|
+
if (checked) {
|
|
77
|
+
updateColorScale({});
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
applyConfig(clearDeckMapLayerColorScale(mapConfig, activeLayerIndex, effectiveColorAccessor));
|
|
81
|
+
}, disabled: !firstColumnName || !effectiveColorAccessor })] }), effectiveColorAccessor && (_jsx(Field, { label: "Color property", children: _jsxs(Select, { value: effectiveColorAccessor, onValueChange: (value) => setColorAccessor(value), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: colorAccessorOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] }) })), colorScale && currentTable && (_jsx(ColumnsProvider, { columns: currentTable.columns, tableName: tableName, children: _jsx(Field, { label: "Color field", required: true, children: colorScaleType === 'categorical' ? (_jsx(ColumnSelector.Categorical, { value: colorScale.field, onChange: (field) => updateColorScale({ field }) })) : (_jsx(ColumnSelector.Quantitative, { value: colorScale.field, onChange: (field) => updateColorScale({ field }) })) }) })), colorScale && (_jsxs(_Fragment, { children: [_jsx(Field, { label: "Scale type", children: _jsxs(Select, { value: colorScaleType, onValueChange: (value) => updateColorScale({
|
|
82
|
+
type: value,
|
|
83
|
+
}), 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", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: schemeOptions.map((scheme) => (_jsx(SelectItem, { value: scheme, children: scheme }, scheme))) })] }) })] }))] })] })), currentTable && showGeometryColumnSetting && (_jsx(ColumnsProvider, { columns: currentTable.columns, tableName: tableName, 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..." }) }) })), currentTable && !showGeometryColumnSetting && (_jsxs(ColumnsProvider, { columns: currentTable.columns, tableName: tableName, children: [_jsx(Field, { label: "Latitude column", required: true, children: _jsx(LatitudeSelector, { dashboardId: dashboardId, panel: panel, currentTable: currentTable }) }), _jsx(Field, { label: "Longitude column", required: true, children: _jsx(LongitudeSelector, { dashboardId: dashboardId, panel: panel, currentTable: currentTable }) })] })), _jsx(Field, { label: "Max rows", children: _jsx(Input, { type: "number", min: 1, value: maxRows, className: "no-spinner", onChange: (event) => {
|
|
84
|
+
const parsed = Number.parseInt(event.target.value, 10);
|
|
85
|
+
if (!Number.isFinite(parsed) || parsed < 1)
|
|
86
|
+
return;
|
|
87
|
+
applyConfig({
|
|
88
|
+
...mapConfig,
|
|
89
|
+
dataPolicy: {
|
|
90
|
+
...mapConfig.dataPolicy,
|
|
91
|
+
maxRows: parsed,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}, placeholder: String(DEFAULT_DECK_MAP_MAX_DATA_POINTS) }) })] })] }));
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=MapSettings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MapSettings.js","sourceRoot":"","sources":["../src/MapSettings.tsx"],"names":[],"mappings":"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","sourcesContent":["import {FC, useCallback, useMemo, useState} from 'react';\nimport {\n Field,\n ColumnSelector,\n ColumnsProvider,\n useStoreWithMosaicDashboard,\n} from '@sqlrooms/mosaic';\nimport type {MosaicDashboardPanelConfigType} from '@sqlrooms/mosaic';\nimport {useStoreWithDuckDb} from '@sqlrooms/duckdb';\nimport {\n binnedNumericSchemes,\n categoricalSchemes,\n continuousDivergingSchemes,\n continuousSequentialSchemes,\n} from '@sqlrooms/color-scales';\nimport type {ColorScaleConfig, ColorScaleScheme} from '@sqlrooms/color-scales';\nimport {\n Button,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Switch,\n} from '@sqlrooms/ui';\nimport {XIcon} from 'lucide-react';\nimport {LatitudeSelector} from './LatitudeSelector';\nimport {LongitudeSelector} from './LongitudeSelector';\nimport type {DeckMapDashboardPanelConfig} from './dashboardConfig';\nimport {DEFAULT_DECK_MAP_MAX_DATA_POINTS} from './dashboardConfig';\nimport {\n clearDeckMapLayerColorScale,\n createDeckMapLayerColorScale,\n DECK_MAP_COLOR_SCALE_TYPE_OPTIONS,\n DECK_MAP_LAYER_TYPE_OPTIONS,\n getDeckMapColorAccessorOptions,\n getDeckMapLayerDatasetId,\n getDeckMapLayerColorScale,\n getDeckMapLayerRecords,\n setDeckMapLayerColorScale,\n setDeckMapLayerGeometryColumn,\n setDeckMapLayerType,\n type DeckMapLayerColorAccessor,\n usesGeometryColumnSetting,\n} from './mapLayerConfigUtils';\n\ninterface MapSettingsPanelProps {\n dashboardId: string;\n panel: MosaicDashboardPanelConfigType;\n onClose?: () => void;\n}\n\nfunction getSchemeOptions(type: ColorScaleConfig['type']) {\n if (type === 'categorical') {\n return categoricalSchemes;\n }\n if (type === 'diverging') {\n return continuousDivergingSchemes;\n }\n if (type === 'sequential') {\n return continuousSequentialSchemes;\n }\n return binnedNumericSchemes;\n}\n\nexport const MapSettingsPanel: FC<MapSettingsPanelProps> = ({\n dashboardId,\n panel,\n onClose,\n}) => {\n const [layerIndex, setLayerIndex] = useState(0);\n const [colorAccessor, setColorAccessor] =\n useState<DeckMapLayerColorAccessor>('getFillColor');\n const tables = useStoreWithDuckDb((state) => state.db.tables);\n const tableName = useStoreWithMosaicDashboard(\n (state) =>\n state.mosaicDashboard.config.dashboardsById[dashboardId]?.selectedTable,\n );\n const updatePanel = useStoreWithMosaicDashboard(\n (state) => state.mosaicDashboard.updatePanel,\n );\n const currentTable = useMemo(\n () => tables.find((t) => t.table.table === tableName),\n [tables, tableName],\n );\n const mapConfig = panel.config as DeckMapDashboardPanelConfig;\n const layers = getDeckMapLayerRecords(mapConfig);\n const activeLayerIndex = Math.min(layerIndex, Math.max(layers.length - 1, 0));\n const activeLayer = layers[activeLayerIndex];\n const activeLayerDatasetId = getDeckMapLayerDatasetId(activeLayer);\n const activeLayerDataset = activeLayerDatasetId\n ? mapConfig.datasets?.[activeLayerDatasetId]\n : undefined;\n const showGeometryColumnSetting = usesGeometryColumnSetting(\n activeLayer?.['@@type'],\n );\n const colorAccessorOptions = getDeckMapColorAccessorOptions(\n activeLayer?.['@@type'],\n );\n const effectiveColorAccessor =\n colorAccessorOptions.find((option) => option.value === colorAccessor)\n ?.value ?? colorAccessorOptions[0]?.value;\n const colorScale = effectiveColorAccessor\n ? getDeckMapLayerColorScale(activeLayer, effectiveColorAccessor)\n : undefined;\n const colorScaleType = colorScale?.type ?? 'sequential';\n const schemeOptions = getSchemeOptions(colorScaleType);\n const firstColumnName = currentTable?.columns[0]?.name;\n const maxRows =\n mapConfig.dataPolicy?.maxRows ?? DEFAULT_DECK_MAP_MAX_DATA_POINTS;\n\n const applyConfig = useCallback(\n (config: DeckMapDashboardPanelConfig) => {\n updatePanel(dashboardId, panel.id, {\n config: {...config, settingsOpen: mapConfig.settingsOpen} as any,\n });\n },\n [dashboardId, mapConfig.settingsOpen, panel.id, updatePanel],\n );\n\n const updateColorScale = (patch: {\n field?: string;\n type?: ColorScaleConfig['type'];\n scheme?: ColorScaleScheme;\n }) => {\n const field = patch.field ?? colorScale?.field ?? firstColumnName;\n if (!field || !effectiveColorAccessor) return;\n\n const type = patch.type ?? colorScale?.type ?? 'sequential';\n const scheme =\n patch.scheme ??\n (patch.type && patch.type !== colorScale?.type\n ? undefined\n : colorScale?.scheme);\n\n applyConfig(\n setDeckMapLayerColorScale(\n mapConfig,\n activeLayerIndex,\n effectiveColorAccessor,\n createDeckMapLayerColorScale({\n field,\n type,\n scheme,\n title: field,\n }),\n ),\n );\n };\n\n return (\n <div className=\"flex h-full flex-col\">\n <div className=\"flex items-center justify-between border-b px-3 py-1.5 text-xs font-medium\">\n <div className=\"flex items-center\">Map settings</div>\n {onClose && (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-5 w-5\"\n onClick={onClose}\n aria-label=\"Close\"\n >\n <XIcon className=\"h-3.5 w-3.5\" />\n </Button>\n )}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-2\">\n {layers.length > 0 && (\n <div className=\"flex flex-col gap-3\">\n {layers.length > 1 && (\n <Field label=\"Layer\">\n <Select\n value={String(activeLayerIndex)}\n onValueChange={(value) => setLayerIndex(Number(value))}\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {layers.map((layer, index) => (\n <SelectItem key={index} value={String(index)}>\n {String(layer.id ?? `Layer ${index + 1}`)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n )}\n\n <Field label=\"Layer type\">\n <Select\n value={\n typeof activeLayer?.['@@type'] === 'string'\n ? activeLayer['@@type']\n : undefined\n }\n onValueChange={(value) =>\n applyConfig(\n setDeckMapLayerType(mapConfig, activeLayerIndex, value),\n )\n }\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue placeholder=\"Select layer type\" />\n </SelectTrigger>\n <SelectContent>\n {DECK_MAP_LAYER_TYPE_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n\n <div className=\"flex flex-col gap-2 rounded-md border p-2\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"text-xs font-medium\">Color scale</span>\n <Switch\n checked={Boolean(colorScale)}\n onCheckedChange={(checked) => {\n if (!effectiveColorAccessor) return;\n if (checked) {\n updateColorScale({});\n return;\n }\n applyConfig(\n clearDeckMapLayerColorScale(\n mapConfig,\n activeLayerIndex,\n effectiveColorAccessor,\n ),\n );\n }}\n disabled={!firstColumnName || !effectiveColorAccessor}\n />\n </div>\n\n {effectiveColorAccessor && (\n <Field label=\"Color property\">\n <Select\n value={effectiveColorAccessor}\n onValueChange={(value) =>\n setColorAccessor(value as DeckMapLayerColorAccessor)\n }\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {colorAccessorOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n )}\n\n {colorScale && currentTable && (\n <ColumnsProvider\n columns={currentTable.columns}\n tableName={tableName}\n >\n <Field label=\"Color field\" required>\n {colorScaleType === 'categorical' ? (\n <ColumnSelector.Categorical\n value={colorScale.field}\n onChange={(field) => updateColorScale({field})}\n />\n ) : (\n <ColumnSelector.Quantitative\n value={colorScale.field}\n onChange={(field) => updateColorScale({field})}\n />\n )}\n </Field>\n </ColumnsProvider>\n )}\n\n {colorScale && (\n <>\n <Field label=\"Scale type\">\n <Select\n value={colorScaleType}\n onValueChange={(value) =>\n updateColorScale({\n type: value as ColorScaleConfig['type'],\n })\n }\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {DECK_MAP_COLOR_SCALE_TYPE_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n\n <Field label=\"Scheme\">\n <Select\n value={colorScale.scheme}\n onValueChange={(value) =>\n updateColorScale({scheme: value as ColorScaleScheme})\n }\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {schemeOptions.map((scheme) => (\n <SelectItem key={scheme} value={scheme}>\n {scheme}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n </>\n )}\n </div>\n </div>\n )}\n\n {currentTable && showGeometryColumnSetting && (\n <ColumnsProvider columns={currentTable.columns} tableName={tableName}>\n <Field label=\"Geometry column\" required>\n <ColumnSelector\n value={activeLayerDataset?.geometryColumn}\n onChange={(geometryColumn) =>\n applyConfig(\n setDeckMapLayerGeometryColumn(\n mapConfig,\n activeLayerIndex,\n geometryColumn,\n ),\n )\n }\n placeholder=\"Select geometry column...\"\n />\n </Field>\n </ColumnsProvider>\n )}\n\n {currentTable && !showGeometryColumnSetting && (\n <ColumnsProvider columns={currentTable.columns} tableName={tableName}>\n <Field label=\"Latitude column\" required>\n <LatitudeSelector\n dashboardId={dashboardId}\n panel={panel}\n currentTable={currentTable}\n />\n </Field>\n <Field label=\"Longitude column\" required>\n <LongitudeSelector\n dashboardId={dashboardId}\n panel={panel}\n currentTable={currentTable}\n />\n </Field>\n </ColumnsProvider>\n )}\n\n <Field label=\"Max rows\">\n <Input\n type=\"number\"\n min={1}\n value={maxRows}\n className=\"no-spinner\"\n onChange={(event) => {\n const parsed = Number.parseInt(event.target.value, 10);\n if (!Number.isFinite(parsed) || parsed < 1) return;\n applyConfig({\n ...mapConfig,\n dataPolicy: {\n ...mapConfig.dataPolicy,\n maxRows: parsed,\n },\n });\n }}\n placeholder={String(DEFAULT_DECK_MAP_MAX_DATA_POINTS)}\n />\n </Field>\n </div>\n </div>\n );\n};\n"]}
|