Skip to content

Events

MapLibreMap reports user input and state changes through one on… callback per event. Set only the callbacks you need: the map doesn't track events that nothing listens to.

Basic Usage

@override
Widget build(BuildContext context) {
  return MapLibreMap(
    options: MapOptions(initCamera: .position(center: Geographic(lon: 9.17, lat: 47.68), zoom: 7)),
    onMapCreated: (controller) => print('map created'),
    onStyleLoaded: (style) => print('style loaded'),
    onClick: (event) => print('clicked at ${event.point.lon}, ${event.point.lat}'),
    onCameraMoveEnd: (event) => print('camera stopped at ${event.camera.zoom}'),
    onError: (event) => print('${event.kind}: ${event.message}'),
  );
}

Each callback gets an event object of its own type, such as MapEventClick for onClick. All of them extend MapEvent.

Available Events

Map gestures are recognized in Flutter, so the user input events behave the same on every platform.

Callback Called when
onMapCreated The map was created. Gets the MapController.
onStyleLoaded A style finished loading, also after MapOptions.style changed. Gets the StyleController.
onClick The user tapped or clicked the map.
onDoubleClick The user double tapped or double clicked the map.
onSecondaryClick The user clicked the map with the secondary (right) mouse button.
onLongClick The user pressed the map for a longer time.
onDragStart The user starts to drag the map with one finger or the primary mouse button, see drags.
onDrag The pointer of a drag moved.
onDragEnd A drag ended.
onPointerMove A mouse or stylus moved over the map without a pressed button. Touches don't hover.
onPointerLeave A mouse or stylus left the map.
onCameraMoveStart The camera starts to move. reason says whether a gesture, the app or the map moved it.
onCameraMove The camera moved. Holds the new CameraPosition and the reason.
onCameraMoveEnd The camera stopped moving. Holds the CameraPosition it ended at and the reason.
onIdle The map finished rendering and no animation runs.
onError The style, a source, glyphs or a sprite failed to load, or rendering failed.
onStyleImageMissing A layer uses an image that the style doesn't have. Add it with StyleController.addImage.
onLoadingStarted The map starts to load a style.
onLoadingFinished The map loaded its style and what the view needs.
onSourceChanged A source of the style changed, such as when its TileJSON arrives.
onRenderFrame The map rendered a frame. Not on web, it holds the frame's statistics.
onRenderingChanged The map stopped or resumed rendering, see paused rendering.
onResize The map changed its size.

Some events are not on every platform:

Callback Platform Called when
onTile not web A tile moved to another step of loading.
onRenderMap not web The map finished rendering a view, partially or fully.
onGlyphs not web The map requested or loaded glyphs of a font.
onSprite not web The map requested or loaded a sprite.
onContextLost, onContextRestored web The browser took the map's WebGL context away or gave it back.
onProjectionChanged web The map switched its projection.

The click and drag events extend MapEventUserInput, which holds the point on the map and the screenPoint in logical pixels.

Double taps

A double tap zooms in while the zoom gesture of MapOptions.gestures is on. To handle it yourself, call preventDefault() on the event. onDoubleClick can be async, for example to check for features under the tap first. The map waits for it before it zooms:

onDoubleClick: (event) async {
  final features = await _controller.queryRenderedFeatures(
    .point(event.screenPoint),
  );
  if (features.isNotEmpty) {
    event.preventDefault();
    // handle the double tap on the feature
  }
},

preventDefault() also keeps the double tap and drag gesture from zooming.

A tap only waits for a possible second tap while double taps mean something: while onDoubleClick is set or the zoom gesture is on. Turn both off and onClick fires right away.

Drags

A drag with one finger or the primary mouse button reports onDragStart where it went down, onDrag while it moves and onDragEnd where it stopped. They are reported whether the drag pans the map or not, also while panning is off. A second finger ends the drag and starts a pinch.

To move something else instead of the map, call preventDefault() on the start event. onDragStart can be async to check for features first, and the map holds the pan until it is done:

onDragStart: (event) async {
  final features = await _controller.queryRenderedFeatures(
    .point(event.screenPoint),
    layerIds: ['points'],
  );
  if (features.isNotEmpty) event.preventDefault();
},
onDrag: (event) {
  // move the feature to event.point
},

Annotation layers can do this for their own features, see Drag annotations.

Layer events

Annotation layers and style layers report taps and the mouse on their own features with onClick, onEnter and onLeave, see click and hover for annotations and for style layers.