@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
|
@@ -3,12 +3,12 @@ import CodeIcon from '@lucide/svelte/icons/file-code';
|
|
|
3
3
|
import GlobeIcon from '@lucide/svelte/icons/globe';
|
|
4
4
|
import LayersIcon from '@lucide/svelte/icons/layers';
|
|
5
5
|
import MapIcon from '@lucide/svelte/icons/map';
|
|
6
|
+
import type { StacRoutableKind } from '@walkthru-earth/objex-utils';
|
|
6
7
|
import { t } from '../../i18n/index.svelte.js';
|
|
7
8
|
import { connectionStore } from '../../stores/connections.svelte.js';
|
|
8
9
|
import type { Tab } from '../../types.js';
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import { getUrlView, updateUrlView } from '../../utils/url-state.js';
|
|
10
|
+
import { canStreamDirectly } from '../../utils/signed-url.js';
|
|
11
|
+
import { getUrlView, pickViewMode, updateUrlView } from '../../utils/url-state.js';
|
|
12
12
|
import { Badge } from '../ui/badge/index.js';
|
|
13
13
|
import { Button } from '../ui/button/index.js';
|
|
14
14
|
import * as Tooltip from '../ui/tooltip/index.js';
|
|
@@ -28,7 +28,11 @@ interface Props {
|
|
|
28
28
|
|
|
29
29
|
let { tab, mapKind, classified }: Props = $props();
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
// 'code' is the URL token for raw-content view on JSON tabs; 'table' is the
|
|
32
|
+
// equivalent token on stac-geoparquet tabs. Both render the nested viewer
|
|
33
|
+
// (CodeViewer for JSON, TableViewer for parquet) but the URL stays
|
|
34
|
+
// semantically meaningful per filetype.
|
|
35
|
+
type ViewMode = 'map' | 'stac-map' | 'stac-browser' | 'code' | 'table';
|
|
32
36
|
|
|
33
37
|
interface CodeActions {
|
|
34
38
|
toggleFormat: () => Promise<void>;
|
|
@@ -70,13 +74,16 @@ const stacBadgeKey = $derived.by(() => {
|
|
|
70
74
|
});
|
|
71
75
|
|
|
72
76
|
function initialView(): ViewMode {
|
|
77
|
+
// `'map'` is conditional on `mapKind`, so it's not in the static vocabulary.
|
|
78
|
+
// Both `'code'` and `'table'` are accepted regardless of filetype so a URL
|
|
79
|
+
// shared from one type still resolves; the render branch dispatches to the
|
|
80
|
+
// appropriate inner viewer (`TableViewer` / `CodeViewer`).
|
|
81
|
+
const picked = pickViewMode<ViewMode>(['stac-map', 'stac-browser', 'code', 'table'], 'stac-map');
|
|
73
82
|
const urlView = getUrlView();
|
|
74
83
|
if (urlView === 'map' && mapKind) return 'map';
|
|
75
|
-
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
if (mapKind) return 'map';
|
|
79
|
-
return 'stac-map';
|
|
84
|
+
// Hash was unknown or empty: prefer the rich map view when available.
|
|
85
|
+
if (mapKind && !urlView) return 'map';
|
|
86
|
+
return picked;
|
|
80
87
|
}
|
|
81
88
|
|
|
82
89
|
let viewMode = $state<ViewMode>(initialView());
|
|
@@ -86,8 +93,12 @@ let codeActions = $state<CodeActions | null>(null);
|
|
|
86
93
|
function setView(next: ViewMode) {
|
|
87
94
|
if (viewMode === next) return;
|
|
88
95
|
viewMode = next;
|
|
89
|
-
updateUrlView(next
|
|
96
|
+
updateUrlView(next);
|
|
90
97
|
}
|
|
98
|
+
|
|
99
|
+
// The "Table" / "JSON" button in the navbar writes a filetype-aware token so
|
|
100
|
+
// the URL stays semantically meaningful (parquet → `#table`, json → `#code`).
|
|
101
|
+
const rawContentMode: ViewMode = $derived(isParquet ? 'table' : 'code');
|
|
91
102
|
</script>
|
|
92
103
|
|
|
93
104
|
<Tooltip.Provider>
|
|
@@ -191,9 +202,9 @@ function setView(next: ViewMode) {
|
|
|
191
202
|
{/if}
|
|
192
203
|
<Button
|
|
193
204
|
size="sm"
|
|
194
|
-
variant={viewMode ===
|
|
205
|
+
variant={viewMode === rawContentMode ? 'default' : 'ghost'}
|
|
195
206
|
class="h-7 gap-1 px-2"
|
|
196
|
-
onclick={() => setView(
|
|
207
|
+
onclick={() => setView(rawContentMode)}
|
|
197
208
|
>
|
|
198
209
|
<CodeIcon class="size-3.5" />
|
|
199
210
|
{isParquet ? t('stac.viewTable') : t('stac.viewJson')}
|
|
@@ -244,7 +255,7 @@ function setView(next: ViewMode) {
|
|
|
244
255
|
{:else if viewMode === 'stac-browser'}
|
|
245
256
|
<StacMapViewer {tab} variant="stac-browser" />
|
|
246
257
|
{:else if isParquet}
|
|
247
|
-
<TableViewer {tab} />
|
|
258
|
+
<TableViewer {tab} nested />
|
|
248
259
|
{:else}
|
|
249
260
|
<CodeViewer {tab} nested bind:wordWrap bind:actions={codeActions} />
|
|
250
261
|
{/if}
|
|
@@ -7,15 +7,15 @@ import ColumnsIcon from '@lucide/svelte/icons/columns-3';
|
|
|
7
7
|
import CopyIcon from '@lucide/svelte/icons/copy';
|
|
8
8
|
import RowsIcon from '@lucide/svelte/icons/rows-3';
|
|
9
9
|
import XIcon from '@lucide/svelte/icons/x';
|
|
10
|
-
import { onDestroy } from 'svelte';
|
|
11
|
-
import { t } from '../../i18n/index.svelte.js';
|
|
12
10
|
import {
|
|
13
11
|
classifyType,
|
|
12
|
+
jsonReplacerBigInt,
|
|
14
13
|
type TypeCategory,
|
|
15
14
|
typeBadgeClass,
|
|
16
15
|
typeLabel
|
|
17
|
-
} from '
|
|
18
|
-
import {
|
|
16
|
+
} from '@walkthru-earth/objex-utils';
|
|
17
|
+
import { onDestroy } from 'svelte';
|
|
18
|
+
import { t } from '../../i18n/index.svelte.js';
|
|
19
19
|
|
|
20
20
|
const INITIAL_ROWS = 100;
|
|
21
21
|
const BATCH_SIZE = 100;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
|
|
3
3
|
import DownloadIcon from '@lucide/svelte/icons/download';
|
|
4
|
+
import { exportToCsv, exportToJson } from '@walkthru-earth/objex-utils';
|
|
4
5
|
import { t } from '../../i18n/index.svelte.js';
|
|
5
|
-
import { exportToCsv, exportToJson } from '../../utils/export.js';
|
|
6
6
|
|
|
7
7
|
let {
|
|
8
8
|
rowCount = 0,
|
|
@@ -16,7 +16,7 @@ import { Separator } from '../ui/separator/index.js';
|
|
|
16
16
|
import { t } from '../../i18n/index.svelte.js';
|
|
17
17
|
import { connections } from '../../stores/connections.svelte.js';
|
|
18
18
|
import type { Tab } from '../../types';
|
|
19
|
-
import { buildHttpsUrl, buildStorageUrl } from '../../utils/url.js';
|
|
19
|
+
import { buildHttpsUrl, buildStorageUrl } from '../../utils/signed-url.js';
|
|
20
20
|
|
|
21
21
|
const PROVIDER_LABELS: Record<string, string> = {
|
|
22
22
|
s3: 'S3',
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { GeoArrowGeomType } from '@walkthru-earth/objex-utils';
|
|
3
|
+
import {
|
|
4
|
+
buildTransformExpr,
|
|
5
|
+
extractBounds,
|
|
6
|
+
extractEpsgFromGeoMeta,
|
|
7
|
+
extractGeometryTypes,
|
|
8
|
+
findGeoColumn,
|
|
9
|
+
findGeoColumnFromRows,
|
|
10
|
+
parseWKB,
|
|
11
|
+
readParquetMetadata,
|
|
12
|
+
toBinary,
|
|
13
|
+
wrapWkbWithCrs
|
|
14
|
+
} from '@walkthru-earth/objex-utils';
|
|
2
15
|
import { format as formatSql } from 'sql-formatter';
|
|
3
16
|
import { untrack } from 'svelte';
|
|
4
17
|
import CodeMirrorEditor from '../editor/CodeMirrorEditor.svelte';
|
|
@@ -18,22 +31,13 @@ import { queryHistory } from '../../stores/query-history.svelte.js';
|
|
|
18
31
|
import { settings } from '../../stores/settings.svelte.js';
|
|
19
32
|
import { tabResources } from '../../stores/tab-resources.svelte.js';
|
|
20
33
|
import type { Tab } from '../../types';
|
|
21
|
-
import type { GeoArrowGeomType } from '../../utils/geoarrow.js';
|
|
22
|
-
import { buildTransformExpr, wrapWkbWithCrs } from '../../utils/geometry-type.js';
|
|
23
|
-
import {
|
|
24
|
-
extractBounds,
|
|
25
|
-
extractEpsgFromGeoMeta,
|
|
26
|
-
extractGeometryTypes,
|
|
27
|
-
readParquetMetadata
|
|
28
|
-
} from '../../utils/parquet-metadata.js';
|
|
29
34
|
import {
|
|
30
35
|
buildDuckDbUrl,
|
|
31
36
|
buildHttpsUrl,
|
|
32
37
|
buildStorageUrl,
|
|
33
38
|
canStreamDirectly
|
|
34
|
-
} from '../../utils/url.js';
|
|
35
|
-
import {
|
|
36
|
-
import { findGeoColumn, findGeoColumnFromRows, parseWKB, toBinary } from '../../utils/wkb.js';
|
|
39
|
+
} from '../../utils/signed-url.js';
|
|
40
|
+
import { pickViewMode, updateUrlView } from '../../utils/url-state.js';
|
|
37
41
|
import FileInfo from './FileInfo.svelte';
|
|
38
42
|
import LoadProgress, { type ProgressEntry } from './LoadProgress.svelte';
|
|
39
43
|
import QueryHistoryPanel from './QueryHistoryPanel.svelte';
|
|
@@ -41,7 +45,11 @@ import TableGrid from './TableGrid.svelte';
|
|
|
41
45
|
import TableStatusBar from './TableStatusBar.svelte';
|
|
42
46
|
import TableToolbar from './TableToolbar.svelte';
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
// `nested = true` when mounted inside `StacTabViewer` for a stac-geoparquet
|
|
49
|
+
// tab. The outer wrapper already exposes `stac-map` / `STAC Browser` buttons,
|
|
50
|
+
// so the inner `TableToolbar` hides its own STAC Map toggle to avoid
|
|
51
|
+
// duplicating the same `StacMapViewer` mount.
|
|
52
|
+
let { tab, nested = false }: { tab: Tab; nested?: boolean } = $props();
|
|
45
53
|
|
|
46
54
|
let pageSize = $state(settings.featureLimit);
|
|
47
55
|
|
|
@@ -56,9 +64,9 @@ let historyVisible = $state(false);
|
|
|
56
64
|
let hasGeo = $state(false);
|
|
57
65
|
let isStac = $state(false);
|
|
58
66
|
// Restore view mode from URL hash if present
|
|
59
|
-
|
|
60
|
-
let viewMode = $state<
|
|
61
|
-
|
|
67
|
+
type TableViewMode = 'table' | 'map' | 'stac' | 'info';
|
|
68
|
+
let viewMode = $state<TableViewMode>(
|
|
69
|
+
pickViewMode<TableViewMode>(['table', 'map', 'stac', 'info'], 'table')
|
|
62
70
|
);
|
|
63
71
|
let sqlQuery = $state('');
|
|
64
72
|
let customSql = $state('');
|
|
@@ -908,7 +916,7 @@ function setStacView() {
|
|
|
908
916
|
{pageSize}
|
|
909
917
|
{historyVisible}
|
|
910
918
|
{hasGeo}
|
|
911
|
-
{isStac}
|
|
919
|
+
isStac={isStac && !nested}
|
|
912
920
|
{viewMode}
|
|
913
921
|
onPrevPage={prevPage}
|
|
914
922
|
onNextPage={nextPage}
|
|
@@ -916,7 +924,7 @@ function setStacView() {
|
|
|
916
924
|
onToggleInfo={toggleInfo}
|
|
917
925
|
onToggleHistory={toggleHistory}
|
|
918
926
|
onToggleView={toggleView}
|
|
919
|
-
onToggleStac={setStacView}
|
|
927
|
+
onToggleStac={nested ? undefined : setStacView}
|
|
920
928
|
onPageSizeChange={handlePageSizeChange}
|
|
921
929
|
/>
|
|
922
930
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { getViewerKind } from '../../file-icons/index.js';
|
|
3
|
-
import { getAdapter } from '../../storage/index.js';
|
|
4
|
-
import type { Tab } from '../../types.js';
|
|
5
|
-
import { readParquetMetadata } from '../../utils/parquet-metadata.js';
|
|
6
2
|
import {
|
|
7
3
|
classifyStac,
|
|
8
4
|
detectMosaicCapable,
|
|
9
5
|
detectMultiCogCapable,
|
|
6
|
+
isStacGeoparquetSchema,
|
|
7
|
+
readParquetMetadata,
|
|
8
|
+
STAC_API_PATH_RE,
|
|
10
9
|
type StacRoutableKind
|
|
11
|
-
} from '
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
10
|
+
} from '@walkthru-earth/objex-utils';
|
|
11
|
+
import { getViewerKind } from '../../file-icons/index.js';
|
|
12
|
+
import { getAdapter } from '../../storage/index.js';
|
|
13
|
+
import type { Tab } from '../../types.js';
|
|
14
|
+
import { buildHttpsUrlAsync } from '../../utils/signed-url.js';
|
|
15
15
|
import CodeViewer from './CodeViewer.svelte';
|
|
16
16
|
import ImageViewer from './ImageViewer.svelte';
|
|
17
17
|
import MediaViewer from './MediaViewer.svelte';
|
|
@@ -164,6 +164,14 @@ function pickMapKind(classified: StacRoutableKind): 'mosaic' | 'multicog' | null
|
|
|
164
164
|
|
|
165
165
|
{#if stacRoute.kind === 'stac' && viewerKind === 'table'}
|
|
166
166
|
<StacTabViewer {tab} mapKind={stacRoute.mapKind} classified={stacRoute.classified} />
|
|
167
|
+
{:else if stacRoute.kind === 'pending' && (viewerKind === 'table' || viewerKind === 'code' || viewerKind === 'raw')}
|
|
168
|
+
<!-- STAC detection (sniff parquet schema or peek 256KB JSON) is in flight.
|
|
169
|
+
Mounting TableViewer / CodeViewer here would let them read the URL hash,
|
|
170
|
+
pick a default viewMode, and potentially write back over an explicit
|
|
171
|
+
hash that StacTabViewer would otherwise own (e.g. `#map` on a STAC
|
|
172
|
+
collection JSON). The pending window is short — render an empty pane
|
|
173
|
+
until detection resolves and the right viewer takes over. -->
|
|
174
|
+
<div class="h-full"></div>
|
|
167
175
|
{:else if viewerKind === 'table'}
|
|
168
176
|
<TableViewer {tab} />
|
|
169
177
|
{:else if viewerKind === 'image'}
|
|
@@ -7,7 +7,7 @@ import { t } from '../../i18n/index.svelte.js';
|
|
|
7
7
|
import { tabResources } from '../../stores/tab-resources.svelte.js';
|
|
8
8
|
import type { Tab } from '../../types.js';
|
|
9
9
|
import { createEpsgResolver } from '../../utils/cog.js';
|
|
10
|
-
import { buildHttpsUrlAsync } from '../../utils/url.js';
|
|
10
|
+
import { buildHttpsUrlAsync } from '../../utils/signed-url.js';
|
|
11
11
|
import {
|
|
12
12
|
detectGeoZarr,
|
|
13
13
|
ensureCodecsRegistered,
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type ZarrHierarchy,
|
|
18
18
|
type ZarrNode
|
|
19
19
|
} from '../../utils/zarr.js';
|
|
20
|
+
import { Slider } from '../ui/slider/index.js';
|
|
20
21
|
import MapContainer from './map/MapContainer.svelte';
|
|
21
22
|
|
|
22
23
|
/** Enriched selector dimension with coordinate metadata. */
|
|
@@ -526,7 +527,7 @@ async function tryAddGeoZarrLayer(
|
|
|
526
527
|
const zarrInfoSnapshot = $state.snapshot(geoZarrInfo) as GeoZarrInfo;
|
|
527
528
|
const layer = new ZarrLayer({
|
|
528
529
|
id: `geozarr-${tab.id}`,
|
|
529
|
-
|
|
530
|
+
node: group,
|
|
530
531
|
variable: zarrInfoSnapshot.variantPath || undefined,
|
|
531
532
|
selection: {},
|
|
532
533
|
epsgResolver: dsZarrEpsg,
|
|
@@ -661,16 +662,17 @@ onDestroy(cleanup);
|
|
|
661
662
|
title={dimLabel(dim)}
|
|
662
663
|
>
|
|
663
664
|
<span class="shrink-0 font-medium text-zinc-500 dark:text-zinc-400">{dim.name}</span>
|
|
664
|
-
<
|
|
665
|
-
type="
|
|
666
|
-
min=
|
|
665
|
+
<Slider
|
|
666
|
+
type="single"
|
|
667
|
+
min={0}
|
|
667
668
|
max={dim.size - 1}
|
|
669
|
+
step={1}
|
|
668
670
|
value={selectorValues[dim.name] ?? 0}
|
|
669
|
-
|
|
670
|
-
selectorValues[dim.name] =
|
|
671
|
+
onValueChange={(v) => {
|
|
672
|
+
selectorValues[dim.name] = v as number;
|
|
671
673
|
}}
|
|
672
|
-
|
|
673
|
-
class="
|
|
674
|
+
onValueCommit={() => updateSelector()}
|
|
675
|
+
class="w-20"
|
|
674
676
|
/>
|
|
675
677
|
{#if dim.isDatetime && dim.minDate && dim.maxDate}
|
|
676
678
|
{@const dateVal = indexToDateStr(selectorValues[dim.name] ?? 0, dim)}
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
} from '../ui/resizable/index.js';
|
|
10
10
|
import { t } from '../../i18n/index.svelte.js';
|
|
11
11
|
import type { Tab } from '../../types';
|
|
12
|
-
import { buildHttpsUrlAsync } from '../../utils/url.js';
|
|
13
|
-
import {
|
|
12
|
+
import { buildHttpsUrlAsync } from '../../utils/signed-url.js';
|
|
13
|
+
import { pickViewMode, updateUrlView } from '../../utils/url-state.js';
|
|
14
14
|
import {
|
|
15
15
|
computeChunkCount,
|
|
16
16
|
computeChunkSize,
|
|
@@ -30,8 +30,8 @@ let { tab }: { tab: Tab } = $props();
|
|
|
30
30
|
|
|
31
31
|
let loading = $state(true);
|
|
32
32
|
let error = $state<string | null>(null);
|
|
33
|
-
|
|
34
|
-
let viewMode = $state<
|
|
33
|
+
type ZarrViewMode = 'inspect' | 'map';
|
|
34
|
+
let viewMode = $state<ZarrViewMode>(pickViewMode<ZarrViewMode>(['inspect', 'map'], 'inspect'));
|
|
35
35
|
|
|
36
36
|
let hierarchy = $state.raw<ZarrHierarchy | null>(null);
|
|
37
37
|
let selectedNode = $state<ZarrNode | null>(null);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ChannelRef, CogAsset } from '@walkthru-earth/objex-utils';
|
|
3
|
+
import { t } from '../../../i18n/index.svelte.js';
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
channel: 'r' | 'g' | 'b' | 'a';
|
|
7
|
+
label: string;
|
|
8
|
+
colorClass: string;
|
|
9
|
+
assets: CogAsset[];
|
|
10
|
+
value: ChannelRef;
|
|
11
|
+
onChange: (next: ChannelRef) => void;
|
|
12
|
+
allowNone?: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
let { channel, label, colorClass, assets, value, onChange, allowNone = false }: Props = $props();
|
|
16
|
+
|
|
17
|
+
const assetByKey = $derived(new Map(assets.map((a) => [a.key, a])));
|
|
18
|
+
const currentAsset = $derived(assetByKey.get(value.assetKey) ?? null);
|
|
19
|
+
const bandCount = $derived(currentAsset?.bandCount ?? 1);
|
|
20
|
+
const bandIndices = $derived(Array.from({ length: bandCount }, (_, i) => i));
|
|
21
|
+
|
|
22
|
+
function assetLabel(a: CogAsset): string {
|
|
23
|
+
const cn = a.eoCommon[0];
|
|
24
|
+
const base = cn ? `${a.key} (${cn})` : a.key;
|
|
25
|
+
return a.bandCount > 1 ? `${base} · ${a.bandCount} bands` : base;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function bandLabel(i: number, asset: CogAsset | null): string {
|
|
29
|
+
if (!asset) return `${t('cog.band')} ${i + 1}`;
|
|
30
|
+
const cn = asset.eoCommon[i];
|
|
31
|
+
return cn ? `${t('cog.band')} ${i + 1} (${cn})` : `${t('cog.band')} ${i + 1}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function setAsset(key: string): void {
|
|
35
|
+
if (channel === 'a' && allowNone && key === '') {
|
|
36
|
+
onChange({ assetKey: '', bandIndex: 0 });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const target = assetByKey.get(key);
|
|
40
|
+
const maxIdx = Math.max(0, (target?.bandCount ?? 1) - 1);
|
|
41
|
+
const nextBand = Math.min(value.bandIndex, maxIdx);
|
|
42
|
+
onChange({ assetKey: key, bandIndex: nextBand });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function setBand(idx: number): void {
|
|
46
|
+
onChange({ assetKey: value.assetKey, bandIndex: idx });
|
|
47
|
+
}
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<div class="flex items-start gap-2">
|
|
51
|
+
<span class="mt-1 w-3 shrink-0 font-bold {colorClass}">{label}</span>
|
|
52
|
+
<div class="flex min-w-0 flex-1 flex-col gap-1 sm:flex-row sm:items-center">
|
|
53
|
+
<select
|
|
54
|
+
class="min-w-0 flex-1 truncate rounded border border-border bg-background px-1.5 py-0.5 text-xs"
|
|
55
|
+
aria-label={`${label} ${t('cog.asset')}`}
|
|
56
|
+
value={value.assetKey}
|
|
57
|
+
onchange={(e) => setAsset((e.target as HTMLSelectElement).value)}
|
|
58
|
+
>
|
|
59
|
+
{#if allowNone}
|
|
60
|
+
<option value="">{t('map.multiCogChannelNone')}</option>
|
|
61
|
+
{/if}
|
|
62
|
+
{#each assets as a (a.key)}
|
|
63
|
+
<option value={a.key}>{assetLabel(a)}</option>
|
|
64
|
+
{/each}
|
|
65
|
+
</select>
|
|
66
|
+
{#if currentAsset && bandCount > 1}
|
|
67
|
+
<select
|
|
68
|
+
class="min-w-0 flex-1 truncate rounded border border-border bg-background px-1.5 py-0.5 text-xs sm:flex-[0_1_auto] sm:min-w-24"
|
|
69
|
+
aria-label={`${label} ${t('cog.band')}`}
|
|
70
|
+
value={value.bandIndex}
|
|
71
|
+
onchange={(e) => setBand(Number((e.target as HTMLSelectElement).value))}
|
|
72
|
+
>
|
|
73
|
+
{#each bandIndices as i (i)}
|
|
74
|
+
<option value={i}>{bandLabel(i, currentAsset)}</option>
|
|
75
|
+
{/each}
|
|
76
|
+
</select>
|
|
77
|
+
{:else if currentAsset}
|
|
78
|
+
<span class="min-w-0 truncate px-1.5 py-0.5 text-[10px] text-muted-foreground sm:min-w-24">
|
|
79
|
+
{t('cog.band')} 1
|
|
80
|
+
</span>
|
|
81
|
+
{/if}
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ChannelRef, CogAsset } from '@walkthru-earth/objex-utils';
|
|
2
|
+
type Props = {
|
|
3
|
+
channel: 'r' | 'g' | 'b' | 'a';
|
|
4
|
+
label: string;
|
|
5
|
+
colorClass: string;
|
|
6
|
+
assets: CogAsset[];
|
|
7
|
+
value: ChannelRef;
|
|
8
|
+
onChange: (next: ChannelRef) => void;
|
|
9
|
+
allowNone?: boolean;
|
|
10
|
+
};
|
|
11
|
+
declare const ChannelPicker: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type ChannelPicker = ReturnType<typeof ChannelPicker>;
|
|
13
|
+
export default ChannelPicker;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
export type PixelInspectorRow = {
|
|
3
|
+
label: string;
|
|
4
|
+
sublabel?: string;
|
|
5
|
+
value: number | null;
|
|
6
|
+
};
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<script lang="ts">
|
|
10
|
+
import { t } from '../../../i18n/index.svelte.js';
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
lng,
|
|
14
|
+
lat,
|
|
15
|
+
rows,
|
|
16
|
+
footnote,
|
|
17
|
+
extraLine,
|
|
18
|
+
onClose,
|
|
19
|
+
inspecting = false
|
|
20
|
+
}: {
|
|
21
|
+
lng: number | null;
|
|
22
|
+
lat: number | null;
|
|
23
|
+
rows: PixelInspectorRow[] | null;
|
|
24
|
+
footnote?: string;
|
|
25
|
+
extraLine?: string;
|
|
26
|
+
onClose: () => void;
|
|
27
|
+
inspecting?: boolean;
|
|
28
|
+
} = $props();
|
|
29
|
+
|
|
30
|
+
// The panel renders whenever we have a coordinate + rows. The "reading" pill
|
|
31
|
+
// renders independently while inspecting is true. Both blocks can render at
|
|
32
|
+
// once during a follow-up click, this matches the existing per-viewer UX.
|
|
33
|
+
const showPanel = $derived(rows !== null && lng !== null && lat !== null);
|
|
34
|
+
const showReading = $derived(inspecting);
|
|
35
|
+
|
|
36
|
+
function formatValue(v: number | null): string {
|
|
37
|
+
if (v === null) return '-';
|
|
38
|
+
return Number.isInteger(v) ? String(v) : v.toFixed(4);
|
|
39
|
+
}
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
{#if showPanel && rows && lng !== null && lat !== null}
|
|
43
|
+
<div
|
|
44
|
+
class="absolute bottom-2 left-2 z-10 max-w-[calc(100vw-1rem)] rounded bg-card/90 p-2.5 text-xs text-card-foreground backdrop-blur-sm sm:max-w-none"
|
|
45
|
+
>
|
|
46
|
+
<div class="mb-1 flex items-center justify-between gap-3">
|
|
47
|
+
<span class="font-medium">{t('cog.pixelValue')}</span>
|
|
48
|
+
<button
|
|
49
|
+
class="inline-flex min-h-8 min-w-8 items-center justify-center text-base text-muted-foreground hover:text-card-foreground sm:min-h-0 sm:min-w-0 sm:text-xs"
|
|
50
|
+
style="touch-action: manipulation;"
|
|
51
|
+
onclick={onClose}
|
|
52
|
+
aria-label={t('stac.close')}
|
|
53
|
+
>
|
|
54
|
+
×
|
|
55
|
+
</button>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="space-y-0.5 text-muted-foreground">
|
|
58
|
+
<div>{lat.toFixed(6)}°, {lng.toFixed(6)}°</div>
|
|
59
|
+
{#if footnote}
|
|
60
|
+
<div class="text-[10px]">{footnote}</div>
|
|
61
|
+
{/if}
|
|
62
|
+
{#if extraLine}
|
|
63
|
+
<div class="truncate text-[10px]" title={extraLine}>{extraLine}</div>
|
|
64
|
+
{/if}
|
|
65
|
+
</div>
|
|
66
|
+
<div class="mt-1.5 space-y-0.5">
|
|
67
|
+
{#each rows as row}
|
|
68
|
+
<div class="flex justify-between gap-2">
|
|
69
|
+
<span class="text-muted-foreground">
|
|
70
|
+
{row.label}{#if row.sublabel}
|
|
71
|
+
<span class="ml-1 text-[10px] opacity-70">({row.sublabel})</span>
|
|
72
|
+
{/if}
|
|
73
|
+
</span>
|
|
74
|
+
<span class="font-mono tabular-nums">{formatValue(row.value)}</span>
|
|
75
|
+
</div>
|
|
76
|
+
{/each}
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
{/if}
|
|
80
|
+
|
|
81
|
+
{#if showReading}
|
|
82
|
+
<div
|
|
83
|
+
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"
|
|
84
|
+
>
|
|
85
|
+
{t('cog.reading')}
|
|
86
|
+
</div>
|
|
87
|
+
{/if}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type PixelInspectorRow = {
|
|
2
|
+
label: string;
|
|
3
|
+
sublabel?: string;
|
|
4
|
+
value: number | null;
|
|
5
|
+
};
|
|
6
|
+
type $$ComponentProps = {
|
|
7
|
+
lng: number | null;
|
|
8
|
+
lat: number | null;
|
|
9
|
+
rows: PixelInspectorRow[] | null;
|
|
10
|
+
footnote?: string;
|
|
11
|
+
extraLine?: string;
|
|
12
|
+
onClose: () => void;
|
|
13
|
+
inspecting?: boolean;
|
|
14
|
+
};
|
|
15
|
+
declare const PixelInspectorPanel: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
16
|
+
type PixelInspectorPanel = ReturnType<typeof PixelInspectorPanel>;
|
|
17
|
+
export default PixelInspectorPanel;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer-construction dispatch for the unified RGB picker.
|
|
3
|
+
*
|
|
4
|
+
* Decision rule:
|
|
5
|
+
* - All three RGB channels point to the SAME asset → COGLayer. When a
|
|
6
|
+
* `preflightGeotiff` is supplied, the per-channel `bandIndex` values are
|
|
7
|
+
* translated into a `BandConfig` and run through `selectCogPipeline`,
|
|
8
|
+
* which returns a custom `getTileData` / `renderTile` pair that swaps
|
|
9
|
+
* bands as requested (the library's COGLayer does not accept a
|
|
10
|
+
* `bandConfig` prop, only the resolved pipeline). Without a preflight
|
|
11
|
+
* GeoTIFF the layer falls back to the library default pipeline, which
|
|
12
|
+
* reads bands 0/1/2 in that order, correct for single-band per-asset
|
|
13
|
+
* COGs and for the default natural-color order on pre-baked multi-band
|
|
14
|
+
* visuals.
|
|
15
|
+
* - Channels point to DIFFERENT assets → MultiCOGLayer with the legacy
|
|
16
|
+
* `composite: { r, g, b }` keyed on asset keys. MultiCOGLayer reads band 0
|
|
17
|
+
* of each source, per-channel band index is silently ignored on this path
|
|
18
|
+
* (library limitation, see spec Known Limitations).
|
|
19
|
+
*
|
|
20
|
+
* `buildRgbLayer` ONLY constructs the layer. It does not add overlays,
|
|
21
|
+
* register cleanup, or touch deck.gl state. Caller owns lifecycle.
|
|
22
|
+
*/
|
|
23
|
+
import { COGLayer, MultiCOGLayer } from '@developmentseed/deck.gl-geotiff';
|
|
24
|
+
import type { DecoderPool, GeoTIFF as GeoTIFFType } from '@developmentseed/geotiff';
|
|
25
|
+
import type { EpsgResolver } from '@developmentseed/proj';
|
|
26
|
+
import { type ChannelComposite, type CogAsset } from '@walkthru-earth/objex-utils';
|
|
27
|
+
import { type GeoBounds, type RescaleConfig } from '../../../utils/cog.js';
|
|
28
|
+
export type RgbLayerKind = 'cog' | 'multicog';
|
|
29
|
+
export interface BuildRgbLayerOptions {
|
|
30
|
+
id: string;
|
|
31
|
+
assets: CogAsset[];
|
|
32
|
+
composite: ChannelComposite;
|
|
33
|
+
rescale: RescaleConfig;
|
|
34
|
+
/** href → presigned-or-passthrough URL. */
|
|
35
|
+
resolveHref: (href: string) => Promise<string>;
|
|
36
|
+
pool?: DecoderPool | null;
|
|
37
|
+
epsgResolver: EpsgResolver;
|
|
38
|
+
signal: AbortSignal;
|
|
39
|
+
onLoad?: (info: {
|
|
40
|
+
kind: RgbLayerKind;
|
|
41
|
+
bounds?: GeoBounds;
|
|
42
|
+
}) => void;
|
|
43
|
+
/**
|
|
44
|
+
* Pre-opened GeoTIFF for the single-asset path. When provided, the per-channel
|
|
45
|
+
* `bandIndex` values from the composite are honored via `selectCogPipeline`,
|
|
46
|
+
* which inspects the COG's sample format / band count and returns a custom
|
|
47
|
+
* `getTileData` + `renderTile` pair that swaps bands as requested.
|
|
48
|
+
*
|
|
49
|
+
* When omitted, the layer falls back to the library default render pipeline,
|
|
50
|
+
* which always reads bands 0/1/2 in that order. That is fine for:
|
|
51
|
+
* - single-band per-asset COGs (Sentinel-2, Landsat per-band) where every
|
|
52
|
+
* `bandIndex` is 0 anyway, OR
|
|
53
|
+
* - pre-baked multi-band visuals (NAIP `image`, S2 `visual`) where the
|
|
54
|
+
* natural-color preset wants the default band order.
|
|
55
|
+
*/
|
|
56
|
+
preflightGeotiff?: GeoTIFFType | null;
|
|
57
|
+
/**
|
|
58
|
+
* Resolved nodata value threaded into `buildBandRenderPipeline` for the
|
|
59
|
+
* multi-asset `MultiCOGLayer` path. `null` (default) disables the nodata
|
|
60
|
+
* filter so legacy callers preserve their previous behaviour.
|
|
61
|
+
*/
|
|
62
|
+
noDataVal?: number | null;
|
|
63
|
+
}
|
|
64
|
+
export interface BuiltRgbLayer {
|
|
65
|
+
kind: RgbLayerKind;
|
|
66
|
+
layer: COGLayer | MultiCOGLayer;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Build the appropriate deck.gl layer for an RGB composite.
|
|
70
|
+
*
|
|
71
|
+
* For single-asset composites the band indices flow through `selectCogPipeline`
|
|
72
|
+
* (when `preflightGeotiff` is provided) into a custom `getTileData` /
|
|
73
|
+
* `renderTile` pair that honors the requested R/G/B band order. Without a
|
|
74
|
+
* preflight GeoTIFF the layer uses the library's default pipeline (bands 0/1/2).
|
|
75
|
+
* For multi-asset composites a warning is logged (once per call) when any
|
|
76
|
+
* non-band-0 index is requested, since MultiCOGLayer cannot honor it today.
|
|
77
|
+
*/
|
|
78
|
+
export declare function buildRgbLayer(opts: BuildRgbLayerOptions): Promise<BuiltRgbLayer>;
|