maplibre-gl-raster 0.2.3 → 0.3.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/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as colormaps_default, a as debounce, c as throttle, d as percentileFromHistogram, f as readBandNames, g as COLORMAP_ROW_COUNT, h as COLORMAP_OPTIONS, i as classNames, l as MAX_SAMPLE_TILES, m as COLORMAP_NAMES, n as PALETTE_COLORMAP, o as formatNumericValue, p as loadGeoTIFF, r as clamp, s as generateId, t as RasterControl, u as computeAutoStats, v as createResilientEpsgResolver } from "./RasterControl-COXL7MI-.js";
1
+ import { C as computeAutoStats, E as createResilientEpsgResolver, S as MAX_SAMPLE_TILES, T as readBandNames, _ as COLORMAP_ROW_COUNT, a as loadColormapSprite, b as autoRangeFor, c as classNames, d as generateId, f as throttle, g as COLORMAP_OPTIONS, h as COLORMAP_NAMES, i as isKnownColormap, l as debounce, m as COLORMAP_DISPLAY_NAMES, n as Colorbar, o as sampleColormapStops, p as loadGeoTIFF, r as PALETTE_COLORMAP, s as clamp, t as RasterControl, u as formatNumericValue, v as colormapDisplayName, w as percentileFromHistogram, x as statsForBand, y as colormaps_default } from "./RasterControl-CV8yzpiz.js";
2
2
  import { a as Photometric, d as TiffTag, i as Compression, l as SampleFormat, o as PlanarConfiguration, s as Predictor } from "./decode-BL-qbDOV.js";
3
3
  //#region src/lib/raster/metadata.ts
4
4
  var SAMPLE_FORMAT_LABELS = {
@@ -218,6 +218,6 @@ function summarizeGeoTIFF(tiff) {
218
218
  };
219
219
  }
220
220
  //#endregion
221
- export { COLORMAP_NAMES, COLORMAP_OPTIONS, COLORMAP_ROW_COUNT, MAX_SAMPLE_TILES, PALETTE_COLORMAP, RasterControl, clamp, classNames, colormaps_default as colormapsPngUrl, computeAutoStats, createResilientEpsgResolver, debounce, formatNumericValue, generateId, loadGeoTIFF, percentileFromHistogram, readBandNames, summarizeGeoTIFF, throttle };
221
+ export { COLORMAP_DISPLAY_NAMES, COLORMAP_NAMES, COLORMAP_OPTIONS, COLORMAP_ROW_COUNT, Colorbar, MAX_SAMPLE_TILES, PALETTE_COLORMAP, RasterControl, autoRangeFor, clamp, classNames, colormapDisplayName, colormaps_default as colormapsPngUrl, computeAutoStats, createResilientEpsgResolver, debounce, formatNumericValue, generateId, isKnownColormap, loadColormapSprite, loadGeoTIFF, percentileFromHistogram, readBandNames, sampleColormapStops, statsForBand, summarizeGeoTIFF, throttle };
222
222
 
223
223
  //# sourceMappingURL=index.mjs.map
@@ -8,7 +8,8 @@
8
8
 
9
9
  .mlr-control,
10
10
  .mlr-control-panel,
