Create a Map view

This is the official documentation of the @forestadmin/agent Node.js agent.

The example below shows how to display a map view:

component.js
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { scheduleOnce } from '@ember/runloop';
import { action } from '@ember/object';
import { observes } from '@ember-decorators/object';
import { tracked } from '@glimmer/tracking';
import { guidFor } from '@ember/object/internals';
import {
  triggerSmartAction,
  deleteRecords,
  getCollectionId,
  loadExternalStyle,
  loadExternalJavascript,
} from 'client/utils/smart-view-utils';

export default class extends Component {
  @service router;
  @service store;

  @tracked map = null;
  @tracked loaded = false;

  constructor(...args) {
    super(...args);

    this.loadPlugin();
  }

  get mapId() {
    return `map-${guidFor(this)}`;
  }

  async loadPlugin() {
    loadExternalStyle('//cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.4/leaflet.css');
    loadExternalStyle(
      '//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css',
    );

    await loadExternalJavascript(
      '//cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.4/leaflet.js',
    );
    await loadExternalJavascript(
      '//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js',
    );

    this.loaded = true;
    this.displayMap();
  }

  @action
  displayMap() {
    if (!this.loaded) {
      return;
    }

    if (this.map) {
      this.map.off();
      this.map.remove();
      this.map = null;
    }

    const markers = [];

    this.args.records?.forEach(function (record) {
      markers.push([
        record.get('forest-lat'),
        record.get('forest-lng'),
        record.get('id'),
      ]);
    });

    this.map = new L.Map(this.mapId);

    const osmUrl =
      'https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png';
    const osmAttrib =
      '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> &copy; <a href="http://cartodb.com/attributions">CartoDB</a>';
    const osm = new L.TileLayer(osmUrl, { attribution: osmAttrib });
    const drawnItems = new L.FeatureGroup();
    this.map.addLayer(drawnItems);

    const drawControl = new L.Control.Draw({
      draw: {
        polygon: false,
        polyline: false,
        rectangle: false,
        circle: false,
        circlemarker: false,
        marker: true,
      },
      edit: {
        featureGroup: drawnItems,
      },
    });

    this.map.setView(new L.LatLng(48.8566, 2.3522), 2);
    this.map.addLayer(osm);
    this.map.addControl(drawControl);

    this.map.on(L.Draw.Event.CREATED, event => {
      const { layer, layerType: type } = event;

      if (type === 'marker') {
        const coordinates = event.layer.getLatLng();
        const newRecord = this.store.createRecord('forest_delivery', {
          'forest-is_delivered': false,
          'forest-lng': coordinates.lng,
          'forest-lat': coordinates.lat,
        });

        newRecord.save().then(savedRecord => {
          layer.on('click', () => {
            this.router.transitionTo(
              'project.rendering.data.collection.list.view-edit.details',
              this.args.collection.id,
              savedRecord.id,
            );
          });
        });
      }

      this.map.addLayer(layer);
    });

    this.addMarkers(markers);
  }

  addMarker(marker) {
    const lat = Number.parseFloat(marker[0]);
    const long = Number.parseFloat(marker[1]);

    const recordId = marker[2];
    marker = L.marker([lat, long]).addTo(this.map);

    marker.on('click', () => {
      this.router.transitionTo(
        'project.rendering.data.collection.list.view-edit.details',
        this.args.collection.id,
        recordId,
      );
    });
  }

  addMarkers(markers) {
    markers.forEach(marker => this.addMarker(marker));
  }

  @action
  triggerSmartAction(...args) {
    return triggerSmartAction(this, ...args);
  }

  @action
  deleteRecords(...args) {
    return deleteRecords(this, ...args);
  }
}
style.css
.c-map {
  width: 100%;
  height: 100%;
  z-index: 4;
}

#map {
  width: 100%;
  z-index: 4;
}

.c-smart-view {
  display: flex;
  white-space: normal;
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  top: 0;
  background-color: var(--color-beta-surface);
}

.c-smart-view__content {
  margin: auto;
  text-align: center;
  color: var(--color-beta-on-surface_medium);
}

.c-smart-view_icon {
  margin-bottom: 32px;
  font-size: 32px;
}
template.hbs
<div
  id={{this.mapId}}
  class='c-map'
  {{did-insert this.displayMap}}
  {{did-update this.displayMap @records}}
></div>

Last updated