Skip to main content

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)

Enabling Leaflet in a consuming application

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:

  1. Import the config in its package.conf.jsonp:
    imports: {
    leaflet: "dependencies/io-oidis-hub-gui/bin/project/configs/leaflet.jsonp"
    }
    This copies the assets into the app's resource/libs/Leaflet, serves them (requestPatterns) and registers the licenses.
  2. Inject the stylesheets/scripts into the page head from its FrontEndLoader with 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.

OptionTypeDefaultDescription
heightstring"360px"CSS height of the map container.
clusteredbooleantrueGroup nearby display markers into clusters.
pickablebooleanfalseEnable pick mode from construction (also enabled lazily by EnablePickMode).
zoomnumber7Initial zoom level.
centernumber[][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​

MethodPurpose
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.
Initialise after the container is visible

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.