11
- .mlr-inspect-popup {
11
+ .mlr-inspect-popup,
12
+ .mlr-colorbar {
12
13
  --mlr-bg: #fff;
13
14
  --mlr-surface-muted: #f1f3f5;
14
15
  --mlr-surface-soft: #f7f8f9;
@@ -39,7 +40,8 @@
39
40
  @media (prefers-color-scheme: dark) {
40
41
  .mlr-control,
41
42
  .mlr-control-panel,
42
- .mlr-inspect-popup {
43
+ .mlr-inspect-popup,
44
+ .mlr-colorbar {
43
45
  --mlr-bg: #23282e;
44
46
  --mlr-surface-muted: #2e343b;
45
47
  --mlr-surface-soft: #2a3036;
@@ -68,6 +70,40 @@
68
70
  }
69
71
  }
70
72
 
73
+ /* Host-controlled dark theme: an app that toggles a `.dark` class (e.g.
74
+ GeoLibre, which sets it on <html>) themes the controls and colorbar to
75
+ match, overriding the OS prefers-color-scheme default above. */
76
+ .dark .mlr-control,
77
+ .dark .mlr-control-panel,
78
+ .dark .mlr-inspect-popup,
79
+ .dark .mlr-colorbar {
80
+ --mlr-bg: #23282e;
81
+ --mlr-surface-muted: #2e343b;
82
+ --mlr-surface-soft: #2a3036;
83
+ --mlr-text: #e3e6e9;
84
+ --mlr-text-strong: #f0f2f4;
85
+ --mlr-text-soft: #c4cad0;
86
+ --mlr-text-muted: #9aa3ab;
87
+ --mlr-text-faint: #828b93;
88
+ --mlr-border: #454d55;
89
+ --mlr-border-soft: #3a4148;
90
+ --mlr-border-faint: #343b42;
91
+ --mlr-border-strong: #525a63;
92
+ --mlr-accent: #5b9ce0;
93
+ --mlr-accent-strong: #6faae6;
94
+ --mlr-accent-soft: rgba(91, 156, 224, 0.2);
95
+ --mlr-hover: rgba(255, 255, 255, 0.08);
96
+ --mlr-error: #e07b6e;
97
+ --mlr-disabled-bg: #4a5158;
98
+ --mlr-disabled-text: #5f666d;
99
+ --mlr-scrollbar: #4a5158;
100
+ --mlr-scrollbar-hover: #5f666d;
101
+ --mlr-shadow: rgba(0, 0, 0, 0.35);
102
+ --mlr-histogram-neutral: #cfd6dd;
103
+
104
+ color-scheme: dark;
105
+ }
106
+
71
107
  /* Container - matches maplibregl-ctrl styling. The doubled selector
72
108
  outranks maplibre-gl's `.maplibregl-ctrl-group { background: #fff }`
73
109
  regardless of stylesheet order, so the button follows the theme (a white
@@ -127,7 +163,10 @@
127
163
  min-width: 240px;
128
164
  max-width: 420px;
129
165
  max-height: min(80vh, 720px);
130
- overflow-y: auto;
166
+ /* The content area is the scroller; the panel clips so the resize handle
167
+ (an absolutely-positioned child) stays pinned to the corner and never
168
+ scrolls away with the content. */
169
+ overflow: hidden;
131
170
  z-index: 1000;
132
171
  padding: 8px;
133
172
  font-size: 12px;
@@ -135,8 +174,33 @@
135
174
  display: none;
136
175
  }
137
176
 
177
+ /* Flex column so the header keeps its height and the content flexes to fill
178
+ the panel (whether the panel auto-sizes to content up to max-height, or the
179
+ user has set an explicit size via the resize handle). */
138
180
  .mlr-control-panel.expanded {
139
- display: block;
181
+ display: flex;
182
+ flex-direction: column;
183
+ }
184
+
185
+ /* Engine-independent resize affordance (CSS `resize` is unreliable in
186
+ WebKitGTK). Placed at the panel's inward corner by _addResizeHandle(). */
187
+ .mlr-control-resize {
188
+ position: absolute;
189
+ width: 16px;
190
+ height: 16px;
191
+ z-index: 5;
192
+ color: var(--mlr-text-faint);
193
+ opacity: 0.55;
194
+ touch-action: none;
195
+ background-image: repeating-linear-gradient(
196
+ 135deg,
197
+ currentcolor 0 1px,
198
+ transparent 1px 3px
199
+ );
200
+ }
201
+
202
+ .mlr-control-resize:hover {
203
+ opacity: 0.9;
140
204
  }
141
205
 
142
206
  /* Panel header */
@@ -179,7 +243,11 @@
179
243
 
180
244
  /* Content */
181
245
  .mlr-control-content {
182
- max-height: min(72vh, 660px);
246
+ /* Flex child of the panel column: fill the remaining height and scroll.
247
+ min-height: 0 lets it shrink below its content so the scrollbar engages
248
+ instead of overflowing the panel. */
249
+ flex: 1 1 auto;
250
+ min-height: 0;
183
251
  overflow-y: auto;
184
252
  /* Histogram drag handles are centered on the chart edges and poke a few
185
253
  pixels past the content box; clip them instead of growing a horizontal
@@ -361,6 +429,22 @@
361
429
  color: var(--mlr-text-soft);
362
430
  }
363
431
 
432
+ /* Inline checkbox row (e.g. Reverse colormap): box and label on one line. */
433
+ .mlr-check {
434
+ display: flex;
435
+ align-items: center;
436
+ gap: 8px;
437
+ font-size: 11px;
438
+ font-weight: 500;
439
+ color: var(--mlr-text-soft);
440
+ cursor: pointer;
441
+ }
442
+
443
+ .mlr-check input[type='checkbox'] {
444
+ margin: 0;
445
+ cursor: pointer;
446
+ }
447
+
364
448
  /* Collapsible field (e.g. Rescale) */
365
449
  .mlr-collapsible > summary {
366
450
  cursor: pointer;
@@ -670,6 +754,69 @@
670
754
  image-rendering: auto;
671
755
  }
672
756
 
757
+ /* Colorbar legend (a standalone IControl docked in a map corner). It shares
758
+ the --mlr-* theme variables defined above, so it follows both the OS
759
+ prefers-color-scheme and a host `.dark` class. */
760
+ .mlr-colorbar {
761
+ box-sizing: border-box;
762
+ padding: 8px 10px;
763
+ background: var(--mlr-bg);
764
+ color: var(--mlr-text);
765
+ border: 1px solid var(--mlr-border-faint);
766
+ border-radius: 4px;
767
+ box-shadow: 0 1px 4px var(--mlr-shadow);
768
+ font: 11px/1.3 system-ui, sans-serif;
769
+ user-select: none;
770
+ }
771
+
772
+ .mlr-colorbar-title {
773
+ margin-bottom: 6px;
774
+ font-weight: 600;
775
+ color: var(--mlr-text);
776
+ }
777
+
778
+ .mlr-colorbar-track {
779
+ display: flex;
780
+ gap: 6px;
781
+ }
782
+
783
+ .mlr-colorbar-horizontal .mlr-colorbar-track {
784
+ flex-direction: column;
785
+ }
786
+
787
+ .mlr-colorbar-vertical .mlr-colorbar-track {
788
+ flex-direction: row;
789
+ }
790
+
791
+ .mlr-colorbar-bar {
792
+ border: 1px solid var(--mlr-border);
793
+ border-radius: 2px;
794
+ }
795
+
796
+ .mlr-colorbar-ticks {
797
+ display: flex;
798
+ justify-content: space-between;
799
+ color: var(--mlr-text-soft);
800
+ white-space: nowrap;
801
+ }
802
+
803
+ .mlr-colorbar-horizontal .mlr-colorbar-ticks {
804
+ flex-direction: row;
805
+ }
806
+
807
+ /* Pull the first/last labels inward so they don't overflow the bar ends. */
808
+ .mlr-colorbar-horizontal .mlr-colorbar-tick:first-child {
809
+ margin-left: -2px;
810
+ }
811
+
812
+ .mlr-colorbar-horizontal .mlr-colorbar-tick:last-child {
813
+ margin-right: -2px;
814
+ }
815
+
816
+ .mlr-colorbar-vertical .mlr-colorbar-ticks {
817
+ flex-direction: column;
818
+ }
819
+
673
820
  /* Settings header + inspect toggle */
674
821
  .mlr-settings-header {
675
822
  display: flex;
package/dist/react.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as RasterControl } from "./RasterControl-COXL7MI-.js";
1
+ import { t as RasterControl } from "./RasterControl-CV8yzpiz.js";
2
2
  import { useCallback, useEffect, useRef, useState } from "react";
3
3
  //#region src/lib/core/RasterControlReact.tsx
4
4
  /**
@@ -1,4 +1,5 @@
1
1
  import { default as colormapsPngUrl } from '@developmentseed/deck.gl-raster/gpu-modules/colormaps.png';
2
+ import { ControlPosition } from 'maplibre-gl';
2
3
  import { EpsgResolver } from '@developmentseed/proj';
3
4
  import { GeoTIFF } from '@developmentseed/geotiff';
4
5
  import { IControl } from 'maplibre-gl';
@@ -23,6 +24,11 @@ export declare interface AddRasterOptions {
23
24
  beforeId?: string;
24
25
  }
25
26
 
27
+ /** 2–98% percentile range from a band's histogram. Falls back to [min, max]
28
+ * if the histogram is empty (e.g. GDAL_METADATA-only stats with no overview
29
+ * sample). Mirrors the displayed default in the settings UI. */
30
+ export declare function autoRangeFor(stats: BandStats): Range_2;
31
+
26
32
  export declare type AutoStats = {
27
33
  /** 1-indexed band → stats map. Null when stats are unknown. */
28
34
  perBand: Map<number, BandStats> | null;
@@ -92,16 +98,138 @@ export declare function clamp(value: number, min: number, max: number): number;
92
98
  */
93
99
  export declare function classNames(classes: Record<string, boolean>): string;
94
100
 
101
+ /**
102
+ * A standalone colorbar legend rendered on the map as a MapLibre `IControl`.
103
+ *
104
+ * The ramp is sampled from the library's own colormap sprite (so named
105
+ * colormaps and the `reversed` flag match the rendered raster exactly), or
106
+ * built from a custom list of colors. Add it with
107
+ * `map.addControl(new Colorbar({ colormap, min, max, ... }))` and reconfigure
108
+ * live with {@link update} (e.g. from a `rasterchange` handler).
109
+ */
110
+ export declare class Colorbar implements IControl {
111
+ private _opts;
112
+ private _root;
113
+ private _bar;
114
+ private _colorToken;
115
+ /**
116
+ * @param options - Initial colorbar configuration.
117
+ */
118
+ constructor(options?: ColorbarOptions);
119
+ /** @returns The configured map corner. */
120
+ getDefaultPosition(): ControlPosition;
121
+ /**
122
+ * MapLibre `IControl` hook: builds and returns the legend element.
123
+ *
124
+ * @returns The root element MapLibre docks into its corner container.
125
+ */
126
+ onAdd(): HTMLElement;
127
+ /** MapLibre `IControl` hook: detaches the legend. */
128
+ onRemove(): void;
129
+ /**
130
+ * Merges a partial configuration and re-renders. `position` changes only
131
+ * take effect on the next add (MapLibre fixes a control's corner at
132
+ * `addControl` time).
133
+ *
134
+ * @param options - Fields to change.
135
+ */
136
+ update(options: Partial<ColorbarOptions>): void;
137
+ /** @returns A copy of the resolved options. */
138
+ getOptions(): ColorbarOptions;
139
+ /** Resolves the tick values shown along the bar. */
140
+ private _tickValues;
141
+ /** Formats a tick value (fixed decimals when configured, else compact auto)
142
+ * with the configured units suffix. */
143
+ private _formatTick;
144
+ private _render;
145
+ /** Sets the bar gradient, sampling the sprite for named colormaps. */
146
+ private _applyColors;
147
+ }
148
+
149
+ /**
150
+ * Configuration for a {@link Colorbar} legend. All fields are optional; the
151
+ * resolved defaults are listed per field.
152
+ */
153
+ export declare interface ColorbarOptions {
154
+ /** Named colormap to sample (case-insensitive), e.g. 'viridis'. Sampled
155
+ * from the same sprite the renderer uses, so it matches the map exactly.
156
+ * Ignored when {@link colors} supplies a custom ramp. @default 'viridis' */
157
+ colormap?: string;
158
+ /** Custom anchor colors (any CSS color). When two or more are given they
159
+ * define the ramp directly and {@link colormap} is ignored. */
160
+ colors?: string[];
161
+ /** Sample the ramp back-to-front (matches a reversed raster render).
162
+ * @default false */
163
+ reversed?: boolean;
164
+ /** Value at the start of the ramp. @default 0 */
165
+ min?: number;
166
+ /** Value at the end of the ramp. @default 1 */
167
+ max?: number;
168
+ /** Title shown above the bar. @default '' */
169
+ title?: string;
170
+ /** Horizontal alignment of the title. @default 'left' */
171
+ titleAlign?: 'left' | 'center' | 'right';
172
+ /** Unit suffix appended to every tick label (e.g. 'm', '°C'). @default '' */
173
+ units?: string;
174
+ /** Bar/label layout. @default 'horizontal' */
175
+ orientation?: ColorbarOrientation;
176
+ /** Map corner to dock in (MapLibre control position). @default 'bottom-right' */
177
+ position?: ControlPosition;
178
+ /** Stretch curve the raster applies before the colormap. Tick values are
179
+ * spaced to match it so the legend stays accurate under log / sqrt.
180
+ * @default 'linear' */
181
+ stretch?: ColorbarStretch;
182
+ /** Number of evenly spaced tick labels (>= 2). Ignored when
183
+ * {@link tickValues} is set. @default 5 */
184
+ ticks?: number;
185
+ /** Explicit tick values, overriding {@link ticks}. */
186
+ tickValues?: number[];
187
+ /** Fixed number of decimal places for tick labels. When omitted, labels use
188
+ * a compact auto format (2 decimals for |value| >= 1, else 4 sig figs). */
189
+ decimals?: number;
190
+ /** Length of the bar along its main axis, in px. @default 180 */
191
+ barLength?: number;
192
+ /** Thickness of the bar across its main axis, in px. @default 12 */
193
+ barThickness?: number;
194
+ /** Extra class added to the root element. */
195
+ className?: string;
196
+ }
197
+
198
+ /** Layout direction of the colorbar bar and its tick labels. */
199
+ export declare type ColorbarOrientation = 'horizontal' | 'vertical';
200
+
201
+ /** Stretch curve the raster applies before the colormap (mirrors RasterStretch). */
202
+ export declare type ColorbarStretch = 'linear' | 'log' | 'sqrt';
203
+
204
+ /**
205
+ * Canonical display casing for colormaps whose matplotlib name is mixed-case.
206
+ * The sprite keys are lowercased, so the value sent to the renderer stays
207
+ * lowercase (see {@link ColormapOption.name}); only the label is restored to
208
+ * the familiar matplotlib spelling (e.g. "ylorbr" → "YlOrBr", "rdbu" → "RdBu").
209
+ * Names not listed here are lowercase in matplotlib too (viridis, jet, …) and
210
+ * are shown as-is.
211
+ */
212
+ export declare const COLORMAP_DISPLAY_NAMES: Readonly<Record<string, string>>;
213
+
95
214
  /** Alphabetical list of the named colormaps shipped in the sprite. */
96
215
  export declare const COLORMAP_NAMES: string[];
97
216
 
98
- /** Picker-ready options: name, display label, and the sprite row to
99
- * preview. */
217
+ /** Picker-ready options: name (renderer value), display label, and the sprite
218
+ * row to preview. */
100
219
  export declare const COLORMAP_OPTIONS: ColormapOption[];
101
220
 
102
221
  /** Number of rows in the colormap sprite. */
103
222
  export declare const COLORMAP_ROW_COUNT: number;
104
223
 
224
+ /**
225
+ * The matplotlib display label for a colormap key (its canonical casing when
226
+ * known, otherwise the key itself).
227
+ *
228
+ * @param name - The lowercase colormap key.
229
+ * @returns The display label.
230
+ */
231
+ export declare function colormapDisplayName(name: string): string;
232
+
105
233
  export declare type ColormapOption = {
106
234
  name: string;
107
235
  label: string;
@@ -228,6 +356,21 @@ export declare type ImageSummary = {
228
356
  nodata: number | null;
229
357
  };
230
358
 
359
+ /**
360
+ * Whether a name maps to a known colormap row in the sprite.
361
+ *
362
+ * @param name - A colormap name (case-insensitive).
363
+ * @returns True when the name has a sprite row.
364
+ */
365
+ export declare function isKnownColormap(name: string): boolean;
366
+
367
+ /**
368
+ * Loads (and memoizes) the colormap sprite PNG.
369
+ *
370
+ * @returns The decoded sprite image, shared across callers.
371
+ */
372
+ export declare function loadColormapSprite(): Promise<HTMLImageElement>;
373
+
231
374
  /**
232
375
  * Open a GeoTIFF from a URL (http(s) or blob:). Equivalent to
233
376
  * `GeoTIFF.fromUrl(url)` plus the CORS workaround above. Dedupes concurrent
@@ -280,6 +423,31 @@ export declare const PALETTE_COLORMAP = "palette";
280
423
  */
281
424
  export declare function percentileFromHistogram(stats: BandStats, p: number): number;
282
425
 
426
+ declare type Range_2 = [number, number];
427
+
428
+ /**
429
+ * Per-layer colorbar legend config. When `visible`, the control shows a
430
+ * {@link import('./Colorbar').Colorbar} for the (single-band) layer, driven by
431
+ * its colormap, `reversed` flag, and effective rescale range. The fields here
432
+ * are the parts the data can't supply.
433
+ */
434
+ declare interface RasterColorbarState {
435
+ /** Whether the legend is shown for this layer. */
436
+ visible: boolean;
437
+ /** Legend title; defaults to the layer name when empty. */
438
+ title?: string;
439
+ /** Horizontal alignment of the title. @default 'left' */
440
+ titleAlign?: 'left' | 'center' | 'right';
441
+ /** Unit suffix appended to tick labels. */
442
+ units?: string;
443
+ /** Fixed decimal places for tick labels; omitted = compact auto format. */
444
+ decimals?: number;
445
+ /** Bar orientation. @default 'horizontal' */
446
+ orientation?: ColorbarOrientation;
447
+ /** Map corner to dock the legend in. @default 'bottom-right' */
448
+ position?: ControlPosition;
449
+ }
450
+
283
451
  /**
284
452
  * A MapLibre GL control for visualizing local and remote raster datasets
285
453
  * (GeoTIFF / Cloud Optimized GeoTIFF). A collapsible button expands into a
@@ -307,6 +475,12 @@ export declare class RasterControl implements IControl {
307
475
  private _panelUI?;
308
476
  private _inspector?;
309
477
  private _onReady;
478
+ /** On-map colorbar legends, one per layer whose `state.colorbar.visible`. */
479
+ private _colorbars;
480
+ /** User-chosen panel size from the resize handle, re-applied on reposition. */
481
+ private _userPanelSize;
482
+ /** Repositions the resize handle to the panel's inward corner. */
483
+ private _placeResizeHandle;
310
484
  private _resizeHandler;
311
485
  private _mapResizeHandler;
312
486
  private _clickOutsideHandler;
@@ -444,8 +618,30 @@ export declare class RasterControl implements IControl {
444
618
  * @param toIndex - Target index (0 = bottom)
445
619
  */
446
620
  reorderRaster(id: string, toIndex: number): void;
621
+ /**
622
+ * Sets the MapLibre layer a raster draws beneath (interleaved mode), so a host
623
+ * can interleave rasters with its own vector layers. Pass null to draw the
624
+ * raster on top. See {@link import('../state/LayerManager').LayerManager.setBeforeId}.
625
+ *
626
+ * @param id - The layer id
627
+ * @param beforeId - The MapLibre style layer id to draw beneath, or null
628
+ */
629
+ setRasterBeforeId(id: string, beforeId: string | null): void;
447
630
  /** Re-emits LayerManager events through the control's event system. */
448
631
  private _forwardLayerManagerEvents;
632
+ /**
633
+ * Reconciles the on-map colorbar legends with the layers' colorbar state:
634
+ * adds/updates a {@link Colorbar} for each single-band layer whose
635
+ * `state.colorbar.visible` is set, and removes the rest. Driven by
636
+ * LayerManager change events, so the panel only has to write
637
+ * `state.colorbar`.
638
+ */
639
+ private _syncColorbars;
640
+ /** Builds colorbar options from a layer's colormap, reverse flag, and
641
+ * effective rescale range (explicit window, else auto-stats percentile). */
642
+ private _colorbarOptionsFor;
643
+ /** Removes all on-map colorbar legends. */
644
+ private _removeAllColorbars;
449
645
  /**
450
646
  * Emits an event to all registered handlers.
451
647
  *
@@ -467,6 +663,23 @@ export declare class RasterControl implements IControl {
467
663
  * @returns The panel element
468
664
  */
469
665
  private _createPanel;
666
+ /**
667
+ * Adds a drag handle that resizes the panel in both dimensions. The panel is
668
+ * absolutely positioned and anchored to its docking corner, so a custom
669
+ * handle is used instead of CSS `resize` (which is unreliable in WebKitGTK):
670
+ * it sits at the panel's inward corner and grows toward the map interior, in
671
+ * any corner. The anchored edges stay fixed; only width/height change.
672
+ *
673
+ * @param panel - The panel element to make resizable.
674
+ */
675
+ private _addResizeHandle;
676
+ /**
677
+ * Applies the user-chosen panel size, clamped to the room available from the
678
+ * panel's anchored corner to the opposite map edge. Re-run on reposition so
679
+ * the size survives expand / window-resize (which rewrite the panel's
680
+ * positioning) and stays within the map.
681
+ */
682
+ private _applyUserPanelSize;
470
683
  /**
471
684
  * Setup event listeners for panel positioning and click-outside behavior.
472
685
  */
@@ -631,6 +844,10 @@ export declare interface RasterLayerState {
631
844
  /** Colormap name (single-band mode only). 'palette' uses the image's
632
845
  * embedded color table; defaults to 'gray'. */
633
846
  colormap: string;
847
+ /** Sample the colormap back-to-front (single-band named colormaps only;
848
+ * ignored for 'palette', whose entries are categorical). Equivalent to a
849
+ * reversed variant of the ramp. */
850
+ reversed: boolean;
634
851
  /** Nodata handling. */
635
852
  nodata: RasterNodata;
636
853
  /** Layer transparency, 0 (invisible) to 1 (fully opaque). */
@@ -641,6 +858,8 @@ export declare interface RasterLayerState {
641
858
  stretch: RasterStretch;
642
859
  /** Whether the layer is drawn on the map. */
643
860
  visible: boolean;
861
+ /** Optional colorbar legend shown on the map for this layer. */
862
+ colorbar?: RasterColorbarState;
644
863
  }
645
864
 
646
865
  /** Rendering mode: RGB composite (one band per channel) or single band
@@ -675,6 +894,24 @@ export declare interface ResilientEpsgResolverOptions {
675
894
  fallback?: EpsgResolver;
676
895
  }
677
896
 
897
+ /**
898
+ * Samples `steps` evenly spaced CSS `rgb()` colors from a named colormap by
899
+ * reading its row of the sprite. `reversed` samples `1 - f`, mirroring the GPU
900
+ * colormap shader, so a reversed legend matches a reversed render exactly.
901
+ *
902
+ * Returns an empty array for an unknown name, for `steps < 2`, or when a 2D
903
+ * canvas is unavailable (e.g. jsdom without the `canvas` package); callers
904
+ * should fall back to a plain gradient in that case.
905
+ *
906
+ * @param name - The colormap name (case-insensitive).
907
+ * @param steps - Number of color stops to sample (>= 2).
908
+ * @param reversed - Sample the ramp back-to-front.
909
+ * @returns Sampled `rgb(r, g, b)` strings, or [] when sampling is impossible.
910
+ */
911
+ export declare function sampleColormapStops(name: string, steps: number, reversed?: boolean): Promise<string[]>;
912
+
913
+ export declare function statsForBand(autoStats: AutoStats | null, band: number): BandStats | null;
914
+
678
915
  /** Pure derivation from an already-loaded GeoTIFF: no fetches, no I/O. */
679
916
  export declare function summarizeGeoTIFF(tiff: MetadataInput): MetadataSummary;
680
917
 
@@ -1,3 +1,4 @@
1
+ import { ControlPosition } from 'maplibre-gl';
1
2
  import { Dispatch } from 'react';
2
3
  import { EpsgResolver } from '@developmentseed/proj';
3
4
  import { IControl } from 'maplibre-gl';
@@ -23,6 +24,9 @@ export declare interface AddRasterOptions {
23
24
  beforeId?: string;
24
25
  }
25
26
 
27
+ /** Layout direction of the colorbar bar and its tick labels. */
28
+ declare type ColorbarOrientation = 'horizontal' | 'vertical';
29
+
26
30
  /** Geographic (WGS84) bounds of a layer, as reported by COGLayer. */
27
31
  export declare type GeographicBounds = {
28
32
  west: number;
@@ -31,6 +35,29 @@ export declare type GeographicBounds = {
31
35
  north: number;
32
36
  };
33
37
 
38
+ /**
39
+ * Per-layer colorbar legend config. When `visible`, the control shows a
40
+ * {@link import('./Colorbar').Colorbar} for the (single-band) layer, driven by
41
+ * its colormap, `reversed` flag, and effective rescale range. The fields here
42
+ * are the parts the data can't supply.
43
+ */
44
+ declare interface RasterColorbarState {
45
+ /** Whether the legend is shown for this layer. */
46
+ visible: boolean;
47
+ /** Legend title; defaults to the layer name when empty. */
48
+ title?: string;
49
+ /** Horizontal alignment of the title. @default 'left' */
50
+ titleAlign?: 'left' | 'center' | 'right';
51
+ /** Unit suffix appended to tick labels. */
52
+ units?: string;
53
+ /** Fixed decimal places for tick labels; omitted = compact auto format. */
54
+ decimals?: number;
55
+ /** Bar orientation. @default 'horizontal' */
56
+ orientation?: ColorbarOrientation;
57
+ /** Map corner to dock the legend in. @default 'bottom-right' */
58
+ position?: ControlPosition;
59
+ }
60
+
34
61
  /**
35
62
  * A MapLibre GL control for visualizing local and remote raster datasets
36
63
  * (GeoTIFF / Cloud Optimized GeoTIFF). A collapsible button expands into a
@@ -58,6 +85,12 @@ export declare class RasterControl implements IControl {
58
85
  private _panelUI?;
59
86
  private _inspector?;
60
87
  private _onReady;
88
+ /** On-map colorbar legends, one per layer whose `state.colorbar.visible`. */
89
+ private _colorbars;
90
+ /** User-chosen panel size from the resize handle, re-applied on reposition. */
91
+ private _userPanelSize;
92
+ /** Repositions the resize handle to the panel's inward corner. */
93
+ private _placeResizeHandle;
61
94
  private _resizeHandler;
62
95
  private _mapResizeHandler;
63
96
  private _clickOutsideHandler;
@@ -195,8 +228,30 @@ export declare class RasterControl implements IControl {
195
228
  * @param toIndex - Target index (0 = bottom)
196
229
  */
197
230
  reorderRaster(id: string, toIndex: number): void;
231
+ /**
232
+ * Sets the MapLibre layer a raster draws beneath (interleaved mode), so a host
233
+ * can interleave rasters with its own vector layers. Pass null to draw the
234
+ * raster on top. See {@link import('../state/LayerManager').LayerManager.setBeforeId}.
235
+ *
236
+ * @param id - The layer id
237
+ * @param beforeId - The MapLibre style layer id to draw beneath, or null
238
+ */
239
+ setRasterBeforeId(id: string, beforeId: string | null): void;
198
240
  /** Re-emits LayerManager events through the control's event system. */
199
241
  private _forwardLayerManagerEvents;
242
+ /**
243
+ * Reconciles the on-map colorbar legends with the layers' colorbar state:
244
+ * adds/updates a {@link Colorbar} for each single-band layer whose
245
+ * `state.colorbar.visible` is set, and removes the rest. Driven by
246
+ * LayerManager change events, so the panel only has to write
247
+ * `state.colorbar`.
248
+ */
249
+ private _syncColorbars;
250
+ /** Builds colorbar options from a layer's colormap, reverse flag, and
251
+ * effective rescale range (explicit window, else auto-stats percentile). */
252
+ private _colorbarOptionsFor;
253
+ /** Removes all on-map colorbar legends. */
254
+ private _removeAllColorbars;
200
255
  /**
201
256
  * Emits an event to all registered handlers.
202
257
  *
@@ -218,6 +273,23 @@ export declare class RasterControl implements IControl {
218
273
  * @returns The panel element
219
274
  */
220
275
  private _createPanel;
276
+ /**
277
+ * Adds a drag handle that resizes the panel in both dimensions. The panel is
278
+ * absolutely positioned and anchored to its docking corner, so a custom
279
+ * handle is used instead of CSS `resize` (which is unreliable in WebKitGTK):
280
+ * it sits at the panel's inward corner and grows toward the map interior, in
281
+ * any corner. The anchored edges stay fixed; only width/height change.
282
+ *
283
+ * @param panel - The panel element to make resizable.
284
+ */
285
+ private _addResizeHandle;
286
+ /**
287
+ * Applies the user-chosen panel size, clamped to the room available from the
288
+ * panel's anchored corner to the opposite map edge. Re-run on reposition so
289
+ * the size survives expand / window-resize (which rewrite the panel's
290
+ * positioning) and stays within the map.
291
+ */
292
+ private _applyUserPanelSize;
221
293
  /**
222
294
  * Setup event listeners for panel positioning and click-outside behavior.
223
295
  */
@@ -434,6 +506,10 @@ export declare interface RasterLayerState {
434
506
  /** Colormap name (single-band mode only). 'palette' uses the image's
435
507
  * embedded color table; defaults to 'gray'. */
436
508
  colormap: string;
509
+ /** Sample the colormap back-to-front (single-band named colormaps only;
510
+ * ignored for 'palette', whose entries are categorical). Equivalent to a
511
+ * reversed variant of the ramp. */
512
+ reversed: boolean;
437
513
  /** Nodata handling. */
438
514
  nodata: RasterNodata;
439
515
  /** Layer transparency, 0 (invisible) to 1 (fully opaque). */
@@ -444,6 +520,8 @@ export declare interface RasterLayerState {
444
520
  stretch: RasterStretch;
445
521
  /** Whether the layer is drawn on the map. */
446
522
  visible: boolean;
523
+ /** Optional colorbar legend shown on the map for this layer. */
524
+ colorbar?: RasterColorbarState;
447
525
  }
448
526
 
449
527
  /** Rendering mode: RGB composite (one band per channel) or single band