asennikov/ember-g-map

View on GitHub
addon/components/g-map-marker.js

Summary

Maintainability
D
1 day
Test Coverage
import { alias } from '@ember/object/computed';
import Component from '@ember/component';
import { observer } from '@ember/object';
import { run } from '@ember/runloop';
import { assert } from '@ember/debug';
import { typeOf, isPresent, isEmpty } from '@ember/utils';
import layout from '../templates/components/g-map-marker';
import GMapComponent from './g-map';

const GMapMarkerComponent = Component.extend({
  layout,
  classNames: ['g-map-marker'],

  map: alias('mapContext.map'),

  init() {
    this._super(...arguments);
    this.infowindow = null;
    if (isEmpty(this.get('group'))) {
      this.set('group', null);
    }

    const mapContext = this.get('mapContext');
    assert('Must be inside {{#g-map}} component with context set', mapContext instanceof GMapComponent);

    mapContext.registerMarker(this);
  },

  didInsertElement() {
    this._super(...arguments);
    if (isEmpty(this.get('marker'))
      && (typeof FastBoot === 'undefined')
      && (typeof google !== 'undefined')) {
      const marker = new google.maps.Marker();
      this.set('marker', marker);
    }
    this.setPosition();
    this.setZIndex();
    this.setIcon();
    this.setDraggable();
    this.setLabel();
    this.setTitle();
    this.setMap();
    this.setOnClick();
    this.setOnDrag();
  },

  willDestroyElement() {
    this.unsetMarkerFromMap();
    this.get('mapContext').unregisterMarker(this);
  },

  registerInfowindow(infowindow, openEvent, closeEvent) {
    this.set('infowindow', infowindow);
    this.attachOpenCloseEvents(infowindow, openEvent, closeEvent);
  },

  unregisterInfowindow() {
    this.set('infowindow', null);
  },

  attachOpenCloseEvents(infowindow, openEvent, closeEvent) {
    const marker = this.get('marker');
    if (openEvent === closeEvent) {
      this.attachTogglingInfowindowEvent(marker, infowindow, openEvent);
    } else {
      this.attachOpenInfowindowEvent(marker, infowindow, openEvent);
      this.attachCloseInfowindowEvent(marker, infowindow, closeEvent);
    }
  },

  attachOpenInfowindowEvent(marker, infowindow, event) {
    if (isPresent(event)) {
      marker.addListener(event, () => infowindow.open());
    }
  },

  attachCloseInfowindowEvent(marker, infowindow, event) {
    if (isPresent(event)) {
      marker.addListener(event, () => infowindow.close());
    }
  },

  attachTogglingInfowindowEvent(marker, infowindow, event) {
    if (isPresent(event)) {
      marker.addListener(event, () => {
        if (infowindow.get('isOpen')) {
          infowindow.close();
        } else {
          infowindow.open();
        }
      });
    }
  },

  unsetMarkerFromMap() {
    const marker = this.get('marker');
    if (isPresent(marker)) {
      marker.setMap(null);
    }
  },

  mapWasSet: observer('map', function() {
    run.once(this, 'setMap');
  }),

  setMap() {
    const map = this.get('map');
    const marker = this.get('marker');

    if (isPresent(marker) && isPresent(map)) {
      marker.setMap(map);
    }
  },

  coordsChanged: observer('lat', 'lng', function() {
    run.once(this, 'setPosition');
  }),

  setPosition() {
    const marker = this.get('marker');
    const lat = this.get('lat');
    const lng = this.get('lng');

    if (isPresent(marker)
      && isPresent(lat)
      && isPresent(lng)
      && (typeof FastBoot === 'undefined')) {
      const position = new google.maps.LatLng(lat, lng);
      if (isPresent(position)) {
        marker.setPosition(position);
      }
    }
  },

  iconChanged: observer('icon', function() {
    run.once(this, 'setIcon');
  }),

  setIcon() {
    const marker = this.get('marker');
    const icon = this.get('icon');

    if (isPresent(marker) && isPresent(icon)) {
      marker.setIcon(icon);
    }
  },

  zIndexChanged: observer('zIndex', function() {
    run.once(this, 'setZIndex');
  }),

  setZIndex() {
    const marker = this.get('marker');
    const zIndex = this.get('zIndex');
    if (isPresent(marker) && isPresent(zIndex)) {
      marker.setZIndex(zIndex);
    }
  },

  draggableChanged: observer('draggable', function() {
    run.once(this, 'setDraggable');
  }),

  setDraggable() {
    const marker = this.get('marker');
    const draggable = this.get('draggable');
    if (isPresent(marker) && isPresent(draggable)) {
      marker.setDraggable(draggable);
    }
  },

  setOnClick() {
    const marker = this.get('marker');
    if (isPresent(marker)) {
      marker.addListener('click', () => this.sendOnClick());
    }
  },

  setOnDrag() {
    const marker = this.get('marker');
    marker.addListener('dragend', (event) => {
      const lat = event.latLng.lat();
      const lng = event.latLng.lng();
      if (isPresent(lat) && isPresent(lng) && isPresent(marker)) {
        const position = new google.maps.LatLng(lat, lng);
        marker.setPosition(position);
        this.sendOnDrag(lat, lng);
      }
    });
  },

  labelChanged: observer('label', function() {
    run.once(this, 'setLabel');
  }),

  setLabel() {
    const marker = this.get('marker');
    const label = this.get('label');

    if (isPresent(marker) && isPresent(label)) {
      marker.setLabel(label);
    }
  },

  titleChanged: observer('title', function() {
    run.once(this, 'setTitle');
  }),

  setTitle() {
    const marker = this.get('marker');
    const title = this.get('title');

    if (isPresent(marker) && isPresent(title)) {
      marker.setTitle(title);
    }
  },

  sendOnClick() {
    const onClick = this.get('onClick');
    const mapContext = this.get('mapContext');
    const group = this.get('group');

    if (typeOf(onClick) === 'function') {
      onClick();
    } else {
      this.sendAction('onClick');
    }

    if (isPresent(group)) {
      mapContext.groupMarkerClicked(this, group);
    }
  },

  sendOnDrag(lat, lng) {
    const onDrag = this.get('onDrag');

    if (typeOf(onDrag) === 'function') {
      onDrag(lat, lng);
    } else {
      this.sendAction('onDrag', lat, lng);
    }
  },

  closeInfowindow() {
    const infowindow = this.get('infowindow');
    if (isPresent(infowindow)) {
      infowindow.close();
    }
  }
});

GMapMarkerComponent.reopenClass({
  positionalParams: ['mapContext']
});

export default GMapMarkerComponent;