@superrouteca/smap 1.1.7 → 1.2.1
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 +57 -0
- package/README.md +118 -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 +3384 -50
- package/dist/smap.css +42 -0
- package/dist/smap.js +3376 -47
- package/dist/smap.mjs +3383 -51
- package/package.json +1 -1
- package/types/smap.d.cts +292 -7
- package/types/smap.d.mts +292 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.1 — 2026-10-28
|
|
4
|
+
|
|
5
|
+
- Pins: the number and the count badge are drawn into each pin at every zoom, so where pins overlap the upper pin
|
|
6
|
+
covers the lower one with its number and badge, as on Superroute's route map. Before, further out than zoom 13
|
|
7
|
+
numbers and badges were their own layers above every pin. `bakeZoom` (a zoom) keeps the former drawing further out
|
|
8
|
+
than it; `bakeZoom: false` at every zoom.
|
|
9
|
+
|
|
10
|
+
## 1.2.0 — 2026-10-28
|
|
11
|
+
|
|
12
|
+
- Maps without WebGL: where the browser has no WebGL 2 (old computers, remote desktops, graphics acceleration
|
|
13
|
+
switched off) or refuses a WebGL context, the map is drawn on a 2D canvas instead — sMap's raster tiles of the same
|
|
14
|
+
scheme, with points, route pins, lines, areas, heat maps, popups, tooltips, custom markers, clusters, drawing and
|
|
15
|
+
selection working through the same calls — so a page is written once. Such a map does not tilt or turn and has no
|
|
16
|
+
3D buildings, terrain, hillshade or 3D models; it says so with an `smap.unsupported` event. `renderer: 'webgl'`
|
|
17
|
+
keeps the WebGL map only, `renderer: 'canvas'` always draws in 2D, and `map.renderer` says which one is in use.
|
|
18
|
+
- Custom markers: `addCustomMarkers(id, data, { render })` puts your own element at each point — any HTML, such as a
|
|
19
|
+
vehicle with its driver's name, a depot icon or a label — above the drawn layers. Elements are made when a point
|
|
20
|
+
first comes into view and are not laid out while out of view, so thousands stay smooth. Anchor, offset, class,
|
|
21
|
+
opacity and z-order per feature, the marker under the pointer brought to the front (`riseOnHover`), clicks and
|
|
22
|
+
popups as on other layers. `setData` keeps the element of every feature still there and renders it again only when
|
|
23
|
+
its properties change; `getMarker(id, key)` gives one marker's element.
|
|
24
|
+
- Dragging: points (`addPoints`) and custom markers take `draggable` (for every feature or per feature) with
|
|
25
|
+
`onDragStart`, `onDrag` and `onDragEnd`. The map does not pan while dragging, the release is not a click, and the
|
|
26
|
+
layer's data holds the new position afterwards (a copy: the objects you gave are not changed). A dragged point of
|
|
27
|
+
a large layer costs two data updates, whatever the layer's size.
|
|
28
|
+
- Tooltips: every layer takes `tooltip` (a template or a function) shown while the pointer is over a feature —
|
|
29
|
+
beside a point or a custom marker, at the pointer on lines and areas — with `direction`, `offset` and `className`.
|
|
30
|
+
- Line labels: `addLines(…, { label: 'name' })` writes a property along each line as a permanent label.
|
|
31
|
+
- Clusters with their own look: `cluster.ring` draws each cluster as its count inside a ring of its points' colours
|
|
32
|
+
(each colour's share of the points, e.g. the drivers whose stops it holds), and `cluster.html(cluster)` draws each
|
|
33
|
+
cluster yourself from its count, its properties and its points. A click still zooms in to where it splits
|
|
34
|
+
(`zoomOnClick: false` turns it off); `maxZoom` is the last zoom with clusters.
|
|
35
|
+
- Controls: a layer switcher (`addTool('layers', 'layers', { options: { base, overlays } })`) chooses one base map at
|
|
36
|
+
a time — a scheme, a custom style or imagery — and turns overlays on and off, reporting each change. `setBaseImagery`
|
|
37
|
+
shows satellite or aerial tiles in place of the street map, with or without the street map's labels on top, your
|
|
38
|
+
layers staying above. `addControl` puts any element or control in a corner without making it a tool. The full
|
|
39
|
+
screen tool takes `{ container }` to make a page element (the map with its side panels) full screen.
|
|
40
|
+
- Drawing and editing: `drawTool()` draws polygons, rectangles, circles, lines and points and edits them — drag a
|
|
41
|
+
vertex, drag a midpoint to add one, move a whole shape, delete a vertex or a shape, draw a hole in a polygon — with
|
|
42
|
+
snapping to other shapes' vertices, undo and redo, keyboard keys and a toolbar whose texts can be translated.
|
|
43
|
+
Rectangles stay rectangles and circles keep their centre and radius. Every change is reported with the shapes as
|
|
44
|
+
GeoJSON.
|
|
45
|
+
- Area selection: `selectArea({ mode: 'box' | 'lasso' })` lets the user draw a box or a free shape and answers the
|
|
46
|
+
features of each layer inside it.
|
|
47
|
+
- Heat maps: `addHeatmap(id, points, { weight, radius, intensity, colors })`.
|
|
48
|
+
- Google base maps: `setGoogleBase({ session, key })` shows Google's road or satellite map read straight from Google
|
|
49
|
+
with a Map Tiles session your server made with your own Google key, with the Google logo and the copyright of the
|
|
50
|
+
area in view; `onFail` is called when Google's tiles do not load.
|
|
51
|
+
- 3D models: `addModels(id, points, { model, size, heading })` places a glTF model at each point, turned to its
|
|
52
|
+
heading, in the map's 3D view (three.js handed over once with `sMap.useThree(THREE, GLTFLoader)`).
|
|
53
|
+
- Terrain: `setTerrain({ tiles, encoding, exaggeration, hillshade })` draws the map over elevation tiles (seen when
|
|
54
|
+
tilted) with hillshading under the roads; kept across scheme and language changes.
|
|
55
|
+
- Synced maps: `syncWith(other, { offsetZoom })` keeps two maps on the same view, both ways (a picture in picture).
|
|
56
|
+
- Drawn tiles: `addCanvasTiles(id, draw)` shows raster tiles your page paints on a canvas.
|
|
57
|
+
- Geometry helpers: `sMap.geo` — `distance`, `length`, `bounds`, `pointInPolygon` (with holes), `nearestPointOnLine`,
|
|
58
|
+
`distanceToLine`, `decodePolyline` and `encodePolyline`.
|
|
59
|
+
|
|
3
60
|
## 1.1.7 — 2026-10-28
|
|
4
61
|
|
|
5
62
|
- Plan editor: faster edits through sMap's fast path, with no code change. When your plan editor token answer names a
|
package/README.md
CHANGED
|
@@ -65,6 +65,23 @@ SDK does not wrap, and `getEngine()` gives the renderer itself.
|
|
|
65
65
|
In a server-rendered page (for example Next.js), create the map in an effect or event handler, never while rendering
|
|
66
66
|
on the server: `new Map()` throws outside a browser. Importing the package is fine anywhere.
|
|
67
67
|
|
|
68
|
+
## Without WebGL
|
|
69
|
+
|
|
70
|
+
Where the browser has no WebGL 2 (old computers, remote desktops, graphics acceleration switched off) or refuses a
|
|
71
|
+
WebGL context, the map is drawn on a 2D canvas: sMap's raster tiles of the same scheme and language, with your
|
|
72
|
+
points, pins, lines, areas, heat maps, popups, tooltips, custom markers, clusters, drawing and selection drawn by the
|
|
73
|
+
SDK through the same calls. Your page needs nothing of its own.
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
const map = new Map({ container: 'map', apiKey: 'smk_…', renderer: 'auto' }); // 'webgl' | 'canvas' to choose
|
|
77
|
+
map.renderer; // 'webgl' or 'canvas'
|
|
78
|
+
map.on('smap.unsupported', (e) => console.info('not without WebGL:', e.feature));
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
A canvas map does not tilt or turn and has no 3D buildings, terrain, hillshade or 3D models; asking for one of them
|
|
82
|
+
fires `smap.unsupported`. Style layers of your own are drawn when they are raster, fill, line, circle, symbol or
|
|
83
|
+
heatmap layers.
|
|
84
|
+
|
|
68
85
|
## Popups
|
|
69
86
|
|
|
70
87
|
Give a layer a `popup` and a click on one of its features opens it. A map has one popup: opening another closes the
|
|
@@ -201,6 +218,52 @@ map.addPoints('stops', stops, { // {lng, lat, stop_number, status_colo
|
|
|
201
218
|
Numbers and badges are drawn over all pins of the layer, so where pins overlap a lower pin's number can show through
|
|
202
219
|
an upper pin.
|
|
203
220
|
|
|
221
|
+
## Custom markers, dragging and tooltips
|
|
222
|
+
|
|
223
|
+
**Custom markers** put your own element at each point, above the drawn layers. `render` returns an element or
|
|
224
|
+
trusted HTML (inserted as is: escape feature data yourself). An element is made the first time its point comes into
|
|
225
|
+
view and is left out of the page while out of view, so a layer of thousands stays smooth.
|
|
226
|
+
|
|
227
|
+
```js
|
|
228
|
+
map.addCustomMarkers('vehicles', vehicles, { // [{ lng, lat, id, name, color, heading }, …]
|
|
229
|
+
idProperty: 'id',
|
|
230
|
+
anchor: 'center', // or top, bottom, left, right, top-left, … (default center)
|
|
231
|
+
render: (p) => `<div class="truck" style="--c:${p.color}">${escapeHtml(p.name)}</div>`,
|
|
232
|
+
zIndex: { property: 'priority' }, // per feature: a constant, a function or { property }
|
|
233
|
+
riseOnHover: true,
|
|
234
|
+
popup: '<b>{name}</b>',
|
|
235
|
+
tooltip: '{name}',
|
|
236
|
+
});
|
|
237
|
+
map.setData('vehicles', moved); // elements of features still there are kept (and only moved)
|
|
238
|
+
map.getMarker('vehicles', 'v-17'); // one marker's element
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Dragging**: points and custom markers take `draggable` (true, or per feature) and `onDragStart` / `onDrag` /
|
|
242
|
+
`onDragEnd(feature, { lngLat, point, originalEvent })`. The map does not pan while a feature is dragged, the release
|
|
243
|
+
is not a click, and the layer's data holds the new position afterwards (a copy of your data).
|
|
244
|
+
|
|
245
|
+
```js
|
|
246
|
+
map.addPoints('stops', stops, {
|
|
247
|
+
marker: { text: { property: 'stop_number' } },
|
|
248
|
+
draggable: (p) => !p.done,
|
|
249
|
+
onDragEnd: (f, e) => save(f.properties.id, e.lngLat),
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**Tooltips**: any layer takes `tooltip` — a template (`'{name}'`, each property HTML-escaped) or a function returning
|
|
254
|
+
trusted HTML or a node — shown while the pointer is over a feature: beside a point or custom marker, at the pointer
|
|
255
|
+
on lines and areas. `tooltipOptions`: `direction` (`top` default, `bottom`, `left`, `right`), `offset`, `className`.
|
|
256
|
+
A map shows one tooltip at a time. **Line labels**: `addLines(id, data, { label: 'name' })` writes a property along
|
|
257
|
+
each line (`labelSpacing`, `labelColor`).
|
|
258
|
+
|
|
259
|
+
**Clusters with their own look**: `cluster.ring` draws each cluster as its count inside a ring of its points' colours
|
|
260
|
+
(each colour's share), `cluster.html(cluster)` draws it yourself (`cluster.count`, `cluster.properties`,
|
|
261
|
+
`await cluster.leaves(limit)`). A click zooms in to where the cluster splits (`zoomOnClick: false` turns it off).
|
|
262
|
+
|
|
263
|
+
```js
|
|
264
|
+
map.addPoints('stops', stops, { marker: { … }, cluster: { radius: 60, maxZoom: 14, ring: 'route_color' } });
|
|
265
|
+
```
|
|
266
|
+
|
|
204
267
|
## Map tools: showing and hiding controls and panels
|
|
205
268
|
|
|
206
269
|
Register what floats on the map, and the map gets a tools control (one button, the last of the map's toolbar) that
|
|
@@ -241,6 +304,61 @@ map.tools(); // [{ id: 'zoom', label: 'Zoom', visible: true }, …]
|
|
|
241
304
|
like (the page's storage, your server).
|
|
242
305
|
- The tools control joins the map with the first tool; a map without tools is unchanged.
|
|
243
306
|
|
|
307
|
+
### Layer switcher, imagery and your own controls
|
|
308
|
+
|
|
309
|
+
```js
|
|
310
|
+
map.addTool('layers', 'layers', { label: 'Layers', options: {
|
|
311
|
+
base: [
|
|
312
|
+
{ id: 'streets', label: 'Streets', style: 'light' },
|
|
313
|
+
{ id: 'satellite', label: 'Satellite', imagery: { tiles: ['https://imagery.example/{z}/{y}/{x}'], maxzoom: 19, attribution: '© Example' } },
|
|
314
|
+
{ id: 'hybrid', label: 'Hybrid', imagery: { tiles: ['https://imagery.example/{z}/{y}/{x}'], labels: true } },
|
|
315
|
+
],
|
|
316
|
+
overlays: [{ id: 'traffic', label: 'Traffic', layers: ['traffic'], visible: false }],
|
|
317
|
+
onChange: ({ base, overlays }) => save(base, overlays),
|
|
318
|
+
} });
|
|
319
|
+
map.setBaseImagery({ tiles: […], labels: true }); // or null for the street map
|
|
320
|
+
map.addControl(document.getElementById('legend'), 'bottom-left'); // in a corner, not a tool
|
|
321
|
+
map.addTool('fullscreen', 'fullscreen', { options: { container: document.getElementById('stage') } });
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Imagery is drawn over the basemap's land, water and roads and under its labels (kept with `labels: true`); your
|
|
325
|
+
layers stay on top. The scheme already shown is not loaded again when only the imagery changes.
|
|
326
|
+
|
|
327
|
+
## Drawing, editing and selecting
|
|
328
|
+
|
|
329
|
+
```js
|
|
330
|
+
const draw = map.drawTool({ features: zones, modes: ['polygon', 'rectangle', 'circle'], labels: { polygon: 'Zone' } });
|
|
331
|
+
draw.on('change', (e) => save(e.features)); // created, edited, deleted: every shape as GeoJSON
|
|
332
|
+
draw.start('polygon'); // or from the toolbar
|
|
333
|
+
draw.select(zoneId); draw.delete(); draw.undo();
|
|
334
|
+
|
|
335
|
+
const picked = await map.selectArea({ mode: 'lasso', layers: ['stops'] });
|
|
336
|
+
if (picked) { assign(picked.features.stops); }
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Drawing: click to add vertices; a click on the first vertex, a double click or Enter finishes, Backspace removes the
|
|
340
|
+
last vertex, Escape cancels. Rectangles and circles are dragged. A selected shape shows its vertices and midpoints:
|
|
341
|
+
drag a vertex, drag a midpoint to add a vertex, drag the shape to move it, Delete removes the selected vertex or the
|
|
342
|
+
shape, Ctrl/⌘+Z undoes (with Shift redoes). New and moved vertices snap to other shapes' vertices within 10 px.
|
|
343
|
+
|
|
344
|
+
## Heat maps, terrain, synced maps, drawn tiles and geometry
|
|
345
|
+
|
|
346
|
+
```js
|
|
347
|
+
map.addHeatmap('density', stops, { weight: { property: 'orders' }, radius: 25, colors: ['#ffffb2', '#fd8d3c', '#bd0026'] });
|
|
348
|
+
map.setTerrain({ tiles: ['https://dem.example/terrarium/{z}/{x}/{y}.png'], encoding: 'terrarium', exaggeration: 1.5 });
|
|
349
|
+
const stop = map.syncWith(overview, { offsetZoom: -4 }); // a picture in picture; stop() ends it
|
|
350
|
+
map.addCanvasTiles('grid', (ctx, z, x, y, { size }) => { ctx.strokeRect(0, 0, size, size); }, { opacity: 0.5 });
|
|
351
|
+
|
|
352
|
+
map.setGoogleBase({ session, key, type: 'satellite', onFail: () => map.setGoogleBase(null) }); // Google's own tiles
|
|
353
|
+
sMap.useThree(THREE, GLTFLoader); // once, for 3D models
|
|
354
|
+
map.addModels('vans', vehicles, { model: '/models/van.glb', size: 1, heading: { property: 'bearing' } });
|
|
355
|
+
|
|
356
|
+
sMap.geo.distance([-79.38, 43.65], [-73.57, 45.5]); // metres
|
|
357
|
+
sMap.geo.pointInPolygon([lng, lat], zone.geometry); // holes and multi-polygons
|
|
358
|
+
sMap.geo.nearestPointOnLine(route.geometry, [lng, lat]); // { point, distance, index, along }
|
|
359
|
+
sMap.geo.decodePolyline(shape, 6); // [[lng, lat], …]
|
|
360
|
+
```
|
|
361
|
+
|
|
244
362
|
## Plan editor: editing routes on the map
|
|
245
363
|
|
|
246
364
|
`map.planEditor(options)` lets a person edit a plan of routes on the map: drag a stop within its route or onto another
|
package/dist/SOURCE.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
|
-
"sdkVersion": "1.1
|
|
2
|
+
"sdkVersion": "1.2.1",
|
|
3
3
|
"engine": "maplibre-gl 6.16.0",
|
|
4
4
|
"files": {
|
|
5
|
-
"smap.js": "
|
|
6
|
-
"smap.css": "
|
|
7
|
-
"smap-client.js": "
|
|
5
|
+
"smap.js": "bbce8821ec3564f5fc7498b0e7973636e98650e956d94a51a2dbd2259b71b89b",
|
|
6
|
+
"smap.css": "9bc4b14821de97da199e6af4f18541eeaf53a2ae91e5831e7224f57fe6b77660",
|
|
7
|
+
"smap-client.js": "5c769f3f9e4e82d3e7c25bfbd8b91f85f106161f65328fe6eaf19eab6561e897",
|
|
8
8
|
"smap-client.d.ts": "5f0df11bf60c5a9ced34522a284de81260c27871678ab772f16da9ccf6883f58",
|
|
9
|
-
"smap.mjs": "
|
|
10
|
-
"smap.cjs": "
|
|
11
|
-
"smap-client.cjs": "
|
|
12
|
-
"smap-client.mjs": "
|
|
9
|
+
"smap.mjs": "8edb30186a60969440415b75f6b14b04eea317dc83637dc49e1757ded0c9b0de",
|
|
10
|
+
"smap.cjs": "5bfc4ff01ed19e861ffde2b908f5509c774912fe4d305c6f8269cb4d9f7eeb69",
|
|
11
|
+
"smap-client.cjs": "13a379343810b63bdaa060499d63844e133d28c00649811dcfe107b5dfbabb53",
|
|
12
|
+
"smap-client.mjs": "58f6aa8cb2cec09569606b088247b0e7803cdf225d5ceb733ae3115572a36241",
|
|
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.2.1 — 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.2.1';
|
|
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.2.1 — 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.2.1';
|
|
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.2.1 — 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.2.1';
|
|
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
|
|