@sqlrooms/deck 0.29.0-rc.2 → 0.29.0-rc.3
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/LICENSE.md +9 -0
- package/README.md +69 -0
- package/dist/DeckJsonMap.d.ts +4 -0
- package/dist/DeckJsonMap.d.ts.map +1 -0
- package/dist/{DeckMap.js → DeckJsonMap.js} +57 -44
- package/dist/DeckJsonMap.js.map +1 -0
- package/dist/DeckJsonMapSpec.d.ts +7617 -0
- package/dist/DeckJsonMapSpec.d.ts.map +1 -0
- package/dist/DeckJsonMapSpec.js +81 -0
- package/dist/DeckJsonMapSpec.js.map +1 -0
- package/dist/DeckMapConfigPopoverEditor.d.ts +8 -0
- package/dist/DeckMapConfigPopoverEditor.d.ts.map +1 -0
- package/dist/DeckMapConfigPopoverEditor.js +43 -0
- package/dist/DeckMapConfigPopoverEditor.js.map +1 -0
- package/dist/createDeckJsonSpecFromDatasets.d.ts +11 -0
- package/dist/createDeckJsonSpecFromDatasets.d.ts.map +1 -0
- package/dist/createDeckJsonSpecFromDatasets.js +85 -0
- package/dist/createDeckJsonSpecFromDatasets.js.map +1 -0
- package/dist/dashboard.d.ts +4 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +465 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/dashboardConfig.d.ts +51 -0
- package/dist/dashboardConfig.d.ts.map +1 -0
- package/dist/dashboardConfig.js +54 -0
- package/dist/dashboardConfig.js.map +1 -0
- package/dist/datasets/PreparedDatasetStore.d.ts +120 -0
- package/dist/datasets/PreparedDatasetStore.d.ts.map +1 -0
- package/dist/datasets/PreparedDatasetStore.js +262 -0
- package/dist/datasets/PreparedDatasetStore.js.map +1 -0
- package/dist/datasets/helpers.d.ts +57 -0
- package/dist/datasets/helpers.d.ts.map +1 -0
- package/dist/datasets/helpers.js +146 -0
- package/dist/datasets/helpers.js.map +1 -0
- package/dist/datasets/normalizeDatasets.d.ts +8 -2
- package/dist/datasets/normalizeDatasets.d.ts.map +1 -1
- package/dist/datasets/normalizeDatasets.js +33 -48
- package/dist/datasets/normalizeDatasets.js.map +1 -1
- package/dist/datasets/tableAdapter.d.ts +11 -0
- package/dist/datasets/tableAdapter.d.ts.map +1 -0
- package/dist/datasets/tableAdapter.js +11 -0
- package/dist/datasets/tableAdapter.js.map +1 -0
- package/dist/datasets/types.d.ts +40 -0
- package/dist/datasets/types.d.ts.map +1 -0
- package/dist/datasets/types.js +2 -0
- package/dist/datasets/types.js.map +1 -0
- package/dist/datasets/usePreparedDatasetStates.d.ts +16 -0
- package/dist/datasets/usePreparedDatasetStates.d.ts.map +1 -0
- package/dist/datasets/usePreparedDatasetStates.js +59 -0
- package/dist/datasets/usePreparedDatasetStates.js.map +1 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/json/colorScaleFunction.d.ts +14 -0
- package/dist/json/colorScaleFunction.d.ts.map +1 -0
- package/dist/json/colorScaleFunction.js +34 -0
- package/dist/json/colorScaleFunction.js.map +1 -0
- package/dist/json/compileColorScale.d.ts +4 -27
- package/dist/json/compileColorScale.d.ts.map +1 -1
- package/dist/json/compileColorScale.js +16 -450
- package/dist/json/compileColorScale.js.map +1 -1
- package/dist/json/compileGeoArrowAccessor.d.ts +7 -0
- package/dist/json/compileGeoArrowAccessor.d.ts.map +1 -1
- package/dist/json/compileGeoArrowAccessor.js +68 -2
- package/dist/json/compileGeoArrowAccessor.js.map +1 -1
- package/dist/json/createDeckJsonConfiguration.d.ts.map +1 -1
- package/dist/json/createDeckJsonConfiguration.js +86 -33
- package/dist/json/createDeckJsonConfiguration.js.map +1 -1
- package/dist/json/defaultClasses.d.ts +12 -6
- package/dist/json/defaultClasses.d.ts.map +1 -1
- package/dist/json/defaultClasses.js +7 -1
- package/dist/json/defaultClasses.js.map +1 -1
- package/dist/json/extractColorScaleLegends.d.ts +1 -1
- package/dist/json/extractColorScaleLegends.d.ts.map +1 -1
- package/dist/json/extractColorScaleLegends.js +8 -6
- package/dist/json/extractColorScaleLegends.js.map +1 -1
- package/dist/json/layerCompatibility.d.ts +9 -3
- package/dist/json/layerCompatibility.d.ts.map +1 -1
- package/dist/json/layerCompatibility.js +135 -11
- package/dist/json/layerCompatibility.js.map +1 -1
- package/dist/json/layerConfig.d.ts +7 -3
- package/dist/json/layerConfig.d.ts.map +1 -1
- package/dist/json/layerConfig.js +19 -8
- package/dist/json/layerConfig.js.map +1 -1
- package/dist/prepare/detectGeometryColumn.d.ts.map +1 -1
- package/dist/prepare/detectGeometryColumn.js +1 -1
- package/dist/prepare/detectGeometryColumn.js.map +1 -1
- package/dist/prepare/geoarrow.d.ts.map +1 -1
- package/dist/prepare/geoarrow.js.map +1 -1
- package/dist/prepare/geometryDecoder.d.ts +1 -2
- package/dist/prepare/geometryDecoder.d.ts.map +1 -1
- package/dist/prepare/geometryDecoder.js.map +1 -1
- package/dist/prepare/prepareDeckDataset.d.ts +46 -0
- package/dist/prepare/prepareDeckDataset.d.ts.map +1 -1
- package/dist/prepare/prepareDeckDataset.js +46 -0
- package/dist/prepare/prepareDeckDataset.js.map +1 -1
- package/dist/prepare/toGeoJsonBinary.d.ts.map +1 -1
- package/dist/prepare/toGeoJsonBinary.js +3 -2
- package/dist/prepare/toGeoJsonBinary.js.map +1 -1
- package/dist/prepare/wkbDecoder.d.ts.map +1 -1
- package/dist/prepare/wkbDecoder.js +36 -9
- package/dist/prepare/wkbDecoder.js.map +1 -1
- package/dist/types.d.ts +31 -92
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -1
- package/dist/types.js.map +1 -1
- package/dist/useDeckLayersReadyRedraw.d.ts +13 -0
- package/dist/useDeckLayersReadyRedraw.d.ts.map +1 -0
- package/dist/useDeckLayersReadyRedraw.js +35 -0
- package/dist/useDeckLayersReadyRedraw.js.map +1 -0
- package/package.json +16 -10
- package/dist/ColorScaleLegend.d.ts +0 -8
- package/dist/ColorScaleLegend.d.ts.map +0 -1
- package/dist/ColorScaleLegend.js +0 -11
- package/dist/ColorScaleLegend.js.map +0 -1
- package/dist/DeckMap.d.ts +0 -4
- package/dist/DeckMap.d.ts.map +0 -1
- package/dist/DeckMap.js.map +0 -1
- package/dist/datasets/usePreparedDeckDatasets.d.ts +0 -3
- package/dist/datasets/usePreparedDeckDatasets.d.ts.map +0 -1
- package/dist/datasets/usePreparedDeckDatasets.js +0 -61
- package/dist/datasets/usePreparedDeckDatasets.js.map +0 -1
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright 2025 SQLRooms Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -127,6 +127,75 @@ const spec = createDeckJsonSpecFromDatasets({
|
|
|
127
127
|
});
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
## Mosaic Dashboard Renderer
|
|
131
|
+
|
|
132
|
+
`@sqlrooms/deck` can contribute a `deck-json-map` panel renderer to
|
|
133
|
+
`@sqlrooms/mosaic` dashboards without making the Mosaic package depend on
|
|
134
|
+
deck.gl or MapLibre. Pass the renderer when creating the Mosaic dashboard
|
|
135
|
+
slice.
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
import {
|
|
139
|
+
createDeckMapDashboardPanelConfig,
|
|
140
|
+
DECK_MAP_DASHBOARD_PANEL_TYPE,
|
|
141
|
+
deckMapDashboardPanelRenderer,
|
|
142
|
+
} from '@sqlrooms/deck';
|
|
143
|
+
import {
|
|
144
|
+
createDefaultMosaicDashboardPanelRenderers,
|
|
145
|
+
createMosaicDashboardSlice,
|
|
146
|
+
MosaicDashboard,
|
|
147
|
+
} from '@sqlrooms/mosaic';
|
|
148
|
+
|
|
149
|
+
const dashboardSlice = createMosaicDashboardSlice({
|
|
150
|
+
panelRenderers: createDefaultMosaicDashboardPanelRenderers({
|
|
151
|
+
[DECK_MAP_DASHBOARD_PANEL_TYPE]: deckMapDashboardPanelRenderer,
|
|
152
|
+
}),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
function Dashboard() {
|
|
156
|
+
return <MosaicDashboard dashboardId="geo" />;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const mapPanel = createDeckMapDashboardPanelConfig({
|
|
160
|
+
title: 'Earthquakes map',
|
|
161
|
+
spec: {
|
|
162
|
+
initialViewState: {longitude: -119.5, latitude: 37, zoom: 4.5},
|
|
163
|
+
layers: [
|
|
164
|
+
{
|
|
165
|
+
'@@type': 'GeoArrowScatterplotLayer',
|
|
166
|
+
id: 'earthquakes',
|
|
167
|
+
_sqlroomsBinding: {dataset: 'earthquakes'},
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
},
|
|
171
|
+
datasets: {
|
|
172
|
+
earthquakes: {
|
|
173
|
+
source: {
|
|
174
|
+
sqlQuery:
|
|
175
|
+
'SELECT *, ST_AsWKB(ST_Point(Longitude, Latitude)) AS geom FROM earthquakes',
|
|
176
|
+
},
|
|
177
|
+
geometryColumn: 'geom',
|
|
178
|
+
geometryEncodingHint: 'wkb',
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
fitToData: {
|
|
182
|
+
dataset: 'earthquakes',
|
|
183
|
+
longitudeColumn: 'Longitude',
|
|
184
|
+
latitudeColumn: 'Latitude',
|
|
185
|
+
padding: 40,
|
|
186
|
+
maxZoom: 12,
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
The dashboard renderer uses `useMosaicClient`, receives Arrow tables directly,
|
|
192
|
+
and passes them to `DeckJsonMap` as Arrow-backed datasets. Dataset sources fall
|
|
193
|
+
back from dataset-level source, to panel source, to the dashboard selected
|
|
194
|
+
table. When `fitToData` is provided, the renderer asks DuckDB Spatial for the
|
|
195
|
+
dataset extent using the declared longitude/latitude columns and fits the
|
|
196
|
+
initial map view once, instead of inferring bounds from the loaded Arrow
|
|
197
|
+
payload in React.
|
|
198
|
+
|
|
130
199
|
## Core Concepts
|
|
131
200
|
|
|
132
201
|
### `DeckJsonMap`
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
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;
|
|
4
|
+
//# sourceMappingURL=DeckJsonMap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeckJsonMap.d.ts","sourceRoot":"","sources":["../src/DeckJsonMap.tsx"],"names":[],"mappings":"AAKA,OAAO,kCAAkC,CAAC;AAW1C,OAAO,KAAK,EAAC,gBAAgB,EAA2B,MAAM,SAAS,CAAC;AA0HxE,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAkB,EAClB,SAAS,EACT,QAAQ,GACT,EAAE,gBAAgB,2CAiIlB"}
|
|
@@ -1,22 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { JSONConverter } from '@deck.gl/json';
|
|
3
3
|
import DeckGL from '@deck.gl/react';
|
|
4
|
-
import {
|
|
4
|
+
import { ColorScaleLegend } from '@sqlrooms/color-scales';
|
|
5
|
+
import { cn, useTheme } from '@sqlrooms/ui';
|
|
5
6
|
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
6
|
-
import { useEffect, useMemo } from 'react';
|
|
7
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
7
8
|
import Map from 'react-map-gl/maplibre';
|
|
9
|
+
import { DeckJsonMapSpec } from './DeckJsonMapSpec';
|
|
8
10
|
import { normalizeDatasets } from './datasets/normalizeDatasets';
|
|
9
|
-
import {
|
|
10
|
-
import { ColorScaleLegend } from './ColorScaleLegend';
|
|
11
|
+
import { usePreparedDatasetStates } from './datasets/usePreparedDatasetStates';
|
|
11
12
|
import { createDeckJsonConfiguration } from './json/createDeckJsonConfiguration';
|
|
12
13
|
import { extractColorScaleLegends } from './json/extractColorScaleLegends';
|
|
13
|
-
import { resolveDatasetId } from './json/layerConfig';
|
|
14
14
|
import { getLayerCompatibility } from './json/layerCompatibility';
|
|
15
|
-
|
|
15
|
+
import { resolveDatasetId } from './json/layerConfig';
|
|
16
|
+
import { useDeckLayersReadyRedraw } from './useDeckLayersReadyRedraw';
|
|
17
|
+
const DEFAULT_MAP_STYLES = {
|
|
18
|
+
light: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
|
|
19
|
+
dark: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',
|
|
20
|
+
};
|
|
16
21
|
function parseSpec(spec) {
|
|
17
22
|
try {
|
|
23
|
+
const parsedValue = typeof spec === 'string' ? JSON.parse(spec) : spec;
|
|
24
|
+
const validatedSpec = DeckJsonMapSpec.safeParse(parsedValue);
|
|
25
|
+
if (!validatedSpec.success) {
|
|
26
|
+
return {
|
|
27
|
+
spec: null,
|
|
28
|
+
error: new Error(formatSpecValidationError(validatedSpec.error)),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
18
31
|
return {
|
|
19
|
-
spec:
|
|
32
|
+
spec: validatedSpec.data,
|
|
20
33
|
error: null,
|
|
21
34
|
};
|
|
22
35
|
}
|
|
@@ -27,6 +40,13 @@ function parseSpec(spec) {
|
|
|
27
40
|
};
|
|
28
41
|
}
|
|
29
42
|
}
|
|
43
|
+
function formatSpecValidationError(error) {
|
|
44
|
+
const issues = error.issues.map((issue) => {
|
|
45
|
+
const path = issue.path.length > 0 ? issue.path.join('.') : 'spec';
|
|
46
|
+
return `${path}: ${issue.message}`;
|
|
47
|
+
});
|
|
48
|
+
return `Invalid DeckJsonMap spec. ${issues.join('; ')}`;
|
|
49
|
+
}
|
|
30
50
|
function extractFallbackDeckProps(spec) {
|
|
31
51
|
if (!spec) {
|
|
32
52
|
return {};
|
|
@@ -66,34 +86,17 @@ function filterUnavailableLayers(spec, datasetIds, datasetStates) {
|
|
|
66
86
|
layers: filteredLayers,
|
|
67
87
|
};
|
|
68
88
|
}
|
|
69
|
-
function
|
|
70
|
-
const loadingDatasets = Object.entries(datasetStates)
|
|
71
|
-
.filter(([, state]) => state.status === 'loading')
|
|
72
|
-
.map(([datasetId]) => datasetId);
|
|
89
|
+
function renderDatasetErrorOverlay(datasetStates) {
|
|
73
90
|
const failedDatasets = Object.entries(datasetStates).filter((entry) => entry[1].status === 'error');
|
|
74
|
-
if (!
|
|
91
|
+
if (!failedDatasets.length) {
|
|
75
92
|
return null;
|
|
76
93
|
}
|
|
77
|
-
return (
|
|
94
|
+
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))) }));
|
|
78
95
|
}
|
|
79
|
-
export function
|
|
80
|
-
const normalizedDatasets = useMemo(() => normalizeDatasets(
|
|
81
|
-
datasets,
|
|
82
|
-
sqlQuery,
|
|
83
|
-
arrowTable,
|
|
84
|
-
queryResult,
|
|
85
|
-
geometryColumn,
|
|
86
|
-
geometryEncodingHint,
|
|
87
|
-
}), [
|
|
88
|
-
datasets,
|
|
89
|
-
sqlQuery,
|
|
90
|
-
arrowTable,
|
|
91
|
-
queryResult,
|
|
92
|
-
geometryColumn,
|
|
93
|
-
geometryEncodingHint,
|
|
94
|
-
]);
|
|
96
|
+
export function DeckJsonMap({ spec, datasets, mapStyle, deckProps, mapProps, showLegends = true, className, children, }) {
|
|
97
|
+
const normalizedDatasets = useMemo(() => normalizeDatasets(datasets), [datasets]);
|
|
95
98
|
const datasetIds = useMemo(() => Object.keys(normalizedDatasets), [normalizedDatasets]);
|
|
96
|
-
const datasetStates =
|
|
99
|
+
const datasetStates = usePreparedDatasetStates(normalizedDatasets);
|
|
97
100
|
const { spec: parsedSpec, error: specError } = useMemo(() => parseSpec(spec), [spec]);
|
|
98
101
|
const availableSpec = useMemo(() => parsedSpec
|
|
99
102
|
? filterUnavailableLayers(parsedSpec, datasetIds, datasetStates)
|
|
@@ -134,24 +137,34 @@ export function DeckMap({ spec, datasets, sqlQuery, arrowTable, queryResult, geo
|
|
|
134
137
|
const extraDeckProps = (deckProps ?? {});
|
|
135
138
|
const extraMapProps = (mapProps ?? {});
|
|
136
139
|
const hasRenderingError = Boolean(convertedDeckPropsResult.error);
|
|
140
|
+
const deckRef = useRef(null);
|
|
141
|
+
const mergedLayers = hasRenderingError
|
|
142
|
+
? []
|
|
143
|
+
: (deckProps?.layers ??
|
|
144
|
+
convertedDeckProps.layers ??
|
|
145
|
+
[]);
|
|
146
|
+
useDeckLayersReadyRedraw({
|
|
147
|
+
deckRef,
|
|
148
|
+
hasRenderingError,
|
|
149
|
+
layers: mergedLayers,
|
|
150
|
+
});
|
|
137
151
|
const mergedDeckProps = {
|
|
138
152
|
...convertedDeckProps,
|
|
139
153
|
...extraDeckProps,
|
|
140
|
-
layers:
|
|
141
|
-
? []
|
|
142
|
-
: (deckProps?.layers ??
|
|
143
|
-
convertedDeckProps.layers ??
|
|
144
|
-
[]),
|
|
154
|
+
layers: mergedLayers,
|
|
145
155
|
};
|
|
156
|
+
const { resolvedTheme } = useTheme();
|
|
146
157
|
const mergedMapProps = {
|
|
147
158
|
...extraMapProps,
|
|
148
|
-
mapStyle: mapStyle ?? mapProps?.mapStyle ??
|
|
159
|
+
mapStyle: mapStyle ?? mapProps?.mapStyle ?? DEFAULT_MAP_STYLES[resolvedTheme],
|
|
149
160
|
};
|
|
150
|
-
const legends = useMemo(() =>
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
161
|
+
const legends = useMemo(() => showLegends
|
|
162
|
+
? extractColorScaleLegends({
|
|
163
|
+
spec: availableSpec,
|
|
164
|
+
datasetIds,
|
|
165
|
+
datasetStates,
|
|
166
|
+
})
|
|
167
|
+
: [], [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, _jsx(DeckGL, { ref: deckRef, ...mergedDeckProps, children: _jsx(Map, { ...mergedMapProps, children: 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] }));
|
|
156
169
|
}
|
|
157
|
-
//# sourceMappingURL=
|
|
170
|
+
//# sourceMappingURL=DeckJsonMap.js.map
|
|
@@ -0,0 +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"]}
|