@superrouteca/smap 1.1.1 → 1.1.5
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/CHANGELOG.md +14 -0
- package/README.md +30 -0
- package/dist/SOURCE.json +8 -8
- package/dist/smap-client.cjs +2 -2
- package/dist/smap-client.js +2 -2
- package/dist/smap-client.mjs +2 -2
- package/dist/smap.cjs +257 -4
- package/dist/smap.css +29 -0
- package/dist/smap.js +256 -3
- package/dist/smap.mjs +257 -4
- package/package.json +1 -1
- package/types/smap.d.cts +45 -0
- package/types/smap.d.mts +45 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.5 — 2026-10-28
|
|
4
|
+
|
|
5
|
+
- Map tools: the controls and panels floating on a map can be shown and hidden one by one or all at once. Register
|
|
6
|
+
each with `addTool` — a page element (an orders list, a legend, a search box), an engine control, or a zoom, locate,
|
|
7
|
+
full screen or scale control the SDK makes — and switch them with `setToolVisible` and `setToolsVisible`. A tools
|
|
8
|
+
control (one button, top right by default) lists every tool with *Show all* and *Hide all*. A hidden tool keeps its
|
|
9
|
+
state and comes back as it was. The map data credit and the sMap badge always stay. The starting state is given in
|
|
10
|
+
`tools.hidden` and every change is reported to `onToolsChange`, so the page decides whether and where to keep it.
|
|
11
|
+
A map without tools is unchanged.
|
|
12
|
+
|
|
13
|
+
## 1.1.2 — 2026-10-27
|
|
14
|
+
|
|
15
|
+
- The version follows the shared 1.1.2 release; no change of its own.
|
|
16
|
+
|
|
3
17
|
## 1.1.1 — 2026-10-27
|
|
4
18
|
|
|
5
19
|
- deck.gl's interleaved overlay works on the map again: `addDeckLayer` and `deckOverlay` with deck.gl 9.x no longer
|
package/README.md
CHANGED
|
@@ -201,6 +201,36 @@ map.addPoints('stops', stops, { // {lng, lat, stop_number, status_colo
|
|
|
201
201
|
Numbers and badges are drawn over all pins of the layer, so where pins overlap a lower pin's number can show through
|
|
202
202
|
an upper pin.
|
|
203
203
|
|
|
204
|
+
## Map tools: showing and hiding controls and panels
|
|
205
|
+
|
|
206
|
+
Register what floats on the map, and the map gets a tools control (one button, top right) that shows or hides each
|
|
207
|
+
tool, plus *Show all* and *Hide all*:
|
|
208
|
+
|
|
209
|
+
```js
|
|
210
|
+
const map = new sMap.Map({ container: 'map', style: 'light', tools: { hidden: saved.hidden } });
|
|
211
|
+
map.addTool('zoom', 'navigation', { options: { showCompass: false } }); // made by the SDK
|
|
212
|
+
map.addTool('fullscreen', 'fullscreen');
|
|
213
|
+
map.addTool('legend', document.getElementById('legend'), { label: 'Legend', position: 'bottom-left' });
|
|
214
|
+
map.addTool('orders', document.getElementById('orders'), { label: 'Orders list', position: 'none' }); // stays in the page
|
|
215
|
+
map.onToolsChange((e) => save({ hidden: e.hidden }));
|
|
216
|
+
|
|
217
|
+
map.setToolVisible('legend', false);
|
|
218
|
+
map.setToolsVisible(true);
|
|
219
|
+
map.tools(); // [{ id: 'zoom', label: 'Zoom', visible: true }, …]
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
- A tool is a page element, an engine control (`onAdd` / `onRemove`), or a kind the SDK makes: `navigation`,
|
|
223
|
+
`geolocate`, `fullscreen`, `scale`, and the mobile SDKs' names `zoom` (zoom buttons only), `compass` and `locate`. `position` is a corner, or `'none'` for an element that stays where the page put
|
|
224
|
+
it. Ids are 1–64 letters, digits, `-`, `_` or `.`; adding an id again replaces the first.
|
|
225
|
+
- A hidden tool is not drawn and keeps its state (an open list stays open, typed text stays). Hiding a switch does not
|
|
226
|
+
turn off what it switches.
|
|
227
|
+
- The map data credit, the sMap badge and the tools control are never tools: *Hide all* leaves them.
|
|
228
|
+
- `tools.control: false` leaves the tools control out (make your own buttons with the calls above);
|
|
229
|
+
`tools.labels: { button, showAll, hideAll }` translates it.
|
|
230
|
+
- The SDK keeps no state: give the starting state in `tools.hidden` and keep `onToolsChange`'s `hidden` where you
|
|
231
|
+
like (the page's storage, your server).
|
|
232
|
+
- The tools control joins the map with the first tool; a map without tools is unchanged.
|
|
233
|
+
|
|
204
234
|
## Style layers and sources
|
|
205
235
|
|
|
206
236
|
Sources and layers of the Style Specification v8 are passed to the map as they are, so a layer copied from Mapbox
|
package/dist/SOURCE.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
|
-
"sdkVersion": "1.1.
|
|
2
|
+
"sdkVersion": "1.1.5",
|
|
3
3
|
"engine": "maplibre-gl 6.16.0",
|
|
4
4
|
"files": {
|
|
5
|
-
"smap.js": "
|
|
6
|
-
"smap.css": "
|
|
7
|
-
"smap-client.js": "
|
|
5
|
+
"smap.js": "d8658ace857ab90b2f2f3dc0af163104d3231e11c119af4a12a0d88b66f6ecae",
|
|
6
|
+
"smap.css": "acb9e11dca261a1f827e1d073e47e13b112b986ee744a712107ff83276d327e7",
|
|
7
|
+
"smap-client.js": "d101ab143691d1973399fb7b45fe396178dc96471048923077e57ce76b413a4a",
|
|
8
8
|
"smap-client.d.ts": "5f0df11bf60c5a9ced34522a284de81260c27871678ab772f16da9ccf6883f58",
|
|
9
|
-
"smap.mjs": "
|
|
10
|
-
"smap.cjs": "
|
|
11
|
-
"smap-client.cjs": "
|
|
12
|
-
"smap-client.mjs": "
|
|
9
|
+
"smap.mjs": "db3e14cce3abb2f2dfdd17578de122ed7a633f8f885e1f5765dfbb92cf862e87",
|
|
10
|
+
"smap.cjs": "34ec49173c1e97b88510ffcfdf1b2db30fcfe28ccef5aa1e8e311e52f459b994",
|
|
11
|
+
"smap-client.cjs": "45d68a640f686d93e10c98468ed0c384bbc696da51193253217f6476d19ac6ed",
|
|
12
|
+
"smap-client.mjs": "45b241183a128671d0422c3684f5987cc1d1e1223fc1d95bcba16ba955c58862",
|
|
13
13
|
"smap-client.d.cts": "e0fe4eb54cd66b831116082f42bd2f7de260f9f12a2741f4004f8cf10c252116",
|
|
14
14
|
"smap-client.d.mts": "96830d316ddb33b4ff8edb8b6f810337479636114f75c4170d95038ffda74103",
|
|
15
15
|
"vendor-licenses.txt": "ee5fc05a0677eaf69601d2c7db0d9ecd6cc27c3abc1d0733bc9ed34707cf8ef2"
|
package/dist/smap-client.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* Generated by js/build.mjs from js/src (see SOURCE.json). Do not edit. */
|
|
2
|
-
/*! sMap JS client 1.1.
|
|
2
|
+
/*! sMap JS client 1.1.5 — tokens, the nearest node, styles, tiles and raw reads, without a map view. */
|
|
3
3
|
/*
|
|
4
4
|
* Runs wherever `fetch` exists: browsers, Node.js 18+, workers; elsewhere (mini programs, older runtimes) pass your
|
|
5
5
|
* own `fetch`. UMD: `window.SMapClient`, `require('smap-client')`, or an AMD module.
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
}(typeof self !== 'undefined' ? self : this, function () {
|
|
20
20
|
'use strict';
|
|
21
21
|
|
|
22
|
-
var VERSION = '1.1.
|
|
22
|
+
var VERSION = '1.1.5';
|
|
23
23
|
var NODE_TTL = 3600 * 1000; // the measured order
|
|
24
24
|
var KNOWN_TTL = 30 * 86400 * 1000; // the last node list received, used when none can be read
|
|
25
25
|
|
package/dist/smap-client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! sMap JS client 1.1.
|
|
1
|
+
/*! sMap JS client 1.1.5 — tokens, the nearest node, styles, tiles and raw reads, without a map view. */
|
|
2
2
|
/*
|
|
3
3
|
* Runs wherever `fetch` exists: browsers, Node.js 18+, workers; elsewhere (mini programs, older runtimes) pass your
|
|
4
4
|
* own `fetch`. UMD: `window.SMapClient`, `require('smap-client')`, or an AMD module.
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
}(typeof self !== 'undefined' ? self : this, function () {
|
|
19
19
|
'use strict';
|
|
20
20
|
|
|
21
|
-
var VERSION = '1.1.
|
|
21
|
+
var VERSION = '1.1.5';
|
|
22
22
|
var NODE_TTL = 3600 * 1000; // the measured order
|
|
23
23
|
var KNOWN_TTL = 30 * 86400 * 1000; // the last node list received, used when none can be read
|
|
24
24
|
|
package/dist/smap-client.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* Generated by js/build.mjs from js/src (see SOURCE.json). Do not edit. */
|
|
2
2
|
var smapClientModule = { exports: {} };
|
|
3
3
|
(function (module, exports, define) {
|
|
4
|
-
/*! sMap JS client 1.1.
|
|
4
|
+
/*! sMap JS client 1.1.5 — tokens, the nearest node, styles, tiles and raw reads, without a map view. */
|
|
5
5
|
/*
|
|
6
6
|
* Runs wherever `fetch` exists: browsers, Node.js 18+, workers; elsewhere (mini programs, older runtimes) pass your
|
|
7
7
|
* own `fetch`. UMD: `window.SMapClient`, `require('smap-client')`, or an AMD module.
|
|
@@ -21,7 +21,7 @@ var smapClientModule = { exports: {} };
|
|
|
21
21
|
}(typeof self !== 'undefined' ? self : this, function () {
|
|
22
22
|
'use strict';
|
|
23
23
|
|
|
24
|
-
var VERSION = '1.1.
|
|
24
|
+
var VERSION = '1.1.5';
|
|
25
25
|
var NODE_TTL = 3600 * 1000; // the measured order
|
|
26
26
|
var KNOWN_TTL = 30 * 86400 * 1000; // the last node list received, used when none can be read
|
|
27
27
|
|
package/dist/smap.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Generated by js/build.mjs from js/src (see SOURCE.json). Do not edit. */
|
|
2
2
|
'use strict';
|
|
3
|
-
/*! sMap Web SDK 1.1.
|
|
3
|
+
/*! sMap Web SDK 1.1.5. Bundles maplibre-gl 6.16.0 (BSD-3-Clause), see vendor-licenses.txt. */
|
|
4
4
|
|
|
5
5
|
var smapCore = null;
|
|
6
6
|
function smapCreateEngine() {
|
|
@@ -28353,7 +28353,7 @@ function smapCreateSdk(engine, interop) {
|
|
|
28353
28353
|
})(typeof self !== 'undefined' ? self : this, function (engine, interop) {
|
|
28354
28354
|
'use strict';
|
|
28355
28355
|
|
|
28356
|
-
var VERSION = '1.1.
|
|
28356
|
+
var VERSION = '1.1.5';
|
|
28357
28357
|
var FLAVORS = ['light', 'white', 'grayscale', 'dark', 'black'];
|
|
28358
28358
|
var BASEMAP_SOURCE = 'basemap';
|
|
28359
28359
|
var BUILDINGS_LAYER = 'smap-buildings-3d';
|
|
@@ -28806,11 +28806,20 @@ function smapCreateSdk(engine, interop) {
|
|
|
28806
28806
|
// True between a style's load and the next style change. The engine's own isStyleLoaded() turns false while any
|
|
28807
28807
|
// source is loading data, which would leave layers added meanwhile waiting for a load that never comes.
|
|
28808
28808
|
this._styleReady = false;
|
|
28809
|
+
// Map tools (M49-M57): the controls and panels floating on the map that the caller registered, in the order added.
|
|
28810
|
+
var toolOptions = options.tools || {};
|
|
28811
|
+
this._tools = [];
|
|
28812
|
+
this._toolsHidden = {};
|
|
28813
|
+
(toolOptions.hidden || []).forEach(function (id) { this._toolsHidden[id] = true; }, this);
|
|
28814
|
+
this._toolsControlAt = toolOptions.control === undefined ? 'top-right' : toolOptions.control;
|
|
28815
|
+
this._toolsLabels = toolOptions.labels || {};
|
|
28816
|
+
this._toolsControl = null;
|
|
28817
|
+
this._toolHandlers = [];
|
|
28809
28818
|
|
|
28810
28819
|
var self = this;
|
|
28811
28820
|
var engineOptions = {};
|
|
28812
28821
|
for (var k in options) {
|
|
28813
|
-
if (Object.prototype.hasOwnProperty.call(options, k) && ['token', 'getToken', 'apiKey', 'style', 'language', 'baseUrl', 'projection', 'nearest', 'nodes', 'popup', 'popupLoading', 'autoZoom', 'keyboard3D'].indexOf(k) < 0) {
|
|
28822
|
+
if (Object.prototype.hasOwnProperty.call(options, k) && ['token', 'getToken', 'apiKey', 'style', 'language', 'baseUrl', 'projection', 'nearest', 'nodes', 'popup', 'popupLoading', 'autoZoom', 'keyboard3D', 'tools'].indexOf(k) < 0) {
|
|
28814
28823
|
engineOptions[k] = options[k];
|
|
28815
28824
|
}
|
|
28816
28825
|
}
|
|
@@ -28843,6 +28852,7 @@ function smapCreateSdk(engine, interop) {
|
|
|
28843
28852
|
self.engine.addControl(badge, 'bottom-right');
|
|
28844
28853
|
badge._place();
|
|
28845
28854
|
}
|
|
28855
|
+
self._mountTools();
|
|
28846
28856
|
self.engine.on('style.load', function () { self._styleReady = true; self._restore(); });
|
|
28847
28857
|
self._keyboard3D();
|
|
28848
28858
|
// One click handler for every layer's popup: the engine's hit test over those layers, the top feature opens.
|
|
@@ -29326,6 +29336,249 @@ function smapCreateSdk(engine, interop) {
|
|
|
29326
29336
|
SMap.prototype.flyTo = function (o) { this.engine.flyTo(o); return this; };
|
|
29327
29337
|
SMap.prototype.remove = function () { clearTimeout(this._refreshTimer); if (this.engine) { this.engine.remove(); } };
|
|
29328
29338
|
|
|
29339
|
+
// ------------------------------------------------------------------ map tools (M49-M57)
|
|
29340
|
+
|
|
29341
|
+
var TOOL_ID = /^[A-Za-z0-9._-]{1,64}$/;
|
|
29342
|
+
var TOOL_CORNERS = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
|
|
29343
|
+
// The tools the SDK makes by name: the engine control, its English label (the caller may give another) and corner.
|
|
29344
|
+
var TOOL_KINDS = {
|
|
29345
|
+
navigation: { control: 'NavigationControl', label: 'Zoom', position: 'top-left' },
|
|
29346
|
+
geolocate: { control: 'GeolocateControl', label: 'Locate', position: 'top-left' },
|
|
29347
|
+
fullscreen: { control: 'FullscreenControl', label: 'Full screen', position: 'top-left' },
|
|
29348
|
+
scale: { control: 'ScaleControl', label: 'Scale', position: 'bottom-left' },
|
|
29349
|
+
// The mobile SDKs' names for the same controls, so one tool list serves every platform.
|
|
29350
|
+
zoom: { control: 'NavigationControl', label: 'Zoom', position: 'top-left', options: { showCompass: false } },
|
|
29351
|
+
compass: { control: 'NavigationControl', label: 'Compass', position: 'top-left', options: { showZoom: false } },
|
|
29352
|
+
locate: { control: 'GeolocateControl', label: 'Locate', position: 'top-left' },
|
|
29353
|
+
};
|
|
29354
|
+
var TOOLS_ICON = '<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true" focusable="false" fill="none" ' +
|
|
29355
|
+
'stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 7h10M18 7h2M4 17h2M10 17h10"/>' +
|
|
29356
|
+
'<circle cx="16" cy="7" r="2"/><circle cx="8" cy="17" r="2"/></svg>';
|
|
29357
|
+
var TOOLS_TEXT = { button: 'Map tools', showAll: 'Show all', hideAll: 'Hide all' };
|
|
29358
|
+
|
|
29359
|
+
function isElement(v) { return !!v && typeof v === 'object' && v.nodeType === 1; }
|
|
29360
|
+
|
|
29361
|
+
// An engine control whose element the SDK can find again to show or hide it: the control's own onAdd, its element kept.
|
|
29362
|
+
function toolControl(tool, inner) {
|
|
29363
|
+
return {
|
|
29364
|
+
onAdd: function (m) { tool.el = inner.onAdd(m); return tool.el; },
|
|
29365
|
+
onRemove: function (m) { if (inner.onRemove) { inner.onRemove(m); } else if (tool.el && tool.el.parentNode) { tool.el.parentNode.removeChild(tool.el); } tool.el = null; },
|
|
29366
|
+
getDefaultPosition: function () { return tool.position; },
|
|
29367
|
+
};
|
|
29368
|
+
}
|
|
29369
|
+
|
|
29370
|
+
// A page element placed in a corner of the map: it moves into the corner and back where it was when removed.
|
|
29371
|
+
function elementControl(tool, element) {
|
|
29372
|
+
var home = null;
|
|
29373
|
+
var next = null;
|
|
29374
|
+
return {
|
|
29375
|
+
onAdd: function () {
|
|
29376
|
+
home = element.parentNode;
|
|
29377
|
+
next = element.nextSibling;
|
|
29378
|
+
element.classList.add('maplibregl-ctrl', 'smap-tool');
|
|
29379
|
+
tool.el = element;
|
|
29380
|
+
return element;
|
|
29381
|
+
},
|
|
29382
|
+
onRemove: function () {
|
|
29383
|
+
element.classList.remove('maplibregl-ctrl', 'smap-tool');
|
|
29384
|
+
if (home) { home.insertBefore(element, next && next.parentNode === home ? next : null); } else if (element.parentNode) { element.parentNode.removeChild(element); }
|
|
29385
|
+
tool.el = null;
|
|
29386
|
+
},
|
|
29387
|
+
getDefaultPosition: function () { return tool.position; },
|
|
29388
|
+
};
|
|
29389
|
+
}
|
|
29390
|
+
|
|
29391
|
+
/**
|
|
29392
|
+
* Registers a tool floating on the map, shown or hidden by setToolVisible / setToolsVisible and the tools control.
|
|
29393
|
+
* map.addTool('legend', document.getElementById('legend'), { label: 'Legend', position: 'bottom-left' })
|
|
29394
|
+
* map.addTool('zoom', 'navigation', { options: { showCompass: false } })
|
|
29395
|
+
* @param {string} id 1-64 letters, digits, '-', '_', '.'; adding an id again replaces the first
|
|
29396
|
+
* @param {Element|Object|string} target a page element, an engine control (onAdd / onRemove), or a kind the SDK
|
|
29397
|
+
* makes: 'navigation', 'geolocate', 'fullscreen', 'scale', or the mobile SDKs' 'zoom' (navigation without the
|
|
29398
|
+
* compass), 'compass' (without the zoom buttons) and 'locate' (geolocate)
|
|
29399
|
+
* @param {Object} [o] label (shown on its button), position ('top-left', 'top-right', 'bottom-left', 'bottom-right',
|
|
29400
|
+
* or 'none': an element stays where the page put it), options (of a kind's engine control)
|
|
29401
|
+
*/
|
|
29402
|
+
SMap.prototype.addTool = function (id, target, o) {
|
|
29403
|
+
o = o || {};
|
|
29404
|
+
if (typeof id !== 'string' || !TOOL_ID.test(id)) { throw new Error('sMap: a tool id is 1-64 letters, digits, "-", "_" or "."'); }
|
|
29405
|
+
var kind = typeof target === 'string' ? TOOL_KINDS[target] : null;
|
|
29406
|
+
if (typeof target === 'string') {
|
|
29407
|
+
if (!kind) { throw new Error('sMap: unknown tool kind "' + target + '"'); }
|
|
29408
|
+
if (!engine[kind.control]) { throw new Error('sMap: the rendering engine has no ' + kind.control); }
|
|
29409
|
+
} else if (!isElement(target) && !(target && typeof target.onAdd === 'function')) {
|
|
29410
|
+
throw new Error('sMap: a tool is an element, an engine control or a tool kind');
|
|
29411
|
+
}
|
|
29412
|
+
var position = o.position || (kind ? kind.position : (isElement(target) ? (target.parentNode ? 'none' : 'top-left') : 'top-right'));
|
|
29413
|
+
if (position !== 'none' && TOOL_CORNERS.indexOf(position) < 0) { throw new Error('sMap: unknown tool position "' + position + '"'); }
|
|
29414
|
+
if (position === 'none' && !isElement(target)) { throw new Error('sMap: only an element may stay out of the map\'s corners'); }
|
|
29415
|
+
if (this._toolIndex(id) >= 0) { this.removeTool(id); }
|
|
29416
|
+
var tool = { id: id, label: String(o.label || (kind ? kind.label : id)), position: position, el: null, control: null };
|
|
29417
|
+
if (kind) { tool.control = toolControl(tool, new engine[kind.control](o.options || kind.options)); }
|
|
29418
|
+
else if (!isElement(target)) { tool.control = toolControl(tool, target); }
|
|
29419
|
+
else if (position !== 'none') { tool.control = elementControl(tool, target); }
|
|
29420
|
+
else { tool.el = target; }
|
|
29421
|
+
this._tools.push(tool);
|
|
29422
|
+
if (this.engine) { this._mountTool(tool); }
|
|
29423
|
+
this._renderToolsControl();
|
|
29424
|
+
return this;
|
|
29425
|
+
};
|
|
29426
|
+
|
|
29427
|
+
/** Removes a tool: an engine control leaves the map, a page element is shown again where the page put it. */
|
|
29428
|
+
SMap.prototype.removeTool = function (id) {
|
|
29429
|
+
var i = this._toolIndex(id);
|
|
29430
|
+
if (i < 0) { return this; }
|
|
29431
|
+
var tool = this._tools[i];
|
|
29432
|
+
this._tools.splice(i, 1);
|
|
29433
|
+
if (tool.el) { tool.el.classList.remove('smap-tool-hidden'); }
|
|
29434
|
+
if (tool.control && this.engine && tool.mounted) { this.engine.removeControl(tool.control); }
|
|
29435
|
+
this._renderToolsControl();
|
|
29436
|
+
return this;
|
|
29437
|
+
};
|
|
29438
|
+
|
|
29439
|
+
/** Shows or hides one tool. A hidden tool keeps its state and shows again as it was (M57). */
|
|
29440
|
+
SMap.prototype.setToolVisible = function (id, visible) {
|
|
29441
|
+
var tool = this._tools[this._toolIndex(id)];
|
|
29442
|
+
if (!tool || this._toolVisible(tool) === !!visible) { return this; }
|
|
29443
|
+
this._setHidden(tool, !visible);
|
|
29444
|
+
this._renderToolsControl();
|
|
29445
|
+
this._toolsChanged(id);
|
|
29446
|
+
return this;
|
|
29447
|
+
};
|
|
29448
|
+
|
|
29449
|
+
/** Shows or hides every tool. The map data credit, the sMap badge and the tools control always stay (M51). */
|
|
29450
|
+
SMap.prototype.setToolsVisible = function (visible) {
|
|
29451
|
+
var changed = false;
|
|
29452
|
+
this._tools.forEach(function (tool) {
|
|
29453
|
+
if (this._toolVisible(tool) !== !!visible) { this._setHidden(tool, !visible); changed = true; }
|
|
29454
|
+
}, this);
|
|
29455
|
+
if (changed) { this._renderToolsControl(); this._toolsChanged(null); }
|
|
29456
|
+
return this;
|
|
29457
|
+
};
|
|
29458
|
+
|
|
29459
|
+
/** The tools in the order added: [{ id, label, visible }]. */
|
|
29460
|
+
SMap.prototype.tools = function () {
|
|
29461
|
+
return this._tools.map(function (tool) { return { id: tool.id, label: tool.label, visible: this._toolVisible(tool) }; }, this);
|
|
29462
|
+
};
|
|
29463
|
+
|
|
29464
|
+
/** Calls handler({ hidden: [ids], changed: id | null }) after every change; the SDK keeps no state itself (M53). */
|
|
29465
|
+
SMap.prototype.onToolsChange = function (handler) { this._toolHandlers.push(handler); return this; };
|
|
29466
|
+
SMap.prototype.offToolsChange = function (handler) {
|
|
29467
|
+
this._toolHandlers = this._toolHandlers.filter(function (h) { return h !== handler; });
|
|
29468
|
+
return this;
|
|
29469
|
+
};
|
|
29470
|
+
|
|
29471
|
+
SMap.prototype._toolIndex = function (id) {
|
|
29472
|
+
for (var i = 0; i < this._tools.length; i++) { if (this._tools[i].id === id) { return i; } }
|
|
29473
|
+
return -1;
|
|
29474
|
+
};
|
|
29475
|
+
SMap.prototype._toolVisible = function (tool) { return !this._toolsHidden[tool.id]; };
|
|
29476
|
+
SMap.prototype._setHidden = function (tool, hidden) {
|
|
29477
|
+
if (hidden) { this._toolsHidden[tool.id] = true; } else { delete this._toolsHidden[tool.id]; }
|
|
29478
|
+
if (tool.el) { tool.el.classList.toggle('smap-tool-hidden', hidden); }
|
|
29479
|
+
};
|
|
29480
|
+
SMap.prototype._toolsChanged = function (id) {
|
|
29481
|
+
var hidden = this._tools.filter(function (t) { return !this._toolVisible(t); }, this).map(function (t) { return t.id; });
|
|
29482
|
+
this._toolHandlers.slice().forEach(function (h) { h({ hidden: hidden, changed: id }); });
|
|
29483
|
+
};
|
|
29484
|
+
|
|
29485
|
+
SMap.prototype._mountTool = function (tool) {
|
|
29486
|
+
// The tools control joins the map with its first tool, so a map without tools is exactly as before.
|
|
29487
|
+
if (this._toolsControlAt && !this._toolsControl && this.engine.addControl) {
|
|
29488
|
+
this._toolsControl = toolsControl(this);
|
|
29489
|
+
this.engine.addControl(this._toolsControl, this._toolsControlAt);
|
|
29490
|
+
}
|
|
29491
|
+
if (tool.control && this.engine.addControl) { this.engine.addControl(tool.control, tool.position); tool.mounted = true; }
|
|
29492
|
+
if (tool.el) { tool.el.classList.toggle('smap-tool-hidden', !this._toolVisible(tool)); }
|
|
29493
|
+
};
|
|
29494
|
+
|
|
29495
|
+
// Called once the engine exists: every tool registered before it.
|
|
29496
|
+
SMap.prototype._mountTools = function () {
|
|
29497
|
+
this._tools.forEach(function (tool) { this._mountTool(tool); }, this);
|
|
29498
|
+
this._renderToolsControl();
|
|
29499
|
+
};
|
|
29500
|
+
SMap.prototype._renderToolsControl = function () { if (this._toolsControl) { this._toolsControl._render(); } };
|
|
29501
|
+
|
|
29502
|
+
// The tools control: one button that opens a panel with one toggle per tool (pressed = shown), Show all and Hide all.
|
|
29503
|
+
// It is not a tool and is never hidden; it joins the map with the first tool and is not drawn while none is left.
|
|
29504
|
+
function toolsControl(map) {
|
|
29505
|
+
var el = null;
|
|
29506
|
+
var button = null;
|
|
29507
|
+
var panel = null;
|
|
29508
|
+
var drawn = null;
|
|
29509
|
+
var text = {};
|
|
29510
|
+
Object.keys(TOOLS_TEXT).forEach(function (k) { text[k] = map._toolsLabels[k] || TOOLS_TEXT[k]; });
|
|
29511
|
+
function open(on) {
|
|
29512
|
+
panel.hidden = !on;
|
|
29513
|
+
button.setAttribute('aria-expanded', on ? 'true' : 'false');
|
|
29514
|
+
}
|
|
29515
|
+
function close() { if (panel && !panel.hidden) { open(false); } }
|
|
29516
|
+
function key(e) { if (e.key === 'Escape' && !panel.hidden) { open(false); button.focus(); } }
|
|
29517
|
+
function make(doc, tag, className, label) {
|
|
29518
|
+
var b = doc.createElement(tag);
|
|
29519
|
+
b.className = className;
|
|
29520
|
+
if (tag === 'button') { b.type = 'button'; }
|
|
29521
|
+
if (label !== undefined) { b.textContent = label; }
|
|
29522
|
+
return b;
|
|
29523
|
+
}
|
|
29524
|
+
var control = {
|
|
29525
|
+
onAdd: function (m) {
|
|
29526
|
+
var doc = m.getContainer().ownerDocument;
|
|
29527
|
+
el = make(doc, 'div', 'maplibregl-ctrl maplibregl-ctrl-group smap-tools');
|
|
29528
|
+
button = make(doc, 'button', 'smap-tools-button');
|
|
29529
|
+
button.innerHTML = TOOLS_ICON;
|
|
29530
|
+
button.title = text.button;
|
|
29531
|
+
button.setAttribute('aria-label', text.button);
|
|
29532
|
+
button.setAttribute('aria-haspopup', 'true');
|
|
29533
|
+
button.addEventListener('click', function () { open(panel.hidden); });
|
|
29534
|
+
panel = make(doc, 'div', 'smap-tools-panel');
|
|
29535
|
+
panel.setAttribute('role', 'group');
|
|
29536
|
+
panel.setAttribute('aria-label', text.button);
|
|
29537
|
+
el.appendChild(button);
|
|
29538
|
+
el.appendChild(panel);
|
|
29539
|
+
el.addEventListener('keydown', key);
|
|
29540
|
+
open(false);
|
|
29541
|
+
m.on('click', close);
|
|
29542
|
+
return el;
|
|
29543
|
+
},
|
|
29544
|
+
onRemove: function (m) {
|
|
29545
|
+
m.off('click', close);
|
|
29546
|
+
if (el && el.parentNode) { el.parentNode.removeChild(el); }
|
|
29547
|
+
el = null;
|
|
29548
|
+
drawn = null;
|
|
29549
|
+
},
|
|
29550
|
+
_render: function () {
|
|
29551
|
+
if (!el) { return; }
|
|
29552
|
+
var doc = el.ownerDocument;
|
|
29553
|
+
el.classList.toggle('smap-tools-empty', map._tools.length === 0);
|
|
29554
|
+
// The same tools as last time: only the pressed states change, so a toggle keeps the keyboard focus.
|
|
29555
|
+
var signature = JSON.stringify(map._tools.map(function (t) { return [t.id, t.label]; }));
|
|
29556
|
+
if (signature === drawn) {
|
|
29557
|
+
map._tools.forEach(function (tool, i) { panel.children[i].setAttribute('aria-pressed', map._toolVisible(tool) ? 'true' : 'false'); });
|
|
29558
|
+
return;
|
|
29559
|
+
}
|
|
29560
|
+
drawn = signature;
|
|
29561
|
+
while (panel.firstChild) { panel.removeChild(panel.firstChild); }
|
|
29562
|
+
map._tools.forEach(function (tool) {
|
|
29563
|
+
var item = make(doc, 'button', 'smap-tools-item', tool.label);
|
|
29564
|
+
item.setAttribute('aria-pressed', map._toolVisible(tool) ? 'true' : 'false');
|
|
29565
|
+
item.setAttribute('data-tool', tool.id);
|
|
29566
|
+
item.addEventListener('click', function () { map.setToolVisible(tool.id, !map._toolVisible(tool)); });
|
|
29567
|
+
panel.appendChild(item);
|
|
29568
|
+
});
|
|
29569
|
+
var all = make(doc, 'div', 'smap-tools-all');
|
|
29570
|
+
var show = make(doc, 'button', 'smap-tools-show-all', text.showAll);
|
|
29571
|
+
show.addEventListener('click', function () { map.setToolsVisible(true); });
|
|
29572
|
+
var hide = make(doc, 'button', 'smap-tools-hide-all', text.hideAll);
|
|
29573
|
+
hide.addEventListener('click', function () { map.setToolsVisible(false); });
|
|
29574
|
+
all.appendChild(show);
|
|
29575
|
+
all.appendChild(hide);
|
|
29576
|
+
panel.appendChild(all);
|
|
29577
|
+
},
|
|
29578
|
+
};
|
|
29579
|
+
return control;
|
|
29580
|
+
}
|
|
29581
|
+
|
|
29329
29582
|
// ------------------------------------------------------------------ Style Specification sources and layers (M24)
|
|
29330
29583
|
|
|
29331
29584
|
function clone(v) { return v === undefined ? undefined : JSON.parse(JSON.stringify(v)); }
|
|
@@ -30294,7 +30547,7 @@ function SMapMap(options) {
|
|
|
30294
30547
|
SMapMap.prototype = core.Map.prototype;
|
|
30295
30548
|
return new core.Map(options);
|
|
30296
30549
|
}
|
|
30297
|
-
var smapVersion = "1.1.
|
|
30550
|
+
var smapVersion = "1.1.5";
|
|
30298
30551
|
var smapStyles = ['light', 'white', 'grayscale', 'dark', 'black'];
|
|
30299
30552
|
/** The bundled rendering engine, for anything the SDK does not wrap (loaded on the first call). */
|
|
30300
30553
|
function smapGetEngine() { return smapLoad().engine; }
|
package/dist/smap.css
CHANGED
|
@@ -76,3 +76,32 @@
|
|
|
76
76
|
padding: 0 4px; box-sizing: border-box; border: 2px solid; border-radius: 11px; color: #fff; font-size: 10px; font-weight: 700;
|
|
77
77
|
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); }
|
|
78
78
|
.smap-chooser-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
79
|
+
|
|
80
|
+
/* Map tools (M49-M57). A hidden tool is not drawn; its corner closes up. */
|
|
81
|
+
.smap-tool-hidden { display: none !important; }
|
|
82
|
+
.maplibregl-ctrl.smap-tools.smap-tools-empty { display: none; }
|
|
83
|
+
.smap-tools { position: relative; }
|
|
84
|
+
.smap-tools .smap-tools-button { display: flex; align-items: center; justify-content: center; color: #1e293b; }
|
|
85
|
+
.smap-tools .smap-tools-button[aria-expanded="true"] { color: #2563eb; }
|
|
86
|
+
.smap-tools-panel {
|
|
87
|
+
position: absolute; top: 0; z-index: 3; display: flex; flex-direction: column; gap: 4px;
|
|
88
|
+
min-width: 170px; max-height: 60vmin; overflow-y: auto; padding: 8px; box-sizing: border-box;
|
|
89
|
+
border-radius: 8px; background: #ffffff; color: #1e293b; box-shadow: 0 2px 10px rgba(15, 23, 42, 0.18);
|
|
90
|
+
font: 12px/1.3 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
91
|
+
}
|
|
92
|
+
.smap-tools-panel[hidden] { display: none; }
|
|
93
|
+
.maplibregl-ctrl-top-right .smap-tools-panel, .maplibregl-ctrl-bottom-right .smap-tools-panel { right: 36px; }
|
|
94
|
+
.maplibregl-ctrl-top-left .smap-tools-panel, .maplibregl-ctrl-bottom-left .smap-tools-panel { left: 36px; }
|
|
95
|
+
.maplibregl-ctrl-bottom-right .smap-tools-panel, .maplibregl-ctrl-bottom-left .smap-tools-panel { top: auto; bottom: 0; }
|
|
96
|
+
.maplibregl-ctrl-group .smap-tools-panel button {
|
|
97
|
+
display: flex; align-items: center; width: 100%; height: auto; min-height: 28px; padding: 4px 8px; box-sizing: border-box;
|
|
98
|
+
border: 1px solid rgba(15, 23, 42, 0.15); border-radius: 6px; background: #ffffff; color: inherit;
|
|
99
|
+
font: inherit; text-align: left; white-space: nowrap; cursor: pointer;
|
|
100
|
+
}
|
|
101
|
+
.maplibregl-ctrl-group .smap-tools-panel button + button { border-top: 1px solid rgba(15, 23, 42, 0.15); }
|
|
102
|
+
.maplibregl-ctrl-group .smap-tools-panel .smap-tools-item[aria-pressed="true"] { border-color: #2563eb; background: #2563eb; color: #ffffff; }
|
|
103
|
+
.maplibregl-ctrl-group .smap-tools-panel button:focus-visible { outline: 2px solid #2563eb; outline-offset: 1px; }
|
|
104
|
+
.smap-tools-all { display: flex; gap: 4px; margin-top: 4px; padding-top: 6px; border-top: 1px solid rgba(15, 23, 42, 0.12); }
|
|
105
|
+
.maplibregl-ctrl-group .smap-tools-all button { justify-content: center; text-align: center; }
|
|
106
|
+
.smap-style-dark .smap-tools-panel, .smap-style-black .smap-tools-panel { background: #1f2430; color: #e5e7eb; }
|
|
107
|
+
.smap-style-dark .smap-tools-panel button, .smap-style-black .smap-tools-panel button { background: #1f2430; border-color: rgba(229, 231, 235, 0.2); }
|
package/dist/smap.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! sMap Web SDK 1.1.
|
|
1
|
+
/*! sMap Web SDK 1.1.5. Bundles maplibre-gl 6.16.0 (BSD-3-Clause), see vendor-licenses.txt. */
|
|
2
2
|
(function () {
|
|
3
3
|
function smapCreateEngine() {
|
|
4
4
|
var SMAP_BASE_URL = (typeof document !== 'undefined' && document.baseURI) || (typeof location !== 'undefined' && location.href) || 'about:blank';
|
|
@@ -28350,7 +28350,7 @@ function smapCreateSdk(engine, interop) {
|
|
|
28350
28350
|
})(typeof self !== 'undefined' ? self : this, function (engine, interop) {
|
|
28351
28351
|
'use strict';
|
|
28352
28352
|
|
|
28353
|
-
var VERSION = '1.1.
|
|
28353
|
+
var VERSION = '1.1.5';
|
|
28354
28354
|
var FLAVORS = ['light', 'white', 'grayscale', 'dark', 'black'];
|
|
28355
28355
|
var BASEMAP_SOURCE = 'basemap';
|
|
28356
28356
|
var BUILDINGS_LAYER = 'smap-buildings-3d';
|
|
@@ -28803,11 +28803,20 @@ function smapCreateSdk(engine, interop) {
|
|
|
28803
28803
|
// True between a style's load and the next style change. The engine's own isStyleLoaded() turns false while any
|
|
28804
28804
|
// source is loading data, which would leave layers added meanwhile waiting for a load that never comes.
|
|
28805
28805
|
this._styleReady = false;
|
|
28806
|
+
// Map tools (M49-M57): the controls and panels floating on the map that the caller registered, in the order added.
|
|
28807
|
+
var toolOptions = options.tools || {};
|
|
28808
|
+
this._tools = [];
|
|
28809
|
+
this._toolsHidden = {};
|
|
28810
|
+
(toolOptions.hidden || []).forEach(function (id) { this._toolsHidden[id] = true; }, this);
|
|
28811
|
+
this._toolsControlAt = toolOptions.control === undefined ? 'top-right' : toolOptions.control;
|
|
28812
|
+
this._toolsLabels = toolOptions.labels || {};
|
|
28813
|
+
this._toolsControl = null;
|
|
28814
|
+
this._toolHandlers = [];
|
|
28806
28815
|
|
|
28807
28816
|
var self = this;
|
|
28808
28817
|
var engineOptions = {};
|
|
28809
28818
|
for (var k in options) {
|
|
28810
|
-
if (Object.prototype.hasOwnProperty.call(options, k) && ['token', 'getToken', 'apiKey', 'style', 'language', 'baseUrl', 'projection', 'nearest', 'nodes', 'popup', 'popupLoading', 'autoZoom', 'keyboard3D'].indexOf(k) < 0) {
|
|
28819
|
+
if (Object.prototype.hasOwnProperty.call(options, k) && ['token', 'getToken', 'apiKey', 'style', 'language', 'baseUrl', 'projection', 'nearest', 'nodes', 'popup', 'popupLoading', 'autoZoom', 'keyboard3D', 'tools'].indexOf(k) < 0) {
|
|
28811
28820
|
engineOptions[k] = options[k];
|
|
28812
28821
|
}
|
|
28813
28822
|
}
|
|
@@ -28840,6 +28849,7 @@ function smapCreateSdk(engine, interop) {
|
|
|
28840
28849
|
self.engine.addControl(badge, 'bottom-right');
|
|
28841
28850
|
badge._place();
|
|
28842
28851
|
}
|
|
28852
|
+
self._mountTools();
|
|
28843
28853
|
self.engine.on('style.load', function () { self._styleReady = true; self._restore(); });
|
|
28844
28854
|
self._keyboard3D();
|
|
28845
28855
|
// One click handler for every layer's popup: the engine's hit test over those layers, the top feature opens.
|
|
@@ -29323,6 +29333,249 @@ function smapCreateSdk(engine, interop) {
|
|
|
29323
29333
|
SMap.prototype.flyTo = function (o) { this.engine.flyTo(o); return this; };
|
|
29324
29334
|
SMap.prototype.remove = function () { clearTimeout(this._refreshTimer); if (this.engine) { this.engine.remove(); } };
|
|
29325
29335
|
|
|
29336
|
+
// ------------------------------------------------------------------ map tools (M49-M57)
|
|
29337
|
+
|
|
29338
|
+
var TOOL_ID = /^[A-Za-z0-9._-]{1,64}$/;
|
|
29339
|
+
var TOOL_CORNERS = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
|
|
29340
|
+
// The tools the SDK makes by name: the engine control, its English label (the caller may give another) and corner.
|
|
29341
|
+
var TOOL_KINDS = {
|
|
29342
|
+
navigation: { control: 'NavigationControl', label: 'Zoom', position: 'top-left' },
|
|
29343
|
+
geolocate: { control: 'GeolocateControl', label: 'Locate', position: 'top-left' },
|
|
29344
|
+
fullscreen: { control: 'FullscreenControl', label: 'Full screen', position: 'top-left' },
|
|
29345
|
+
scale: { control: 'ScaleControl', label: 'Scale', position: 'bottom-left' },
|
|
29346
|
+
// The mobile SDKs' names for the same controls, so one tool list serves every platform.
|
|
29347
|
+
zoom: { control: 'NavigationControl', label: 'Zoom', position: 'top-left', options: { showCompass: false } },
|
|
29348
|
+
compass: { control: 'NavigationControl', label: 'Compass', position: 'top-left', options: { showZoom: false } },
|
|
29349
|
+
locate: { control: 'GeolocateControl', label: 'Locate', position: 'top-left' },
|
|
29350
|
+
};
|
|
29351
|
+
var TOOLS_ICON = '<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true" focusable="false" fill="none" ' +
|
|
29352
|
+
'stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 7h10M18 7h2M4 17h2M10 17h10"/>' +
|
|
29353
|
+
'<circle cx="16" cy="7" r="2"/><circle cx="8" cy="17" r="2"/></svg>';
|
|
29354
|
+
var TOOLS_TEXT = { button: 'Map tools', showAll: 'Show all', hideAll: 'Hide all' };
|
|
29355
|
+
|
|
29356
|
+
function isElement(v) { return !!v && typeof v === 'object' && v.nodeType === 1; }
|
|
29357
|
+
|
|
29358
|
+
// An engine control whose element the SDK can find again to show or hide it: the control's own onAdd, its element kept.
|
|
29359
|
+
function toolControl(tool, inner) {
|
|
29360
|
+
return {
|
|
29361
|
+
onAdd: function (m) { tool.el = inner.onAdd(m); return tool.el; },
|
|
29362
|
+
onRemove: function (m) { if (inner.onRemove) { inner.onRemove(m); } else if (tool.el && tool.el.parentNode) { tool.el.parentNode.removeChild(tool.el); } tool.el = null; },
|
|
29363
|
+
getDefaultPosition: function () { return tool.position; },
|
|
29364
|
+
};
|
|
29365
|
+
}
|
|
29366
|
+
|
|
29367
|
+
// A page element placed in a corner of the map: it moves into the corner and back where it was when removed.
|
|
29368
|
+
function elementControl(tool, element) {
|
|
29369
|
+
var home = null;
|
|
29370
|
+
var next = null;
|
|
29371
|
+
return {
|
|
29372
|
+
onAdd: function () {
|
|
29373
|
+
home = element.parentNode;
|
|
29374
|
+
next = element.nextSibling;
|
|
29375
|
+
element.classList.add('maplibregl-ctrl', 'smap-tool');
|
|
29376
|
+
tool.el = element;
|
|
29377
|
+
return element;
|
|
29378
|
+
},
|
|
29379
|
+
onRemove: function () {
|
|
29380
|
+
element.classList.remove('maplibregl-ctrl', 'smap-tool');
|
|
29381
|
+
if (home) { home.insertBefore(element, next && next.parentNode === home ? next : null); } else if (element.parentNode) { element.parentNode.removeChild(element); }
|
|
29382
|
+
tool.el = null;
|
|
29383
|
+
},
|
|
29384
|
+
getDefaultPosition: function () { return tool.position; },
|
|
29385
|
+
};
|
|
29386
|
+
}
|
|
29387
|
+
|
|
29388
|
+
/**
|
|
29389
|
+
* Registers a tool floating on the map, shown or hidden by setToolVisible / setToolsVisible and the tools control.
|
|
29390
|
+
* map.addTool('legend', document.getElementById('legend'), { label: 'Legend', position: 'bottom-left' })
|
|
29391
|
+
* map.addTool('zoom', 'navigation', { options: { showCompass: false } })
|
|
29392
|
+
* @param {string} id 1-64 letters, digits, '-', '_', '.'; adding an id again replaces the first
|
|
29393
|
+
* @param {Element|Object|string} target a page element, an engine control (onAdd / onRemove), or a kind the SDK
|
|
29394
|
+
* makes: 'navigation', 'geolocate', 'fullscreen', 'scale', or the mobile SDKs' 'zoom' (navigation without the
|
|
29395
|
+
* compass), 'compass' (without the zoom buttons) and 'locate' (geolocate)
|
|
29396
|
+
* @param {Object} [o] label (shown on its button), position ('top-left', 'top-right', 'bottom-left', 'bottom-right',
|
|
29397
|
+
* or 'none': an element stays where the page put it), options (of a kind's engine control)
|
|
29398
|
+
*/
|
|
29399
|
+
SMap.prototype.addTool = function (id, target, o) {
|
|
29400
|
+
o = o || {};
|
|
29401
|
+
if (typeof id !== 'string' || !TOOL_ID.test(id)) { throw new Error('sMap: a tool id is 1-64 letters, digits, "-", "_" or "."'); }
|
|
29402
|
+
var kind = typeof target === 'string' ? TOOL_KINDS[target] : null;
|
|
29403
|
+
if (typeof target === 'string') {
|
|
29404
|
+
if (!kind) { throw new Error('sMap: unknown tool kind "' + target + '"'); }
|
|
29405
|
+
if (!engine[kind.control]) { throw new Error('sMap: the rendering engine has no ' + kind.control); }
|
|
29406
|
+
} else if (!isElement(target) && !(target && typeof target.onAdd === 'function')) {
|
|
29407
|
+
throw new Error('sMap: a tool is an element, an engine control or a tool kind');
|
|
29408
|
+
}
|
|
29409
|
+
var position = o.position || (kind ? kind.position : (isElement(target) ? (target.parentNode ? 'none' : 'top-left') : 'top-right'));
|
|
29410
|
+
if (position !== 'none' && TOOL_CORNERS.indexOf(position) < 0) { throw new Error('sMap: unknown tool position "' + position + '"'); }
|
|
29411
|
+
if (position === 'none' && !isElement(target)) { throw new Error('sMap: only an element may stay out of the map\'s corners'); }
|
|
29412
|
+
if (this._toolIndex(id) >= 0) { this.removeTool(id); }
|
|
29413
|
+
var tool = { id: id, label: String(o.label || (kind ? kind.label : id)), position: position, el: null, control: null };
|
|
29414
|
+
if (kind) { tool.control = toolControl(tool, new engine[kind.control](o.options || kind.options)); }
|
|
29415
|
+
else if (!isElement(target)) { tool.control = toolControl(tool, target); }
|
|
29416
|
+
else if (position !== 'none') { tool.control = elementControl(tool, target); }
|
|
29417
|
+
else { tool.el = target; }
|
|
29418
|
+
this._tools.push(tool);
|
|
29419
|
+
if (this.engine) { this._mountTool(tool); }
|
|
29420
|
+
this._renderToolsControl();
|
|
29421
|
+
return this;
|
|
29422
|
+
};
|
|
29423
|
+
|
|
29424
|
+
/** Removes a tool: an engine control leaves the map, a page element is shown again where the page put it. */
|
|
29425
|
+
SMap.prototype.removeTool = function (id) {
|
|
29426
|
+
var i = this._toolIndex(id);
|
|
29427
|
+
if (i < 0) { return this; }
|
|
29428
|
+
var tool = this._tools[i];
|
|
29429
|
+
this._tools.splice(i, 1);
|
|
29430
|
+
if (tool.el) { tool.el.classList.remove('smap-tool-hidden'); }
|
|
29431
|
+
if (tool.control && this.engine && tool.mounted) { this.engine.removeControl(tool.control); }
|
|
29432
|
+
this._renderToolsControl();
|
|
29433
|
+
return this;
|
|
29434
|
+
};
|
|
29435
|
+
|
|
29436
|
+
/** Shows or hides one tool. A hidden tool keeps its state and shows again as it was (M57). */
|
|
29437
|
+
SMap.prototype.setToolVisible = function (id, visible) {
|
|
29438
|
+
var tool = this._tools[this._toolIndex(id)];
|
|
29439
|
+
if (!tool || this._toolVisible(tool) === !!visible) { return this; }
|
|
29440
|
+
this._setHidden(tool, !visible);
|
|
29441
|
+
this._renderToolsControl();
|
|
29442
|
+
this._toolsChanged(id);
|
|
29443
|
+
return this;
|
|
29444
|
+
};
|
|
29445
|
+
|
|
29446
|
+
/** Shows or hides every tool. The map data credit, the sMap badge and the tools control always stay (M51). */
|
|
29447
|
+
SMap.prototype.setToolsVisible = function (visible) {
|
|
29448
|
+
var changed = false;
|
|
29449
|
+
this._tools.forEach(function (tool) {
|
|
29450
|
+
if (this._toolVisible(tool) !== !!visible) { this._setHidden(tool, !visible); changed = true; }
|
|
29451
|
+
}, this);
|
|
29452
|
+
if (changed) { this._renderToolsControl(); this._toolsChanged(null); }
|
|
29453
|
+
return this;
|
|
29454
|
+
};
|
|
29455
|
+
|
|
29456
|
+
/** The tools in the order added: [{ id, label, visible }]. */
|
|
29457
|
+
SMap.prototype.tools = function () {
|
|
29458
|
+
return this._tools.map(function (tool) { return { id: tool.id, label: tool.label, visible: this._toolVisible(tool) }; }, this);
|
|
29459
|
+
};
|
|
29460
|
+
|
|
29461
|
+
/** Calls handler({ hidden: [ids], changed: id | null }) after every change; the SDK keeps no state itself (M53). */
|
|
29462
|
+
SMap.prototype.onToolsChange = function (handler) { this._toolHandlers.push(handler); return this; };
|
|
29463
|
+
SMap.prototype.offToolsChange = function (handler) {
|
|
29464
|
+
this._toolHandlers = this._toolHandlers.filter(function (h) { return h !== handler; });
|
|
29465
|
+
return this;
|
|
29466
|
+
};
|
|
29467
|
+
|
|
29468
|
+
SMap.prototype._toolIndex = function (id) {
|
|
29469
|
+
for (var i = 0; i < this._tools.length; i++) { if (this._tools[i].id === id) { return i; } }
|
|
29470
|
+
return -1;
|
|
29471
|
+
};
|
|
29472
|
+
SMap.prototype._toolVisible = function (tool) { return !this._toolsHidden[tool.id]; };
|
|
29473
|
+
SMap.prototype._setHidden = function (tool, hidden) {
|
|
29474
|
+
if (hidden) { this._toolsHidden[tool.id] = true; } else { delete this._toolsHidden[tool.id]; }
|
|
29475
|
+
if (tool.el) { tool.el.classList.toggle('smap-tool-hidden', hidden); }
|
|
29476
|
+
};
|
|
29477
|
+
SMap.prototype._toolsChanged = function (id) {
|
|
29478
|
+
var hidden = this._tools.filter(function (t) { return !this._toolVisible(t); }, this).map(function (t) { return t.id; });
|
|
29479
|
+
this._toolHandlers.slice().forEach(function (h) { h({ hidden: hidden, changed: id }); });
|
|
29480
|
+
};
|
|
29481
|
+
|
|
29482
|
+
SMap.prototype._mountTool = function (tool) {
|
|
29483
|
+
// The tools control joins the map with its first tool, so a map without tools is exactly as before.
|
|
29484
|
+
if (this._toolsControlAt && !this._toolsControl && this.engine.addControl) {
|
|
29485
|
+
this._toolsControl = toolsControl(this);
|
|
29486
|
+
this.engine.addControl(this._toolsControl, this._toolsControlAt);
|
|
29487
|
+
}
|
|
29488
|
+
if (tool.control && this.engine.addControl) { this.engine.addControl(tool.control, tool.position); tool.mounted = true; }
|
|
29489
|
+
if (tool.el) { tool.el.classList.toggle('smap-tool-hidden', !this._toolVisible(tool)); }
|
|
29490
|
+
};
|
|
29491
|
+
|
|
29492
|
+
// Called once the engine exists: every tool registered before it.
|
|
29493
|
+
SMap.prototype._mountTools = function () {
|
|
29494
|
+
this._tools.forEach(function (tool) { this._mountTool(tool); }, this);
|
|
29495
|
+
this._renderToolsControl();
|
|
29496
|
+
};
|
|
29497
|
+
SMap.prototype._renderToolsControl = function () { if (this._toolsControl) { this._toolsControl._render(); } };
|
|
29498
|
+
|
|
29499
|
+
// The tools control: one button that opens a panel with one toggle per tool (pressed = shown), Show all and Hide all.
|
|
29500
|
+
// It is not a tool and is never hidden; it joins the map with the first tool and is not drawn while none is left.
|
|
29501
|
+
function toolsControl(map) {
|
|
29502
|
+
var el = null;
|
|
29503
|
+
var button = null;
|
|
29504
|
+
var panel = null;
|
|
29505
|
+
var drawn = null;
|
|
29506
|
+
var text = {};
|
|
29507
|
+
Object.keys(TOOLS_TEXT).forEach(function (k) { text[k] = map._toolsLabels[k] || TOOLS_TEXT[k]; });
|
|
29508
|
+
function open(on) {
|
|
29509
|
+
panel.hidden = !on;
|
|
29510
|
+
button.setAttribute('aria-expanded', on ? 'true' : 'false');
|
|
29511
|
+
}
|
|
29512
|
+
function close() { if (panel && !panel.hidden) { open(false); } }
|
|
29513
|
+
function key(e) { if (e.key === 'Escape' && !panel.hidden) { open(false); button.focus(); } }
|
|
29514
|
+
function make(doc, tag, className, label) {
|
|
29515
|
+
var b = doc.createElement(tag);
|
|
29516
|
+
b.className = className;
|
|
29517
|
+
if (tag === 'button') { b.type = 'button'; }
|
|
29518
|
+
if (label !== undefined) { b.textContent = label; }
|
|
29519
|
+
return b;
|
|
29520
|
+
}
|
|
29521
|
+
var control = {
|
|
29522
|
+
onAdd: function (m) {
|
|
29523
|
+
var doc = m.getContainer().ownerDocument;
|
|
29524
|
+
el = make(doc, 'div', 'maplibregl-ctrl maplibregl-ctrl-group smap-tools');
|
|
29525
|
+
button = make(doc, 'button', 'smap-tools-button');
|
|
29526
|
+
button.innerHTML = TOOLS_ICON;
|
|
29527
|
+
button.title = text.button;
|
|
29528
|
+
button.setAttribute('aria-label', text.button);
|
|
29529
|
+
button.setAttribute('aria-haspopup', 'true');
|
|
29530
|
+
button.addEventListener('click', function () { open(panel.hidden); });
|
|
29531
|
+
panel = make(doc, 'div', 'smap-tools-panel');
|
|
29532
|
+
panel.setAttribute('role', 'group');
|
|
29533
|
+
panel.setAttribute('aria-label', text.button);
|
|
29534
|
+
el.appendChild(button);
|
|
29535
|
+
el.appendChild(panel);
|
|
29536
|
+
el.addEventListener('keydown', key);
|
|
29537
|
+
open(false);
|
|
29538
|
+
m.on('click', close);
|
|
29539
|
+
return el;
|
|
29540
|
+
},
|
|
29541
|
+
onRemove: function (m) {
|
|
29542
|
+
m.off('click', close);
|
|
29543
|
+
if (el && el.parentNode) { el.parentNode.removeChild(el); }
|
|
29544
|
+
el = null;
|
|
29545
|
+
drawn = null;
|
|
29546
|
+
},
|
|
29547
|
+
_render: function () {
|
|
29548
|
+
if (!el) { return; }
|
|
29549
|
+
var doc = el.ownerDocument;
|
|
29550
|
+
el.classList.toggle('smap-tools-empty', map._tools.length === 0);
|
|
29551
|
+
// The same tools as last time: only the pressed states change, so a toggle keeps the keyboard focus.
|
|
29552
|
+
var signature = JSON.stringify(map._tools.map(function (t) { return [t.id, t.label]; }));
|
|
29553
|
+
if (signature === drawn) {
|
|
29554
|
+
map._tools.forEach(function (tool, i) { panel.children[i].setAttribute('aria-pressed', map._toolVisible(tool) ? 'true' : 'false'); });
|
|
29555
|
+
return;
|
|
29556
|
+
}
|
|
29557
|
+
drawn = signature;
|
|
29558
|
+
while (panel.firstChild) { panel.removeChild(panel.firstChild); }
|
|
29559
|
+
map._tools.forEach(function (tool) {
|
|
29560
|
+
var item = make(doc, 'button', 'smap-tools-item', tool.label);
|
|
29561
|
+
item.setAttribute('aria-pressed', map._toolVisible(tool) ? 'true' : 'false');
|
|
29562
|
+
item.setAttribute('data-tool', tool.id);
|
|
29563
|
+
item.addEventListener('click', function () { map.setToolVisible(tool.id, !map._toolVisible(tool)); });
|
|
29564
|
+
panel.appendChild(item);
|
|
29565
|
+
});
|
|
29566
|
+
var all = make(doc, 'div', 'smap-tools-all');
|
|
29567
|
+
var show = make(doc, 'button', 'smap-tools-show-all', text.showAll);
|
|
29568
|
+
show.addEventListener('click', function () { map.setToolsVisible(true); });
|
|
29569
|
+
var hide = make(doc, 'button', 'smap-tools-hide-all', text.hideAll);
|
|
29570
|
+
hide.addEventListener('click', function () { map.setToolsVisible(false); });
|
|
29571
|
+
all.appendChild(show);
|
|
29572
|
+
all.appendChild(hide);
|
|
29573
|
+
panel.appendChild(all);
|
|
29574
|
+
},
|
|
29575
|
+
};
|
|
29576
|
+
return control;
|
|
29577
|
+
}
|
|
29578
|
+
|
|
29326
29579
|
// ------------------------------------------------------------------ Style Specification sources and layers (M24)
|
|
29327
29580
|
|
|
29328
29581
|
function clone(v) { return v === undefined ? undefined : JSON.parse(JSON.stringify(v)); }
|
package/dist/smap.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* Generated by js/build.mjs from js/src (see SOURCE.json). Do not edit. */
|
|
2
|
-
/*! sMap Web SDK 1.1.
|
|
2
|
+
/*! sMap Web SDK 1.1.5. Bundles maplibre-gl 6.16.0 (BSD-3-Clause), see vendor-licenses.txt. */
|
|
3
3
|
|
|
4
4
|
var smapCore = null;
|
|
5
5
|
function smapCreateEngine() {
|
|
@@ -28352,7 +28352,7 @@ function smapCreateSdk(engine, interop) {
|
|
|
28352
28352
|
})(typeof self !== 'undefined' ? self : this, function (engine, interop) {
|
|
28353
28353
|
'use strict';
|
|
28354
28354
|
|
|
28355
|
-
var VERSION = '1.1.
|
|
28355
|
+
var VERSION = '1.1.5';
|
|
28356
28356
|
var FLAVORS = ['light', 'white', 'grayscale', 'dark', 'black'];
|
|
28357
28357
|
var BASEMAP_SOURCE = 'basemap';
|
|
28358
28358
|
var BUILDINGS_LAYER = 'smap-buildings-3d';
|
|
@@ -28805,11 +28805,20 @@ function smapCreateSdk(engine, interop) {
|
|
|
28805
28805
|
// True between a style's load and the next style change. The engine's own isStyleLoaded() turns false while any
|
|
28806
28806
|
// source is loading data, which would leave layers added meanwhile waiting for a load that never comes.
|
|
28807
28807
|
this._styleReady = false;
|
|
28808
|
+
// Map tools (M49-M57): the controls and panels floating on the map that the caller registered, in the order added.
|
|
28809
|
+
var toolOptions = options.tools || {};
|
|
28810
|
+
this._tools = [];
|
|
28811
|
+
this._toolsHidden = {};
|
|
28812
|
+
(toolOptions.hidden || []).forEach(function (id) { this._toolsHidden[id] = true; }, this);
|
|
28813
|
+
this._toolsControlAt = toolOptions.control === undefined ? 'top-right' : toolOptions.control;
|
|
28814
|
+
this._toolsLabels = toolOptions.labels || {};
|
|
28815
|
+
this._toolsControl = null;
|
|
28816
|
+
this._toolHandlers = [];
|
|
28808
28817
|
|
|
28809
28818
|
var self = this;
|
|
28810
28819
|
var engineOptions = {};
|
|
28811
28820
|
for (var k in options) {
|
|
28812
|
-
if (Object.prototype.hasOwnProperty.call(options, k) && ['token', 'getToken', 'apiKey', 'style', 'language', 'baseUrl', 'projection', 'nearest', 'nodes', 'popup', 'popupLoading', 'autoZoom', 'keyboard3D'].indexOf(k) < 0) {
|
|
28821
|
+
if (Object.prototype.hasOwnProperty.call(options, k) && ['token', 'getToken', 'apiKey', 'style', 'language', 'baseUrl', 'projection', 'nearest', 'nodes', 'popup', 'popupLoading', 'autoZoom', 'keyboard3D', 'tools'].indexOf(k) < 0) {
|
|
28813
28822
|
engineOptions[k] = options[k];
|
|
28814
28823
|
}
|
|
28815
28824
|
}
|
|
@@ -28842,6 +28851,7 @@ function smapCreateSdk(engine, interop) {
|
|
|
28842
28851
|
self.engine.addControl(badge, 'bottom-right');
|
|
28843
28852
|
badge._place();
|
|
28844
28853
|
}
|
|
28854
|
+
self._mountTools();
|
|
28845
28855
|
self.engine.on('style.load', function () { self._styleReady = true; self._restore(); });
|
|
28846
28856
|
self._keyboard3D();
|
|
28847
28857
|
// One click handler for every layer's popup: the engine's hit test over those layers, the top feature opens.
|
|
@@ -29325,6 +29335,249 @@ function smapCreateSdk(engine, interop) {
|
|
|
29325
29335
|
SMap.prototype.flyTo = function (o) { this.engine.flyTo(o); return this; };
|
|
29326
29336
|
SMap.prototype.remove = function () { clearTimeout(this._refreshTimer); if (this.engine) { this.engine.remove(); } };
|
|
29327
29337
|
|
|
29338
|
+
// ------------------------------------------------------------------ map tools (M49-M57)
|
|
29339
|
+
|
|
29340
|
+
var TOOL_ID = /^[A-Za-z0-9._-]{1,64}$/;
|
|
29341
|
+
var TOOL_CORNERS = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
|
|
29342
|
+
// The tools the SDK makes by name: the engine control, its English label (the caller may give another) and corner.
|
|
29343
|
+
var TOOL_KINDS = {
|
|
29344
|
+
navigation: { control: 'NavigationControl', label: 'Zoom', position: 'top-left' },
|
|
29345
|
+
geolocate: { control: 'GeolocateControl', label: 'Locate', position: 'top-left' },
|
|
29346
|
+
fullscreen: { control: 'FullscreenControl', label: 'Full screen', position: 'top-left' },
|
|
29347
|
+
scale: { control: 'ScaleControl', label: 'Scale', position: 'bottom-left' },
|
|
29348
|
+
// The mobile SDKs' names for the same controls, so one tool list serves every platform.
|
|
29349
|
+
zoom: { control: 'NavigationControl', label: 'Zoom', position: 'top-left', options: { showCompass: false } },
|
|
29350
|
+
compass: { control: 'NavigationControl', label: 'Compass', position: 'top-left', options: { showZoom: false } },
|
|
29351
|
+
locate: { control: 'GeolocateControl', label: 'Locate', position: 'top-left' },
|
|
29352
|
+
};
|
|
29353
|
+
var TOOLS_ICON = '<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true" focusable="false" fill="none" ' +
|
|
29354
|
+
'stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 7h10M18 7h2M4 17h2M10 17h10"/>' +
|
|
29355
|
+
'<circle cx="16" cy="7" r="2"/><circle cx="8" cy="17" r="2"/></svg>';
|
|
29356
|
+
var TOOLS_TEXT = { button: 'Map tools', showAll: 'Show all', hideAll: 'Hide all' };
|
|
29357
|
+
|
|
29358
|
+
function isElement(v) { return !!v && typeof v === 'object' && v.nodeType === 1; }
|
|
29359
|
+
|
|
29360
|
+
// An engine control whose element the SDK can find again to show or hide it: the control's own onAdd, its element kept.
|
|
29361
|
+
function toolControl(tool, inner) {
|
|
29362
|
+
return {
|
|
29363
|
+
onAdd: function (m) { tool.el = inner.onAdd(m); return tool.el; },
|
|
29364
|
+
onRemove: function (m) { if (inner.onRemove) { inner.onRemove(m); } else if (tool.el && tool.el.parentNode) { tool.el.parentNode.removeChild(tool.el); } tool.el = null; },
|
|
29365
|
+
getDefaultPosition: function () { return tool.position; },
|
|
29366
|
+
};
|
|
29367
|
+
}
|
|
29368
|
+
|
|
29369
|
+
// A page element placed in a corner of the map: it moves into the corner and back where it was when removed.
|
|
29370
|
+
function elementControl(tool, element) {
|
|
29371
|
+
var home = null;
|
|
29372
|
+
var next = null;
|
|
29373
|
+
return {
|
|
29374
|
+
onAdd: function () {
|
|
29375
|
+
home = element.parentNode;
|
|
29376
|
+
next = element.nextSibling;
|
|
29377
|
+
element.classList.add('maplibregl-ctrl', 'smap-tool');
|
|
29378
|
+
tool.el = element;
|
|
29379
|
+
return element;
|
|
29380
|
+
},
|
|
29381
|
+
onRemove: function () {
|
|
29382
|
+
element.classList.remove('maplibregl-ctrl', 'smap-tool');
|
|
29383
|
+
if (home) { home.insertBefore(element, next && next.parentNode === home ? next : null); } else if (element.parentNode) { element.parentNode.removeChild(element); }
|
|
29384
|
+
tool.el = null;
|
|
29385
|
+
},
|
|
29386
|
+
getDefaultPosition: function () { return tool.position; },
|
|
29387
|
+
};
|
|
29388
|
+
}
|
|
29389
|
+
|
|
29390
|
+
/**
|
|
29391
|
+
* Registers a tool floating on the map, shown or hidden by setToolVisible / setToolsVisible and the tools control.
|
|
29392
|
+
* map.addTool('legend', document.getElementById('legend'), { label: 'Legend', position: 'bottom-left' })
|
|
29393
|
+
* map.addTool('zoom', 'navigation', { options: { showCompass: false } })
|
|
29394
|
+
* @param {string} id 1-64 letters, digits, '-', '_', '.'; adding an id again replaces the first
|
|
29395
|
+
* @param {Element|Object|string} target a page element, an engine control (onAdd / onRemove), or a kind the SDK
|
|
29396
|
+
* makes: 'navigation', 'geolocate', 'fullscreen', 'scale', or the mobile SDKs' 'zoom' (navigation without the
|
|
29397
|
+
* compass), 'compass' (without the zoom buttons) and 'locate' (geolocate)
|
|
29398
|
+
* @param {Object} [o] label (shown on its button), position ('top-left', 'top-right', 'bottom-left', 'bottom-right',
|
|
29399
|
+
* or 'none': an element stays where the page put it), options (of a kind's engine control)
|
|
29400
|
+
*/
|
|
29401
|
+
SMap.prototype.addTool = function (id, target, o) {
|
|
29402
|
+
o = o || {};
|
|
29403
|
+
if (typeof id !== 'string' || !TOOL_ID.test(id)) { throw new Error('sMap: a tool id is 1-64 letters, digits, "-", "_" or "."'); }
|
|
29404
|
+
var kind = typeof target === 'string' ? TOOL_KINDS[target] : null;
|
|
29405
|
+
if (typeof target === 'string') {
|
|
29406
|
+
if (!kind) { throw new Error('sMap: unknown tool kind "' + target + '"'); }
|
|
29407
|
+
if (!engine[kind.control]) { throw new Error('sMap: the rendering engine has no ' + kind.control); }
|
|
29408
|
+
} else if (!isElement(target) && !(target && typeof target.onAdd === 'function')) {
|
|
29409
|
+
throw new Error('sMap: a tool is an element, an engine control or a tool kind');
|
|
29410
|
+
}
|
|
29411
|
+
var position = o.position || (kind ? kind.position : (isElement(target) ? (target.parentNode ? 'none' : 'top-left') : 'top-right'));
|
|
29412
|
+
if (position !== 'none' && TOOL_CORNERS.indexOf(position) < 0) { throw new Error('sMap: unknown tool position "' + position + '"'); }
|
|
29413
|
+
if (position === 'none' && !isElement(target)) { throw new Error('sMap: only an element may stay out of the map\'s corners'); }
|
|
29414
|
+
if (this._toolIndex(id) >= 0) { this.removeTool(id); }
|
|
29415
|
+
var tool = { id: id, label: String(o.label || (kind ? kind.label : id)), position: position, el: null, control: null };
|
|
29416
|
+
if (kind) { tool.control = toolControl(tool, new engine[kind.control](o.options || kind.options)); }
|
|
29417
|
+
else if (!isElement(target)) { tool.control = toolControl(tool, target); }
|
|
29418
|
+
else if (position !== 'none') { tool.control = elementControl(tool, target); }
|
|
29419
|
+
else { tool.el = target; }
|
|
29420
|
+
this._tools.push(tool);
|
|
29421
|
+
if (this.engine) { this._mountTool(tool); }
|
|
29422
|
+
this._renderToolsControl();
|
|
29423
|
+
return this;
|
|
29424
|
+
};
|
|
29425
|
+
|
|
29426
|
+
/** Removes a tool: an engine control leaves the map, a page element is shown again where the page put it. */
|
|
29427
|
+
SMap.prototype.removeTool = function (id) {
|
|
29428
|
+
var i = this._toolIndex(id);
|
|
29429
|
+
if (i < 0) { return this; }
|
|
29430
|
+
var tool = this._tools[i];
|
|
29431
|
+
this._tools.splice(i, 1);
|
|
29432
|
+
if (tool.el) { tool.el.classList.remove('smap-tool-hidden'); }
|
|
29433
|
+
if (tool.control && this.engine && tool.mounted) { this.engine.removeControl(tool.control); }
|
|
29434
|
+
this._renderToolsControl();
|
|
29435
|
+
return this;
|
|
29436
|
+
};
|
|
29437
|
+
|
|
29438
|
+
/** Shows or hides one tool. A hidden tool keeps its state and shows again as it was (M57). */
|
|
29439
|
+
SMap.prototype.setToolVisible = function (id, visible) {
|
|
29440
|
+
var tool = this._tools[this._toolIndex(id)];
|
|
29441
|
+
if (!tool || this._toolVisible(tool) === !!visible) { return this; }
|
|
29442
|
+
this._setHidden(tool, !visible);
|
|
29443
|
+
this._renderToolsControl();
|
|
29444
|
+
this._toolsChanged(id);
|
|
29445
|
+
return this;
|
|
29446
|
+
};
|
|
29447
|
+
|
|
29448
|
+
/** Shows or hides every tool. The map data credit, the sMap badge and the tools control always stay (M51). */
|
|
29449
|
+
SMap.prototype.setToolsVisible = function (visible) {
|
|
29450
|
+
var changed = false;
|
|
29451
|
+
this._tools.forEach(function (tool) {
|
|
29452
|
+
if (this._toolVisible(tool) !== !!visible) { this._setHidden(tool, !visible); changed = true; }
|
|
29453
|
+
}, this);
|
|
29454
|
+
if (changed) { this._renderToolsControl(); this._toolsChanged(null); }
|
|
29455
|
+
return this;
|
|
29456
|
+
};
|
|
29457
|
+
|
|
29458
|
+
/** The tools in the order added: [{ id, label, visible }]. */
|
|
29459
|
+
SMap.prototype.tools = function () {
|
|
29460
|
+
return this._tools.map(function (tool) { return { id: tool.id, label: tool.label, visible: this._toolVisible(tool) }; }, this);
|
|
29461
|
+
};
|
|
29462
|
+
|
|
29463
|
+
/** Calls handler({ hidden: [ids], changed: id | null }) after every change; the SDK keeps no state itself (M53). */
|
|
29464
|
+
SMap.prototype.onToolsChange = function (handler) { this._toolHandlers.push(handler); return this; };
|
|
29465
|
+
SMap.prototype.offToolsChange = function (handler) {
|
|
29466
|
+
this._toolHandlers = this._toolHandlers.filter(function (h) { return h !== handler; });
|
|
29467
|
+
return this;
|
|
29468
|
+
};
|
|
29469
|
+
|
|
29470
|
+
SMap.prototype._toolIndex = function (id) {
|
|
29471
|
+
for (var i = 0; i < this._tools.length; i++) { if (this._tools[i].id === id) { return i; } }
|
|
29472
|
+
return -1;
|
|
29473
|
+
};
|
|
29474
|
+
SMap.prototype._toolVisible = function (tool) { return !this._toolsHidden[tool.id]; };
|
|
29475
|
+
SMap.prototype._setHidden = function (tool, hidden) {
|
|
29476
|
+
if (hidden) { this._toolsHidden[tool.id] = true; } else { delete this._toolsHidden[tool.id]; }
|
|
29477
|
+
if (tool.el) { tool.el.classList.toggle('smap-tool-hidden', hidden); }
|
|
29478
|
+
};
|
|
29479
|
+
SMap.prototype._toolsChanged = function (id) {
|
|
29480
|
+
var hidden = this._tools.filter(function (t) { return !this._toolVisible(t); }, this).map(function (t) { return t.id; });
|
|
29481
|
+
this._toolHandlers.slice().forEach(function (h) { h({ hidden: hidden, changed: id }); });
|
|
29482
|
+
};
|
|
29483
|
+
|
|
29484
|
+
SMap.prototype._mountTool = function (tool) {
|
|
29485
|
+
// The tools control joins the map with its first tool, so a map without tools is exactly as before.
|
|
29486
|
+
if (this._toolsControlAt && !this._toolsControl && this.engine.addControl) {
|
|
29487
|
+
this._toolsControl = toolsControl(this);
|
|
29488
|
+
this.engine.addControl(this._toolsControl, this._toolsControlAt);
|
|
29489
|
+
}
|
|
29490
|
+
if (tool.control && this.engine.addControl) { this.engine.addControl(tool.control, tool.position); tool.mounted = true; }
|
|
29491
|
+
if (tool.el) { tool.el.classList.toggle('smap-tool-hidden', !this._toolVisible(tool)); }
|
|
29492
|
+
};
|
|
29493
|
+
|
|
29494
|
+
// Called once the engine exists: every tool registered before it.
|
|
29495
|
+
SMap.prototype._mountTools = function () {
|
|
29496
|
+
this._tools.forEach(function (tool) { this._mountTool(tool); }, this);
|
|
29497
|
+
this._renderToolsControl();
|
|
29498
|
+
};
|
|
29499
|
+
SMap.prototype._renderToolsControl = function () { if (this._toolsControl) { this._toolsControl._render(); } };
|
|
29500
|
+
|
|
29501
|
+
// The tools control: one button that opens a panel with one toggle per tool (pressed = shown), Show all and Hide all.
|
|
29502
|
+
// It is not a tool and is never hidden; it joins the map with the first tool and is not drawn while none is left.
|
|
29503
|
+
function toolsControl(map) {
|
|
29504
|
+
var el = null;
|
|
29505
|
+
var button = null;
|
|
29506
|
+
var panel = null;
|
|
29507
|
+
var drawn = null;
|
|
29508
|
+
var text = {};
|
|
29509
|
+
Object.keys(TOOLS_TEXT).forEach(function (k) { text[k] = map._toolsLabels[k] || TOOLS_TEXT[k]; });
|
|
29510
|
+
function open(on) {
|
|
29511
|
+
panel.hidden = !on;
|
|
29512
|
+
button.setAttribute('aria-expanded', on ? 'true' : 'false');
|
|
29513
|
+
}
|
|
29514
|
+
function close() { if (panel && !panel.hidden) { open(false); } }
|
|
29515
|
+
function key(e) { if (e.key === 'Escape' && !panel.hidden) { open(false); button.focus(); } }
|
|
29516
|
+
function make(doc, tag, className, label) {
|
|
29517
|
+
var b = doc.createElement(tag);
|
|
29518
|
+
b.className = className;
|
|
29519
|
+
if (tag === 'button') { b.type = 'button'; }
|
|
29520
|
+
if (label !== undefined) { b.textContent = label; }
|
|
29521
|
+
return b;
|
|
29522
|
+
}
|
|
29523
|
+
var control = {
|
|
29524
|
+
onAdd: function (m) {
|
|
29525
|
+
var doc = m.getContainer().ownerDocument;
|
|
29526
|
+
el = make(doc, 'div', 'maplibregl-ctrl maplibregl-ctrl-group smap-tools');
|
|
29527
|
+
button = make(doc, 'button', 'smap-tools-button');
|
|
29528
|
+
button.innerHTML = TOOLS_ICON;
|
|
29529
|
+
button.title = text.button;
|
|
29530
|
+
button.setAttribute('aria-label', text.button);
|
|
29531
|
+
button.setAttribute('aria-haspopup', 'true');
|
|
29532
|
+
button.addEventListener('click', function () { open(panel.hidden); });
|
|
29533
|
+
panel = make(doc, 'div', 'smap-tools-panel');
|
|
29534
|
+
panel.setAttribute('role', 'group');
|
|
29535
|
+
panel.setAttribute('aria-label', text.button);
|
|
29536
|
+
el.appendChild(button);
|
|
29537
|
+
el.appendChild(panel);
|
|
29538
|
+
el.addEventListener('keydown', key);
|
|
29539
|
+
open(false);
|
|
29540
|
+
m.on('click', close);
|
|
29541
|
+
return el;
|
|
29542
|
+
},
|
|
29543
|
+
onRemove: function (m) {
|
|
29544
|
+
m.off('click', close);
|
|
29545
|
+
if (el && el.parentNode) { el.parentNode.removeChild(el); }
|
|
29546
|
+
el = null;
|
|
29547
|
+
drawn = null;
|
|
29548
|
+
},
|
|
29549
|
+
_render: function () {
|
|
29550
|
+
if (!el) { return; }
|
|
29551
|
+
var doc = el.ownerDocument;
|
|
29552
|
+
el.classList.toggle('smap-tools-empty', map._tools.length === 0);
|
|
29553
|
+
// The same tools as last time: only the pressed states change, so a toggle keeps the keyboard focus.
|
|
29554
|
+
var signature = JSON.stringify(map._tools.map(function (t) { return [t.id, t.label]; }));
|
|
29555
|
+
if (signature === drawn) {
|
|
29556
|
+
map._tools.forEach(function (tool, i) { panel.children[i].setAttribute('aria-pressed', map._toolVisible(tool) ? 'true' : 'false'); });
|
|
29557
|
+
return;
|
|
29558
|
+
}
|
|
29559
|
+
drawn = signature;
|
|
29560
|
+
while (panel.firstChild) { panel.removeChild(panel.firstChild); }
|
|
29561
|
+
map._tools.forEach(function (tool) {
|
|
29562
|
+
var item = make(doc, 'button', 'smap-tools-item', tool.label);
|
|
29563
|
+
item.setAttribute('aria-pressed', map._toolVisible(tool) ? 'true' : 'false');
|
|
29564
|
+
item.setAttribute('data-tool', tool.id);
|
|
29565
|
+
item.addEventListener('click', function () { map.setToolVisible(tool.id, !map._toolVisible(tool)); });
|
|
29566
|
+
panel.appendChild(item);
|
|
29567
|
+
});
|
|
29568
|
+
var all = make(doc, 'div', 'smap-tools-all');
|
|
29569
|
+
var show = make(doc, 'button', 'smap-tools-show-all', text.showAll);
|
|
29570
|
+
show.addEventListener('click', function () { map.setToolsVisible(true); });
|
|
29571
|
+
var hide = make(doc, 'button', 'smap-tools-hide-all', text.hideAll);
|
|
29572
|
+
hide.addEventListener('click', function () { map.setToolsVisible(false); });
|
|
29573
|
+
all.appendChild(show);
|
|
29574
|
+
all.appendChild(hide);
|
|
29575
|
+
panel.appendChild(all);
|
|
29576
|
+
},
|
|
29577
|
+
};
|
|
29578
|
+
return control;
|
|
29579
|
+
}
|
|
29580
|
+
|
|
29328
29581
|
// ------------------------------------------------------------------ Style Specification sources and layers (M24)
|
|
29329
29582
|
|
|
29330
29583
|
function clone(v) { return v === undefined ? undefined : JSON.parse(JSON.stringify(v)); }
|
|
@@ -30293,7 +30546,7 @@ function SMapMap(options) {
|
|
|
30293
30546
|
SMapMap.prototype = core.Map.prototype;
|
|
30294
30547
|
return new core.Map(options);
|
|
30295
30548
|
}
|
|
30296
|
-
var smapVersion = "1.1.
|
|
30549
|
+
var smapVersion = "1.1.5";
|
|
30297
30550
|
var smapStyles = ['light', 'white', 'grayscale', 'dark', 'black'];
|
|
30298
30551
|
/** The bundled rendering engine, for anything the SDK does not wrap (loaded on the first call). */
|
|
30299
30552
|
function smapGetEngine() { return smapLoad().engine; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superrouteca/smap",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "sMap for the web: maps from Superroute's sMap service, the Web SDK (map view) and the JS client (tokens, nearest node, styles, tiles).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Goodneo Solutions",
|
package/types/smap.d.cts
CHANGED
|
@@ -292,10 +292,39 @@ export interface MapOptions {
|
|
|
292
292
|
popup?: PopupOptions;
|
|
293
293
|
/** Shown while a popup's content is a pending promise (HTML string or DOM node; default pulsing dots). */
|
|
294
294
|
popupLoading?: string | Node;
|
|
295
|
+
/** Map tools: the starting state, where the tools control sits (or false for none) and its labels. */
|
|
296
|
+
tools?: ToolsOptions;
|
|
295
297
|
/** Every other option goes to the rendering engine. */
|
|
296
298
|
[engineOption: string]: unknown;
|
|
297
299
|
}
|
|
298
300
|
|
|
301
|
+
/** A corner of the map, or 'none' for an element that stays where the page put it. */
|
|
302
|
+
export type ToolPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'none';
|
|
303
|
+
/** The tools the SDK makes by name. */
|
|
304
|
+
export type ToolKind = 'navigation' | 'geolocate' | 'fullscreen' | 'scale' | 'zoom' | 'compass' | 'locate';
|
|
305
|
+
export interface ToolOptions {
|
|
306
|
+
/** Shown on the tool's button in the tools control and read by screen readers. */
|
|
307
|
+
label?: string;
|
|
308
|
+
position?: ToolPosition;
|
|
309
|
+
/** Options of a kind's engine control (e.g. `{ showCompass: false }` for navigation). */
|
|
310
|
+
options?: Record<string, unknown>;
|
|
311
|
+
}
|
|
312
|
+
export interface ToolsOptions {
|
|
313
|
+
/** Ids of the tools hidden from the start. */
|
|
314
|
+
hidden?: string[];
|
|
315
|
+
/** Where the tools control sits ('top-right' by default), or false to leave it out. */
|
|
316
|
+
control?: Exclude<ToolPosition, 'none'> | false;
|
|
317
|
+
/** The tools control's texts (English by default). */
|
|
318
|
+
labels?: { button?: string; showAll?: string; hideAll?: string };
|
|
319
|
+
}
|
|
320
|
+
export interface ToolState { id: string; label: string; visible: boolean }
|
|
321
|
+
export interface ToolsChangeEvent {
|
|
322
|
+
/** Ids of the registered tools that are hidden now. */
|
|
323
|
+
hidden: string[];
|
|
324
|
+
/** The tool switched, or null when every tool was switched at once. */
|
|
325
|
+
changed: string | null;
|
|
326
|
+
}
|
|
327
|
+
|
|
299
328
|
/** addData: how the file is read, then the options of addPoints / addLines / addPolygons for its parts. */
|
|
300
329
|
export type DataOptions = ReadOptions & PointOptions & LineOptions & PolygonOptions;
|
|
301
330
|
|
|
@@ -497,6 +526,22 @@ export declare class Map {
|
|
|
497
526
|
closePopup(): this;
|
|
498
527
|
setAutoZoom(on: boolean): this;
|
|
499
528
|
autoZoom(): boolean;
|
|
529
|
+
/**
|
|
530
|
+
* Registers a tool floating on the map: a page element, an engine control, or a kind the SDK makes. Adding an id
|
|
531
|
+
* again replaces the first. The map data credit, the sMap badge and the tools control are never tools.
|
|
532
|
+
*/
|
|
533
|
+
addTool(id: string, target: HTMLElement | { onAdd(map: any): HTMLElement; onRemove?(map: any): void } | ToolKind, options?: ToolOptions): this;
|
|
534
|
+
/** Removes a tool: an engine control leaves the map, a page element is shown again where the page put it. */
|
|
535
|
+
removeTool(id: string): this;
|
|
536
|
+
/** Shows or hides one tool; a hidden tool keeps its state. */
|
|
537
|
+
setToolVisible(id: string, visible: boolean): this;
|
|
538
|
+
/** Shows or hides every tool. */
|
|
539
|
+
setToolsVisible(visible: boolean): this;
|
|
540
|
+
/** The tools in the order added. */
|
|
541
|
+
tools(): ToolState[];
|
|
542
|
+
/** Called after every change; the SDK keeps no state itself. */
|
|
543
|
+
onToolsChange(handler: (event: ToolsChangeEvent) => void): this;
|
|
544
|
+
offToolsChange(handler: (event: ToolsChangeEvent) => void): this;
|
|
500
545
|
on(type: string, ...args: any[]): this;
|
|
501
546
|
off(type: string, ...args: any[]): this;
|
|
502
547
|
once(type: string, ...args: any[]): any;
|
package/types/smap.d.mts
CHANGED
|
@@ -292,10 +292,39 @@ export interface MapOptions {
|
|
|
292
292
|
popup?: PopupOptions;
|
|
293
293
|
/** Shown while a popup's content is a pending promise (HTML string or DOM node; default pulsing dots). */
|
|
294
294
|
popupLoading?: string | Node;
|
|
295
|
+
/** Map tools: the starting state, where the tools control sits (or false for none) and its labels. */
|
|
296
|
+
tools?: ToolsOptions;
|
|
295
297
|
/** Every other option goes to the rendering engine. */
|
|
296
298
|
[engineOption: string]: unknown;
|
|
297
299
|
}
|
|
298
300
|
|
|
301
|
+
/** A corner of the map, or 'none' for an element that stays where the page put it. */
|
|
302
|
+
export type ToolPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'none';
|
|
303
|
+
/** The tools the SDK makes by name. */
|
|
304
|
+
export type ToolKind = 'navigation' | 'geolocate' | 'fullscreen' | 'scale' | 'zoom' | 'compass' | 'locate';
|
|
305
|
+
export interface ToolOptions {
|
|
306
|
+
/** Shown on the tool's button in the tools control and read by screen readers. */
|
|
307
|
+
label?: string;
|
|
308
|
+
position?: ToolPosition;
|
|
309
|
+
/** Options of a kind's engine control (e.g. `{ showCompass: false }` for navigation). */
|
|
310
|
+
options?: Record<string, unknown>;
|
|
311
|
+
}
|
|
312
|
+
export interface ToolsOptions {
|
|
313
|
+
/** Ids of the tools hidden from the start. */
|
|
314
|
+
hidden?: string[];
|
|
315
|
+
/** Where the tools control sits ('top-right' by default), or false to leave it out. */
|
|
316
|
+
control?: Exclude<ToolPosition, 'none'> | false;
|
|
317
|
+
/** The tools control's texts (English by default). */
|
|
318
|
+
labels?: { button?: string; showAll?: string; hideAll?: string };
|
|
319
|
+
}
|
|
320
|
+
export interface ToolState { id: string; label: string; visible: boolean }
|
|
321
|
+
export interface ToolsChangeEvent {
|
|
322
|
+
/** Ids of the registered tools that are hidden now. */
|
|
323
|
+
hidden: string[];
|
|
324
|
+
/** The tool switched, or null when every tool was switched at once. */
|
|
325
|
+
changed: string | null;
|
|
326
|
+
}
|
|
327
|
+
|
|
299
328
|
/** addData: how the file is read, then the options of addPoints / addLines / addPolygons for its parts. */
|
|
300
329
|
export type DataOptions = ReadOptions & PointOptions & LineOptions & PolygonOptions;
|
|
301
330
|
|
|
@@ -497,6 +526,22 @@ export declare class Map {
|
|
|
497
526
|
closePopup(): this;
|
|
498
527
|
setAutoZoom(on: boolean): this;
|
|
499
528
|
autoZoom(): boolean;
|
|
529
|
+
/**
|
|
530
|
+
* Registers a tool floating on the map: a page element, an engine control, or a kind the SDK makes. Adding an id
|
|
531
|
+
* again replaces the first. The map data credit, the sMap badge and the tools control are never tools.
|
|
532
|
+
*/
|
|
533
|
+
addTool(id: string, target: HTMLElement | { onAdd(map: any): HTMLElement; onRemove?(map: any): void } | ToolKind, options?: ToolOptions): this;
|
|
534
|
+
/** Removes a tool: an engine control leaves the map, a page element is shown again where the page put it. */
|
|
535
|
+
removeTool(id: string): this;
|
|
536
|
+
/** Shows or hides one tool; a hidden tool keeps its state. */
|
|
537
|
+
setToolVisible(id: string, visible: boolean): this;
|
|
538
|
+
/** Shows or hides every tool. */
|
|
539
|
+
setToolsVisible(visible: boolean): this;
|
|
540
|
+
/** The tools in the order added. */
|
|
541
|
+
tools(): ToolState[];
|
|
542
|
+
/** Called after every change; the SDK keeps no state itself. */
|
|
543
|
+
onToolsChange(handler: (event: ToolsChangeEvent) => void): this;
|
|
544
|
+
offToolsChange(handler: (event: ToolsChangeEvent) => void): this;
|
|
500
545
|
on(type: string, ...args: any[]): this;
|
|
501
546
|
off(type: string, ...args: any[]): this;
|
|
502
547
|
once(type: string, ...args: any[]): any;
|