jawj / OverlappingMarkerSpiderfier-Leaflet

Deals with overlapping markers in the Leaflet maps API, Google Earth-style
253 stars 68 forks source link

Integration with Angular #50

Open shammy8 opened 4 years ago

shammy8 commented 4 years ago

Any ides on how i can integrate this plugin with Angular?

jhenrich commented 4 years ago

Don`t know if you managed to integrate it but i did it like this:

  1. Install it via npm: npm i --save overlapping-marker-spiderfier-leaflet
  2. Then import it in the component where you need it: import 'overlapping-marker-spiderfier-leaflet/dist/oms';
  3. Add this line on top of the file where you import it: const OverlappingMarkerSpiderfier = (<any>window).OverlappingMarkerSpiderfier;
  4. Add the oms markup like that: this.oms = new OverlappingMarkerSpiderfier(this.map, { nearbyDistance: 20, keepSpiderfied: true });
  5. Add the markers to oms at the same place where you add your markers to the map so oms can track them properly this.oms.addMarker(marker);
Cyberphinx commented 2 years ago

What would step 3 be to integrate with React then? @jhenrich

wwwizzarrdry commented 2 years ago

What would step 3 be to integrate with React then? @jhenrich

This worked fine for me in my Vue project. So it should be, relatively, the same for a React project:

<template>
    <l-map ref="myMap" style="position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 0" @ready="mapIsReady">
    </l-map>
</template>
<script>
import L, { Icon, latLng, Polyline } from 'leaflet'
import { LMap, LTileLayer, LMarker, LControlLayers } from 'vue2-leaflet'
import 'overlapping-marker-spiderfier-leaflet/dist/oms'

const OverlappingMarkerSpiderfier = window.OverlappingMarkerSpiderfier;

export default {
    data() {
        return {
            map: null,
            oms: null,
        }
    },
    methods: {
        mapIsReady(){
            this.map = this.$refs.myMap.mapObject; //.ANY_LEAFLET_MAP_METHOD();
            this.oms = new OverlappingMarkerSpiderfier(this.map, { nearbyDistance: 20, keepSpiderfied: true });
        }
    }
}
</script>
ikbenignace commented 8 months ago

I did not really get it working for angular:

TypeError: undefined is not a constructor (evaluating 'new window.OverlappingMarkerSpiderfier(this.map,{nearbyDistance:20,keepSpiderfied:!0})')

import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import 'overlapping-marker-spiderfier-leaflet/dist/oms';
import { JobOffer } from 'src/models/jobOffer';
import { SearchForm } from 'src/services/filter-form.service';
import { MapService } from 'src/services/map.service';
import { JobModalComponent } from '../job-modal/job-modal.component';
import { observeFields } from './util';

@Component({
  selector: 'app-open-map',
  templateUrl: './open-map.component.html',
  styleUrls: ['./open-map.component.scss']
})
export class OpenMapComponent implements OnInit {
  @Input() jobs!: JobOffer[];
  @Input() height: number = 500;
  @Input() filter!: SearchForm;
  @Input() centerLng: number = 4.34878;
  @Input() lat = 50.85045;
  @Input() lng = 4.34878;
  @ViewChild('leafletMap') leafletMap!: ElementRef;
  fields = observeFields(this);
  map!: L.Map;
  oms: any; 

  constructor(private modalService: NgbModal, private mapService: MapService) {
  }

  ngOnInit(): void {
    if (this.mapService.L) {
      this.fields.leafletMap.subscribe(() => this.setupMap());
    }
  }

  public selectJob(job: JobOffer): void {
    let modal = this.modalService.open(JobModalComponent, { ariaLabelledBy: 'modal-basic-title', size: 'lg', centered: true, windowClass: 'pxp-user-modal' });
    modal.componentInstance.job = job;
  }

  private setupMap() {
    if (!this.map && this.leafletMap) {
      this.map = this.mapService.L.map(this.leafletMap.nativeElement).setView([this.lat, this.lng], 12);
      this.oms = new (<any>window).OverlappingMarkerSpiderfier(this.map, { nearbyDistance: 20, keepSpiderfied: true });
      this.loadLocation()
      if (this.filter.post.value)
        this.centerMap(this.filter.post.value.latitude, this.filter.post.value.longitude);
      else
        this.centerMap(this.filter.latitude.value, this.filter.longitude.value);

      this.mapService.L.tileLayer(
        'https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png'
      ).addTo(this.map);
      (document.querySelector('.leaflet-control-attribution') as HTMLElement).style.display = 'none';
      if (this.jobs) this.loadJobs(this.jobs);
      this.fields.jobs.subscribe((val) => {
        this.loadJobs(val);
      })
    }
  }

  private loadJobs(val: JobOffer[]) {
    if(val) {
      for (let job of val) {
        if(this.map && job.jobLocation.latitude && job.jobLocation.longitude) this.map.addLayer(this.mapService.L.marker([job.jobLocation.latitude, job.jobLocation.longitude], {
          icon: this.mapService.L.icon({
            iconSize: [ 48, 48],
            iconUrl: 'assets/images/leaflet/location-pin.png',
          })
        }).on('click', () => {
          this.selectJob(job);
        }));
      }
    }
  }

  private loadLocation() {
    this.filter.get("post")?.valueChanges.subscribe((val) => {
      console.log(val)
      if (val)
        this.centerMap(val.latitude, val.longitude);
    });

    this.filter.latitude.valueChanges.subscribe((val) => {
      this.centerMap(this.filter.latitude.value, this.filter.longitude.value);
    });
  }

  centerMap(lat: number, lng: number) {
    if (this.map) this.map.panTo(this.mapService.L.latLng(lat, lng));

  }

}