Search code examples
google-maps-api-3angular2-google-maps

angular2 google map infowindow opens so many times and it starts lagging


I'm using angular-google-map. In the project, I create hundreds of markers and all of them share one info window. Below is the code in the template:

<div *ngFor="let property of _properties">
  <agm-marker [latitude]="property.Lat"
              [longitude]="property.Lng"
              [iconUrl]="_markerIconUrl"
              (mouseOver)="infoWindow.open();"
              (mouseOut)="infoWindow.close();">
  </agm-marker>
</div>
...
<agm-info-window #infoWindow>
</agm-info-window>

At the begining it works well. But as I mouseover many markers, it starts slow down. Here is the screenshot of performance and memory:

performance

memory

It seems like garbage collection slows down the page and I really don't know how to fix it..

I tried these:

  1. I thought it might be mouseover/mouseout emitter slows it down. But if I replace infoWindow.open() to other function, it works fine.
  2. Then I checked the angular-google-map source code, and found the infoWindow.open():
  open(infoWindow: AgmInfoWindow): Promise<void> {
    return this._infoWindows.get(infoWindow).then((w) => {
      if (infoWindow.hostMarker != null) {
        return this._markerManager.getNativeMarker(infoWindow.hostMarker).then((marker) => {
          return this._mapsWrapper.getNativeMap().then((map) => w.open(map, marker));
        });
      }
      return this._mapsWrapper.getNativeMap().then((map) => w.open(map));
    });
  }

I thought it might be the Promise slows it down, but when I comment out w.open(map) and w.open(map, marker) it works fine.

So I think the problem might be because it called w.open(map) so many times? I found that open function is from Google Map API infoWindow. I tried clear the conent and set infoWindow conent='' and close it everytime, but still can't fix it.


Solution

  • I finally fixed it. The issue caused by too many change detections. And I found the solution here: https://github.com/angular/angular/issues/10883#issuecomment-240423378
    What I did is called the infowindow.open() outside of Angular to avoid change detections:

    map.component.html

    <div *ngFor="let property of _properties">
      <agm-marker [latitude]="property.Lat"
                  [longitude]="property.Lng"
                  [iconUrl]="_markerIconUrl"
                  (mouseOver)="_infoWindowOpen($event, infoWindow);"
                  (mouseOut)="_infoWindowClose($event, infoWindow);">
      </agm-marker>
    </div>
    ...
    <agm-info-window #infoWindow>
    </agm-info-window>
    

    map.component.ts

    import { Component, OnInit, NgZone } from '@angular/core';
    ...
    constructor(private _zone: NgZone) {...}
    ...
      private _infoWindowOpen(mouseEvent: any, infoWindow: any) {
        infoWindow.hostMarker = mouseEvent.marker;
        this._zone.runOutsideAngular(() => {
          infoWindow.open();
        });
      }
    ...
      private _infoWindowClose(mouseEvent: any, infoWindow: any) {
        this._zone.runOutsideAngular(() => {
          infoWindow.close();
        });
      }