maplibre-gl-raster 0.9.0 → 0.10.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/dist/{RasterControl-BfTDWAnW.js → RasterControl-D9JDQUVb.js} +113 -11
- package/dist/{RasterControl-BfTDWAnW.js.map → RasterControl-D9JDQUVb.js.map} +1 -1
- package/dist/index.mjs +1 -1
- package/dist/react.mjs +1 -1
- package/dist/types/index.d.ts +27 -0
- package/dist/types/react.d.ts +10 -0
- package/package.json +2 -2
|
@@ -18206,6 +18206,7 @@ function toLayerInfo(layer) {
|
|
|
18206
18206
|
bandCount: layer.bandCount,
|
|
18207
18207
|
bandNames: layer.bandNames ? new Map(layer.bandNames) : null,
|
|
18208
18208
|
beforeId: layer.beforeId,
|
|
18209
|
+
attribution: layer.attribution,
|
|
18209
18210
|
bounds: layer.bounds ? { ...layer.bounds } : null,
|
|
18210
18211
|
loading: layer.loading,
|
|
18211
18212
|
error: layer.error,
|
|
@@ -18232,6 +18233,26 @@ function deriveLayerName(source) {
|
|
|
18232
18233
|
/** Default engine when none is configured: the deck.gl GPU pipeline. */
|
|
18233
18234
|
var DEFAULT_ENGINE = "maplibre-gl-raster";
|
|
18234
18235
|
/**
|
|
18236
|
+
* Clamps a bounds' latitudes to the valid WGS84 range. GeoTIFF bounds are
|
|
18237
|
+
* derived as `origin + n * pixelSize`, so a global raster whose pixel size was
|
|
18238
|
+
* stored rounded (e.g. GEBCO's 1/240° stored as 0.004166666666667) can
|
|
18239
|
+
* overshoot the poles by a floating-point epsilon — and MapLibre's LngLat
|
|
18240
|
+
* rejects any latitude outside [-90, 90], crashing fitBounds. Longitudes are
|
|
18241
|
+
* left alone: MapLibre accepts any longitude, and clamping would corrupt
|
|
18242
|
+
* antimeridian-crossing rasters.
|
|
18243
|
+
*/
|
|
18244
|
+
function clampBoundsLatitude(bounds) {
|
|
18245
|
+
const clamp = (lat) => Math.min(90, Math.max(-90, lat));
|
|
18246
|
+
const south = clamp(bounds.south);
|
|
18247
|
+
const north = clamp(bounds.north);
|
|
18248
|
+
if (south === bounds.south && north === bounds.north) return bounds;
|
|
18249
|
+
return {
|
|
18250
|
+
...bounds,
|
|
18251
|
+
south,
|
|
18252
|
+
north
|
|
18253
|
+
};
|
|
18254
|
+
}
|
|
18255
|
+
/**
|
|
18235
18256
|
* The band indexes a layer actually samples, deduped and sorted. Mirrors the
|
|
18236
18257
|
* `requested` logic in render-pipeline's buildRenderTile: RGB samples the first
|
|
18237
18258
|
* three entries (R, G, B); single-band / colormap / palette the first one. The
|
|
@@ -18358,6 +18379,9 @@ var LayerManager = class {
|
|
|
18358
18379
|
_colormapTexture = null;
|
|
18359
18380
|
_handlers = new globalThis.Map();
|
|
18360
18381
|
_crsFailed = /* @__PURE__ */ new Set();
|
|
18382
|
+
_attributions = new globalThis.Map();
|
|
18383
|
+
_attribStyleReady = false;
|
|
18384
|
+
_onAttribStyleLoad = null;
|
|
18361
18385
|
_destroyed = false;
|
|
18362
18386
|
/**
|
|
18363
18387
|
* Creates a LayerManager bound to a map.
|
|
@@ -18444,6 +18468,7 @@ var LayerManager = class {
|
|
|
18444
18468
|
palette: null,
|
|
18445
18469
|
paletteTexture: null,
|
|
18446
18470
|
beforeId: options?.beforeId?.trim() || null,
|
|
18471
|
+
attribution: options?.attribution?.trim() || null,
|
|
18447
18472
|
bounds: null,
|
|
18448
18473
|
zoomTo: options?.zoomTo ?? true,
|
|
18449
18474
|
loading: true,
|
|
@@ -18649,6 +18674,11 @@ var LayerManager = class {
|
|
|
18649
18674
|
}
|
|
18650
18675
|
this._layers = [];
|
|
18651
18676
|
this._selectedId = null;
|
|
18677
|
+
for (const id of [...this._attributions.keys()]) this._removeAttribution(id);
|
|
18678
|
+
if (this._onAttribStyleLoad) {
|
|
18679
|
+
this._map.off("load", this._onAttribStyleLoad);
|
|
18680
|
+
this._onAttribStyleLoad = null;
|
|
18681
|
+
}
|
|
18652
18682
|
if (this._overlay) {
|
|
18653
18683
|
this._deps.removeOverlay(this._map, this._overlay);
|
|
18654
18684
|
this._overlay = null;
|
|
@@ -18700,10 +18730,10 @@ var LayerManager = class {
|
|
|
18700
18730
|
const layer = this.getLayer(id);
|
|
18701
18731
|
if (!layer) return;
|
|
18702
18732
|
const boundsArrived = !layer.bounds;
|
|
18703
|
-
layer.bounds = bounds;
|
|
18733
|
+
layer.bounds = clampBoundsLatitude(bounds);
|
|
18704
18734
|
if (zoomTo && layer.zoomTo) {
|
|
18705
18735
|
layer.zoomTo = false;
|
|
18706
|
-
this._fitBounds(bounds);
|
|
18736
|
+
this._fitBounds(layer.bounds);
|
|
18707
18737
|
}
|
|
18708
18738
|
if (boundsArrived) this._emit({
|
|
18709
18739
|
type: "rasterchange",
|
|
@@ -18793,10 +18823,66 @@ var LayerManager = class {
|
|
|
18793
18823
|
duration: 800
|
|
18794
18824
|
});
|
|
18795
18825
|
}
|
|
18826
|
+
/** Reconciles per-layer attributions with the map's attribution control.
|
|
18827
|
+
*
|
|
18828
|
+
* Neither engine gives every raster a MapLibre source the control could read
|
|
18829
|
+
* an attribution from (the deck.gl path renders through an overlay with no
|
|
18830
|
+
* source at all), so each attributed, visible layer gets a helper: an empty
|
|
18831
|
+
* GeoJSON source carrying the attribution string plus a no-op circle layer
|
|
18832
|
+
* referencing it. The layer marks the source as used, which is what makes
|
|
18833
|
+
* the stock AttributionControl display (and de-duplicate) the string; the
|
|
18834
|
+
* empty feature collection means nothing is ever drawn or fetched. */
|
|
18835
|
+
_syncAttributions() {
|
|
18836
|
+
if (!this._attribStyleReady) if (this._map.isStyleLoaded()) this._attribStyleReady = true;
|
|
18837
|
+
else {
|
|
18838
|
+
if (!this._onAttribStyleLoad) {
|
|
18839
|
+
this._onAttribStyleLoad = () => {
|
|
18840
|
+
this._onAttribStyleLoad = null;
|
|
18841
|
+
this._attribStyleReady = true;
|
|
18842
|
+
this._syncAttributions();
|
|
18843
|
+
};
|
|
18844
|
+
this._map.once("load", this._onAttribStyleLoad);
|
|
18845
|
+
}
|
|
18846
|
+
return;
|
|
18847
|
+
}
|
|
18848
|
+
const desired = /* @__PURE__ */ new Map();
|
|
18849
|
+
for (const l of this._layers) if (l.attribution && l.geotiff && l.state.visible && !l.error && !this._crsFailed.has(l.id)) desired.set(l.id, l.attribution);
|
|
18850
|
+
for (const [id, applied] of this._attributions) if (desired.get(id) !== applied) this._removeAttribution(id);
|
|
18851
|
+
for (const [id, attribution] of desired) {
|
|
18852
|
+
if (this._attributions.has(id)) continue;
|
|
18853
|
+
const helperId = `mlr-attribution-${id}`;
|
|
18854
|
+
try {
|
|
18855
|
+
this._map.addSource(helperId, {
|
|
18856
|
+
type: "geojson",
|
|
18857
|
+
data: {
|
|
18858
|
+
type: "FeatureCollection",
|
|
18859
|
+
features: []
|
|
18860
|
+
},
|
|
18861
|
+
attribution
|
|
18862
|
+
});
|
|
18863
|
+
this._map.addLayer({
|
|
18864
|
+
id: helperId,
|
|
18865
|
+
type: "circle",
|
|
18866
|
+
source: helperId
|
|
18867
|
+
});
|
|
18868
|
+
this._attributions.set(id, attribution);
|
|
18869
|
+
} catch {}
|
|
18870
|
+
}
|
|
18871
|
+
}
|
|
18872
|
+
/** Removes a layer's attribution helper source/layer, if present. */
|
|
18873
|
+
_removeAttribution(id) {
|
|
18874
|
+
if (!this._attributions.delete(id)) return;
|
|
18875
|
+
const helperId = `mlr-attribution-${id}`;
|
|
18876
|
+
try {
|
|
18877
|
+
if (this._map.getLayer(helperId)) this._map.removeLayer(helperId);
|
|
18878
|
+
if (this._map.getSource(helperId)) this._map.removeSource(helperId);
|
|
18879
|
+
} catch {}
|
|
18880
|
+
}
|
|
18796
18881
|
/** Re-derives the deck.gl layer array from current layer states and pushes
|
|
18797
18882
|
* it to the overlay. Layer ids are stable so deck.gl preserves each
|
|
18798
18883
|
* layer's tile cache across rebuilds. */
|
|
18799
18884
|
_rebuild() {
|
|
18885
|
+
this._syncAttributions();
|
|
18800
18886
|
if (this._engine === "cog-tiler-wasm") {
|
|
18801
18887
|
this._overlay?.setProps({ layers: [] });
|
|
18802
18888
|
this._ensureCogEngine().sync(this._cogRenderableLayers());
|
|
@@ -18823,7 +18909,7 @@ var LayerManager = class {
|
|
|
18823
18909
|
}),
|
|
18824
18910
|
onGeoTIFFLoad: (_tiff, options) => {
|
|
18825
18911
|
const boundsArrived = !layer.bounds;
|
|
18826
|
-
layer.bounds = options.geographicBounds;
|
|
18912
|
+
layer.bounds = clampBoundsLatitude(options.geographicBounds);
|
|
18827
18913
|
if (layer.zoomTo) {
|
|
18828
18914
|
layer.zoomTo = false;
|
|
18829
18915
|
this._fitBounds(layer.bounds);
|
|
@@ -19152,7 +19238,8 @@ var AddDataSection = class {
|
|
|
19152
19238
|
const addFiles = (files) => {
|
|
19153
19239
|
if (!files) return;
|
|
19154
19240
|
const beforeId = currentBeforeId();
|
|
19155
|
-
|
|
19241
|
+
const attribution = currentAttribution();
|
|
19242
|
+
for (const file of Array.from(files)) if (isTiff(file)) options.onAddFile(file, beforeId, attribution);
|
|
19156
19243
|
};
|
|
19157
19244
|
const input = el("input", {
|
|
19158
19245
|
className: "mlr-input",
|
|
@@ -19179,10 +19266,18 @@ var AddDataSection = class {
|
|
|
19179
19266
|
title: "Id of an existing map layer to insert the raster beneath (e.g. a label layer). Leave empty to draw on top."
|
|
19180
19267
|
});
|
|
19181
19268
|
const currentBeforeId = () => beforeIdInput.value.trim() || void 0;
|
|
19269
|
+
const attributionInput = el("input", {
|
|
19270
|
+
className: "mlr-input",
|
|
19271
|
+
type: "text",
|
|
19272
|
+
placeholder: "Attribution (optional)",
|
|
19273
|
+
ariaLabel: "attribution",
|
|
19274
|
+
title: "Data credit shown in the map's attribution control while the layer is visible (plain text or an HTML link)."
|
|
19275
|
+
});
|
|
19276
|
+
const currentAttribution = () => attributionInput.value.trim() || void 0;
|
|
19182
19277
|
const submitUrl = () => {
|
|
19183
19278
|
const url = input.value.trim();
|
|
19184
19279
|
if (!url) return;
|
|
19185
|
-
options.onAddUrl(url, currentBeforeId());
|
|
19280
|
+
options.onAddUrl(url, currentBeforeId(), currentAttribution());
|
|
19186
19281
|
};
|
|
19187
19282
|
loadBtn.addEventListener("click", submitUrl);
|
|
19188
19283
|
input.addEventListener("keydown", (e) => {
|
|
@@ -19234,6 +19329,7 @@ var AddDataSection = class {
|
|
|
19234
19329
|
setMenuOpen(false);
|
|
19235
19330
|
trigger.focus();
|
|
19236
19331
|
input.value = sample.url;
|
|
19332
|
+
if (sample.attribution) attributionInput.value = sample.attribution;
|
|
19237
19333
|
loadBtn.disabled = input.value.trim().length === 0;
|
|
19238
19334
|
submitUrl();
|
|
19239
19335
|
});
|
|
@@ -19295,7 +19391,7 @@ var AddDataSection = class {
|
|
|
19295
19391
|
this.el = el("div", { className: "mlr-section mlr-add-data" }, el("div", {
|
|
19296
19392
|
className: "mlr-section-title",
|
|
19297
19393
|
text: "Add data"
|
|
19298
|
-
}), urlRow, dropZone, beforeIdInput, ...sampleRow ? [sampleRow] : []);
|
|
19394
|
+
}), urlRow, dropZone, beforeIdInput, attributionInput, ...sampleRow ? [sampleRow] : []);
|
|
19299
19395
|
}
|
|
19300
19396
|
};
|
|
19301
19397
|
//#endregion
|
|
@@ -20461,11 +20557,17 @@ var PanelUI = class {
|
|
|
20461
20557
|
initialUrl: options?.defaultUrl,
|
|
20462
20558
|
sampleData: options?.sampleData,
|
|
20463
20559
|
sampleDataLabel: options?.sampleDataLabel,
|
|
20464
|
-
onAddUrl: (url, beforeId) => {
|
|
20465
|
-
this._manager.addRaster(url, {
|
|
20560
|
+
onAddUrl: (url, beforeId, attribution) => {
|
|
20561
|
+
this._manager.addRaster(url, {
|
|
20562
|
+
beforeId,
|
|
20563
|
+
attribution
|
|
20564
|
+
}).catch(() => {});
|
|
20466
20565
|
},
|
|
20467
|
-
onAddFile: (file, beforeId) => {
|
|
20468
|
-
this._manager.addRaster(file, {
|
|
20566
|
+
onAddFile: (file, beforeId, attribution) => {
|
|
20567
|
+
this._manager.addRaster(file, {
|
|
20568
|
+
beforeId,
|
|
20569
|
+
attribution
|
|
20570
|
+
}).catch(() => {});
|
|
20469
20571
|
}
|
|
20470
20572
|
});
|
|
20471
20573
|
this._layerList = new LayerList({
|
|
@@ -21430,4 +21532,4 @@ var RasterControl = class {
|
|
|
21430
21532
|
//#endregion
|
|
21431
21533
|
export { statsForBand as A, COLORMAP_NAMES as C, colormaps_default as D, colormapDisplayName as E, createResilientEpsgResolver as F, computeAutoStats as M, percentileFromHistogram as N, DEFAULT_INDEX_RANGE as O, readBandNames as P, COLORMAP_DISPLAY_NAMES as S, COLORMAP_ROW_COUNT as T, debounce as _, NORMALIZED_DIFFERENCE_INDICES as a, throttle as b, readPixelValues as c, PALETTE_COLORMAP as d, isKnownColormap as f, classNames as g, clamp as h, CUSTOM_NORMALIZED_DIFFERENCE as i, MAX_SAMPLE_TILES as j, autoRangeFor as k, DEFAULT_ENGINE as l, sampleColormapStops as m, Colorbar as n, guessBandForRole as o, loadColormapSprite as p, CUSTOM_INDEX_ID as r, indexById as s, RasterControl as t, LayerManager as u, formatNumericValue as v, COLORMAP_OPTIONS as w, loadGeoTIFF as x, generateId as y };
|
|
21432
21534
|
|
|
21433
|
-
//# sourceMappingURL=RasterControl-
|
|
21535
|
+
//# sourceMappingURL=RasterControl-D9JDQUVb.js.map
|