@walkthru-earth/objex 1.3.1 → 1.4.0
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 +5 -0
- package/README.md +20 -12
- package/dist/components/browser/FileTreeSidebar.svelte +32 -17
- package/dist/components/layout/AboutSheet.svelte +5 -2
- package/dist/components/layout/ConnectionDialog.svelte +1 -1
- package/dist/components/layout/SettingsSheet.svelte +237 -0
- package/dist/components/layout/SettingsSheet.svelte.d.ts +6 -0
- package/dist/components/layout/Sidebar.svelte +73 -6
- package/dist/components/layout/Sidebar.svelte.d.ts +4 -1
- package/dist/components/layout/StatusBar.svelte +1 -1
- package/dist/components/layout/TabBar.svelte +2 -2
- package/dist/components/ui/context-menu/context-menu-radio-group.svelte.d.ts +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +1 -1
- package/dist/components/ui/input/input.svelte.d.ts +1 -1
- package/dist/components/ui/resizable/index.d.ts +1 -1
- package/dist/components/ui/resizable/index.js +2 -2
- package/dist/components/ui/slider/index.d.ts +3 -0
- package/dist/components/ui/slider/index.js +5 -0
- package/dist/components/ui/slider/range-slider.svelte +94 -0
- package/dist/components/ui/slider/range-slider.svelte.d.ts +21 -0
- package/dist/components/ui/slider/slider.svelte +83 -0
- package/dist/components/ui/slider/slider.svelte.d.ts +7 -0
- package/dist/components/viewers/ArchiveViewer.svelte +2 -2
- package/dist/components/viewers/CodeViewer.svelte +31 -22
- package/dist/components/viewers/CogControls.svelte +338 -184
- package/dist/components/viewers/CogControls.svelte.d.ts +33 -10
- package/dist/components/viewers/CogViewer.svelte +263 -112
- package/dist/components/viewers/CopcViewer.svelte +1 -1
- package/dist/components/viewers/FlatGeobufViewer.svelte +1 -1
- package/dist/components/viewers/GeoParquetMapViewer.svelte +6 -6
- package/dist/components/viewers/GeoParquetMapViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/ImageViewer.svelte +2 -2
- package/dist/components/viewers/MarkdownViewer.svelte +12 -9
- package/dist/components/viewers/MediaViewer.svelte +2 -2
- package/dist/components/viewers/ModelViewer.svelte +1 -1
- package/dist/components/viewers/MultiCogViewer.svelte +467 -102
- package/dist/components/viewers/MultiCogViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/NotebookViewer.svelte +6 -3
- package/dist/components/viewers/PdfViewer.svelte +2 -2
- package/dist/components/viewers/PmtilesViewer.svelte +3 -6
- package/dist/components/viewers/RawViewer.svelte +6 -3
- package/dist/components/viewers/StacMapViewer.svelte +1 -1
- package/dist/components/viewers/StacMosaicViewer.svelte +1760 -408
- package/dist/components/viewers/StacMosaicViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/StacTabViewer.svelte +24 -13
- package/dist/components/viewers/StacTabViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/TableGrid.svelte +4 -4
- package/dist/components/viewers/TableStatusBar.svelte +1 -1
- package/dist/components/viewers/TableToolbar.svelte +1 -1
- package/dist/components/viewers/TableViewer.svelte +25 -17
- package/dist/components/viewers/TableViewer.svelte.d.ts +1 -0
- package/dist/components/viewers/ViewerRouter.svelte +16 -8
- package/dist/components/viewers/ZarrMapViewer.svelte +11 -9
- package/dist/components/viewers/ZarrViewer.svelte +4 -4
- package/dist/components/viewers/cog/ChannelPicker.svelte +83 -0
- package/dist/components/viewers/cog/ChannelPicker.svelte.d.ts +13 -0
- package/dist/components/viewers/cog/PixelInspectorPanel.svelte +87 -0
- package/dist/components/viewers/cog/PixelInspectorPanel.svelte.d.ts +17 -0
- package/dist/components/viewers/cog/buildRgbLayer.d.ts +78 -0
- package/dist/components/viewers/cog/buildRgbLayer.js +176 -0
- package/dist/components/viewers/map/AttributeTable.svelte +1 -1
- package/dist/components/viewers/map/MapContainer.svelte +37 -11
- package/dist/components/viewers/pmtiles/PmtilesArchiveView.svelte +1 -1
- package/dist/components/viewers/pmtiles/PmtilesTileInspector.svelte +1 -1
- package/dist/components/viewers/stac/StacDatetimeBar.svelte +175 -0
- package/dist/components/viewers/stac/StacDatetimeBar.svelte.d.ts +10 -0
- package/dist/components/viewers/stac/StacFilterPanel.svelte +243 -0
- package/dist/components/viewers/stac/StacFilterPanel.svelte.d.ts +14 -0
- package/dist/components/viewers/stac/StacItemInspector.svelte +223 -0
- package/dist/components/viewers/stac/StacItemInspector.svelte.d.ts +10 -0
- package/dist/components/viewers/stac/StacItemStrip.svelte +228 -0
- package/dist/components/viewers/stac/StacItemStrip.svelte.d.ts +12 -0
- package/dist/file-icons/index.d.ts +1 -1
- package/dist/file-icons/index.js +1 -1
- package/dist/i18n/ar.js +110 -2
- package/dist/i18n/en.js +110 -2
- package/dist/index.d.ts +2 -28
- package/dist/index.js +7 -23
- package/dist/query/engine.d.ts +10 -0
- package/dist/query/source.js +1 -1
- package/dist/query/stac-source-factory.d.ts +65 -0
- package/dist/query/stac-source-factory.js +77 -0
- package/dist/query/stac-source-parquet.d.ts +135 -0
- package/dist/query/stac-source-parquet.js +465 -0
- package/dist/query/wasm.d.ts +8 -0
- package/dist/query/wasm.js +304 -2
- package/dist/storage/presign.js +1 -1
- package/dist/storage/providers.js +5 -5
- package/dist/stores/config.svelte.d.ts +15 -0
- package/dist/stores/config.svelte.js +46 -0
- package/dist/stores/connections.svelte.d.ts +2 -2
- package/dist/stores/connections.svelte.js +1 -2
- package/dist/stores/files.svelte.d.ts +1 -1
- package/dist/stores/files.svelte.js +1 -1
- package/dist/stores/query-history.svelte.js +1 -1
- package/dist/stores/settings.svelte.d.ts +16 -1
- package/dist/stores/settings.svelte.js +104 -48
- package/dist/stores/tabs.svelte.d.ts +3 -0
- package/dist/stores/tabs.svelte.js +17 -0
- package/dist/utils/cog-histogram.d.ts +121 -0
- package/dist/utils/cog-histogram.js +424 -0
- package/dist/utils/cog.d.ts +177 -20
- package/dist/utils/cog.js +361 -76
- package/dist/utils/colormap-sprite.d.ts +0 -9
- package/dist/utils/colormap-sprite.js +0 -21
- package/dist/utils/deck.d.ts +16 -12
- package/dist/utils/deck.js +10 -4
- package/dist/utils/pmtiles-tile.js +2 -2
- package/dist/utils/{url.d.ts → signed-url.d.ts} +15 -1
- package/dist/utils/{url.js → signed-url.js} +32 -10
- package/dist/utils/url-state.d.ts +36 -0
- package/dist/utils/url-state.js +72 -2
- package/dist/utils/zarr-tab.d.ts +1 -2
- package/dist/utils/zarr-tab.js +1 -2
- package/dist/utils/zarr.d.ts +0 -17
- package/dist/utils/zarr.js +1 -45
- package/package.json +55 -84
- package/dist/components/browser/Breadcrumb.svelte +0 -50
- package/dist/components/browser/Breadcrumb.svelte.d.ts +0 -7
- package/dist/components/browser/CreateFolderDialog.svelte +0 -98
- package/dist/components/browser/CreateFolderDialog.svelte.d.ts +0 -6
- package/dist/components/browser/DeleteConfirmDialog.svelte +0 -90
- package/dist/components/browser/DeleteConfirmDialog.svelte.d.ts +0 -8
- package/dist/components/browser/DropZone.svelte +0 -83
- package/dist/components/browser/DropZone.svelte.d.ts +0 -7
- package/dist/components/browser/FileBrowser.svelte +0 -252
- package/dist/components/browser/FileBrowser.svelte.d.ts +0 -3
- package/dist/components/browser/FileRow.svelte +0 -117
- package/dist/components/browser/FileRow.svelte.d.ts +0 -9
- package/dist/components/browser/RenameDialog.svelte +0 -101
- package/dist/components/browser/RenameDialog.svelte.d.ts +0 -8
- package/dist/components/browser/SearchBar.svelte +0 -40
- package/dist/components/browser/SearchBar.svelte.d.ts +0 -6
- package/dist/components/browser/UploadButton.svelte +0 -65
- package/dist/components/browser/UploadButton.svelte.d.ts +0 -3
- package/dist/query/stac-geoparquet.d.ts +0 -31
- package/dist/query/stac-geoparquet.js +0 -136
- package/dist/utils/clipboard.d.ts +0 -13
- package/dist/utils/clipboard.js +0 -38
- package/dist/utils/cloud-url.d.ts +0 -27
- package/dist/utils/cloud-url.js +0 -61
- package/dist/utils/cog-pure.d.ts +0 -25
- package/dist/utils/cog-pure.js +0 -35
- package/dist/utils/column-types.d.ts +0 -5
- package/dist/utils/column-types.js +0 -137
- package/dist/utils/connection-identity.d.ts +0 -51
- package/dist/utils/connection-identity.js +0 -97
- package/dist/utils/error.d.ts +0 -8
- package/dist/utils/error.js +0 -12
- package/dist/utils/evidence-context.d.ts +0 -22
- package/dist/utils/evidence-context.js +0 -56
- package/dist/utils/export.d.ts +0 -22
- package/dist/utils/export.js +0 -76
- package/dist/utils/file-sort.d.ts +0 -20
- package/dist/utils/file-sort.js +0 -41
- package/dist/utils/format.d.ts +0 -24
- package/dist/utils/format.js +0 -78
- package/dist/utils/geoarrow.d.ts +0 -32
- package/dist/utils/geoarrow.js +0 -672
- package/dist/utils/geometry-type.d.ts +0 -52
- package/dist/utils/geometry-type.js +0 -76
- package/dist/utils/hex.d.ts +0 -10
- package/dist/utils/hex.js +0 -27
- package/dist/utils/host-detection.d.ts +0 -23
- package/dist/utils/host-detection.js +0 -95
- package/dist/utils/local-storage.d.ts +0 -16
- package/dist/utils/local-storage.js +0 -37
- package/dist/utils/markdown-sql.d.ts +0 -30
- package/dist/utils/markdown-sql.js +0 -72
- package/dist/utils/notebook.d.ts +0 -59
- package/dist/utils/notebook.js +0 -211
- package/dist/utils/parquet-metadata.d.ts +0 -64
- package/dist/utils/parquet-metadata.js +0 -262
- package/dist/utils/stac-geoparquet.d.ts +0 -90
- package/dist/utils/stac-geoparquet.js +0 -223
- package/dist/utils/stac-hydrate.d.ts +0 -38
- package/dist/utils/stac-hydrate.js +0 -243
- package/dist/utils/stac.d.ts +0 -136
- package/dist/utils/stac.js +0 -176
- package/dist/utils/storage-url.d.ts +0 -90
- package/dist/utils/storage-url.js +0 -568
- package/dist/utils/wkb.d.ts +0 -43
- package/dist/utils/wkb.js +0 -359
|
@@ -1,16 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import type { ChannelComposite, CogAsset, PresetDef } from '@walkthru-earth/objex-utils';
|
|
2
|
+
import { type BandConfig, type NodataConfig, type RescaleConfig } from '../../utils/cog.js';
|
|
3
|
+
type Props = {
|
|
4
|
+
/** All raster-COG-ish assets on the current item (or `[selfAsset]` for plain CogViewer). */
|
|
5
|
+
assets: CogAsset[];
|
|
6
|
+
/** Current RGB composite. Always present. */
|
|
7
|
+
composite: ChannelComposite;
|
|
8
|
+
onCompositeChange: (next: ChannelComposite) => void;
|
|
9
|
+
/** Presets that resolve on this item. Empty when no preset applies. */
|
|
10
|
+
presets: PresetDef[];
|
|
11
|
+
activePresetId: string;
|
|
12
|
+
onPresetChange: (id: string) => void;
|
|
13
|
+
/** Rendering mode toggle: 'rgb' uses the channel pickers; 'single' the band+ramp picker. */
|
|
14
|
+
mode: 'rgb' | 'single';
|
|
15
|
+
onModeChange: (m: 'rgb' | 'single') => void;
|
|
16
|
+
/** Band/ramp config used when mode === 'single'. Optional for RGB-only callers. */
|
|
17
|
+
bandConfig?: BandConfig | null;
|
|
18
|
+
bandCount?: number;
|
|
19
|
+
onBandConfigChange?: (next: BandConfig) => void;
|
|
7
20
|
rescale: RescaleConfig;
|
|
8
21
|
rescaleApplicable: boolean;
|
|
9
|
-
onRescaleChange: (
|
|
10
|
-
/** Optional histogram bins (normalized, single-band only) for the slider overlay. */
|
|
22
|
+
onRescaleChange: (next: RescaleConfig) => void;
|
|
11
23
|
histogram?: Uint32Array | null;
|
|
12
|
-
|
|
24
|
+
/** Optional 4th channel UI affordance (alpha). When false, alpha row is hidden. */
|
|
25
|
+
showAlpha?: boolean;
|
|
26
|
+
/** User-selected nodata config. Default `{ mode: 'auto' }`. */
|
|
27
|
+
nodata?: NodataConfig;
|
|
28
|
+
/**
|
|
29
|
+
* Value resolved by the viewer for Auto mode (typically the GeoTIFF's
|
|
30
|
+
* GDAL_NODATA tag). Surfaced as a hint pill next to the segmented control.
|
|
31
|
+
* `null` means the file has no GDAL_NODATA tag.
|
|
32
|
+
*/
|
|
33
|
+
autoNodata?: number | null;
|
|
34
|
+
/** Fired when the user changes nodata mode or value. */
|
|
35
|
+
onNodataChange?: (next: NodataConfig) => void;
|
|
13
36
|
};
|
|
14
|
-
declare const CogControls: import("svelte").Component
|
|
37
|
+
declare const CogControls: import("svelte").Component<Props, {}, "">;
|
|
15
38
|
type CogControls = ReturnType<typeof CogControls>;
|
|
16
39
|
export default CogControls;
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
import { MapboxOverlay } from '@deck.gl/mapbox';
|
|
3
3
|
import { COGLayer } from '@developmentseed/deck.gl-geotiff';
|
|
4
4
|
import { DecoderPool, GeoTIFF } from '@developmentseed/geotiff';
|
|
5
|
+
import {
|
|
6
|
+
attachPixelInspector,
|
|
7
|
+
type ChannelComposite,
|
|
8
|
+
type CogAsset,
|
|
9
|
+
smokeTestHref,
|
|
10
|
+
syntheticSelfAsset
|
|
11
|
+
} from '@walkthru-earth/objex-utils';
|
|
5
12
|
import type maplibregl from 'maplibre-gl';
|
|
6
13
|
import { onDestroy, untrack } from 'svelte';
|
|
7
14
|
import { t } from '../../i18n/index.svelte.js';
|
|
@@ -9,28 +16,39 @@ import { tabResources } from '../../stores/tab-resources.svelte.js';
|
|
|
9
16
|
import type { Tab } from '../../types.js';
|
|
10
17
|
import {
|
|
11
18
|
type BandConfig,
|
|
19
|
+
buildCustomRenderTile,
|
|
12
20
|
buildDataTypeLabel,
|
|
13
21
|
type CogInfo,
|
|
22
|
+
type ConfigurableTileLoader,
|
|
14
23
|
type CustomTileData,
|
|
15
24
|
clampBounds,
|
|
16
25
|
cleanupNativeBitmap,
|
|
26
|
+
createConfigurableGetTileData,
|
|
17
27
|
createEpsgResolver,
|
|
28
|
+
DEFAULT_NODATA_CONFIG,
|
|
18
29
|
DEFAULT_RESCALE,
|
|
19
30
|
defaultBandConfig,
|
|
20
31
|
fitCogBounds,
|
|
21
32
|
HISTOGRAM_BIN_COUNT,
|
|
22
33
|
inspectCogTags,
|
|
34
|
+
loadGeoTIFF,
|
|
35
|
+
mapResolutionMetersPerPixel,
|
|
36
|
+
type NodataConfig,
|
|
23
37
|
needsCustomPipelineForConfig,
|
|
24
38
|
normalizeCogGeotiff,
|
|
25
39
|
type PixelValue,
|
|
26
40
|
type RescaleConfig,
|
|
41
|
+
readGdalNodata,
|
|
27
42
|
readPixelAtLngLat,
|
|
28
43
|
renderNonTiledBitmap,
|
|
29
44
|
resolveProj4Def,
|
|
30
|
-
selectCogPipeline
|
|
45
|
+
selectCogPipeline,
|
|
46
|
+
selectOverviewForResolution
|
|
31
47
|
} from '../../utils/cog.js';
|
|
32
|
-
import {
|
|
48
|
+
import { seedRescaleFromGeotiff } from '../../utils/cog-histogram.js';
|
|
49
|
+
import { buildHttpsUrlAsync } from '../../utils/signed-url.js';
|
|
33
50
|
import CogControls from './CogControls.svelte';
|
|
51
|
+
import PixelInspectorPanel, { type PixelInspectorRow } from './cog/PixelInspectorPanel.svelte';
|
|
34
52
|
import MapContainer from './map/MapContainer.svelte';
|
|
35
53
|
|
|
36
54
|
// ─── State ───────────────────────────────────────────────────────
|
|
@@ -43,24 +61,69 @@ let showControls = $state(false);
|
|
|
43
61
|
let bounds = $state<[number, number, number, number] | undefined>();
|
|
44
62
|
let cogInfo = $state<CogInfo | null>(null);
|
|
45
63
|
let bandConfig = $state<BandConfig | null>(null);
|
|
64
|
+
let resolvedHrefForControls = $state<string | null>(null);
|
|
65
|
+
let probedBandCount = $state<number | null>(null);
|
|
66
|
+
|
|
67
|
+
const cogControlsAssets = $derived.by<CogAsset[]>(() => {
|
|
68
|
+
const href = resolvedHrefForControls;
|
|
69
|
+
if (!href) return [];
|
|
70
|
+
return [syntheticSelfAsset(href, probedBandCount ?? undefined)];
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const cogControlsComposite = $derived.by<ChannelComposite>(() => {
|
|
74
|
+
const bc = bandConfig;
|
|
75
|
+
if (!bc) {
|
|
76
|
+
return {
|
|
77
|
+
r: { assetKey: 'self', bandIndex: 0 },
|
|
78
|
+
g: { assetKey: 'self', bandIndex: 0 },
|
|
79
|
+
b: { assetKey: 'self', bandIndex: 0 }
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (bc.mode === 'rgb') {
|
|
83
|
+
return {
|
|
84
|
+
r: { assetKey: 'self', bandIndex: bc.rBand ?? 0 },
|
|
85
|
+
g: { assetKey: 'self', bandIndex: bc.gBand ?? 0 },
|
|
86
|
+
b: { assetKey: 'self', bandIndex: bc.bBand ?? 0 }
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const i = bc.band ?? 0;
|
|
90
|
+
return {
|
|
91
|
+
r: { assetKey: 'self', bandIndex: i },
|
|
92
|
+
g: { assetKey: 'self', bandIndex: i },
|
|
93
|
+
b: { assetKey: 'self', bandIndex: i }
|
|
94
|
+
};
|
|
95
|
+
});
|
|
46
96
|
let histogram = $state.raw<Uint32Array | null>(null);
|
|
47
97
|
let histogramTick = $state(0);
|
|
48
98
|
let rescale = $state<RescaleConfig>({ ...DEFAULT_RESCALE });
|
|
99
|
+
// User-facing nodata override (Auto/Value/Off). Auto resolves at read time
|
|
100
|
+
// from the GeoTIFF's GDAL_NODATA tag, surfaced as a hint pill in CogControls.
|
|
101
|
+
let nodataConfig = $state<NodataConfig>({ ...DEFAULT_NODATA_CONFIG });
|
|
102
|
+
let autoNodata = $state<number | null>(null);
|
|
49
103
|
// Palette-indexed COGs render through the library's Colormap module; a GPU
|
|
50
104
|
// rescale at that stage is cosmetic and would confuse the legend. Keep the
|
|
51
105
|
// slider hidden when a ColorMap tag is present.
|
|
52
106
|
let isPaletteIndexed = $state(false);
|
|
53
107
|
let pixelValue = $state<PixelValue | null>(null);
|
|
54
108
|
let inspecting = $state(false);
|
|
109
|
+
// Storage smoke-test result for the primary asset href. Inspired by
|
|
110
|
+
// lazycogs `_smoketest_store`, surfaces auth / CORS / bucket failures at
|
|
111
|
+
// open time as a small amber pill, never blocks the layer mount.
|
|
112
|
+
let smokeWarning = $state<string | null>(null);
|
|
113
|
+
let smokeProbed = false;
|
|
55
114
|
|
|
56
115
|
let abortController = new AbortController();
|
|
57
116
|
let mapRef: maplibregl.Map | null = null;
|
|
58
117
|
let overlayRef: MapboxOverlay | null = null;
|
|
59
118
|
let geotiffRef: GeoTIFF | null = null;
|
|
119
|
+
// Identity-stable tile loader for the configurable CPU path. Lives for the
|
|
120
|
+
// duration of the current GeoTIFF identity, so deck.gl's TileLayer cache
|
|
121
|
+
// survives band/ramp swaps (a fresh getTileData reference would invalidate it).
|
|
122
|
+
let tileLoaderRef: ConfigurableTileLoader | null = null;
|
|
60
123
|
let proj4DefRef: string | null = null;
|
|
61
124
|
let sampleFormatRef = 1;
|
|
62
125
|
let isTiledRef = true;
|
|
63
|
-
let
|
|
126
|
+
let detachInspector: (() => void) | null = null;
|
|
64
127
|
let resolvedHttpsUrl: string | null = null;
|
|
65
128
|
// LinearRescale operates on a 0..1 scalar. Two cases expose a meaningful
|
|
66
129
|
// slider: (1) the library-default uint RGB pipeline (scales `color.rgb`
|
|
@@ -111,8 +174,11 @@ $effect(() => {
|
|
|
111
174
|
}
|
|
112
175
|
overlayRef = null;
|
|
113
176
|
geotiffRef = null;
|
|
177
|
+
tileLoaderRef = null;
|
|
114
178
|
proj4DefRef = null;
|
|
115
179
|
resolvedHttpsUrl = null;
|
|
180
|
+
resolvedHrefForControls = null;
|
|
181
|
+
probedBandCount = null;
|
|
116
182
|
loading = true;
|
|
117
183
|
error = null;
|
|
118
184
|
cogInfo = null;
|
|
@@ -120,8 +186,12 @@ $effect(() => {
|
|
|
120
186
|
histogram = null;
|
|
121
187
|
histogramTick = 0;
|
|
122
188
|
rescale = { ...DEFAULT_RESCALE };
|
|
189
|
+
nodataConfig = { ...DEFAULT_NODATA_CONFIG };
|
|
190
|
+
autoNodata = null;
|
|
123
191
|
isPaletteIndexed = false;
|
|
124
192
|
pixelValue = null;
|
|
193
|
+
smokeWarning = null;
|
|
194
|
+
smokeProbed = false;
|
|
125
195
|
bounds = undefined;
|
|
126
196
|
hasFittedOnce = false;
|
|
127
197
|
showControls = false;
|
|
@@ -140,34 +210,32 @@ function onMapReady(map: maplibregl.Map) {
|
|
|
140
210
|
// ─── Click handler for pixel inspection ──────────────────────────
|
|
141
211
|
|
|
142
212
|
function removeClickHandler() {
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
213
|
+
if (detachInspector) {
|
|
214
|
+
detachInspector();
|
|
215
|
+
detachInspector = null;
|
|
146
216
|
}
|
|
147
217
|
}
|
|
148
218
|
|
|
149
219
|
function setupClickHandler(map: maplibregl.Map) {
|
|
150
220
|
removeClickHandler();
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
221
|
+
detachInspector = attachPixelInspector<PixelValue>(map, {
|
|
222
|
+
probe: async ({ lng, lat, signal }) => {
|
|
223
|
+
if (!geotiffRef) return null;
|
|
224
|
+
// matches overview shown on screen
|
|
225
|
+
const targetRes = mapResolutionMetersPerPixel(map.getZoom(), lat);
|
|
226
|
+
const overview = selectOverviewForResolution(geotiffRef, targetRes);
|
|
227
|
+
return readPixelAtLngLat(geotiffRef, lng, lat, proj4DefRef, pool, signal, {
|
|
228
|
+
overview
|
|
229
|
+
});
|
|
230
|
+
},
|
|
231
|
+
onStart: () => {
|
|
232
|
+
inspecting = true;
|
|
233
|
+
},
|
|
234
|
+
onResult: (result) => {
|
|
163
235
|
pixelValue = result;
|
|
164
|
-
} catch {
|
|
165
|
-
pixelValue = null;
|
|
166
|
-
} finally {
|
|
167
236
|
inspecting = false;
|
|
168
237
|
}
|
|
169
|
-
};
|
|
170
|
-
map.on('click', clickHandlerRef);
|
|
238
|
+
});
|
|
171
239
|
}
|
|
172
240
|
|
|
173
241
|
// ─── Core load function ──────────────────────────────────────────
|
|
@@ -179,12 +247,30 @@ async function loadCog(map: maplibregl.Map) {
|
|
|
179
247
|
const url = await buildHttpsUrlAsync(tab);
|
|
180
248
|
if (signal.aborted) return;
|
|
181
249
|
resolvedHttpsUrl = url;
|
|
250
|
+
resolvedHrefForControls = url;
|
|
251
|
+
|
|
252
|
+
// One-shot storage smoke-test. lazycogs-style probe surfaces auth /
|
|
253
|
+
// CORS / bucket failures at open time as an amber pill, never blocks
|
|
254
|
+
// the layer mount. Aborts via the viewer's existing controller.
|
|
255
|
+
if (!smokeProbed) {
|
|
256
|
+
smokeProbed = true;
|
|
257
|
+
void (async () => {
|
|
258
|
+
try {
|
|
259
|
+
const result = await smokeTestHref(url, signal);
|
|
260
|
+
if (signal.aborted) return;
|
|
261
|
+
if (!result.ok) smokeWarning = result.reason;
|
|
262
|
+
} catch (err) {
|
|
263
|
+
if (err instanceof DOMException && err.name === 'AbortError') return;
|
|
264
|
+
smokeWarning = err instanceof Error ? err.message : String(err);
|
|
265
|
+
}
|
|
266
|
+
})();
|
|
267
|
+
}
|
|
182
268
|
|
|
183
269
|
// Pre-flight: read first IFD to check if tiled (single range request).
|
|
184
270
|
let isTiled = true;
|
|
185
271
|
let preflightGeotiff: GeoTIFF | undefined;
|
|
186
272
|
try {
|
|
187
|
-
preflightGeotiff = await
|
|
273
|
+
preflightGeotiff = await loadGeoTIFF(url);
|
|
188
274
|
if (signal.aborted) return;
|
|
189
275
|
isTiled = preflightGeotiff.isTiled;
|
|
190
276
|
|
|
@@ -233,6 +319,22 @@ async function loadCog(map: maplibregl.Map) {
|
|
|
233
319
|
|
|
234
320
|
// Set default band config
|
|
235
321
|
bandConfig = defaultBandConfig(preflightGeotiff.count, sampleFormatRef);
|
|
322
|
+
probedBandCount = preflightGeotiff.count;
|
|
323
|
+
|
|
324
|
+
// Surface GDAL_NODATA + a shader-space rescale seed (when present) so
|
|
325
|
+
// the nodata hint pill and rescale slider have meaningful defaults
|
|
326
|
+
// before the first tile decodes — matches source-cooperative/cog-viewer
|
|
327
|
+
// UX. The slider operates in normalized [0, 1] shader space, so
|
|
328
|
+
// `seedRescaleFromGeotiff` divides GDAL STATISTICS_MIN/MAX by the
|
|
329
|
+
// sample-format factor and falls back to a p2/p98 histogram + the
|
|
330
|
+
// bit-depth-aware default.
|
|
331
|
+
autoNodata = readGdalNodata(preflightGeotiff);
|
|
332
|
+
try {
|
|
333
|
+
rescale = await seedRescaleFromGeotiff(preflightGeotiff, { signal });
|
|
334
|
+
} catch {
|
|
335
|
+
// fall through, defaults remain
|
|
336
|
+
}
|
|
337
|
+
if (signal.aborted) return;
|
|
236
338
|
}
|
|
237
339
|
|
|
238
340
|
if (!isTiled && preflightGeotiff) {
|
|
@@ -267,25 +369,48 @@ async function loadCog(map: maplibregl.Map) {
|
|
|
267
369
|
|
|
268
370
|
// ─── Build & add COGLayer ────────────────────────────────────────
|
|
269
371
|
|
|
270
|
-
|
|
372
|
+
// Build the pipeline props (getTileData/renderTile/etc) for the current state.
|
|
373
|
+
// When the configurable CPU path applies, the tile loader is created once per
|
|
374
|
+
// GeoTIFF identity and its `getTileData` reference is reused across rebuilds so
|
|
375
|
+
// deck.gl's TileLayer cache survives band/ramp swaps. Only `renderTile` and
|
|
376
|
+
// downstream uniforms vary across style changes.
|
|
377
|
+
function buildPipelineProps(geotiff: GeoTIFF | undefined): Record<string, unknown> {
|
|
378
|
+
if (!geotiff || !bandConfig) {
|
|
379
|
+
return geotiff ? selectCogPipeline(geotiff, { bandConfig, rescale }) : {};
|
|
380
|
+
}
|
|
381
|
+
if (needsCustomPipelineForConfig(geotiff, bandConfig)) {
|
|
382
|
+
if (!tileLoaderRef) {
|
|
383
|
+
tileLoaderRef = createConfigurableGetTileData(geotiff, bandConfig);
|
|
384
|
+
} else {
|
|
385
|
+
tileLoaderRef.updateConfig(bandConfig);
|
|
386
|
+
}
|
|
387
|
+
return {
|
|
388
|
+
getTileData: tileLoaderRef.getTileData,
|
|
389
|
+
renderTile: buildCustomRenderTile(bandConfig, rescale)
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
// Library-default or rescaled-only path. The loader (if previously seeded)
|
|
393
|
+
// is harmless to keep, but the upcoming rebuild won't reference it.
|
|
394
|
+
return selectCogPipeline(geotiff, { bandConfig, rescale });
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function buildCogLayer(
|
|
271
398
|
map: maplibregl.Map,
|
|
272
399
|
preflightGeotiff: GeoTIFF | undefined,
|
|
273
400
|
signal: AbortSignal
|
|
274
|
-
) {
|
|
401
|
+
): COGLayer {
|
|
275
402
|
// Pick the library-default or one of three custom pipelines. Empty when the
|
|
276
403
|
// library-default uint path runs unchanged.
|
|
277
|
-
const customProps = preflightGeotiff
|
|
278
|
-
? selectCogPipeline(preflightGeotiff, { bandConfig, rescale })
|
|
279
|
-
: {};
|
|
404
|
+
const customProps = buildPipelineProps(preflightGeotiff);
|
|
280
405
|
|
|
281
406
|
// Apply upstream-bug workarounds in place (overview filter, 4326 bbox clamp).
|
|
282
407
|
if (preflightGeotiff) normalizeCogGeotiff(preflightGeotiff);
|
|
283
408
|
|
|
284
409
|
const cogInput = preflightGeotiff ?? resolvedHttpsUrl ?? '';
|
|
285
410
|
|
|
286
|
-
// Cast: `onViewportLoad` is forwarded by
|
|
287
|
-
//
|
|
288
|
-
//
|
|
411
|
+
// Cast: `onViewportLoad` is forwarded natively by COGLayer's RasterTileLayer
|
|
412
|
+
// base in 0.7.0 (deck.gl-raster PR #546), but COGLayer's generated .d.ts does
|
|
413
|
+
// not surface it.
|
|
289
414
|
const cogProps: any = {
|
|
290
415
|
// Stable id per tab so rebuilds on band/style change don't force deck.gl
|
|
291
416
|
// to treat this as a brand-new layer and drop cached tile state.
|
|
@@ -351,7 +476,18 @@ function buildAndAddLayer(
|
|
|
351
476
|
loading = false;
|
|
352
477
|
}
|
|
353
478
|
};
|
|
354
|
-
|
|
479
|
+
return new COGLayer(cogProps);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// First-mount: create the MapboxOverlay once and attach via addControl.
|
|
483
|
+
// Subsequent style changes go through pushLayer() which only calls setProps,
|
|
484
|
+
// preserving deck.gl's WebGL context and tile cache.
|
|
485
|
+
function buildAndAddLayer(
|
|
486
|
+
map: maplibregl.Map,
|
|
487
|
+
preflightGeotiff: GeoTIFF | undefined,
|
|
488
|
+
signal: AbortSignal
|
|
489
|
+
) {
|
|
490
|
+
const layer = buildCogLayer(map, preflightGeotiff, signal);
|
|
355
491
|
|
|
356
492
|
const overlay = new MapboxOverlay({
|
|
357
493
|
interleaved: false,
|
|
@@ -368,6 +504,15 @@ function buildAndAddLayer(
|
|
|
368
504
|
map.addControl(overlay as unknown as maplibregl.IControl);
|
|
369
505
|
}
|
|
370
506
|
|
|
507
|
+
// Style-change update path: swap layers in place via setProps. Identity of the
|
|
508
|
+
// COGLayer's `id` and `getTileData` is preserved so deck.gl reconciles the
|
|
509
|
+
// existing layer instance and keeps its tile cache.
|
|
510
|
+
function pushLayer() {
|
|
511
|
+
if (!mapRef || !geotiffRef || !overlayRef) return;
|
|
512
|
+
const layer = buildCogLayer(mapRef, geotiffRef, abortController.signal);
|
|
513
|
+
overlayRef.setProps({ layers: [layer] });
|
|
514
|
+
}
|
|
515
|
+
|
|
371
516
|
// ─── Viewport-scoped histogram aggregation ───────────────────────
|
|
372
517
|
|
|
373
518
|
/**
|
|
@@ -418,35 +563,41 @@ function handleConfigChange(newConfig: BandConfig) {
|
|
|
418
563
|
histogramTick = 0;
|
|
419
564
|
if (!mapRef || !geotiffRef || !isTiledRef) return;
|
|
420
565
|
|
|
421
|
-
//
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
} catch {
|
|
426
|
-
/* already removed */
|
|
427
|
-
}
|
|
428
|
-
overlayRef = null;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Rebuild with new config
|
|
432
|
-
buildAndAddLayer(mapRef, geotiffRef, abortController.signal);
|
|
566
|
+
// Swap layers in place: deck.gl diffs on layer id and reuses the stable
|
|
567
|
+
// `getTileData` reference held by `tileLoaderRef`, so the tile cache and
|
|
568
|
+
// in-flight fetches survive band/style changes.
|
|
569
|
+
pushLayer();
|
|
433
570
|
}
|
|
434
571
|
|
|
435
572
|
function handleRescaleChange(next: RescaleConfig) {
|
|
436
573
|
rescale = next;
|
|
437
574
|
if (!mapRef || !geotiffRef || !isTiledRef) return;
|
|
575
|
+
pushLayer();
|
|
576
|
+
}
|
|
438
577
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
578
|
+
// ─── Unified picker change handlers ──────────────────────────────
|
|
579
|
+
|
|
580
|
+
function handleCompositeChange(next: ChannelComposite): void {
|
|
581
|
+
if (!bandConfig) return;
|
|
582
|
+
if (bandConfig.mode === 'rgb') {
|
|
583
|
+
handleConfigChange({
|
|
584
|
+
...bandConfig,
|
|
585
|
+
rBand: next.r.bandIndex,
|
|
586
|
+
gBand: next.g.bandIndex,
|
|
587
|
+
bBand: next.b.bandIndex
|
|
588
|
+
});
|
|
589
|
+
} else {
|
|
590
|
+
handleConfigChange({ ...bandConfig, band: next.r.bandIndex });
|
|
448
591
|
}
|
|
449
|
-
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function handleModeChange(m: 'rgb' | 'single'): void {
|
|
595
|
+
if (!bandConfig) return;
|
|
596
|
+
handleConfigChange({ ...bandConfig, mode: m });
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
function handleBandConfigChange(next: BandConfig): void {
|
|
600
|
+
handleConfigChange(next);
|
|
450
601
|
}
|
|
451
602
|
|
|
452
603
|
// ─── Cleanup ─────────────────────────────────────────────────────
|
|
@@ -465,9 +616,12 @@ function cleanup() {
|
|
|
465
616
|
mapRef = null;
|
|
466
617
|
overlayRef = null;
|
|
467
618
|
geotiffRef = null;
|
|
619
|
+
tileLoaderRef = null;
|
|
468
620
|
proj4DefRef = null;
|
|
469
621
|
pixelValue = null;
|
|
470
622
|
resolvedHttpsUrl = null;
|
|
623
|
+
resolvedHrefForControls = null;
|
|
624
|
+
probedBandCount = null;
|
|
471
625
|
}
|
|
472
626
|
|
|
473
627
|
$effect(() => {
|
|
@@ -484,7 +638,7 @@ onDestroy(cleanup);
|
|
|
484
638
|
</div>
|
|
485
639
|
|
|
486
640
|
<!-- Top-left: Loading + metadata badges -->
|
|
487
|
-
<div class="pointer-events-none absolute left-2 top-2 z-10 flex flex-col gap-1">
|
|
641
|
+
<div class="pointer-events-none absolute left-2 top-2 z-10 flex max-w-[calc(100vw-7rem)] flex-col gap-1 sm:max-w-none">
|
|
488
642
|
{#if loading}
|
|
489
643
|
<div
|
|
490
644
|
class="rounded bg-card/80 px-2 py-1 text-xs text-card-foreground backdrop-blur-sm"
|
|
@@ -512,14 +666,23 @@ onDestroy(cleanup);
|
|
|
512
666
|
{error}
|
|
513
667
|
</div>
|
|
514
668
|
{/if}
|
|
669
|
+
|
|
670
|
+
{#if smokeWarning && !error}
|
|
671
|
+
<div
|
|
672
|
+
class="pointer-events-auto max-w-sm rounded bg-amber-900/80 px-2 py-1 text-xs text-amber-100"
|
|
673
|
+
title={t('stac.smokeWarningHint')}
|
|
674
|
+
>
|
|
675
|
+
{t('stac.smokeWarning', { reason: smokeWarning })}
|
|
676
|
+
</div>
|
|
677
|
+
{/if}
|
|
515
678
|
</div>
|
|
516
679
|
|
|
517
680
|
<!-- Top-right: Info + Style buttons -->
|
|
518
681
|
{#if cogInfo}
|
|
519
|
-
<div class="absolute right-2 top-2 z-10 flex gap-1">
|
|
682
|
+
<div class="absolute right-2 top-2 z-10 flex gap-1" style="touch-action: manipulation;">
|
|
520
683
|
{#if bandConfig}
|
|
521
684
|
<button
|
|
522
|
-
class="rounded bg-card/80 px-
|
|
685
|
+
class="inline-flex min-h-11 min-w-11 items-center justify-center rounded bg-card/80 px-3 py-1.5 text-xs text-card-foreground backdrop-blur-sm hover:bg-card sm:min-h-0 sm:min-w-0 sm:px-2 sm:py-1"
|
|
523
686
|
class:ring-1={showControls}
|
|
524
687
|
class:ring-primary={showControls}
|
|
525
688
|
onclick={() => {
|
|
@@ -531,7 +694,7 @@ onDestroy(cleanup);
|
|
|
531
694
|
</button>
|
|
532
695
|
{/if}
|
|
533
696
|
<button
|
|
534
|
-
class="rounded bg-card/80 px-
|
|
697
|
+
class="inline-flex min-h-11 min-w-11 items-center justify-center rounded bg-card/80 px-3 py-1.5 text-xs text-card-foreground backdrop-blur-sm hover:bg-card sm:min-h-0 sm:min-w-0 sm:px-2 sm:py-1"
|
|
535
698
|
class:ring-1={showInfo}
|
|
536
699
|
class:ring-primary={showInfo}
|
|
537
700
|
onclick={() => {
|
|
@@ -543,23 +706,39 @@ onDestroy(cleanup);
|
|
|
543
706
|
</button>
|
|
544
707
|
</div>
|
|
545
708
|
|
|
546
|
-
<!-- Band/Color controls panel
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
709
|
+
<!-- Band/Color controls panel. Kept mounted so slider drag state and focus
|
|
710
|
+
survive every visibility toggle; only the `hidden` class is flipped. -->
|
|
711
|
+
{#if bandConfig}
|
|
712
|
+
<div class={showControls ? 'contents' : 'hidden'}>
|
|
713
|
+
<CogControls
|
|
714
|
+
assets={cogControlsAssets}
|
|
715
|
+
composite={cogControlsComposite}
|
|
716
|
+
onCompositeChange={handleCompositeChange}
|
|
717
|
+
presets={[]}
|
|
718
|
+
activePresetId=""
|
|
719
|
+
onPresetChange={() => {}}
|
|
720
|
+
mode={bandConfig?.mode ?? 'rgb'}
|
|
721
|
+
onModeChange={handleModeChange}
|
|
722
|
+
{bandConfig}
|
|
723
|
+
bandCount={probedBandCount ?? cogInfo.bandCount}
|
|
724
|
+
onBandConfigChange={handleBandConfigChange}
|
|
725
|
+
{rescale}
|
|
726
|
+
rescaleApplicable={rescaleApplicable}
|
|
727
|
+
onRescaleChange={handleRescaleChange}
|
|
728
|
+
{histogram}
|
|
729
|
+
nodata={nodataConfig}
|
|
730
|
+
{autoNodata}
|
|
731
|
+
onNodataChange={(next) => {
|
|
732
|
+
nodataConfig = next;
|
|
733
|
+
}}
|
|
734
|
+
/>
|
|
735
|
+
</div>
|
|
557
736
|
{/if}
|
|
558
737
|
|
|
559
738
|
<!-- Info panel -->
|
|
560
739
|
{#if showInfo}
|
|
561
740
|
<div
|
|
562
|
-
class="absolute
|
|
741
|
+
class="absolute inset-x-2 top-16 z-10 max-h-[60vh] overflow-auto rounded bg-card/90 p-3 text-xs text-card-foreground backdrop-blur-sm sm:inset-x-auto sm:right-2 sm:top-10 sm:max-h-[70vh] sm:w-64"
|
|
563
742
|
>
|
|
564
743
|
<h3 class="mb-2 font-medium">{t('map.cogInfo')}</h3>
|
|
565
744
|
<dl class="space-y-1.5">
|
|
@@ -579,45 +758,17 @@ onDestroy(cleanup);
|
|
|
579
758
|
{/if}
|
|
580
759
|
|
|
581
760
|
<!-- Bottom-left: Pixel value on click -->
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
<div class="space-y-0.5 text-muted-foreground">
|
|
596
|
-
<div>
|
|
597
|
-
{pixelValue.lat.toFixed(6)}°, {pixelValue.lng.toFixed(6)}°
|
|
598
|
-
</div>
|
|
599
|
-
<div class="text-[10px]">
|
|
600
|
-
px ({pixelValue.col}, {pixelValue.row})
|
|
601
|
-
</div>
|
|
602
|
-
</div>
|
|
603
|
-
<div class="mt-1.5 space-y-0.5">
|
|
604
|
-
{#each pixelValue.values as val, i}
|
|
605
|
-
<div class="flex justify-between gap-2">
|
|
606
|
-
<span class="text-muted-foreground">{t('cog.band')} {i + 1}</span>
|
|
607
|
-
<span class="font-mono tabular-nums">
|
|
608
|
-
{Number.isInteger(val) ? val : val.toFixed(4)}
|
|
609
|
-
</span>
|
|
610
|
-
</div>
|
|
611
|
-
{/each}
|
|
612
|
-
</div>
|
|
613
|
-
</div>
|
|
614
|
-
{/if}
|
|
615
|
-
|
|
616
|
-
{#if inspecting}
|
|
617
|
-
<div
|
|
618
|
-
class="pointer-events-none absolute bottom-2 left-2 z-10 rounded bg-card/80 px-2 py-1 text-xs text-card-foreground backdrop-blur-sm"
|
|
619
|
-
>
|
|
620
|
-
{t('cog.reading')}
|
|
621
|
-
</div>
|
|
622
|
-
{/if}
|
|
761
|
+
<PixelInspectorPanel
|
|
762
|
+
lng={pixelValue?.lng ?? null}
|
|
763
|
+
lat={pixelValue?.lat ?? null}
|
|
764
|
+
rows={pixelValue
|
|
765
|
+
? (pixelValue.values.map((v, i) => ({
|
|
766
|
+
label: `${t('cog.band')} ${i + 1}`,
|
|
767
|
+
value: v
|
|
768
|
+
})) satisfies PixelInspectorRow[])
|
|
769
|
+
: null}
|
|
770
|
+
footnote={pixelValue ? `px (${pixelValue.col}, ${pixelValue.row})` : undefined}
|
|
771
|
+
onClose={() => (pixelValue = null)}
|
|
772
|
+
{inspecting}
|
|
773
|
+
/>
|
|
623
774
|
</div>
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
hoverCursor,
|
|
20
20
|
loadDeckModules
|
|
21
21
|
} from '../../utils/deck.js';
|
|
22
|
-
import { buildHttpsUrlAsync } from '../../utils/url.js';
|
|
22
|
+
import { buildHttpsUrlAsync } from '../../utils/signed-url.js';
|
|
23
23
|
import AttributeTable from './map/AttributeTable.svelte';
|
|
24
24
|
import MapContainer from './map/MapContainer.svelte';
|
|
25
25
|
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import LocateIcon from '@lucide/svelte/icons/locate';
|
|
3
|
+
import {
|
|
4
|
+
buildGeoArrowTables,
|
|
5
|
+
type GeoArrowGeomType,
|
|
6
|
+
type GeoArrowResult,
|
|
7
|
+
parseWKB
|
|
8
|
+
} from '@walkthru-earth/objex-utils';
|
|
3
9
|
import type maplibregl from 'maplibre-gl';
|
|
4
10
|
import { onDestroy } from 'svelte';
|
|
5
11
|
import { t } from '../../i18n/index.svelte.js';
|
|
@@ -14,12 +20,6 @@ import {
|
|
|
14
20
|
hoverCursor,
|
|
15
21
|
loadGeoArrowModules
|
|
16
22
|
} from '../../utils/deck.js';
|
|
17
|
-
import {
|
|
18
|
-
buildGeoArrowTables,
|
|
19
|
-
type GeoArrowGeomType,
|
|
20
|
-
type GeoArrowResult
|
|
21
|
-
} from '../../utils/geoarrow.js';
|
|
22
|
-
import { parseWKB } from '../../utils/wkb.js';
|
|
23
23
|
import LoadProgress, { type ProgressEntry } from './LoadProgress.svelte';
|
|
24
24
|
import AttributeTable from './map/AttributeTable.svelte';
|
|
25
25
|
import MapContainer from './map/MapContainer.svelte';
|