Home button fits all of Slovakia; add an overview map, top-right
CI / check (push) Successful in 1m33s
CI / deploy (push) Successful in 27s

Home now fitBounds()s a country-wide bbox instead of resetting to
CENTER/ZOOM's Bratislava point, since Home resetting into the same
city you'd already be looking at wasn't useful.

The overview map is NPS's own overview plugin (npmap5-plugins, still
on an unmerged branch), vendored and converted from its UMD dist
build to a plain ES module. Patched one MapLibre API break found while
verifying it: the plugin reads map.transform (public in the MapLibre
~2.4 it targets) to relax the inset's polar pan limit; MapLibre 6 (this
app's vendored version) no longer exposes .transform at all, so it
threw on load. Guarded to skip that cosmetic adjustment when absent
instead.
This commit is contained in:
randy committed 2026-09-07 22:30:56 +02:00
1 parent ddf2ee4990
commit 96065b1237
7 files changed
+441 -31

No files matched your search

+29 -15
View File
@@ -137,26 +137,40 @@ Now that any view can be the starting one (via that permalink), a way
back to the app's actual default is worth having: a "Home" button back to the app's actual default is worth having: a "Home" button
(`public/vendor/npmap-home-button/`, the National Park Service's own (`public/vendor/npmap-home-button/`, the National Park Service's own
`home-button` MapLibre control — see `docs/third-party-notices.adoc`) `home-button` MapLibre control — see `docs/third-party-notices.adoc`)
sits top-left on the map, pinned to `CENTER`/`ZOOM` explicitly rather sits top-left on the map. It fits to `SLOVAKIA_BOUNDS` (a country-wide
than its own fallback (the view at construction time, which would just bounding box) rather than the plain `CENTER`/`ZOOM` point the map
be wherever a loaded permalink happened to point). It resets to the itself starts at — "home" is meant as a full-country overview, not a
app's default view, not the visitor's own location — that's re-centering on Bratislava. It resets to that fixed default view, not
`GeolocateControl`, a separate button in the same stack (below). the visitor's own location — that's `GeolocateControl`, a separate
button in the same stack (below).
That Home button is the top of a small top-left stack — Home, zoom That Home button is the top of a small top-left stack — Home, zoom
in/out (`NavigationControl`, `showCompass: false` since this map never in/out (`NavigationControl`, `showCompass: false` since this map never
rotates), a passive zoom-level readout (`ZoomLevelControl`, a plain div rotates), a passive zoom-level readout (`ZoomLevelControl`, a plain div
updated on the map's `zoom` event — not a button, since it has no updated on the map's `zoom` event — not a button, since it has no
click behavior of its own), locate-me (`GeolocateControl`), and a click behavior of its own), a distance/area measuring tool
"Base map" button — matching the National Park Service's own map (`MeasureControl`, `public/js/measure.js`), locate-me
control layout (grouped (`GeolocateControl`), and a "Base map" button — matching the National
together on the map itself, rather than split across corners or Park Service's own map control layout (grouped together on the map
between the map and a side panel). The last of those, itself, rather than split across corners or between the map and a side
`MapLayersButton` (`public/js/map.js`), is a second entry point into panel). The last of those, `MapLayersButton` (`public/js/map.js`), is
the exact same Online/Offline panel `LayerToggleControl` already a second entry point into the exact same Online/Offline panel
manages in the page's own sidebar — both call the same `LayerToggleControl` already manages in the page's own sidebar — both
`LayerToggleControl#toggle()`, so there's one source of truth for the call the same `LayerToggleControl#toggle()`, so there's one source of
panel's open/closed state either way. truth for the panel's open/closed state either way.
A separate control sits top-right: a small inset overview map
(`public/vendor/npmap-overview/`, NPS's `overview` plugin — see
`docs/nps-resources.adoc`) showing the current view's location in a
wider, zoomed-out context, with the visible area drawn as a box on top
of it; dragging that box pans the main map. It clones whichever base
style the main map is currently showing (`style: ''`, its own default —
the plugin reads `map.style.serialize()`) rather than a separate style
of its own, so it stays visually consistent with the Online/Offline
toggle without this app maintaining a second style for it. Vendored
from an unmerged upstream branch and patched for a MapLibre API break
(it targeted MapLibre ~2.4's public `map.transform`, since removed) —
see `docs/third-party-notices.adoc` for the exact patch.
=== Debug inspector (Alt+click) === Debug inspector (Alt+click)
+13 -8
View File
@@ -27,6 +27,10 @@ checking here before searching from zero next time.
| Park Tiles color palette (offline basemap theme) | Park Tiles color palette (offline basemap theme)
| `public/js/map.js`'s `OFFLINE_THEME` | `public/js/map.js`'s `OFFLINE_THEME`
| Colors only — see <<park-tiles>> for why the actual tile service isn't used | Colors only — see <<park-tiles>> for why the actual tile service isn't used
| `overview` (top-right minimap/inset control)
| `public/vendor/npmap-overview/`
| MIT (per that branch's `package.json`); same public-domain repo as above
|=== |===
See `docs/third-party-notices.adoc` for the formal vendored-library See `docs/third-party-notices.adoc` for the formal vendored-library
@@ -99,18 +103,19 @@ https://github.com/nationalparkservice/npmap5-plugins/issues/7[#7].
=== On unmerged feature branches (less vetted — not on `main` yet) === On unmerged feature branches (less vetted — not on `main` yet)
`overview` (branch `maplibre-gl-overview`) has since been adopted —
see "What this app actually uses" above and
`docs/architecture.adoc`'s control-stack section. Live demo (as
upstream ships it, unpatched):
https://raw.githack.com/nationalparkservice/npmap5-plugins/maplibre-gl-overview/examples/index.html.
Note: MapLibre GL JS has no first-party minimap of its own — this
isn't more "official" than any other third-party minimap plugin, just
NPS-flavored.
[cols="1,3"] [cols="1,3"]
|=== |===
| Plugin | What it is | Plugin | What it is
| `overview` (branch `maplibre-gl-overview`)
| A minimap/inset control, any corner, respects pitch/bearing. Live
demo: https://raw.githack.com/nationalparkservice/npmap5-plugins/maplibre-gl-overview/examples/index.html.
Note: MapLibre GL JS has no first-party minimap of its own — this
wouldn't be more "official" than any other third-party minimap
plugin, just NPS-flavored. No minimap has been requested for this
app; would be a nice-to-have, not a fix for anything.
| `carto` (branch `maplibre-gl-carto-source`) | `carto` (branch `maplibre-gl-carto-source`)
| Adds a vector-tile source backed by Carto.com-hosted data. Only | Adds a vector-tile source backed by Carto.com-hosted data. Only
useful if we actually have a Carto-hosted dataset to point at — we useful if we actually have a Carto-hosted dataset to point at — we
+13
View File
@@ -36,8 +36,21 @@ required):
| NPS Home Button (`home-button`) | NPS Home Button (`home-button`)
| 0.0.1-d | 0.0.1-d
| https://github.com/nationalparkservice/npmap5-plugins/tree/main/home-button | https://github.com/nationalparkservice/npmap5-plugins/tree/main/home-button
| NPS Overview Map (`maplibre-gl-overview`)
| 5.0.1
| https://github.com/nationalparkservice/npmap5-plugins/tree/maplibre-gl-overview
|=== |===
The overview map is vendored from an unmerged branch, not `main` (see
`docs/nps-resources.adoc`), and converted from its UMD dist build to a
plain ES module — no functional change except the module wrapper. It
was also patched for a MapLibre API break: it reads `map.transform`
(public in the MapLibre ~2.4 this plugin targets) to relax the
overview's polar pan limit, but MapLibre 6's `Map` no longer exposes
`.transform` at all — guarded to skip that (cosmetic) adjustment
instead of throwing when it's absent.
Offline map text labels need font glyphs too (see Offline map text labels need font glyphs too (see
`docs/architecture.adoc`), vendored under `public/vendor/fonts/` — `docs/architecture.adoc`), vendored under `public/vendor/fonts/` —
SIL Open Font License, not BSD-3-Clause like the above: SIL Open Font License, not BSD-3-Clause like the above:
+6
View File
@@ -472,6 +472,12 @@ html, body {
word-break: break-word; word-break: break-word;
} }
.maplibregl-ctrl-overview-map {
border-radius: 4px;
overflow: hidden;
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
}
.measure-ctrl { .measure-ctrl {
position: relative; position: relative;
} }
+29 -8
View File
@@ -14,6 +14,8 @@ import { MeasureControl } from "/js/measure.js";
import { LAYERS_ICON } from "/js/icons.js"; import { LAYERS_ICON } from "/js/icons.js";
import { notifySidePanelOpen, onlyOneSidePanelOpen } from "/js/panels.js"; import { notifySidePanelOpen, onlyOneSidePanelOpen } from "/js/panels.js";
import HomeButton from "/vendor/npmap-home-button/home-button.esm.js"; import HomeButton from "/vendor/npmap-home-button/home-button.esm.js";
import OverviewMap from "/vendor/npmap-overview/overview.esm.js";
import * as maplibregl from "/vendor/maplibre-gl/maplibre-gl.mjs";
const CENTER = [17.1077, 48.1486]; const CENTER = [17.1077, 48.1486];
const ZOOM = 13; const ZOOM = 13;
@@ -235,14 +237,18 @@ const map = new MaplibreMap({
// all grouped together rather than split across corners. Added in this // all grouped together rather than split across corners. Added in this
// order since MapLibre stacks same-position controls in add order. // order since MapLibre stacks same-position controls in add order.
// //
// homePosition/zoom pinned to the app's own default rather than left to the // bounds (rather than homePosition/zoom) so Home resets to an overview of
// button's own fallback (current center/zoom at construction) — now that // the whole country, not back to CENTER/ZOOM's initial Bratislava view —
// the URL hash can restore any view on load (see the Hash option above), // now that the URL hash can restore any view on load (see the Hash option
// "current view" and "the default view" are no longer the same thing, and // above), "current view" and "the default view" are no longer the same
// a home button that resets to wherever you happened to load the page // thing, and a home button that resets to wherever you happened to load
// wouldn't be a home button. This is *not* "go to my location" — that's // the page wouldn't be a home button. This is *not* "go to my location" —
// GeolocateControl, below. // that's GeolocateControl, below.
map.addControl(new HomeButton({ homePosition: CENTER, zoom: ZOOM }), "top-left"); const SLOVAKIA_BOUNDS = [
[16.83, 47.73],
[22.57, 49.61],
];
map.addControl(new HomeButton({ bounds: SLOVAKIA_BOUNDS }), "top-left");
// showCompass: false — this map never rotates, so a bearing-reset button // showCompass: false — this map never rotates, so a bearing-reset button
// (NavigationControl's default third button) would just be dead weight. // (NavigationControl's default third button) would just be dead weight.
map.addControl(new NavigationControl({ showCompass: false }), "top-left"); map.addControl(new NavigationControl({ showCompass: false }), "top-left");
@@ -257,6 +263,21 @@ map.addControl(
"top-left", "top-left",
); );
// A small inset map showing where the current view sits in context — NPS's
// own overview plugin (docs/nps-resources.adoc's "overview" entry, still on
// an unmerged branch upstream). It draws its own embedded MapLibre map, so
// it needs the maplibregl module itself (not just the Map class) — style
// '' (the default) means it clones whatever the main map's current style
// is (`this._mainMap.style.serialize()`), so it stays in sync with the
// Online/Offline toggle without a second style to maintain here. Built only
// once the main map's own style has loaded, matching the plugin's own
// example — its internal map is constructed eagerly in the constructor,
// before that clone happens in onAdd.
map.once("style.load", () => {
const OverviewMapControl = OverviewMap(maplibregl);
map.addControl(new OverviewMapControl({}), "top-right");
});
const sidebar = document.getElementById("sidebar"); const sidebar = document.getElementById("sidebar");
const layerToggle = new LayerToggleControl(applyStyle); const layerToggle = new LayerToggleControl(applyStyle);
+5
View File
@@ -0,0 +1,5 @@
### LICENSE.md
This project constitutes a work of the United States Government and is not subject to domestic copyright protection under [17 USC § 105](https://www.govinfo.gov/app/details/USCODE-2010-title17/USCODE-2010-title17-chap1-sec105).
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+346
View File
@@ -0,0 +1,346 @@
// Vendored from nationalparkservice/npmap5-plugins, branch
// maplibre-gl-overview (not yet merged to main — see
// docs/nps-resources.adoc). MIT-licensed per that branch's package.json;
// see LICENSE.md alongside this file for the repo's own notice.
//
// Converted from its UMD dist build (dist/maplibre-gl-overview.min.js) to a
// plain ES module export — the only change from upstream besides that
// wrapper swap.
const blankGeoJsonFeature = () => ({
"type": "FeatureCollection",
"features": []
});
const between = (min, value, max) => Math.min(max, Math.max(min, value));
function OverviewMap(mapLibrary) {
return class OverviewMapControl {
constructor(options) {
this._extent = blankGeoJsonFeature();
this._moving = false;
this._easingMain = false;
this._keyboardEvents = (e) => {
if (e.altKey || e.ctrlKey || e.metaKey)
return;
// The +1 directions are in Pixel space, not LngLat, in pixel space 0,0 it the top left
const events = {
"ArrowLeft": () => {
e.preventDefault();
return { xDir: 1 };
},
"ArrowRight": () => {
e.preventDefault();
return { xDir: -1 };
},
"ArrowUp": () => {
e.preventDefault();
return { yDir: 1 };
},
"ArrowDown": () => {
e.preventDefault();
return { yDir: -1 };
},
"+": () => ({ zoomDir: +1 }),
"-": () => ({ zoomDir: -1 }),
};
if (events[e.key]) {
// Update the variables
let { xDir, yDir, zoomDir } = events[e.key]();
xDir = xDir || 0;
yDir = yDir || 0;
zoomDir = zoomDir || 0;
if (this._mainMap) {
const zoomMain = this._mainMap.getZoom();
// Convert the current center of the overview map to pixel space
const overviewMapCenterPixels = this._overviewMap.project(this._overviewMap.getCenter());
// Get the point that would be panned that center
const newCenter = this._overviewMap.unproject(new this._mapLibrary.Point(overviewMapCenterPixels.x + (xDir * this._overviewMap.keyboard._panStep), overviewMapCenterPixels.y + (yDir * this._overviewMap.keyboard._panStep)));
// Get the current center of the main map
const mainMapCenterPixels = this._mainMap.project(this._mainMap.getCenter());
// Get the new point on the main map in pixels
const mainMapNewCenterPixels = this._mainMap.project(newCenter);
// Define the offset to pan to
const xyOffset = {
x: mainMapNewCenterPixels.x - mainMapCenterPixels.x,
y: mainMapNewCenterPixels.y - mainMapCenterPixels.y
};
this._mainMap.easeTo({
duration: 300,
easeId: 'keyboardHandler',
easing: (t) => t * (2 - t),
zoom: zoomDir ? Math.round(zoomMain) + zoomDir * (e.shiftKey ? 2 : 1) : zoomMain,
offset: [xyOffset.x, xyOffset.y],
center: this._mainMap.getCenter()
}, { originalEvent: e });
}
}
};
// Create a container for the overview map
this._container = document.createElement("div");
this._container.className = "maplibregl-ctrl-overview-map maplibregl-ctrl";
this._container.addEventListener("contextmenu", (e) => e.preventDefault());
// options
const defaultOptions = {
zoomLevelOffset: -5,
watchEvents: ['move', 'rotate', 'pitch'],
overlayPaint: {
'fill-color': '#d29700',
'fill-opacity': 0.75
},
selectionPaint: {
'fill-color': '#d29700',
'fill-opacity': 0.25,
'fill-outline-color': '#000000'
},
width: 150,
height: 150,
style: '',
_keyboardPanStep: 15
};
this.options = { ...defaultOptions, ...options };
this._mapLibrary = mapLibrary;
this._container.setAttribute('style', `width: ${this.options.width}px; height: ${this.options.height}px;`);
// Create the map for the overview
this._overviewMap = new mapLibrary.Map({
container: this._container,
style: this.options.style,
interactive: true,
pitchWithRotate: false,
attributionControl: false,
boxZoom: false,
dragRotate: false,
touchZoomRotate: false,
touchPitch: false,
minZoom: -2
});
this._overviewMap.on('load', () => {
// `.transform` existed as a public Map property when this
// plugin was built (~MapLibre 2.4.0); this app vendors a
// newer MapLibre where it's gone entirely, so this relaxes
// nothing and the overview keeps MapLibre's default ~85°
// Web Mercator pan limit instead — harmless, just means the
// inset can't scroll arbitrarily close to the poles.
if (this._overviewMap.transform) {
const maxLat = this._overviewMap.transform.maxValidLatitude || 85.051129;
this._overviewMap.transform.latRange = [maxLat * -2, maxLat * 2];
}
this._overviewMap.resize();
this._overviewMap.addSource('bboxSource', {
'type': 'geojson',
'data': this._extent
});
this._overviewMap.addSource('selectionSource', {
'type': 'geojson',
'data': blankGeoJsonFeature()
});
// Add a new layer to visualize the polygon.
this._overviewMap.addLayer({
'id': 'bboxLayer',
'type': 'fill',
'source': 'bboxSource',
'layout': {},
'paint': this.options.overlayPaint
});
this._overviewMap.addLayer({
'id': 'selectionFillLayer',
'type': 'fill',
'source': 'selectionSource',
'layout': {},
'paint': this.options.selectionPaint
});
this._overviewMap.addLayer({
'id': 'selectionLineLayer',
'type': 'line',
'source': 'selectionSource',
'layout': {},
'paint': {
'line-color': this.options.selectionPaint['fill-outline-color'] || '#000000',
'line-width': 2
}
});
});
}
onAdd(map) {
this._mainMap = map;
if (this.options.style === '') {
this._overviewMap.setStyle(this._mainMap.style.serialize());
}
// Disable the keyboard events, but use our own
this._overviewMap.keyboard.disable();
// we still use the _panstep from the keyboard events in out custom function
this._overviewMap.keyboard._panStep = this.options._keyboardPanStep;
//this._overviewMap.getCanvas().addEventListener('keydown', this._keyboardEvents, true);
// Update the overview map when the main map moves
this.options.watchEvents.forEach(event => map.on(event, () => this._updateOverview(map)));
/////////////////////////////
// Update Overview Map triggers
// Once the style is loaded, start listening
map.once('style.load', () => this._updateOverview(map));
// Start listening when it's added
this._updateOverview(map);
// Update the main map when the overview moves if the map is loaded (otherwise the style.load will pick up the change)
this._overviewMap.on('movestart', () => map.loaded() && this._updateMain(map));
// Make the overview map take control whenever the viewview map gets clicked
const takeControl = () => {
map.stop();
this._moving = false;
this._updateMain(map);
};
this._overviewMap.on('mousedown', takeControl);
this._overviewMap.on('touchstart', takeControl);
// Forward keydown events to the main map
this._overviewMap.getCanvas().addEventListener('keydown', (e) => {
//e.preventDefault();
map.stop();
this._keyboardEvents(e);
});
/////////////////////////////
return this._container;
}
onRemove() {
if (this._mainMap) {
//this._overviewMap.off('movestart', () => this._mainMap && this._moveOverview(this._mainMap));
this.options.watchEvents
.forEach(event => this._mainMap && this._mainMap
.off(event, () => this._updateOverview(this._mainMap)));
this._overviewMap.off('movestart', () => this._updateMain(this._mainMap));
}
if (this.options.style === '') {
this._overviewMap.setStyle('');
}
this._mainMap = undefined;
}
_updateOverview(map) {
var _a;
// Don't update the overview map if it's already moving
if (this._moving || !this._overviewMap)
return;
const pixelRatio = map.getPixelRatio();
const geojson = blankGeoJsonFeature();
if (map) {
const center = map.unproject([(map.getCanvas().width / pixelRatio) / 2, (map.getCanvas().height / pixelRatio) / 2]);
const bounds = map.getBounds();
let extentCoordinates = [
[-179.99, bounds.getNorth()],
[179.99, bounds.getNorth()],
[179.99, bounds.getSouth()],
[-179.99, bounds.getSouth()],
[-179.99, bounds.getNorth()],
];
// If the extent isn't larger that the earth, create a better one
if ((bounds.getEast() - bounds.getWest()) < 360 + (Math.abs(90 - Math.abs(90 - Math.abs(map.getBearing())))) * (map.getPitch() / 60)) {
extentCoordinates = [
map.unproject([0, 0]).toArray(),
map.unproject([map.getCanvas().width / pixelRatio, 0]).toArray(),
map.unproject([map.getCanvas().width / pixelRatio, map.getCanvas().height / pixelRatio]).toArray(),
map.unproject([0, map.getCanvas().height / pixelRatio]).toArray(),
map.unproject([0, 0]).toArray()
];
}
geojson.features.push({
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [extentCoordinates]
}
});
const newOverviewZoom = between(this._overviewMap.getMinZoom(), map.getZoom() + this.options.zoomLevelOffset, this._overviewMap.getMaxZoom());
if (!this._easingMain) {
this._moving = true;
this._overviewMap.setCenter(center);
this._overviewMap.setZoom(newOverviewZoom);
this._moving = false;
}
(_a = this._overviewMap.getSource('bboxSource')) === null || _a === void 0 ? void 0 : _a.setData(geojson);
this._extent = geojson;
}
}
_updateMain(map) {
var _a;
// Don't update the main map if it's already moving or if it doesn't exist
if (this._moving || !this._mainMap)
return;
const moveStartCenter = this._overviewMap.getCenter();
// Take control of the main map
this._mainMap.stop();
// Get the current extent, and copy it
const selectionExtent = JSON.parse(JSON.stringify(this._extent));
// Get the coordinates on the screen for the current map extent
const screenCoords = (selectionExtent.features[0]).geometry.coordinates[0].map(pos => this._overviewMap.project(pos));
// Update the GeoJSON object in the overview map to match the extent
(_a = this._overviewMap.getSource('selectionSource')) === null || _a === void 0 ? void 0 : _a.setData(selectionExtent);
// Used when overzoomed
const overZoomOffset = Math.max(this._overviewMap.getZoom() - this._mainMap.getZoom(), this.options.zoomLevelOffset);
// Called when the overview map is moving
const moving = () => {
var _a;
// Gets the current position
const currentSelectionExtentCoordinates = screenCoords
.map(pos => this._overviewMap.unproject([pos.x, pos.y]))
.map(xy => [xy.lng, xy.lat]);
// Updates the GeoJSON to match the new position
const geojson = blankGeoJsonFeature();
geojson.features.push({
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [currentSelectionExtentCoordinates]
}
});
// Updates the box on the overview map
(_a = this._overviewMap.getSource('selectionSource')) === null || _a === void 0 ? void 0 : _a.setData(geojson);
};
const doneEvents = () => {
var _a;
// Draw the current box on the overview map
(_a = this._overviewMap.getSource('selectionSource')) === null || _a === void 0 ? void 0 : _a.setData(blankGeoJsonFeature());
this._moving = false;
this._easingMain = false;
// Start up the event listeners again
this._updateOverview(map);
};
// Called when the overview map is done moving
const moveend = () => {
// Stop listening for events
this._overviewMap.off('move', moving);
this._overviewMap.off('moveend', moveend);
this._overviewMap.off('mouseup', moveend);
this._overviewMap.off('touchend', moveend);
if (this._easingMain)
return;
// If the map and the oveview map are ready, then we can update the map's center
if (this._mainMap) {
// Deal with the overview map being outside of its minZoom
let newCenter = this._overviewMap.getCenter();
const newMainZoom = between(this._mainMap.getMinZoom(), this._overviewMap.getZoom() - overZoomOffset, this._mainMap.getMaxZoom());
// Check if the overview map has moved, if so, ease the main map, otherwise finish events
if (newCenter.lng !== moveStartCenter.lng || newCenter.lat !== moveStartCenter.lat) {
// Execute the "doneEvents" code when the map stops moving
this._mainMap.once('moveend', (event) => event.doneEvents && event.doneEvents());
this._moving = true;
this._easingMain = true;
this._mainMap.easeTo({
center: newCenter,
zoom: newMainZoom
}, {
doneEvents
});
}
else {
doneEvents();
}
}
};
this._overviewMap.on('move', moving);
this._overviewMap.once('moveend', moveend);
this._overviewMap.once('mouseup', moveend);
this._overviewMap.once('touchend', moveend);
}
_getCenterAtPitch(map, pitch, rotation) {
const pixelRatio = map.getPixelRatio();
const center = map.unproject([(map.getCanvas().width / pixelRatio) / 2, (map.getCanvas().height / pixelRatio) / 2]);
return center;
}
};
}
export default OverviewMap;