ol-elevation-profile 2.0.1 → 2.1.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.
@@ -0,0 +1,947 @@
1
+ /**
2
+ * Synchronized elevation profile control for OpenLayers, rendered with d3.
3
+ *
4
+ * Reads elevation (Z) directly from 3D line geometries (`[lon, lat, z]`). A track without
5
+ * Z is completed from a terrain model - keyless AWS Terrain Tiles by default, which means
6
+ * the control fetches tiles on its own; set `dem: null` to keep it entirely offline.
7
+ * Clicking (or hovering) a track shows its profile; a marker stays synchronized on both
8
+ * the map and the chart.
9
+ *
10
+ * Peer dependencies (provided by the host application, not bundled):
11
+ * - OpenLayers >= 6 (https://openlayers.org/)
12
+ * - d3 >= 7 (https://d3js.org/)
13
+ *
14
+ * @module ol-elevation-profile
15
+ * @license MIT
16
+ */
17
+ import Control from 'ol/control/Control.js';
18
+ import Overlay from 'ol/Overlay.js';
19
+ declare const THEMES: {
20
+ steelblue: {
21
+ area: string;
22
+ line: string;
23
+ axis: string;
24
+ text: string;
25
+ focus: string;
26
+ };
27
+ lime: {
28
+ area: string;
29
+ line: string;
30
+ axis: string;
31
+ text: string;
32
+ focus: string;
33
+ };
34
+ purple: {
35
+ area: string;
36
+ line: string;
37
+ axis: string;
38
+ text: string;
39
+ focus: string;
40
+ };
41
+ slate: {
42
+ area: string;
43
+ line: string;
44
+ axis: string;
45
+ text: string;
46
+ focus: string;
47
+ };
48
+ graphite: {
49
+ area: string;
50
+ line: string;
51
+ axis: string;
52
+ text: string;
53
+ focus: string;
54
+ };
55
+ amber: {
56
+ area: string;
57
+ line: string;
58
+ axis: string;
59
+ text: string;
60
+ focus: string;
61
+ };
62
+ };
63
+ declare const POSITIONS: string[];
64
+ /**
65
+ * Known terrain-tile sources.
66
+ *
67
+ * A PNG tile carries elevation in its R/G/B channels; it is read on a canvas rather
68
+ * than queried point by point from an API. That is what makes a 10 000-point track a
69
+ * handful of requests, with no key, no quota and no rate limit, where the free
70
+ * elevation APIs cap out at 100 or 200 points per call.
71
+ *
72
+ * Attribution is not automatic: the library does not own the map. It is up to the
73
+ * application to carry `attributions` in its own basemap source - and since the DEM is
74
+ * on by default, that obligation arrives without having been asked for. `dem: null`
75
+ * turns the whole thing off.
76
+ */
77
+ declare const DEM_PRESETS: {
78
+ terrarium: {
79
+ url: string;
80
+ encoding: string;
81
+ maxZoom: number;
82
+ attributions: string;
83
+ };
84
+ /**
85
+ * IGN Géoplateforme, serving the RGE ALTI over France and its overseas territories.
86
+ *
87
+ * A point API rather than tiles, hence its own sampler: it answers 200 points per
88
+ * request and announces one request per second, so a 10 000 point track takes about
89
+ * fifty calls spread over as many seconds. In exchange it is metre-accurate where the
90
+ * world models are at ninety.
91
+ *
92
+ * **No key is required** on the public endpoint - verified against the live service.
93
+ * `apiKey` exists for a deployment that does demand one; it is appended as a query
94
+ * parameter, named by `apiKeyParam`.
95
+ *
96
+ * Outside its coverage the service does not error: it answers OUT_OF_COVERAGE for the
97
+ * point. No border is coded here - one asks, and it says itself where it does not know.
98
+ */
99
+ ign: {
100
+ api: string;
101
+ url: string;
102
+ resource: string;
103
+ batch: number;
104
+ minInterval: number;
105
+ attributions: string;
106
+ };
107
+ };
108
+ /**
109
+ * Reads elevations from a set of terrain tiles.
110
+ *
111
+ * Positions are held in **world pixels** rather than tile by tile: the four neighbours
112
+ * of a point can fall in two different tiles whenever it runs along an edge, which is
113
+ * the common case on a track. Converting to world pixels first, then resolving the
114
+ * tile, makes the edge case disappear instead of handling it.
115
+ */
116
+ declare class DemSampler {
117
+ cfg: any;
118
+ decode: any;
119
+ tileUrl: (z: any, x: any, y: any) => any;
120
+ tiles: Map<any, any>;
121
+ /** @param {Object} cfg `url`, `encoding`, `tileSize`, `concurrency`. */
122
+ constructor(cfg: any);
123
+ /**
124
+ * North-west neighbour of the point plus the interpolation fractions, in world pixels.
125
+ *
126
+ * The half-pixel subtracted is not a fudge: pixel centres fall on half-integers, and
127
+ * without that shift `floor()` would return the cell containing the point rather than
128
+ * its western neighbour, offsetting the whole profile by half a pixel.
129
+ */
130
+ _neighbours(lon: any, lat: any, z: any): {
131
+ i0: number;
132
+ j0: number;
133
+ tx: number;
134
+ ty: number;
135
+ };
136
+ /** Tile key of a world pixel; x wraps around the globe, y clamps at the poles. */
137
+ _key(i: any, j: any, z: any): {
138
+ key: string;
139
+ ii: number;
140
+ jj: number;
141
+ };
142
+ /** Elevation of one pixel, or null if its tile is missing. */
143
+ _at(i: any, j: any, z: any): any;
144
+ /**
145
+ * Elevation **bilinearly interpolated** between the four surrounding pixels; null as
146
+ * soon as a single one is missing.
147
+ *
148
+ * Bilinear rather than "the pixel containing the point": on a 30 or 90 m model, taking
149
+ * the pixel value makes the profile advance in stairs, and every stair counts as a
150
+ * climb then a descent in the ascent total. The interpolation invents no relief: it
151
+ * renders the same surface, without the steps of the sampling grid.
152
+ */
153
+ sample(lon: any, lat: any, z: any): any;
154
+ /** Keys of the tiles needed by the four neighbours of each of the points. */
155
+ tilesFor(lonlats: any, z: any): Set<any>;
156
+ /** Pixels of one tile, or null if it could not be read. */
157
+ _fetch(key: any): Promise<any>;
158
+ /**
159
+ * Loads the missing tiles, `concurrency` in flight. Resolves false if one is missing.
160
+ *
161
+ * Lost tiles are remembered as such: without that, a second pass over the same track
162
+ * would fire the same requests, doomed to fail again.
163
+ */
164
+ load(keys: any): Promise<boolean>;
165
+ }
166
+ export type ElevationProfileOptions = {
167
+ /**
168
+ * Panel placement strategy (floating is partial).
169
+ */
170
+ immersion?: 'docked' | 'floating';
171
+ /**
172
+ * Anchor on the map.
173
+ */
174
+ position?: 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
175
+ /**
176
+ * Width in px (capped to the map width), or full map width.
177
+ */
178
+ width?: number | 'auto' | '100%' | 'full';
179
+ /**
180
+ * Height in px.
181
+ */
182
+ height?: number;
183
+ /**
184
+ * Inner chart margins.
185
+ */
186
+ margins?: {
187
+ unit: ('px' | 'em' | 'rem');
188
+ top: number;
189
+ right: number;
190
+ bottom: number;
191
+ left: number;
192
+ };
193
+ /**
194
+ * Distance/elevation units.
195
+ */
196
+ units?: 'meters' | 'imperial';
197
+ /**
198
+ * Built-in theme name or a colors object.
199
+ */
200
+ theme?: string;
201
+ /**
202
+ * `null` = theme, `'auto'` = track color (area = color, darker line), or a CSS color.
203
+ */
204
+ color?: string | null;
205
+ /**
206
+ * Layer used to read the track color when `color:'auto'`.
207
+ */
208
+ trackLayer?: import('ol/layer/Vector').default | null;
209
+ /**
210
+ * `false`, `true` (= transparencyLevel), or alpha 0..1 (0 = fully transparent).
211
+ */
212
+ transparency?: boolean | number;
213
+ /**
214
+ * Background alpha when `transparency===true`.
215
+ */
216
+ transparencyLevel?: number;
217
+ /**
218
+ * Horizontal grid lines.
219
+ */
220
+ grid?: boolean;
221
+ /**
222
+ * Split the profile into slope-class colored portions.
223
+ */
224
+ slope?: boolean;
225
+ /**
226
+ * Slope class width, in percent.
227
+ */
228
+ slopeClassSize?: number;
229
+ /**
230
+ * Maximum number of slope classes (colors + legend).
231
+ */
232
+ maxClasses?: number;
233
+ /**
234
+ * `null` = blue-to-red ramp; otherwise an interpolated color array.
235
+ */
236
+ slopeColors?: string[] | null;
237
+ /**
238
+ * Vertical separator at each slope-class change.
239
+ */
240
+ slopeSeparators?: boolean;
241
+ /**
242
+ * Color legend under the title.
243
+ */
244
+ slopeLegend?: boolean;
245
+ /**
246
+ * Elevation smoothing window, in METERS (0 = none).
247
+ */
248
+ smoothing?: number;
249
+ /**
250
+ * X axis ticks (null = auto from width).
251
+ */
252
+ xTicks?: number | null;
253
+ /**
254
+ * Y axis ticks (null = auto from height).
255
+ */
256
+ yTicks?: number | null;
257
+ /**
258
+ * `'auto'`: the
259
+ * profile fills the height, which is legible but changes scale from one track to the
260
+ * next, so a 2 % ramp looks like a wall and two profiles cannot be compared. A number
261
+ * fixes the metres covered per physical centimetre, which makes RANGES comparable.
262
+ * `{exaggeration}` fixes the ratio between the two axes instead, which makes SLOPES
263
+ * comparable: the gradient read off the chart is the real one, multiplied by the same
264
+ * factor on every track, and the control recomputes it per track and per A/B crop.
265
+ * Either form is a **floor**, not a cage: a track whose range exceeds what the height
266
+ * can show would spill out of the frame, which is worse than losing comparability, so
267
+ * the scale then widens silently, nothing being drawn on the chart to say so.
268
+ */
269
+ verticalScale?: ('auto' | number | {
270
+ exaggeration: number;
271
+ });
272
+ /**
273
+ * How a track is selected on the map.
274
+ */
275
+ show?: 'click' | 'mouseover';
276
+ /**
277
+ * What to do with a track that ends up
278
+ * with no elevation at all: none in its geometry, and none the terrain model could
279
+ * supply either (`dem: null`, or a fill that failed). `true` shows the panel with the
280
+ * track's title and the `noElevation` message where the chart would be; `false` hides
281
+ * the panel outright. Either way no chart is drawn: a flat line at zero under a D+ of
282
+ * 0 m is not a missing figure, it is a wrong one.
283
+ */
284
+ showWithoutElevation?: boolean;
285
+ /**
286
+ * Click on empty map hides the profile.
287
+ */
288
+ hideOnMapClick?: boolean;
289
+ /**
290
+ * Show the collapse/expand button.
291
+ */
292
+ collapsable?: boolean;
293
+ /**
294
+ * Initial collapsed state.
295
+ */
296
+ collapsed?: boolean;
297
+ /**
298
+ * Hovering the map moves the chart indicator.
299
+ */
300
+ followMap?: boolean;
301
+ /**
302
+ * Show the position marker on the map.
303
+ */
304
+ marker?: boolean;
305
+ /**
306
+ * Adapt width/placement; mobile included.
307
+ */
308
+ responsive?: boolean;
309
+ /**
310
+ * Below this width: mobile mode (100% width, top/bottom only).
311
+ */
312
+ mobileBreakpoint?: number;
313
+ /**
314
+ * A/B buttons to crop map + profile to a sub-range.
315
+ */
316
+ zoom?: boolean;
317
+ /**
318
+ * Nested crops allowed: a crop can itself be cropped,
319
+ * down to this depth. `1` restores the former single level. A "back" button appears
320
+ * from the second level; "show all" empties the stack whatever the depth.
321
+ */
322
+ zoomLevels?: number;
323
+ /**
324
+ * Toolbar button exporting the whole panel as a PNG.
325
+ */
326
+ exportPng?: boolean;
327
+ /**
328
+ * When computing time, ignore stopped segments (moving time).
329
+ */
330
+ ignoreStops?: boolean;
331
+ /**
332
+ * Speed threshold (m/s) below which a segment counts as a stop.
333
+ */
334
+ stopSpeed?: number;
335
+ /**
336
+ * Tooltip content (`'time'` = elapsed time at the cursor, if the track has time data).
337
+ */
338
+ tooltipItems?: Array<'distance' | 'elevation' | 'slope' | 'time'>;
339
+ /**
340
+ * Header content (string tokens: distance, ascent, descent, min, max, minmax, `'duration'` = total elapsed time).
341
+ */
342
+ headerItems?: Array<string | {
343
+ property: string;
344
+ label?: string;
345
+ asLink?: boolean;
346
+ linkText?: string;
347
+ }>;
348
+ /**
349
+ * Language of the shipped labels. An unknown
350
+ * code falls back to English rather than leaving keys empty.
351
+ */
352
+ lang?: ('en' | 'fr' | 'es');
353
+ /**
354
+ * Per-key overrides applied on top of `lang`. They survive
355
+ * a later language change, so a corrected key stays corrected.
356
+ */
357
+ labels?: any;
358
+ /**
359
+ * Feature property used as the title,
360
+ * or a list of them tried in order - the first one holding a value wins. A feature with
361
+ * none falls back on the `untitled` label.
362
+ */
363
+ titleProperty?: (string | string[]);
364
+ /**
365
+ * Feature property holding a URL, which
366
+ * makes the title a link, or a list tried in order - the first one holding an actual
367
+ * URL wins, so a property carrying something else is stepped over rather than rendered
368
+ * as a broken link. `null`, the default, never links the title: a dataset is not asked
369
+ * to explain that its `url` column is not the one meant for the reader.
370
+ */
371
+ titleLink?: (string | string[]) | null;
372
+ /**
373
+ * Decimation for render/interaction (stats use full data).
374
+ */
375
+ maxPoints?: number;
376
+ /**
377
+ * Projection of the feature coordinates.
378
+ */
379
+ dataProjection?: (import('ol/proj/Projection').default | null) | string;
380
+ /**
381
+ * Fill missing elevations
382
+ * from a terrain model. Sources: `'terrarium'` (default) or `true` = AWS Terrain Tiles;
383
+ * `'ign'` = IGN Géoplateforme RGE ALTI (France, keyless, `apiKey` optional);
384
+ * `{url}` = XYZ template; `{wms:{url,layers,params}}` = WMS tiles;
385
+ * `{olSource}` = any `ol/source/TileImage` (XYZ, TileWMS, and so on);
386
+ * `{featureInfo:{url,layers,property}}` = WMS GetFeatureInfo, one request per point,
387
+ * for a greyscale coverage that cannot be decoded from its pixels (slow);
388
+ * `{track:{url,coords,parse,fetchOptions}}` = a profile the application computed
389
+ * beforehand and serves per track, `url` being a `{property}` template read off the
390
+ * feature (or a function). Unlike every other source it answers with the whole track:
391
+ * `[[lon,lat,z],…]` replaces the geometry, so a decimated profile is accepted, while a
392
+ * plain `[z,…]` still lines up with the geometry's own points;
393
+ * a function or `{sample}` `(lonlats, ctx) => number[]|Promise<number[]>` to source them
394
+ * yourself; `null` disables the whole thing.
395
+ * Decoding: `encoding` is `'terrarium'`, `'mapbox'`, or a function `(r,g,b,a) => metres`.
396
+ */
397
+ dem?: (boolean | string | Function | any) | null;
398
+ };
399
+ /**
400
+ * @typedef {Object} ElevationProfileOptions
401
+ * @property {'docked'|'floating'} [immersion='docked'] Panel placement strategy (floating is partial).
402
+ * @property {'top'|'bottom'|'left'|'right'|'top-left'|'top-right'|'bottom-left'|'bottom-right'} [position='bottom'] Anchor on the map.
403
+ * @property {number|'auto'|'100%'|'full'} [width=520] Width in px (capped to the map width), or full map width.
404
+ * @property {number} [height=180] Height in px.
405
+ * @property {{unit:('px'|'em'|'rem'),top:number,right:number,bottom:number,left:number}} [margins] Inner chart margins.
406
+ * @property {'meters'|'imperial'} [units='meters'] Distance/elevation units.
407
+ * @property {string} [theme='steelblue'] Built-in theme name or a colors object.
408
+ * @property {?string} [color=null] `null` = theme, `'auto'` = track color (area = color, darker line), or a CSS color.
409
+ * @property {?import('ol/layer/Vector').default} [trackLayer=null] Layer used to read the track color when `color:'auto'`.
410
+ * @property {boolean|number} [transparency=false] `false`, `true` (= transparencyLevel), or alpha 0..1 (0 = fully transparent).
411
+ * @property {number} [transparencyLevel=0.45] Background alpha when `transparency===true`.
412
+ * @property {boolean} [grid=true] Horizontal grid lines.
413
+ * @property {boolean} [slope=false] Split the profile into slope-class colored portions.
414
+ * @property {number} [slopeClassSize=2.5] Slope class width, in percent.
415
+ * @property {number} [maxClasses=8] Maximum number of slope classes (colors + legend).
416
+ * @property {?string[]} [slopeColors=null] `null` = blue-to-red ramp; otherwise an interpolated color array.
417
+ * @property {boolean} [slopeSeparators=true] Vertical separator at each slope-class change.
418
+ * @property {boolean} [slopeLegend=true] Color legend under the title.
419
+ * @property {number} [smoothing=0] Elevation smoothing window, in METERS (0 = none).
420
+ * @property {?number} [xTicks=null] X axis ticks (null = auto from width).
421
+ * @property {?number} [yTicks=null] Y axis ticks (null = auto from height).
422
+ * @property {('auto'|number|{exaggeration:number})} [verticalScale='auto'] `'auto'`: the
423
+ * profile fills the height, which is legible but changes scale from one track to the
424
+ * next, so a 2 % ramp looks like a wall and two profiles cannot be compared. A number
425
+ * fixes the metres covered per physical centimetre, which makes RANGES comparable.
426
+ * `{exaggeration}` fixes the ratio between the two axes instead, which makes SLOPES
427
+ * comparable: the gradient read off the chart is the real one, multiplied by the same
428
+ * factor on every track, and the control recomputes it per track and per A/B crop.
429
+ * Either form is a **floor**, not a cage: a track whose range exceeds what the height
430
+ * can show would spill out of the frame, which is worse than losing comparability, so
431
+ * the scale then widens silently, nothing being drawn on the chart to say so.
432
+ * @property {'click'|'mouseover'} [show='click'] How a track is selected on the map.
433
+ * @property {boolean} [showWithoutElevation=true] What to do with a track that ends up
434
+ * with no elevation at all: none in its geometry, and none the terrain model could
435
+ * supply either (`dem: null`, or a fill that failed). `true` shows the panel with the
436
+ * track's title and the `noElevation` message where the chart would be; `false` hides
437
+ * the panel outright. Either way no chart is drawn: a flat line at zero under a D+ of
438
+ * 0 m is not a missing figure, it is a wrong one.
439
+ * @property {boolean} [hideOnMapClick=true] Click on empty map hides the profile.
440
+ * @property {boolean} [collapsable=true] Show the collapse/expand button.
441
+ * @property {boolean} [collapsed=false] Initial collapsed state.
442
+ * @property {boolean} [followMap=true] Hovering the map moves the chart indicator.
443
+ * @property {boolean} [marker=true] Show the position marker on the map.
444
+ * @property {boolean} [responsive=true] Adapt width/placement; mobile included.
445
+ * @property {number} [mobileBreakpoint=640] Below this width: mobile mode (100% width, top/bottom only).
446
+ * @property {boolean} [zoom=false] A/B buttons to crop map + profile to a sub-range.
447
+ * @property {number} [zoomLevels=3] Nested crops allowed: a crop can itself be cropped,
448
+ * down to this depth. `1` restores the former single level. A "back" button appears
449
+ * from the second level; "show all" empties the stack whatever the depth.
450
+ * @property {boolean} [exportPng=false] Toolbar button exporting the whole panel as a PNG.
451
+ * @property {boolean} [ignoreStops=true] When computing time, ignore stopped segments (moving time).
452
+ * @property {number} [stopSpeed=0.5] Speed threshold (m/s) below which a segment counts as a stop.
453
+ * @property {Array<'distance'|'elevation'|'slope'|'time'>} [tooltipItems=['distance','elevation']] Tooltip content (`'time'` = elapsed time at the cursor, if the track has time data).
454
+ * @property {Array<string|{property:string,label?:string,asLink?:boolean,linkText?:string}>} [headerItems] Header content (string tokens: distance, ascent, descent, min, max, minmax, `'duration'` = total elapsed time).
455
+ * @property {('en'|'fr'|'es')} [lang='en'] Language of the shipped labels. An unknown
456
+ * code falls back to English rather than leaving keys empty.
457
+ * @property {Object} [labels={}] Per-key overrides applied on top of `lang`. They survive
458
+ * a later language change, so a corrected key stays corrected.
459
+ * @property {(string|string[])} [titleProperty='name'] Feature property used as the title,
460
+ * or a list of them tried in order - the first one holding a value wins. A feature with
461
+ * none falls back on the `untitled` label.
462
+ * @property {?(string|string[])} [titleLink=null] Feature property holding a URL, which
463
+ * makes the title a link, or a list tried in order - the first one holding an actual
464
+ * URL wins, so a property carrying something else is stepped over rather than rendered
465
+ * as a broken link. `null`, the default, never links the title: a dataset is not asked
466
+ * to explain that its `url` column is not the one meant for the reader.
467
+ * @property {number} [maxPoints=2000] Decimation for render/interaction (stats use full data).
468
+ * @property {?import('ol/proj/Projection').default|string} [dataProjection=null] Projection of the feature coordinates.
469
+ * @property {?(boolean|string|Function|Object)} [dem='terrarium'] Fill missing elevations
470
+ * from a terrain model. Sources: `'terrarium'` (default) or `true` = AWS Terrain Tiles;
471
+ * `'ign'` = IGN Géoplateforme RGE ALTI (France, keyless, `apiKey` optional);
472
+ * `{url}` = XYZ template; `{wms:{url,layers,params}}` = WMS tiles;
473
+ * `{olSource}` = any `ol/source/TileImage` (XYZ, TileWMS, and so on);
474
+ * `{featureInfo:{url,layers,property}}` = WMS GetFeatureInfo, one request per point,
475
+ * for a greyscale coverage that cannot be decoded from its pixels (slow);
476
+ * `{track:{url,coords,parse,fetchOptions}}` = a profile the application computed
477
+ * beforehand and serves per track, `url` being a `{property}` template read off the
478
+ * feature (or a function). Unlike every other source it answers with the whole track:
479
+ * `[[lon,lat,z],…]` replaces the geometry, so a decimated profile is accepted, while a
480
+ * plain `[z,…]` still lines up with the geometry's own points;
481
+ * a function or `{sample}` `(lonlats, ctx) => number[]|Promise<number[]>` to source them
482
+ * yourself; `null` disables the whole thing.
483
+ * Decoding: `encoding` is `'terrarium'`, `'mapbox'`, or a function `(r,g,b,a) => metres`.
484
+ */
485
+ /**
486
+ * Elevation profile control.
487
+ * @extends {import('ol/control/Control').default}
488
+ *
489
+ * @example
490
+ * const profile = new OlElevationProfile({ theme: 'steelblue', color: 'auto', trackLayer });
491
+ * map.addControl(profile);
492
+ * profile.setFeature(feature); // feature with a 3D LineString geometry
493
+ */
494
+ declare class ElevationProfile extends Control {
495
+ options: {};
496
+ _userLabels: any;
497
+ slopeColors: any;
498
+ _feature: import("ol/Feature").default<import("ol/geom").Geometry, {
499
+ [x: string]: any;
500
+ }>;
501
+ _fullSamples: any;
502
+ _fullStats: {
503
+ distance: number;
504
+ duration: number;
505
+ ascent: number;
506
+ descent: number;
507
+ min: number;
508
+ max: number;
509
+ maxAbsSlope: number;
510
+ points: any;
511
+ };
512
+ _samples: any;
513
+ _stats: {
514
+ distance: number;
515
+ duration: number;
516
+ ascent: number;
517
+ descent: number;
518
+ min: number;
519
+ max: number;
520
+ maxAbsSlope: number;
521
+ points: any;
522
+ };
523
+ _marker: Overlay;
524
+ _collapsed: boolean;
525
+ _crops: any[];
526
+ _off: number;
527
+ _zoomA: any;
528
+ _zoomB: any;
529
+ _armed: any;
530
+ _demZ: any[];
531
+ _demFor: any;
532
+ _demSeq: number;
533
+ _demLoading: boolean;
534
+ _trackLines: any[][];
535
+ _linesFor: any;
536
+ _onResize: () => void;
537
+ _titleEl: HTMLSpanElement;
538
+ _statsEl: HTMLSpanElement;
539
+ _toolbar: HTMLSpanElement;
540
+ _btnA: HTMLButtonElement;
541
+ _btnB: HTMLButtonElement;
542
+ _btnBack: HTMLButtonElement;
543
+ _btnAll: HTMLButtonElement;
544
+ _btnPng: HTMLButtonElement;
545
+ _toggleBtn: HTMLButtonElement;
546
+ _legendEl: HTMLDivElement;
547
+ _body: HTMLDivElement;
548
+ themeColors: any;
549
+ _mapKeys: any[];
550
+ _hasTime: boolean;
551
+ _vScale: number;
552
+ _vExaggeration: number;
553
+ _x: any;
554
+ _y: any;
555
+ _dims: {
556
+ innerW: number;
557
+ innerH: number;
558
+ };
559
+ _focus: any;
560
+ /** @param {ElevationProfileOptions} [opts] */
561
+ constructor(opts?: ElevationProfileOptions);
562
+ /** Recadré dès qu'un niveau est empilé. Lu partout où le booléen l'était. */
563
+ get _cropMode(): boolean;
564
+ /** Profondeur courante ; 0 quand on voit la trace entière. */
565
+ get _cropDepth(): number;
566
+ /** Niveaux imbriqués autorisés, au moins un. */
567
+ get _cropMax(): number;
568
+ /**
569
+ * Whether a feature has any Z (elevation) coordinate.
570
+ * @param {import('ol/Feature').default} feature
571
+ * @returns {boolean}
572
+ */
573
+ static featureHasZ(feature: import('ol/Feature').default): boolean;
574
+ /**
575
+ * Whether a feature carries per-point time data (coordTimes / XYZM).
576
+ * @param {import('ol/Feature').default} feature
577
+ * @returns {boolean}
578
+ */
579
+ static featureHasTime(feature: import('ol/Feature').default): boolean;
580
+ _buildDom(root: any): void;
581
+ /**
582
+ * Reporte les libellés courants sur ce que le rendu ne réécrit pas.
583
+ *
584
+ * Les boutons et le bouton de repli sont construits une fois pour toutes ; sans cela,
585
+ * changer de langue ne toucherait que le graphe et laisserait les infobulles dans
586
+ * l'ancienne. Le titre n'est repris que faute de tracé : sinon il porte le nom du tracé,
587
+ * qui n'est pas un libellé de la librairie.
588
+ */
589
+ _applyLabels(): void;
590
+ /**
591
+ * Le bouton de repli dit ce qu'il va faire, non ce qu'il montre.
592
+ *
593
+ * Un seul libellé pour les deux états ("réduire ou agrandir") laisse deviner lequel
594
+ * des deux le clic déclenche ; l'icône, elle, a déjà basculé. Le titre suit donc l'état,
595
+ * et l'infobulle visible dit la même chose que le nom accessible.
596
+ */
597
+ _applyToggleLabel(): void;
598
+ _resolveColor(): any;
599
+ _featureColor(): string;
600
+ _applyTheme(): void;
601
+ _applyTransparency(): void;
602
+ _applyCollapsable(): void;
603
+ /** @param {boolean} [force] Force collapsed (true) or expanded (false). */
604
+ toggleCollapsed(force?: boolean): void;
605
+ _availWidth(): number;
606
+ _isMobile(): boolean;
607
+ _applyPlacement(): boolean;
608
+ _adjustAttribution(): void;
609
+ setMap(map: any): void;
610
+ /**
611
+ * Show the profile for the given feature (LineString, MultiLineString, or a Polygon /
612
+ * MultiPolygon profiled along its outer ring), ideally 3D.
613
+ * Passing a falsy value hides the control.
614
+ * @param {?import('ol/Feature').default} feature
615
+ * @returns {this}
616
+ */
617
+ setFeature(feature: import('ol/Feature').default | null): this;
618
+ /** Hide the profile and clear the current feature. @returns {this} */
619
+ clear(): this;
620
+ /**
621
+ * @returns {?{distance:number,duration:?number,ascent:number,descent:number,min:number,max:number,maxAbsSlope:number,points:number}}
622
+ * `duration` is `null` when the track carries no time data.
623
+ */
624
+ getStats(): {
625
+ distance: number;
626
+ duration: number | null;
627
+ ascent: number;
628
+ descent: number;
629
+ min: number;
630
+ max: number;
631
+ maxAbsSlope: number;
632
+ points: number;
633
+ } | null;
634
+ /** @param {string|Object} t Theme name or colors object. @returns {this} */
635
+ setTheme(t: string | any): this;
636
+ /** @param {?string} c CSS color, `'auto'`, or `null` (theme). @returns {this} */
637
+ setColor(c: string | null): this;
638
+ /**
639
+ * Update one or more options at runtime and re-render.
640
+ * @param {Partial<ElevationProfileOptions>} patch
641
+ * @returns {this}
642
+ */
643
+ setOptions(patch: Partial<ElevationProfileOptions>): this;
644
+ /**
645
+ * Fills the missing elevations from a terrain model, then redraws.
646
+ *
647
+ * **A track is filled entirely or not at all.** A profile missing a few points is not
648
+ * an incomplete profile: points without Z count as zero, the line dives to sea level
649
+ * and the ascent total becomes absurd. Better the flat profile we would have had
650
+ * without the DEM.
651
+ *
652
+ * Nothing is reported to the user on failure: the fill is a supplement, it has no
653
+ * business breaking a display that succeeded without it. The `demload` event lets the
654
+ * application know if it wants to.
655
+ *
656
+ * @param {import('ol/Feature').default} feature
657
+ * @fires demload
658
+ * @private
659
+ */
660
+ private _fillFromDem;
661
+ /** @private */
662
+ private _startFill;
663
+ /**
664
+ * Va chercher un profil déjà calculé, que l'application tient prêt pour cette trace.
665
+ *
666
+ * Les dix autres sources échantillonnent un modèle de terrain aux points de la trace.
667
+ * Celle-ci ne fait rien de tel : elle demande à l'application le profil qu'elle a déjà,
668
+ * calculé une fois à l'ingestion sur le modèle qu'elle voulait, décimé comme elle
669
+ * l'entendait. C'est le cas d'une application qui a fait son altimétrie en amont et ne
670
+ * veut ni la refaire dans le navigateur ni dépendre d'un service au clic.
671
+ *
672
+ * La réponse peut prendre deux formes, et elles ne veulent pas dire la même chose :
673
+ * un tableau de nombres est une altitude par point de la géométrie, qui rejoint le
674
+ * chemin ordinaire ; un tableau de triplets `[lon, lat, z]` porte SA propre géométrie
675
+ * et remplace celle de la trace, ce qui est le seul moyen d'accepter un profil décimé.
676
+ *
677
+ * @private
678
+ */
679
+ private _startTrackFill;
680
+ /**
681
+ * Adopte un profil précalculé, sous l'une ou l'autre de ses deux formes.
682
+ *
683
+ * Un triplet incomplet fait tout refuser, par la même règle que `_demDone` : un profil
684
+ * auquel il manque des points n'est pas un profil incomplet, c'est un profil faux.
685
+ *
686
+ * @fires demload
687
+ * @private
688
+ */
689
+ private _trackDone;
690
+ /**
691
+ * Outcome of a fill, whatever produced it: adopt the elevations, drop the spinner,
692
+ * redraw, announce.
693
+ *
694
+ * A result of the wrong length is refused outright rather than padded. Elevations one
695
+ * can no longer map to their points are worse than absent ones: they would land on the
696
+ * wrong places, and nothing downstream would notice.
697
+ *
698
+ * @fires demload
699
+ * @private
700
+ */
701
+ private _demDone;
702
+ _compute(): void;
703
+ /**
704
+ * Pixels CSS d'un centimètre physique, mesurés plutôt que déduits.
705
+ *
706
+ * Le rapport nominal est de 96 px par pouce, soit 37,8 px par centimètre, mais le zoom
707
+ * du navigateur le déplace : mesurer un élément d'un centimètre suit ce zoom là où une
708
+ * constante mentirait. Non mémorisé - la mesure force un calcul de disposition, mais un
709
+ * rendu est rare et un cache se périmerait au premier Ctrl+molette.
710
+ */
711
+ _pxPerCm(): number;
712
+ /**
713
+ * Échelle verticale du graphe.
714
+ *
715
+ * En `'auto'`, le profil remplit la hauteur : c'est lisible, mais l'échelle change d'une
716
+ * trace à l'autre, si bien qu'une pente de 2 % y prend l'allure d'un mur et que deux
717
+ * profils ne se comparent pas. Un nombre fixe au contraire les mètres couverts par
718
+ * centimètre physique.
719
+ *
720
+ * La valeur demandée est un **plancher**, non un carcan : une trace dont l'amplitude
721
+ * dépasse ce que la hauteur peut montrer déborderait du cadre, ce qui est pire que de
722
+ * perdre la comparabilité. Le graphe n'en dit rien : l'échelle n'est pas une donnée de
723
+ * la trace et n'a pas à encombrer le dessin ; l'échelle réellement appliquée est
724
+ * seulement publiée dans `_vScale`, à qui veut la connaître.
725
+ *
726
+ * `nice()` n'est pas appliqué en échelle absolue : il arrondit le domaine vers
727
+ * l'extérieur, donc il fausserait le rapport qu'on vient de fixer.
728
+ */
729
+ _yScale(s: any, zpad: any, innerH: any, innerW: any): any;
730
+ /**
731
+ * Les mètres par centimètre demandés, sous l'une ou l'autre forme de `verticalScale`.
732
+ *
733
+ * Une échelle absolue rend les AMPLITUDES comparables, pas les pentes : l'axe
734
+ * horizontal s'étire toujours sur toute la trace, si bien qu'une même pente de 5 %
735
+ * paraît trois fois plus raide sur une boucle de 3 km que sur une traversée de 30. Une
736
+ * exagération fixe le RAPPORT entre les deux axes : la pente lue sur le dessin est
737
+ * alors la pente réelle, multipliée par un facteur constant d'une trace à l'autre.
738
+ *
739
+ * Elle se calcule ici et pas chez l'appelant parce qu'elle demande deux choses que lui
740
+ * n'a pas : la largeur du graphe une fois les marges retirées, et la distance
741
+ * réellement affichée - celle du recadrage A/B en cours, non celle de la trace.
742
+ *
743
+ * @private
744
+ */
745
+ private _verticalScaleFor;
746
+ _statsOf(samples: any, fromTotal: any): {
747
+ distance: number;
748
+ duration: number;
749
+ ascent: number;
750
+ descent: number;
751
+ min: number;
752
+ max: number;
753
+ maxAbsSlope: number;
754
+ points: any;
755
+ };
756
+ _smooth(pts: any, meters: any): void;
757
+ _decimate(pts: any, maxPoints: any): any;
758
+ _addSlope(samples: any): void;
759
+ _slopeScale(): {
760
+ classSize: any;
761
+ maxIdx: number;
762
+ capped: boolean;
763
+ colorByIndex: any;
764
+ };
765
+ _classIndex(slope: any, sc: any): number;
766
+ _fmtDuration(sec: any): string;
767
+ /**
768
+ * Track title, and its optional link.
769
+ *
770
+ * Its own method because it is the only part of the header that stays visible once
771
+ * collapsed: the CSS hides the body, the stats, the legend and the toolbar. `_render`
772
+ * is skipped while collapsed, so without a separate entry point the title would keep
773
+ * naming the previous track after a change of feature.
774
+ */
775
+ /**
776
+ * Cette trace a-t-elle une altitude, d'où qu'elle vienne ?
777
+ *
778
+ * Trois sources possibles, et une seule suffit : le Z de la géométrie, les altitudes
779
+ * rapportées par un modèle de terrain, ou le profil précalculé d'une source `track`.
780
+ * Aucune des trois, et il n'y a rien à dessiner - ce qui ne veut pas dire zéro.
781
+ *
782
+ * @private
783
+ */
784
+ private _hasElevation;
785
+ /**
786
+ * Ce qui prend la place du graphe quand la trace n'a aucune altitude.
787
+ *
788
+ * Même forme que le spinner, et pour la même raison : la hauteur du graphe est tenue,
789
+ * si bien que le panneau ne saute pas si un profil finit par arriver. Le titre reste,
790
+ * lui : c'est la trace cliquée, et l'utilisateur a besoin de savoir laquelle.
791
+ *
792
+ * @private
793
+ */
794
+ private _renderNoElevation;
795
+ /**
796
+ * La première propriété qui répond, parmi celles proposées.
797
+ *
798
+ * Un nom de propriété unique reste un nom de propriété unique ; une liste est essayée
799
+ * dans l'ordre. `garde` filtre ce qu'on accepte : n'importe quelle valeur non vide pour
800
+ * un titre, une URL véritable pour un lien - sans quoi une propriété `url` contenant
801
+ * autre chose ferait un lien mort plutôt que pas de lien du tout.
802
+ *
803
+ * @private
804
+ */
805
+ private _pickProperty;
806
+ _renderTitle(): void;
807
+ _renderHeader(sansAltimetrie: any): void;
808
+ /**
809
+ * Spinner shown in place of the chart while the terrain model loads.
810
+ *
811
+ * It keeps the chart's height so the panel does not jump when the profile replaces it,
812
+ * and it carries no colour of its own: the CSS takes `--oep-area`, which `_applyTheme`
813
+ * has just set - the theme colour, or the track colour under `color: 'auto'`.
814
+ */
815
+ _renderSpinner(): void;
816
+ _render(): void;
817
+ /**
818
+ * Properties frozen onto the exported clone.
819
+ *
820
+ * A serialized SVG carries no stylesheet: rules that live in the CSS file, and every
821
+ * `var(--oep-*)` they resolve, vanish the moment the markup leaves the document. The
822
+ * export would come out as black shapes on nothing. So the computed value of each
823
+ * painting property is written inline, node by node.
824
+ */
825
+ static get _EXPORT_PROPS(): string[];
826
+ /** Copies the computed painting styles of `src` onto `dst`, recursively. */
827
+ _freezeStyles(src: any, dst: any): void;
828
+ /**
829
+ * The whole panel as an SVG string: background, title, stats, legend, chart.
830
+ *
831
+ * Rebuilt rather than screenshotted. The header is HTML and the chart is SVG, and the
832
+ * only way to put HTML in an SVG is a `foreignObject`, which browsers refuse to
833
+ * rasterise consistently. Redrawing the two text lines as `<text>` is a handful of
834
+ * lines and works everywhere.
835
+ *
836
+ * The current-position indicator is dropped: it marks where the pointer happens to be,
837
+ * which means nothing once the image is saved.
838
+ */
839
+ _exportSvg(): {
840
+ width: number;
841
+ height: number;
842
+ svg: string;
843
+ };
844
+ /**
845
+ * Export the whole panel - title, stats, legend and chart - as a PNG.
846
+ *
847
+ * Resolves with the Blob. Unless `download` is false, it also saves the file, which is
848
+ * what the toolbar button does.
849
+ *
850
+ * @param {{scale?:number, filename?:string, download?:boolean}} [opts]
851
+ * `scale` defaults to the device pixel ratio, so the image is not soft on a retina
852
+ * screen. `filename` defaults to the track title.
853
+ * @returns {Promise<Blob>}
854
+ */
855
+ exportPNG(opts?: {
856
+ scale?: number;
857
+ filename?: string;
858
+ download?: boolean;
859
+ }): Promise<Blob>;
860
+ /** @private */
861
+ private _save;
862
+ _arm(which: any): void;
863
+ /**
864
+ * Pose la borne armée à l'abscisse [x0], puis arme l'autre tant qu'elle manque.
865
+ *
866
+ * Poser A n'a d'intérêt que pour poser B ensuite : enchaîner d'un clic sur l'autre
867
+ * évite l'aller-retour par la barre d'outils entre les deux. Les deux bornes réunies,
868
+ * le recadrage part et rien ne reste armé.
869
+ */
870
+ _placeBound(x0: any): void;
871
+ _updateZoomButtons(): void;
872
+ /**
873
+ * Recadre sur le sommet de la pile : échantillons, statistiques, origine des abscisses.
874
+ *
875
+ * Les bornes empilées sont gardées en abscisse de la trace **entière**, jamais dans le
876
+ * repère du niveau courant : sinon chaque cran se lirait dans celui du précédent et
877
+ * l'erreur de rebasage se composerait de niveau en niveau. Rend les coordonnées
878
+ * cartographiques du niveau, dont le cadrage a besoin.
879
+ */
880
+ _applyCrops(): any;
881
+ /** Cadre la carte sur un niveau, ou sur la trace entière si [coords] est nul. */
882
+ _fitMap(coords: any): any;
883
+ /** Empile un niveau. [a0] et [b0] sont lus dans le repère du niveau courant. */
884
+ _pushCrop(a0: any, b0: any): void;
885
+ /**
886
+ * Recadre sur A..B déjà posés. Conservé : c'était le point d'entrée du niveau unique,
887
+ * et le supprimer casserait ce qui l'appelle sans rien apporter.
888
+ */
889
+ _applyZoom(): void;
890
+ /** Remonte d'un niveau. */
891
+ _popCrop(): void;
892
+ /** Vide la pile d'un coup, quel que soit le nombre de niveaux. */
893
+ _exitZoom(): void;
894
+ /**
895
+ * Point of the profiled outline closest to a map coordinate.
896
+ *
897
+ * A polygon's own `getClosestPoint` answers for its **surface**: with the cursor inside
898
+ * the ring it returns the cursor itself, so the marker would follow the pointer across
899
+ * the whole shape instead of sliding along the outline. Lines keep the geometry's own
900
+ * answer, which is exact rather than limited to the decimated samples.
901
+ */
902
+ _closestOnProfile(coordinate: any): any;
903
+ /**
904
+ * Projeté d'une coordonnée sur la ligne brisée [data] : le point, et son abscisse
905
+ * curviligne dans le repère de [data].
906
+ *
907
+ * Retenir l'échantillon le plus proche ferait sauter le marqueur de sommet en sommet,
908
+ * l'écart entre deux points de trace étant souvent bien plus grand que le pas du
909
+ * pointeur. La projection sur les segments donne le point réellement visé.
910
+ */
911
+ _projectOn(data: any, coord: any): any;
912
+ _tooltipText(d: any): string;
913
+ _setFocus(d: any): void;
914
+ /**
915
+ * Point du profil à une abscisse quelconque, interpolé entre les deux échantillons qui
916
+ * l'encadrent.
917
+ *
918
+ * Se caler sur l'échantillon le plus proche ferait avancer le curseur de sommet en
919
+ * sommet : sur un tracé peu dense, ou décimé par `maxPoints`, le saut est franc et le
920
+ * survol perd sa continuité. Les échantillons sont les points *mesurés*, non les seules
921
+ * positions que le curseur ait le droit d'occuper.
922
+ *
923
+ * La pente n'est pas interpolée : `_addSlope` la pose sur le segment qui précède chaque
924
+ * échantillon, elle est donc constante sur ce segment et vaut celle de son extrémité.
925
+ * Le temps l'est, mais seulement si les deux bornes en portent un.
926
+ */
927
+ _sampleAt(x0: any): any;
928
+ /** Suit une coordonnée de la carte, projetée sur le tracé courant. */
929
+ _focusByCoord(coord: any): void;
930
+ _clearFocus(): void;
931
+ _clear(): void;
932
+ }
933
+ declare namespace ElevationProfile {
934
+ var addTheme: (name: string, colors: {
935
+ area: string;
936
+ line: string;
937
+ axis: string;
938
+ text: string;
939
+ focus: string;
940
+ }) => void;
941
+ export { THEMES };
942
+ export { DEM_PRESETS };
943
+ export { DemSampler };
944
+ export { POSITIONS };
945
+ export var version: string;
946
+ }
947
+ export default ElevationProfile;