@walkthru-earth/objex 1.0.0 → 1.2.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/README.md +11 -2
- package/dist/components/browser/FileBrowser.svelte +41 -54
- package/dist/components/browser/FileTreeSidebar.svelte +43 -7
- package/dist/components/layout/ConnectionDialog.svelte +100 -1
- package/dist/components/layout/Sidebar.svelte +43 -25
- package/dist/components/viewers/CodeViewer.svelte +23 -0
- package/dist/components/viewers/CogControls.svelte +208 -0
- package/dist/components/viewers/CogControls.svelte.d.ts +12 -0
- package/dist/components/viewers/CogViewer.svelte +353 -1160
- package/dist/components/viewers/CogViewer.svelte.d.ts +1 -1
- package/dist/components/viewers/DatabaseViewer.svelte +345 -37
- package/dist/components/viewers/MarkdownViewer.svelte +1 -1
- package/dist/components/viewers/TableViewer.svelte +123 -41
- package/dist/components/viewers/ZarrMapViewer.svelte +29 -0
- package/dist/components/viewers/ZarrViewer.svelte +1 -4
- package/dist/constants.d.ts +6 -2
- package/dist/constants.js +6 -2
- package/dist/file-icons/index.d.ts +1 -1
- package/dist/file-icons/index.js +12 -2
- package/dist/i18n/ar.js +24 -0
- package/dist/i18n/en.js +24 -0
- package/dist/i18n/index.svelte.d.ts +0 -1
- package/dist/i18n/index.svelte.js +0 -3
- package/dist/index.d.ts +11 -0
- package/dist/index.js +10 -0
- package/dist/query/engine.d.ts +20 -4
- package/dist/query/index.d.ts +2 -1
- package/dist/query/index.js +1 -0
- package/dist/query/source.d.ts +30 -0
- package/dist/query/source.js +37 -0
- package/dist/query/wasm.d.ts +7 -5
- package/dist/query/wasm.js +138 -85
- package/dist/storage/providers.d.ts +47 -0
- package/dist/storage/providers.js +160 -0
- package/dist/stores/connections.svelte.js +5 -31
- package/dist/stores/files.svelte.d.ts +2 -8
- package/dist/stores/files.svelte.js +5 -38
- package/dist/stores/query-history.svelte.js +3 -25
- package/dist/stores/settings.svelte.d.ts +1 -0
- package/dist/stores/settings.svelte.js +10 -30
- package/dist/stores/tabs.svelte.d.ts +9 -2
- package/dist/stores/tabs.svelte.js +11 -2
- package/dist/types.d.ts +11 -0
- package/dist/utils/cloud-url.d.ts +27 -0
- package/dist/utils/cloud-url.js +61 -0
- package/dist/utils/cog.d.ts +244 -0
- package/dist/utils/cog.js +1039 -0
- package/dist/utils/deck.d.ts +0 -18
- package/dist/utils/deck.js +0 -36
- package/dist/utils/export.d.ts +22 -2
- package/dist/utils/export.js +35 -10
- package/dist/utils/file-sort.d.ts +20 -0
- package/dist/utils/file-sort.js +41 -0
- package/dist/utils/geometry-type.d.ts +52 -0
- package/dist/utils/geometry-type.js +76 -0
- package/dist/utils/local-storage.d.ts +16 -0
- package/dist/utils/local-storage.js +37 -0
- package/dist/utils/markdown-sql.d.ts +1 -1
- package/dist/utils/markdown-sql.js +3 -4
- package/dist/utils/pmtiles-tile.d.ts +0 -2
- package/dist/utils/pmtiles-tile.js +0 -8
- package/dist/utils/url-state.d.ts +6 -0
- package/dist/utils/url-state.js +34 -26
- package/dist/utils/url.d.ts +13 -25
- package/dist/utils/url.js +17 -78
- package/dist/utils/zarr-tab.d.ts +22 -0
- package/dist/utils/zarr-tab.js +30 -0
- package/dist/utils/zarr.d.ts +0 -2
- package/dist/utils/zarr.js +73 -44
- package/package.json +50 -46
- package/dist/components/ui/tabs/index.d.ts +0 -5
- package/dist/components/ui/tabs/index.js +0 -7
- package/dist/components/ui/tabs/tabs-content.svelte +0 -17
- package/dist/components/ui/tabs/tabs-content.svelte.d.ts +0 -4
- package/dist/components/ui/tabs/tabs-list.svelte +0 -16
- package/dist/components/ui/tabs/tabs-list.svelte.d.ts +0 -4
- package/dist/components/ui/tabs/tabs-trigger.svelte +0 -20
- package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +0 -4
- package/dist/components/ui/tabs/tabs.svelte +0 -19
- package/dist/components/ui/tabs/tabs.svelte.d.ts +0 -4
- package/dist/components/viewers/MapViewer.svelte +0 -234
- package/dist/components/viewers/MapViewer.svelte.d.ts +0 -7
- package/dist/components/viewers/StyleEditorOverlay.svelte +0 -27
- package/dist/components/viewers/StyleEditorOverlay.svelte.d.ts +0 -7
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type maplibregl from 'maplibre-gl';
|
|
3
|
-
import { onDestroy } from 'svelte';
|
|
4
|
-
import { t } from '../../i18n/index.svelte.js';
|
|
5
|
-
import { getAdapter } from '../../storage/index.js';
|
|
6
|
-
import { tabResources } from '../../stores/tab-resources.svelte.js';
|
|
7
|
-
import type { Tab } from '../../types';
|
|
8
|
-
import { setupSelectionLayer, updateSelection } from '../../utils/map-selection.js';
|
|
9
|
-
import AttributeTable from './map/AttributeTable.svelte';
|
|
10
|
-
import MapContainer from './map/MapContainer.svelte';
|
|
11
|
-
|
|
12
|
-
let { tab }: { tab: Tab } = $props();
|
|
13
|
-
|
|
14
|
-
let abortController: AbortController | null = null;
|
|
15
|
-
let loading = $state(true);
|
|
16
|
-
let error = $state<string | null>(null);
|
|
17
|
-
let geojsonData = $state.raw<any>(null);
|
|
18
|
-
let selectedFeature = $state<Record<string, any> | null>(null);
|
|
19
|
-
let showAttributes = $state(false);
|
|
20
|
-
let bounds = $state<[number, number, number, number] | undefined>();
|
|
21
|
-
|
|
22
|
-
$effect(() => {
|
|
23
|
-
if (!tab) return;
|
|
24
|
-
loadGeoJson();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
function cleanup() {
|
|
28
|
-
abortController?.abort();
|
|
29
|
-
abortController = null;
|
|
30
|
-
geojsonData = null;
|
|
31
|
-
selectedFeature = null;
|
|
32
|
-
bounds = undefined;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
$effect(() => {
|
|
36
|
-
if (!tab) return;
|
|
37
|
-
const unregister = tabResources.register(tab.id, cleanup);
|
|
38
|
-
return unregister;
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
onDestroy(cleanup);
|
|
42
|
-
|
|
43
|
-
async function loadGeoJson() {
|
|
44
|
-
abortController?.abort();
|
|
45
|
-
abortController = new AbortController();
|
|
46
|
-
const { signal } = abortController;
|
|
47
|
-
|
|
48
|
-
loading = true;
|
|
49
|
-
error = null;
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
const adapter = getAdapter(tab.source, tab.connectionId);
|
|
53
|
-
const data = await adapter.read(tab.path, undefined, undefined, signal);
|
|
54
|
-
const text = new TextDecoder().decode(data);
|
|
55
|
-
geojsonData = JSON.parse(text);
|
|
56
|
-
|
|
57
|
-
// Compute bounds from features
|
|
58
|
-
if (geojsonData.bbox) {
|
|
59
|
-
bounds = geojsonData.bbox as [number, number, number, number];
|
|
60
|
-
} else {
|
|
61
|
-
bounds = computeBounds(geojsonData);
|
|
62
|
-
}
|
|
63
|
-
} catch (err) {
|
|
64
|
-
if (err instanceof DOMException && err.name === 'AbortError') return;
|
|
65
|
-
error = err instanceof Error ? err.message : String(err);
|
|
66
|
-
} finally {
|
|
67
|
-
loading = false;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function computeBounds(geojson: any): [number, number, number, number] | undefined {
|
|
72
|
-
let minLng = Infinity,
|
|
73
|
-
minLat = Infinity,
|
|
74
|
-
maxLng = -Infinity,
|
|
75
|
-
maxLat = -Infinity;
|
|
76
|
-
let found = false;
|
|
77
|
-
|
|
78
|
-
function processCoord(coord: number[]) {
|
|
79
|
-
if (coord.length >= 2) {
|
|
80
|
-
found = true;
|
|
81
|
-
minLng = Math.min(minLng, coord[0]);
|
|
82
|
-
minLat = Math.min(minLat, coord[1]);
|
|
83
|
-
maxLng = Math.max(maxLng, coord[0]);
|
|
84
|
-
maxLat = Math.max(maxLat, coord[1]);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function processCoords(coords: any) {
|
|
89
|
-
if (!coords) return;
|
|
90
|
-
if (typeof coords[0] === 'number') {
|
|
91
|
-
processCoord(coords);
|
|
92
|
-
} else {
|
|
93
|
-
for (const c of coords) processCoords(c);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function processGeometry(geom: any) {
|
|
98
|
-
if (!geom) return;
|
|
99
|
-
if (geom.coordinates) processCoords(geom.coordinates);
|
|
100
|
-
if (geom.geometries) geom.geometries.forEach(processGeometry);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (geojson.type === 'FeatureCollection') {
|
|
104
|
-
for (const f of geojson.features || []) processGeometry(f.geometry);
|
|
105
|
-
} else if (geojson.type === 'Feature') {
|
|
106
|
-
processGeometry(geojson.geometry);
|
|
107
|
-
} else {
|
|
108
|
-
processGeometry(geojson);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return found ? [minLng, minLat, maxLng, maxLat] : undefined;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function onMapReady(map: maplibregl.Map) {
|
|
115
|
-
if (!geojsonData) return;
|
|
116
|
-
|
|
117
|
-
map.addSource('geojson-source', {
|
|
118
|
-
type: 'geojson',
|
|
119
|
-
data: geojsonData
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// Fill layer for polygons (orange)
|
|
123
|
-
map.addLayer({
|
|
124
|
-
id: 'geojson-fill',
|
|
125
|
-
type: 'fill',
|
|
126
|
-
source: 'geojson-source',
|
|
127
|
-
filter: ['==', '$type', 'Polygon'],
|
|
128
|
-
paint: {
|
|
129
|
-
'fill-color': '#e8793d',
|
|
130
|
-
'fill-opacity': 0.35
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
// Outline layer for polygons (orange)
|
|
135
|
-
map.addLayer({
|
|
136
|
-
id: 'geojson-polygon-outline',
|
|
137
|
-
type: 'line',
|
|
138
|
-
source: 'geojson-source',
|
|
139
|
-
filter: ['==', '$type', 'Polygon'],
|
|
140
|
-
paint: {
|
|
141
|
-
'line-color': '#e65100',
|
|
142
|
-
'line-width': 2.5
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
// Line layer for linestrings (teal)
|
|
147
|
-
map.addLayer({
|
|
148
|
-
id: 'geojson-line',
|
|
149
|
-
type: 'line',
|
|
150
|
-
source: 'geojson-source',
|
|
151
|
-
filter: ['==', '$type', 'LineString'],
|
|
152
|
-
paint: {
|
|
153
|
-
'line-color': '#00838f',
|
|
154
|
-
'line-width': 2.5
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
// Circle layer for points (blue)
|
|
159
|
-
map.addLayer({
|
|
160
|
-
id: 'geojson-points',
|
|
161
|
-
type: 'circle',
|
|
162
|
-
source: 'geojson-source',
|
|
163
|
-
filter: ['==', '$type', 'Point'],
|
|
164
|
-
paint: {
|
|
165
|
-
'circle-radius': 7,
|
|
166
|
-
'circle-color': '#4285f4',
|
|
167
|
-
'circle-stroke-width': 1.5,
|
|
168
|
-
'circle-stroke-color': '#fff'
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
// Selection highlight
|
|
173
|
-
setupSelectionLayer(map);
|
|
174
|
-
|
|
175
|
-
// Click handler
|
|
176
|
-
for (const layerId of [
|
|
177
|
-
'geojson-fill',
|
|
178
|
-
'geojson-polygon-outline',
|
|
179
|
-
'geojson-line',
|
|
180
|
-
'geojson-points'
|
|
181
|
-
]) {
|
|
182
|
-
map.on('click', layerId, (e: any) => {
|
|
183
|
-
if (e.features && e.features.length > 0) {
|
|
184
|
-
selectedFeature = { ...e.features[0].properties };
|
|
185
|
-
showAttributes = true;
|
|
186
|
-
updateSelection(map, e.features[0] as GeoJSON.Feature);
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
map.on('mouseenter', layerId, () => {
|
|
191
|
-
map.getCanvas().style.cursor = 'pointer';
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
map.on('mouseleave', layerId, () => {
|
|
195
|
-
map.getCanvas().style.cursor = '';
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
</script>
|
|
200
|
-
|
|
201
|
-
<div class="relative flex h-full overflow-hidden">
|
|
202
|
-
{#if loading}
|
|
203
|
-
<div class="flex flex-1 items-center justify-center">
|
|
204
|
-
<p class="text-sm text-zinc-400">{t('map.loadingData')}</p>
|
|
205
|
-
</div>
|
|
206
|
-
{:else if error}
|
|
207
|
-
<div class="flex flex-1 items-center justify-center">
|
|
208
|
-
<p class="text-sm text-red-400">{error}</p>
|
|
209
|
-
</div>
|
|
210
|
-
{:else}
|
|
211
|
-
<div class="flex-1">
|
|
212
|
-
<MapContainer {onMapReady} {bounds} />
|
|
213
|
-
</div>
|
|
214
|
-
|
|
215
|
-
{#if selectedFeature}
|
|
216
|
-
<div class="absolute right-2 top-2 z-10 flex gap-1">
|
|
217
|
-
<button
|
|
218
|
-
class="rounded bg-card/80 px-2 py-1 text-xs text-card-foreground backdrop-blur-sm hover:bg-card"
|
|
219
|
-
class:ring-1={showAttributes}
|
|
220
|
-
class:ring-primary={showAttributes}
|
|
221
|
-
onclick={() => (showAttributes = !showAttributes)}
|
|
222
|
-
>
|
|
223
|
-
{t('map.attributes')}
|
|
224
|
-
</button>
|
|
225
|
-
</div>
|
|
226
|
-
{/if}
|
|
227
|
-
|
|
228
|
-
<AttributeTable
|
|
229
|
-
feature={selectedFeature}
|
|
230
|
-
visible={showAttributes}
|
|
231
|
-
onClose={() => (showAttributes = false)}
|
|
232
|
-
/>
|
|
233
|
-
{/if}
|
|
234
|
-
</div>
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
let { styleUrl, onclose }: { styleUrl: string; onclose: () => void } = $props();
|
|
3
|
-
|
|
4
|
-
const maputnikUrl = $derived(
|
|
5
|
-
`https://maplibre.org/maputnik/?style=${encodeURIComponent(styleUrl)}`
|
|
6
|
-
);
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<div class="fixed inset-0 z-50 flex flex-col bg-zinc-950">
|
|
10
|
-
<div
|
|
11
|
-
class="flex items-center justify-between border-b border-zinc-800 bg-zinc-900 px-4 py-2"
|
|
12
|
-
>
|
|
13
|
-
<span class="text-sm font-medium text-zinc-300">Maputnik Style Editor</span>
|
|
14
|
-
<button
|
|
15
|
-
class="rounded px-3 py-1 text-xs text-zinc-400 hover:bg-zinc-800 hover:text-zinc-200"
|
|
16
|
-
onclick={onclose}
|
|
17
|
-
>
|
|
18
|
-
Close
|
|
19
|
-
</button>
|
|
20
|
-
</div>
|
|
21
|
-
<iframe
|
|
22
|
-
src={maputnikUrl}
|
|
23
|
-
class="flex-1 border-0"
|
|
24
|
-
title="Maputnik Style Editor"
|
|
25
|
-
allow="clipboard-read; clipboard-write"
|
|
26
|
-
></iframe>
|
|
27
|
-
</div>
|