@walkthru-earth/objex 1.3.1 → 1.5.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 +28 -20
- package/dist/components/browser/FileTreeSidebar.svelte +32 -17
- package/dist/components/layout/AboutSheet.svelte +5 -2
- package/dist/components/layout/ConnectionDialog.svelte +7 -2
- package/dist/components/layout/SettingsSheet.svelte +238 -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 +17 -14
- package/dist/components/layout/TabBar.svelte +4 -4
- 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 +140 -113
- package/dist/components/viewers/CodeViewer.svelte +45 -48
- package/dist/components/viewers/CodeViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/CogControls.svelte +338 -184
- package/dist/components/viewers/CogControls.svelte.d.ts +33 -10
- package/dist/components/viewers/CogViewer.svelte +269 -116
- package/dist/components/viewers/CopcViewer.svelte +8 -15
- package/dist/components/viewers/DatabaseViewer.svelte +22 -21
- package/dist/components/viewers/FileInfo.svelte +16 -16
- package/dist/components/viewers/FlatGeobufViewer.svelte +16 -46
- package/dist/components/viewers/GeoParquetMapViewer.svelte +11 -9
- package/dist/components/viewers/GeoParquetMapViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/ImageViewer.svelte +12 -14
- package/dist/components/viewers/LoadProgress.svelte +6 -6
- package/dist/components/viewers/MarkdownViewer.svelte +29 -30
- package/dist/components/viewers/MediaViewer.svelte +13 -14
- package/dist/components/viewers/ModelViewer.svelte +18 -21
- package/dist/components/viewers/MultiCogViewer.svelte +474 -106
- package/dist/components/viewers/MultiCogViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/NotebookViewer.svelte +28 -29
- package/dist/components/viewers/PdfViewer.svelte +24 -33
- package/dist/components/viewers/PmtilesViewer.svelte +13 -15
- package/dist/components/viewers/QueryHistoryPanel.svelte +18 -18
- package/dist/components/viewers/RawViewer.svelte +27 -21
- package/dist/components/viewers/StacMapViewer.svelte +6 -13
- package/dist/components/viewers/StacMosaicViewer.svelte +1764 -410
- package/dist/components/viewers/StacMosaicViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/StacTabViewer.svelte +26 -15
- package/dist/components/viewers/StacTabViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/TableGrid.svelte +38 -34
- package/dist/components/viewers/TableStatusBar.svelte +7 -7
- package/dist/components/viewers/TableToolbar.svelte +10 -9
- package/dist/components/viewers/TableViewer.svelte +47 -30
- package/dist/components/viewers/TableViewer.svelte.d.ts +1 -0
- package/dist/components/viewers/ViewerHeader.svelte +18 -0
- package/dist/components/viewers/ViewerHeader.svelte.d.ts +10 -0
- package/dist/components/viewers/ViewerRouter.svelte +16 -8
- package/dist/components/viewers/ViewerStatus.svelte +19 -0
- package/dist/components/viewers/ViewerStatus.svelte.d.ts +7 -0
- package/dist/components/viewers/ZarrMapViewer.svelte +24 -21
- package/dist/components/viewers/ZarrViewer.svelte +98 -65
- 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 +7 -7
- package/dist/components/viewers/map/MapContainer.svelte +38 -12
- package/dist/components/viewers/pmtiles/PmtilesArchiveView.svelte +109 -83
- package/dist/components/viewers/pmtiles/PmtilesTileInspector.svelte +16 -16
- 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/constants.d.ts +6 -0
- package/dist/constants.js +8 -0
- package/dist/file-icons/index.d.ts +1 -1
- package/dist/file-icons/index.js +1 -1
- package/dist/i18n/ar.js +113 -2
- package/dist/i18n/en.js +113 -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 +468 -0
- package/dist/query/wasm.d.ts +8 -0
- package/dist/query/wasm.js +310 -65
- package/dist/storage/presign.js +3 -2
- package/dist/storage/providers.js +7 -6
- 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 +18 -12
- package/dist/utils/deck.js +15 -7
- package/dist/utils/media-query.svelte.d.ts +14 -0
- package/dist/utils/media-query.svelte.js +29 -0
- package/dist/utils/pmtiles-tile.js +2 -2
- package/dist/utils/signed-url-effect.d.ts +7 -0
- package/dist/utils/signed-url-effect.js +19 -0
- 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,14 +1,26 @@
|
|
|
1
|
+
import { DEFAULT_APP_CONFIG, loadFromStorage, parseVisibilityParam, persistToStorage, resolveSetting } from '@walkthru-earth/objex-utils';
|
|
1
2
|
import { STORAGE_KEYS } from '../constants.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
import { appConfig } from './config.svelte.js';
|
|
4
|
+
/**
|
|
5
|
+
* Heuristic mobile detection. iOS Safari caps the WASM heap at ~1.8 GiB and
|
|
6
|
+
* Safari < 17.6 has no `credentialless` COEP, so OPFS spill rarely engages.
|
|
7
|
+
* A 2000-item stac-geoparquet scan with deep STRUCT `assets`/`links` columns
|
|
8
|
+
* blows the heap before the streaming engine can pace it. Clamp the default
|
|
9
|
+
* mosaic item limit lower on mobile so first-run mosaic loads succeed; users
|
|
10
|
+
* can still raise it explicitly in settings.
|
|
11
|
+
*/
|
|
12
|
+
function isMobileLikeAtLoad() {
|
|
13
|
+
if (typeof navigator === 'undefined')
|
|
14
|
+
return false;
|
|
15
|
+
if (/Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent))
|
|
16
|
+
return true;
|
|
17
|
+
if (typeof window === 'undefined')
|
|
18
|
+
return false;
|
|
19
|
+
return Math.min(window.innerWidth, window.innerHeight) <= 820;
|
|
20
|
+
}
|
|
21
|
+
const MOBILE_MOSAIC_LIMIT = 200;
|
|
22
|
+
function loadUser() {
|
|
23
|
+
return loadFromStorage(STORAGE_KEYS.SETTINGS, {});
|
|
12
24
|
}
|
|
13
25
|
export function resolveTheme(theme) {
|
|
14
26
|
if (theme !== 'system')
|
|
@@ -17,63 +29,107 @@ export function resolveTheme(theme) {
|
|
|
17
29
|
return 'light';
|
|
18
30
|
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
19
31
|
}
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
let resolved = $state(resolveTheme(initial.theme));
|
|
26
|
-
// Sync i18n module and document dir with persisted locale
|
|
27
|
-
setLocale(initial.locale);
|
|
28
|
-
if (typeof document !== 'undefined') {
|
|
29
|
-
const dir = initial.locale === 'ar' ? 'rtl' : 'ltr';
|
|
30
|
-
document.documentElement.dir = dir;
|
|
31
|
-
document.documentElement.lang = initial.locale;
|
|
32
|
+
function readVisibilityParam(name) {
|
|
33
|
+
if (typeof window === 'undefined')
|
|
34
|
+
return undefined;
|
|
35
|
+
try {
|
|
36
|
+
return parseVisibilityParam(new URL(window.location.href).searchParams.get(name));
|
|
32
37
|
}
|
|
38
|
+
catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function createSettingsStore() {
|
|
43
|
+
let user = $state(loadUser());
|
|
44
|
+
// Query params and mobile detection are static for the session, read once.
|
|
45
|
+
const railParam = readVisibilityParam('sidebar');
|
|
46
|
+
const treeParam = readVisibilityParam('tree');
|
|
47
|
+
const mobileLikeAtLoad = isMobileLikeAtLoad();
|
|
33
48
|
function persist() {
|
|
34
|
-
persistToStorage(STORAGE_KEYS.SETTINGS,
|
|
49
|
+
persistToStorage(STORAGE_KEYS.SETTINGS, user);
|
|
35
50
|
}
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
resolved = resolveTheme(t);
|
|
39
|
-
persist();
|
|
40
|
-
if (typeof document !== 'undefined') {
|
|
41
|
-
document.documentElement.classList.toggle('dark', resolved === 'dark');
|
|
42
|
-
}
|
|
51
|
+
function cfg() {
|
|
52
|
+
return appConfig.value;
|
|
43
53
|
}
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
setLocale(l);
|
|
47
|
-
persist();
|
|
48
|
-
if (typeof document !== 'undefined') {
|
|
49
|
-
const dir = l === 'ar' ? 'rtl' : 'ltr';
|
|
50
|
-
document.documentElement.dir = dir;
|
|
51
|
-
document.documentElement.lang = l;
|
|
52
|
-
}
|
|
54
|
+
function effTheme() {
|
|
55
|
+
return resolveSetting(user.theme, cfg().defaults.theme, 'system');
|
|
53
56
|
}
|
|
54
|
-
// System theme changes are handled by the $effect in +layout.svelte
|
|
55
|
-
// which properly cleans up the listener. No module-level listener needed.
|
|
56
57
|
return {
|
|
57
58
|
get theme() {
|
|
58
|
-
return
|
|
59
|
+
return effTheme();
|
|
59
60
|
},
|
|
60
61
|
get resolved() {
|
|
61
|
-
return
|
|
62
|
+
return resolveTheme(effTheme());
|
|
62
63
|
},
|
|
63
64
|
get locale() {
|
|
64
|
-
return locale;
|
|
65
|
+
return resolveSetting(user.locale, cfg().defaults.locale, 'en');
|
|
65
66
|
},
|
|
66
67
|
get featureLimit() {
|
|
67
|
-
return featureLimit;
|
|
68
|
+
return resolveSetting(user.featureLimit, cfg().defaults.featureLimit, DEFAULT_APP_CONFIG.defaults.featureLimit);
|
|
69
|
+
},
|
|
70
|
+
get mosaicItemLimit() {
|
|
71
|
+
// Explicit user/query choice always wins, at any value.
|
|
72
|
+
if (user.mosaicItemLimit !== undefined)
|
|
73
|
+
return user.mosaicItemLimit;
|
|
74
|
+
const configured = resolveSetting(cfg().defaults.mosaicItemLimit, DEFAULT_APP_CONFIG.defaults.mosaicItemLimit);
|
|
75
|
+
// Mobile heap safety: clamp the default so API/static mosaic loads don't OOM.
|
|
76
|
+
return mobileLikeAtLoad ? Math.min(configured, MOBILE_MOSAIC_LIMIT) : configured;
|
|
77
|
+
},
|
|
78
|
+
get showConnectionRail() {
|
|
79
|
+
return resolveSetting(railParam, user.showConnectionRail, cfg().ui.showConnectionRail, true);
|
|
80
|
+
},
|
|
81
|
+
get showFileTree() {
|
|
82
|
+
return resolveSetting(treeParam, user.showFileTree, cfg().ui.showFileTree, true);
|
|
83
|
+
},
|
|
84
|
+
/** True when a link param is forcing the connection-rail visibility. */
|
|
85
|
+
get railLockedByParam() {
|
|
86
|
+
return railParam !== undefined;
|
|
87
|
+
},
|
|
88
|
+
/** True when a link param is forcing the file-tree visibility. */
|
|
89
|
+
get treeLockedByParam() {
|
|
90
|
+
return treeParam !== undefined;
|
|
91
|
+
},
|
|
92
|
+
/** The user-picked basemap id, or undefined to follow config/theme defaults. */
|
|
93
|
+
get basemapId() {
|
|
94
|
+
return user.basemapId;
|
|
68
95
|
},
|
|
69
96
|
setTheme(t) {
|
|
70
|
-
|
|
97
|
+
user = { ...user, theme: t };
|
|
98
|
+
persist();
|
|
71
99
|
},
|
|
72
100
|
setLocale(l) {
|
|
73
|
-
|
|
101
|
+
user = { ...user, locale: l };
|
|
102
|
+
persist();
|
|
74
103
|
},
|
|
75
104
|
setFeatureLimit(n) {
|
|
76
|
-
|
|
105
|
+
user = { ...user, featureLimit: Math.max(1, Math.floor(n)) };
|
|
106
|
+
persist();
|
|
107
|
+
},
|
|
108
|
+
setMosaicItemLimit(n) {
|
|
109
|
+
user = { ...user, mosaicItemLimit: Math.max(1, Math.floor(n)) };
|
|
110
|
+
persist();
|
|
111
|
+
},
|
|
112
|
+
setShowConnectionRail(v) {
|
|
113
|
+
user = { ...user, showConnectionRail: v };
|
|
114
|
+
persist();
|
|
115
|
+
},
|
|
116
|
+
setShowFileTree(v) {
|
|
117
|
+
user = { ...user, showFileTree: v };
|
|
118
|
+
persist();
|
|
119
|
+
},
|
|
120
|
+
setBasemap(id) {
|
|
121
|
+
if (id === undefined) {
|
|
122
|
+
const { basemapId: _omit, ...rest } = user;
|
|
123
|
+
user = rest;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
user = { ...user, basemapId: id };
|
|
127
|
+
}
|
|
128
|
+
persist();
|
|
129
|
+
},
|
|
130
|
+
/** Clear all user overrides, reverting every value to config or hardcoded fallback. */
|
|
131
|
+
reset() {
|
|
132
|
+
user = {};
|
|
77
133
|
persist();
|
|
78
134
|
}
|
|
79
135
|
};
|
|
@@ -11,6 +11,9 @@ export declare const tabs: {
|
|
|
11
11
|
readonly items: Tab[];
|
|
12
12
|
readonly activeTabId: string | null;
|
|
13
13
|
readonly active: Tab | undefined;
|
|
14
|
+
readonly migrating: boolean;
|
|
15
|
+
beginMigration(): void;
|
|
16
|
+
endMigration(): void;
|
|
14
17
|
/**
|
|
15
18
|
* Tabs that should be kept alive in the DOM (mounted but hidden if inactive).
|
|
16
19
|
* Returns up to MAX_ALIVE tabs in MRU order. The active tab is always included.
|
|
@@ -22,6 +22,14 @@ function createTabsStore() {
|
|
|
22
22
|
// LRU order: most recently activated tab IDs first.
|
|
23
23
|
// Used to decide which tabs stay alive in the DOM.
|
|
24
24
|
let recentOrder = $state([]);
|
|
25
|
+
// True while the Sidebar is migrating an eager URL tab to a remote tab
|
|
26
|
+
// (close eager → await credentials/connection save → open remote).
|
|
27
|
+
// During this window, `tabs.items` is briefly empty, but the tab-sync
|
|
28
|
+
// effect MUST NOT clear `?url=` / `#hash` — the new viewer needs them.
|
|
29
|
+
// User-initiated tab closes happen with `migrating === false` and DO
|
|
30
|
+
// clear URL state, so subsequent Sidebar remounts (e.g. mobile Sheet
|
|
31
|
+
// open/close) don't auto-re-open the tab the user just closed.
|
|
32
|
+
let migrating = $state(false);
|
|
25
33
|
function touchRecent(id) {
|
|
26
34
|
recentOrder = [id, ...recentOrder.filter((r) => r !== id)];
|
|
27
35
|
// Dispose resources for tabs that fell out of the alive window.
|
|
@@ -50,6 +58,15 @@ function createTabsStore() {
|
|
|
50
58
|
return undefined;
|
|
51
59
|
return tabs.find((t) => t.id === activeTabId);
|
|
52
60
|
},
|
|
61
|
+
get migrating() {
|
|
62
|
+
return migrating;
|
|
63
|
+
},
|
|
64
|
+
beginMigration() {
|
|
65
|
+
migrating = true;
|
|
66
|
+
},
|
|
67
|
+
endMigration() {
|
|
68
|
+
migrating = false;
|
|
69
|
+
},
|
|
53
70
|
/**
|
|
54
71
|
* Tabs that should be kept alive in the DOM (mounted but hidden if inactive).
|
|
55
72
|
* Returns up to MAX_ALIVE tabs in MRU order. The active tab is always included.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming histogram + GDAL stats reader for COGs.
|
|
3
|
+
*
|
|
4
|
+
* This module owns the canonical `HISTOGRAM_BINS` constant (128) and a
|
|
5
|
+
* tile-by-tile histogram builder. The streamer fetches tiles from the
|
|
6
|
+
* coarsest overview, bins pixel values into a `Uint32Array` of length
|
|
7
|
+
* `HISTOGRAM_BINS`, and emits a snapshot via `onProgress` after each
|
|
8
|
+
* tile so the UI can fill in the histogram chart incrementally.
|
|
9
|
+
*
|
|
10
|
+
* When GDAL_METADATA `STATISTICS_MINIMUM` / `STATISTICS_MAXIMUM` are
|
|
11
|
+
* present we use them as fixed bin edges (single-pass streaming). When
|
|
12
|
+
* they are absent we fall back to a two-pass scan (min/max first, then
|
|
13
|
+
* bin), in which case progress fires only at the end, bin edges are
|
|
14
|
+
* not stable until the first pass finishes.
|
|
15
|
+
*
|
|
16
|
+
* Runs in workers and on the main thread. No DOM APIs (window,
|
|
17
|
+
* document, DOMParser), no Svelte runes. XML parsing is a tolerant
|
|
18
|
+
* regex over the GDAL_METADATA tag string, not a DOMParser pass.
|
|
19
|
+
*/
|
|
20
|
+
import type { GeoTIFF as GeoTIFFType } from '@developmentseed/geotiff';
|
|
21
|
+
import { type RescaleConfig } from './cog.js';
|
|
22
|
+
/** Number of histogram buckets. PR #3 bumps from 64 to 128. */
|
|
23
|
+
export declare const HISTOGRAM_BINS = 128;
|
|
24
|
+
/** Per-band GDAL statistics block read from the GDAL_METADATA tag. */
|
|
25
|
+
export type GdalBandStats = {
|
|
26
|
+
min: number;
|
|
27
|
+
max: number;
|
|
28
|
+
mean?: number;
|
|
29
|
+
stddev?: number;
|
|
30
|
+
};
|
|
31
|
+
/** Map of 1-based band index to per-band stats. Empty when absent. */
|
|
32
|
+
export type GdalImageStats = Map<number, GdalBandStats>;
|
|
33
|
+
/** Snapshot of an in-progress histogram bake. */
|
|
34
|
+
export type HistogramSnapshot = {
|
|
35
|
+
/** Bin counts of length `HISTOGRAM_BINS`. */
|
|
36
|
+
bins: Uint32Array;
|
|
37
|
+
/** Lower bin-edge (inclusive). */
|
|
38
|
+
min: number;
|
|
39
|
+
/** Upper bin-edge (exclusive for inner bins, inclusive for the last). */
|
|
40
|
+
max: number;
|
|
41
|
+
/** Tiles binned so far. */
|
|
42
|
+
tilesProcessed: number;
|
|
43
|
+
/** Total tiles the streamer plans to consume, or null if unknown. */
|
|
44
|
+
tilesTotal: number | null;
|
|
45
|
+
};
|
|
46
|
+
/** Options for {@link streamHistogram}. */
|
|
47
|
+
export type StreamHistogramOptions = {
|
|
48
|
+
geotiff: GeoTIFFType;
|
|
49
|
+
/** 1-based band index. */
|
|
50
|
+
bandIndex: number;
|
|
51
|
+
signal: AbortSignal;
|
|
52
|
+
onProgress: (snap: HistogramSnapshot) => void;
|
|
53
|
+
/**
|
|
54
|
+
* 0-based overview index. When omitted, the lowest-resolution overview
|
|
55
|
+
* (i.e. the smallest available source, last entry of `geotiff.overviews`)
|
|
56
|
+
* is used. Falls back to the full-resolution image when `overviews` is
|
|
57
|
+
* empty.
|
|
58
|
+
*/
|
|
59
|
+
overviewIndex?: number;
|
|
60
|
+
/** Hard upper bound on tiles consumed. Defaults to 32. */
|
|
61
|
+
maxTiles?: number;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Parse per-band stats out of the GDAL_METADATA tag. Tolerant of
|
|
65
|
+
* malformed XML, uses a regex pass over `<Item ...>...</Item>` rather
|
|
66
|
+
* than DOMParser so this can run inside a Web Worker.
|
|
67
|
+
*
|
|
68
|
+
* Prefers the library's pre-parsed `geotiff.storedStats` when present,
|
|
69
|
+
* falls back to scanning the raw `cachedTags.gdalMetadata` string when
|
|
70
|
+
* the library could not parse it but the tag is still present (defensive
|
|
71
|
+
* path, rarely fires with current @developmentseed/geotiff but cheap).
|
|
72
|
+
*
|
|
73
|
+
* Returns an empty Map when no usable per-band ranges are found.
|
|
74
|
+
*/
|
|
75
|
+
export declare function readGdalStats(geotiff: GeoTIFFType): GdalImageStats;
|
|
76
|
+
/**
|
|
77
|
+
* Stream a 128-bin histogram for a single band. Fires `onProgress` after
|
|
78
|
+
* each tile so the UI can fill in the chart incrementally, the snapshots
|
|
79
|
+
* share no buffer references between calls (each `bins` is a fresh
|
|
80
|
+
* `Uint32Array`).
|
|
81
|
+
*
|
|
82
|
+
* Algorithm:
|
|
83
|
+
* - With GDAL priors, one pass, known bin edges, progressive snapshots.
|
|
84
|
+
* - Without priors, two passes, pass 1 finds min/max across all
|
|
85
|
+
* selected tiles, pass 2 bins into 128 buckets. Snapshots fire
|
|
86
|
+
* per-cached-tile in pass 2 so the UI still sees the histogram fill
|
|
87
|
+
* in on the no-priors path, bin edges aren't stable during pass 1.
|
|
88
|
+
*
|
|
89
|
+
* Honors `signal.aborted` between every tile fetch and after each bin
|
|
90
|
+
* pass. Throws no error on abort, returns silently with whatever
|
|
91
|
+
* partial snapshot the caller already received.
|
|
92
|
+
*/
|
|
93
|
+
export declare function streamHistogram(opts: StreamHistogramOptions): Promise<void>;
|
|
94
|
+
/** Options for {@link seedRescaleFromGeotiff}. */
|
|
95
|
+
export type SeedRescaleOptions = {
|
|
96
|
+
signal?: AbortSignal;
|
|
97
|
+
/** 1-based band index. Defaults to 1. */
|
|
98
|
+
bandIndex?: number;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Seed a {@link RescaleConfig} for a freshly opened COG in the same
|
|
102
|
+
* normalized shader-space [0, 1] coordinate system the rescale slider
|
|
103
|
+
* operates on. The GPU's hardware normalization (`r8unorm` / `r16unorm`)
|
|
104
|
+
* and the `Colormap` CPU baker both divide raw integer samples by the
|
|
105
|
+
* format's max (255 for uint8, 65535 for uint16) before sampling, and
|
|
106
|
+
* `CogControls`'s `setRescaleMin/Max` clamps the slider via `clamp01`.
|
|
107
|
+
* Storing raw GeoTIFF stats (e.g. `{min: 0, max: 10000}` for uint16
|
|
108
|
+
* reflectance) here would snap back to `{0, 1}` on the user's first
|
|
109
|
+
* slider touch.
|
|
110
|
+
*
|
|
111
|
+
* Fallback chain:
|
|
112
|
+
* 1. GDAL `STATISTICS_MINIMUM` / `STATISTICS_MAXIMUM` for the band,
|
|
113
|
+
* normalized to shader space by dividing by the sample-format
|
|
114
|
+
* factor (255 for uint8, 65535 for uint ≥ 8 bps). Float bands are
|
|
115
|
+
* passed through unchanged because they already live near [0, 1].
|
|
116
|
+
* 2. `buildHistogramFromGeotiff` + p2 / p98 percentile lookup so a
|
|
117
|
+
* uint16 reflectance band with no STATISTICS tag still gets a
|
|
118
|
+
* contrasted preview from the first tile of the smallest overview.
|
|
119
|
+
* 3. {@link defaultRescaleForGeotiff} bit-depth-aware constants.
|
|
120
|
+
*/
|
|
121
|
+
export declare function seedRescaleFromGeotiff(geotiff: GeoTIFFType, options?: SeedRescaleOptions): Promise<RescaleConfig>;
|