Advanced

Raw map access, synced viewports, and the map context service.

Using the Map Instance

#

The mapReady output hands you the raw maplibre-gl Map instance for anything the declarative API doesn't cover. Here it drives flyTo on a globe projection.

import { Component } from '@angular/core';
import type { Map as MapLibreMap } from 'maplibre-gl';
import { MapComponent } from 'ng-mapcn';

@Component({
  selector: 'app-globe-flyto',
  standalone: true,
  imports: [MapComponent],
  template: `
    <div class="h-[420px]">
      <ng-map
        [center]="[0, 20]"
        [zoom]="1.5"
        [projection]="{ type: 'globe' }"
        (mapReady)="onMapReady($event)"
      />
    </div>
  `,
})
export class GlobeFlytoComponent {
  private map?: MapLibreMap;

  onMapReady(map: MapLibreMap): void {
    this.map = map;
  }

  flyTo(center: [number, number]): void {
    // Full access to the raw MapLibre instance.
    this.map?.flyTo({ center, zoom: 8, duration: 2500, essential: true });
  }
}

Fly to Markers

#

Combine markerClick with the map instance: click a marker to fly to its city.

<ng-map [center]="[10, 48]" [zoom]="4" (mapReady)="onMapReady($event)">
  @for (city of cities; track city.name) {
    <ng-map-marker
      [longitude]="city.lng"
      [latitude]="city.lat"
      (markerClick)="flyTo(city)"
    >
      <ng-marker-content>
        <div class="size-3.5 cursor-pointer rounded-full border-2 border-white bg-blue-500 shadow-lg"></div>
        <ng-marker-label position="top">{{ city.name }}</ng-marker-label>
      </ng-marker-content>
    </ng-map-marker>
  }
</ng-map>

Synced Viewports

#

Two maps sharing one controlled viewport signal. Pan or zoom either map and the other follows.

import { Component, signal } from '@angular/core';
import { MapComponent, MapViewport } from 'ng-mapcn';

@Component({
  selector: 'app-synced-viewports',
  standalone: true,
  imports: [MapComponent],
  template: `
    <div class="grid h-[420px] grid-cols-2 gap-2">
      <!-- Single source of truth shared by both maps (controlled viewport). -->
      <ng-map [viewport]="viewport()" (viewportChange)="viewport.set($event)" />
      <ng-map [viewport]="viewport()" (viewportChange)="viewport.set($event)" />
    </div>
  `,
})
export class SyncedViewportsComponent {
  readonly viewport = signal<MapViewport>({
    center: [-46.63, -23.55],
    zoom: 10,
    bearing: 0,
    pitch: 0,
  });
}

Using the Context Service

#

Build your own map components: any component projected inside ng-map can inject MapContextService to access the map instance, isLoaded, and the resolved theme — the Angular equivalent of mapcn's useMap() hook.

import { Component, effect, inject } from '@angular/core';
import { MapContextService } from 'ng-mapcn';

// Any component placed inside <ng-map> can inject the map context —
// the Angular equivalent of mapcn's useMap() hook.
@Component({
  selector: 'app-my-custom-control',
  standalone: true,
  template: `...`,
})
export class MyCustomControlComponent {
  private readonly ctx = inject(MapContextService);

  constructor() {
    effect(() => {
      if (!this.ctx.isLoaded()) return;
      const map = this.ctx.map(); // raw maplibre-gl Map
      // add sources, layers, event handlers...
    });
  }
}