MapView
Reusable Leaflet map component living in the Hub GUI package. It extends GuiCommons and covers the two map use cases shared across Oidis solutions:
- Display mode — plot an array of markers, optionally clustered, each with an optional popup, and auto-fit the viewport to their bounds.
- Pick mode — let the user select a single coordinate by clicking the map or dragging the marker, reported through a callback.
Both modes can be combined on the same instance. Markers use the Oidis primary colour (var(--bs-primary)) by default, and Ctrl + mouse wheel zooms the map (a plain wheel scrolls the page).
Import: @io-oidis-hub-gui/Io/Oidis/Hub/Gui/UserControls/MapView.js (also exports IMapMarker, IMapViewOptions)
MapView references the global L (Leaflet) and, when clustering is enabled, L.markerClusterGroup (the leaflet.markercluster plugin). io-oidis-hub-gui ships the Leaflet + markercluster assets and their license registration via bin/project/configs/leaflet.jsonp, so a consumer only has to:
- Import the config in its
package.conf.jsonp:This copies the assets into the app'simports: {
leaflet: "dependencies/io-oidis-hub-gui/bin/project/configs/leaflet.jsonp"
}resource/libs/Leaflet, serves them (requestPatterns) and registers the licenses. - Inject the stylesheets/scripts into the page head from its
FrontEndLoaderwith the shared helper:import { MapViewAssets } from "@io-oidis-hub-gui/Io/Oidis/Hub/Gui/UserControls/MapViewAssets.js";
// inside setContent():
MapViewAssets.AppendHeadAssets(`?v=${new Date(env.getBuildTime()).getTime()}`);
If Leaflet is missing at runtime the component logs an info message and renders an empty container; if the cluster plugin is missing it silently falls back to a non-clustered layer.
Options
Configuration is passed once to the constructor as IMapViewOptions. All fields are optional.
| Option | Type | Default | Description |
|---|---|---|---|
height | string | "360px" | CSS height of the map container. |
clustered | boolean | true | Group nearby display markers into clusters. |
pickable | boolean | false | Enable pick mode from construction (also enabled lazily by EnablePickMode). |
zoom | number | 7 | Initial zoom level. |
center | number[] | [49.8, 15.5] | Initial [latitude, longitude] (defaults to the centre of Czechia). |
Display Mode
Create the component, bind it in the template, initialise the map once its container is visible, then push markers.
// Panel
public readonly map : MapView;
// Constructor
this.map = new MapView({clustered: true});
<!-- innerHtml() -->
<div data-oidis-bind="${this.map}"></div>
// Controller
$instance.map.InitMap(); // lazily creates the Leaflet map
$instance.map.SetMarkers([
{latitude: 50.08, longitude: 14.43, title: "Praha"},
{
latitude : 49.19,
longitude: 16.61,
popupHtml: "<strong>Brno</strong><br>Visited: 3x"
}
]);
Each IMapMarker carries latitude / longitude plus an optional popup. Supply either a plain title (escaped by the component) or a fully built popupHtml fragment. popupHtml is rendered as-is, so the caller is responsible for escaping any user-controlled content inside it. Markers at 0,0 are skipped.
Pick Mode
// Constructor — clustering off, pick on, shorter map
this.pickMap = new MapView({clustered: false, pickable: true, height: "260px"});
// Controller
$instance.pickMap.InitMap();
$instance.pickMap.EnablePickMode(($latitude : number, $longitude : number) : void => {
this.form.latitude = $latitude;
this.form.longitude = $longitude;
});
$instance.pickMap.SetPickedCoordinates(50.08, 14.43); // place/move the marker programmatically
const picked : IMapMarker = $instance.pickMap.GetPickedCoordinates();
EnablePickMode registers the callback and turns on click-to-place and marker dragging; both gestures fire the callback with the new coordinates. SetPickedCoordinates moves the marker and centres the map on it, GetPickedCoordinates returns the current position, and ClearPickedCoordinates / DisablePickMode remove it.
Lifecycle
| Method | Purpose |
|---|---|
InitMap() | Lazily build the Leaflet map; re-entrant calls only refresh the size. Call after the container becomes visible (e.g. on tab activation). |
InvalidateSize() | Recalculate the map size after its container changed dimensions or became visible. |
ResetView() | Reset the viewport to the configured centre and zoom. |
Dispose() | Tear down the map, marker layers and the internal resize observer. |
Leaflet cannot measure a hidden container. When the map lives inside a tab or collapsible section, call InitMap() (or InvalidateSize() if already initialised) when that section is shown — otherwise the tiles render with a zero-size or grey area.
Styling
The component renders a .OidisMapView section with an inner .oidis-map-container. Markers, the pick marker and cluster bubbles use the Oidis primary colour through var(--bs-primary); the cluster bubble class is .oidis-map-cluster. Styles ship with the Hub GUI package, so any solution that pulls in @io-oidis-hub-gui/reference.d gets them automatically.
Thin wrappers
Solutions typically wrap MapView in a small GuiCommons subclass that maps their domain objects onto IMapMarker and exposes a task-specific API, rather than calling MapView directly from controllers. For example the vehicle logbook in io-oidis-labs wraps it as VehicleLogbookMap (clustered display, building popups from visit counts) and PlacePickMap (pick mode for choosing a place's coordinates). This keeps controllers decoupled from the generic marker shape while still sharing one map implementation across projects.