define(function(require) {
    "use strict";

    var EditTreePopup = require('components/TreeVarietiesMap/EditTreePopupComponent');
    var forEach = require('mout/array/forEach');
    var L = require('leaflet');
    var pluck = require('mout/array/pluck');
    var TreesLayer = require('components/TreeVarietiesMap/TreesLayerComponent');

    return L.Class.extend({
        initialize: function(varieties) {
            this.controlLayers = L.control.layers(null, null, { collapsed: false });
            this.editTreePopup = new EditTreePopup(varieties);

            this.addVarietyHandler = this.addVariety.bind(this);
            this.onVarietiesChangeHandler = this.onVarietiesChange.bind(this);

            varieties.subscribe(this.onVarietiesChangeHandler, null, 'arrayChange');
        },
        addVariety: function(variety) {
            this.controlLayers
                .addOverlay(new TreesLayer(variety.trees, this.editTreePopup), variety.name);
        },
        onAdd: function(map) {
            this.controlLayers.addTo(map);
        },
        onRemove: function(map) {
            this.controlLayers.removeFrom(map);
        },
        onVarietiesChange: function(changes) {
            forEach(pluck(changes, 'value'), this.addVarietyHandler);
        }
    });
});
(function() {
	'use strict';

	var L = require('leaflet');
	L.Routing = L.Routing || {};

	L.Routing.ItineraryBuilder = L.Class.extend({
		options: {
			containerClassName: ''
		},

		initialize: function(options) {
			L.setOptions(this, options);
		},

		createContainer: function() {
			return L.DomUtil.create('table', this.options.containerClassName);
		},

		createStepsContainer: function() {
			return L.DomUtil.create('tbody', '');
		},

		createStep: function(text, distance, icon, steps) {
			var row = L.DomUtil.create('tr', '', steps),
				span,
				td;
			td = L.DomUtil.create('td', '', row);
			span = L.DomUtil.create('span', 'leaflet-routing-icon leaflet-routing-icon-'+icon, td);
			td.appendChild(span);
			td = L.DomUtil.create('td', '', row);
			td.appendChild(document.createTextNode(text));
			td = L.DomUtil.create('td', '', row);
			td.appendChild(document.createTextNode(distance));
			return row;
		}
	});

	module.exports = L.Routing;
})();
(function() {
	'use strict';

	var L = require('leaflet');
	L.Routing = L.Routing || {};

	L.Routing.Waypoint = L.Class.extend({
			options: {
				allowUTurn: false,
			},
			initialize: function(latLng, name, options) {
				L.Util.setOptions(this, options);
				this.latLng = L.latLng(latLng);
				this.name = name;
			}
		});

	L.Routing.waypoint = function(latLng, name, options) {
		return new L.Routing.Waypoint(latLng, name, options);
	};

	module.exports = L.Routing;
})();
var MapIcon = Leaflet.Class.extend({
	/*
	options: {
		iconUrl: (String)
		iconSize: (Point) (can be set through CSS)
		iconAnchor: (Point) (centered by default, can be set in CSS with negative margins)
		popupAnchor: (Point) (if not specified, popup opens in the anchor point)
		shadowUrl: (String) (no shadow by default)
		shadowSize: (Point)
		shadowAnchor: (Point)
		className: (String)
	},
	*/

  initialize: function (options) {
    this.options = Object.assign({}, options);
  },

  createIcon: function (oldIcon) {
    return this._createIcon('icon', oldIcon);
  },

  createShadow: function (oldIcon) {
    return this._createIcon('shadow', oldIcon);
  },

  _createIcon: function (name, oldIcon) {
    var el = this._createIconEl(name, oldIcon && oldIcon.tagName ? oldIcon : null);
    this._setIconStyles(el, name);
    return el;
  },

  _setIconStyles: function (el, name) {
    var options = this.options;
    var size = Leaflet.point(options[name + 'Size']);
    var anchor = Leaflet.point((name === 'shadow') ? options.shadowAnchor : options.iconAnchor);
    if (anchor == null && size != null) {
      anchor = size.divideBy(2, true);
    }
    el.classList.add('leaflet-marker-' + name);
    if (options.className) {
      el.classList.add(options.className);
    }
    if (anchor) {
      el.style.marginLeft = (-anchor.x) + 'px';
      el.style.marginTop  = (-anchor.y) + 'px';
    }
    if (size) {
      el.style.width  = size.x + 'px';
      el.style.height = size.y + 'px';
    }
  },

  _createIconEl: function (name, el) {
    var src = this._getIconUrl(name);
    if (el) {
      while (el.firstChild) {
        el.removeChild(el.firstChild);
      }
    } else {
      el = document.createElement('div');
    }
    if (src) {
      var img = document.createElement('img');
      img.src = src;
      el.appendChild(img);
    }
    return el;
  },

  _getIconUrl: function (name) {
    return this.options[name + 'Url'];
  }
});
export var ArcGis = L.Class.extend({
  options: {
    service_url: 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer'
  },

  initialize: function(accessToken, options) {
    L.setOptions(this, options);
    this._accessToken = accessToken;
  },

  geocode: function(query, cb, context) {
    var params = {
      SingleLine: query,
      outFields: 'Addr_Type',
      forStorage: false,
      maxLocations: 10,
      f: 'json'
    };

    if (this._key && this._key.length) {
      params.token = this._key;
    }

    getJSON(
      this.options.service_url + '/findAddressCandidates',
      L.extend(params, this.options.geocodingQueryParams),
      function(data) {
        var results = [],
          loc,
          latLng,
          latLngBounds;

        if (data.candidates && data.candidates.length) {
          for (var i = 0; i <= data.candidates.length - 1; i++) {
            loc = data.candidates[i];
            latLng = L.latLng(loc.location.y, loc.location.x);
            latLngBounds = L.latLngBounds(
              L.latLng(loc.extent.ymax, loc.extent.xmax),
              L.latLng(loc.extent.ymin, loc.extent.xmin)
            );
            results[i] = {
              name: loc.address,
              bbox: latLngBounds,
              center: latLng
            };
          }
        }

        cb.call(context, results);
      }
    );
  },

  suggest: function(query, cb, context) {
    return this.geocode(query, cb, context);
  },

  reverse: function(location, scale, cb, context) {
    var params = {
      location: encodeURIComponent(location.lng) + ',' + encodeURIComponent(location.lat),
      distance: 100,
      f: 'json'
    };

    getJSON(this.options.service_url + '/reverseGeocode', params, function(data) {
      var result = [],
        loc;

      if (data && !data.error) {
        loc = L.latLng(data.location.y, data.location.x);
        result.push({
          name: data.address.Match_addr,
          center: loc,
          bounds: L.latLngBounds(loc, loc)
        });
      }

      cb.call(context, result);
    });
  }
});
L.Symbol.Dash = L.Class.extend({
    options: {
        pixelSize: 10,
        pathOptions: { }
    },

    initialize: function (options) {
        L.Util.setOptions(this, options);
        this.options.pathOptions.clickable = false;
    },

    buildSymbol: function(dirPoint, latLngs, map, index, total) {
        const opts = this.options;
        const d2r = Math.PI / 180;

        // for a dot, nothing more to compute
        if(opts.pixelSize <= 1) {
            return L.polyline([dirPoint.latLng, dirPoint.latLng], opts.pathOptions);
        }

        const midPoint = map.project(dirPoint.latLng);
        const angle = (-(dirPoint.heading - 90)) * d2r;
        const a = L.point(
            midPoint.x + opts.pixelSize * Math.cos(angle + Math.PI) / 2,
            midPoint.y + opts.pixelSize * Math.sin(angle) / 2
        );
        // compute second point by central symmetry to avoid unecessary cos/sin
        const b = midPoint.add(midPoint.subtract(a));
        return L.polyline([map.unproject(a), map.unproject(b)], opts.pathOptions);
    }
});
Example #7
0
L.Editable.BaseEditor = L.Class.extend({

    initialize: function (map, feature, options) {
        L.setOptions(this, options);
        this.map = map;
        this.feature = feature;
        this.feature.editor = this;
        this.editLayer = new L.LayerGroup();
        this.tools = this.options.editTools || map.editTools;
    },

    enable: function () {
        if (this._enabled) return this;
        this.tools.editLayer.addLayer(this.editLayer);
        this.onEnable();
        this._enabled = true;
        this.feature.on('remove', this.disable, this);
        return this;
    },

    disable: function () {
        this.feature.off('remove', this.disable, this);
        this.editLayer.clearLayers();
        this.tools.editLayer.removeLayer(this.editLayer);
        this.onDisable();
        delete this._enabled;
        if (this._drawing) this.cancelDrawing();
        return this;
    },

    drawing: function () {
        return !!this._drawing;
    },

    fireAndForward: function (type, e) {
        e = e || {};
        e.layer = this.feature;
        this.feature.fire(type, e);
        this.tools.fireAndForward(type, e);
    },

    onEnable: function () {
        this.fireAndForward('editable:enable');
    },

    onDisable: function () {
        this.fireAndForward('editable:disable');
    },

    onEditing: function () {
        this.fireAndForward('editable:editing');
    },

    onStartDrawing: function () {
        this.fireAndForward('editable:drawing:start');
    },

    onEndDrawing: function () {
        this.fireAndForward('editable:drawing:end');
    },

    onCancelDrawing: function () {
        this.fireAndForward('editable:drawing:cancel');
    },

    onCommitDrawing: function (e) {
        this.fireAndForward('editable:drawing:commit', e);
    },

    startDrawing: function () {
        if (!this._drawing) this._drawing = L.Editable.FORWARD;
        this.tools.registerForDrawing(this);
        this.onStartDrawing();
    },

    commitDrawing: function (e) {
        this.onCommitDrawing(e);
        this.endDrawing();
    },

    cancelDrawing: function () {
        this.onCancelDrawing();
        this.endDrawing();
    },

    endDrawing: function () {
        this._drawing = false;
        this.tools.unregisterForDrawing(this);
        this.onEndDrawing();
    },

    onDrawingClick: function (e) {
        if (!this.drawing) return;
        L.Editable.makeCancellable(e);
        this.fireAndForward('editable:drawing:click', e);
        if (e._cancelled) return;
        this.processDrawingClick(e);
    },

    onMove: function (e) {
        this.fireAndForward('editable:drawing:move', e);
    },

    onMouseMove: function (e) {
        this.onMove(e);
    }

});
Example #8
0
module.exports = L.Class.extend({

  includes: L.Mixin.Events,

  options: {
    opacity: 1,
    padding: L.Path.CLIP_PADDING,
    zIndex: 1,
    usePathContainer: false
  },

  /**
   * @class SvgLayer - basically, just the SVG container simiar to the one
   * used by leaflet internally to render vector layers
   *
   * @extends {L.Class}
   * @constructor
   * @param  {Object=} options
   */
  initialize: function(options) {
    /**
     * @type {Element}
     */
    this._container = null;


    /**
     * @type {SVGElement}
     */
    this._pathRoot  = null;


    /**
     * @type {L.Map}
     */
    this._map = null;


    /**
     * @type {L.Bounds}
     */
    this._pathViewport = null;


    /**
     * @type {Boolean}
     */
    this._pathZooming = false;

    L.Util.setOptions(this, options);
  },


  /**
   * @param  {L.Map} map
   * @return {SvgLayer}
   */
  onAdd: function(map) {
    this._map = map;
    this._initPathRoot();
    return this;
  },


  /**
   * @param {L.Map} map
   * @return {SvgLayer}
   */
  addTo: function(map) {
    map.addLayer(this);
    return this;
  },


  /**
   * @param  {L.Map} map
   * @return {SvgLayer}
   */
  onRemove: function(map) {
    if (this._map.options.zoomAnimation && L.Browser.any3d) {
      this._map.off({
        'zoomanim': this._animatePathZoom,
        'zoomend': this._endPathZoom
      }, this);
    }

    this._map.off('moveend', this._updateSvgViewport, this);
    this._map.getPanes().overlayPane.removeChild(this._container);

    return this;
  },


  /**
   * @param  {L.Map} map
   * @return {SvgLayer}
   */
  removeFrom: function(map) {
    map.removeLayer(this);
    return this;
  },


  /**
   * @return {SvgLayer}
   */
  bringToFront: function () {
    var root = this._container.parentNode;
    var container = this._container;

    if (container && root.lastChild !== container) {
      root.appendChild(container);
    }

    return this;
  },


  /**
   * @return {SvgLayer}
   */
  bringToBack: function () {
    var root = this._container.parentNode;
    var container = this._container;
    var first = root.firstChild;

    if (container && first !== container) {
      root.insertBefore(container, first);
    }
    return this;
  },


  /**
   * @param {Number} opacity
   * @return {SVGLayer}
   */
  setOpacity: function (opacity) {
    this.options.opacity = opacity;
    this._updateOpacity();
    return this;
  },


  /**
   * @param {Number} zIndex
   * @return {SVGLayet}
   */
  setZIndex: function (zIndex) {
    this.options.zIndex = zIndex;
    this._updateZIndex();

    return this;
  },


  /**
   * Create svg root
   */
  _createRoot: function() {
    this._container = L.DomUtil.create('div', 'leaflet-schematic-layer');
    if (this.options.usePathContainer) {
      if (!this._map._pathRoot) {
        this._map._initPathRoot();
      }
      this._pathRoot = this._map._pathRoot;
    } else {
      this._pathRoot = L.Path.prototype._createElement('svg');
      this._container.appendChild(this._pathRoot);
    }
  },


  /**
   * Init the root element
   */
  _initPathRoot: function () {
    if (!this._pathRoot) {
      var pane = this._map.getPanes().overlayPane;
      this._createRoot();
      pane.insertBefore(this._container, pane.firstChild);

      if (this._map.options.zoomAnimation && L.Browser.any3d) {
        L.DomUtil.addClass(this._pathRoot, 'leaflet-zoom-animated');

        this._map.on({
          'zoomanim': this._animatePathZoom,
          'zoomend': this._endPathZoom
        }, this);
      } else {
        L.DomUtil.addClass(this._pathRoot, 'leaflet-zoom-hide');
      }

      this._map.on('moveend', this._updateSvgViewport, this);
      this._updateSvgViewport();

      this._updateOpacity();
      this._updateZIndex();
    }
  },


  /**
   * Sets conatiner opacity
   */
  _updateOpacity: function() {
    L.DomUtil.setOpacity(this._container, this.options.opacity);
  },


  /**
   * Sets container zIndex
   */
  _updateZIndex: function () {
    if (this._container && this.options.zIndex !== undefined) {
      this._container.style.zIndex = this.options.zIndex;
    }
  },


  /**
   * To override in the child classes
   * @return {L.Bounds}
   */
  _getViewport: function() {
    return this._pathViewport;
  },


  /**
   * Update root position to get the viewport covered
   */
  _updateContentViewport: function () {
    var p = this.options.padding;
    var size = this._map.getSize();
    var panePos = L.DomUtil.getPosition(this._map._mapPane);
    var min = panePos.multiplyBy(-1)._subtract(size.multiplyBy(p)._round());
    var max = min.add(size.multiplyBy(1 + p * 2)._round());

    this._pathViewport = new L.Bounds([min.x, min.y], [max.x, max.y]);
  },


  /**
   * @param  {ZoomEvent} e
   */
  _animatePathZoom: function (e) {
    if (!this.options.usePathContainer) {
      var scale = this._map.getZoomScale(e.zoom);
      var offset = this._map
        ._getCenterOffset(e.center)
        ._multiplyBy(-scale)
        ._add(this._getViewport().min);

      this._pathRoot.style[L.DomUtil.TRANSFORM] =
        L.DomUtil.getTranslateString(offset) + ' scale(' + scale + ') ';
    }

    this._pathZooming = true;
  },


  /**
   * Here we can do additional post-animation transforms
   */
  _endPathZoom: function () {
    this._pathZooming = false;
  },


  /**
   * Apply the viewport correction
   */
  _updateSvgViewport: function () {

    if (this._pathZooming) {
      // Do not update SVGs while a zoom animation is going on
      // otherwise the animation will break.
      // When the zoom animation ends we will be updated again anyway
      // This fixes the case where you do a momentum move and
      // zoom while the move is still ongoing.
      return;
    }

    this._updateContentViewport();

    var vp     = this._getViewport();
    var min    = vp.min;
    var max    = vp.max;
    var width  = max.x - min.x;
    var height = max.y - min.y;
    var root   = this._pathRoot;
    var pane   = this._map.getPanes().overlayPane;

    // Hack to make flicker on drag end on mobile webkit less irritating
    if (L.Browser.mobileWebkit) {
      this._container.removeChild(root);
    }

    if (!this.options.usePathContainer) {
      L.DomUtil.setPosition(this._pathRoot, min);
      root.setAttribute('width', width);
      root.setAttribute('height', height);
      root.setAttribute('viewBox', [min.x, min.y, width, height].join(' '));
    }

    if (L.Browser.mobileWebkit && !this.options.usePathContainer) {
      this._container.appendChild(root);
    }
  }

});
Example #9
0
module.exports = L.Class.extend({
  initialize: function() {
    this.projections = {
      'EPSG:4326': proj4.WGS84
    };
  },

  get: function(name, cb, context) {
    var parts = name.split(':'),
        authority,
        code,
        transformation,
        proj;

    if (parts.length === 2) {
      authority = parts[0].toUpperCase();
      codeParts = codePattern.exec(parts[1]);
    } else if (parts.length === 1) {
      authority = 'EPSG';
      codeParts = codePattern.exec(parts[0]);
    } else {
      throw 'Unable to parse SRS name';
    }

    if (!codeParts || !codeParts[1]) {
      throw 'Unable to parse SRS name';
    }

    code = codeParts[1];
    transformation = codeParts[3];

    name = authority + ':' + code;
    proj = this.projections[name];

    if (!proj) {
      try {
        proj4.Proj(name);
        // Known, since no exception
        this._store(name, cb, context);
      } catch (e) {
        this._fetch(authority, code, transformation, cb, context);
      }
    } else {
      cb.call(context || cb, name, proj);
    }
  },

  _fetch: function(authority, code, transformation, cb, context) {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = 'http://epsg.io/' + code + (transformation ? '-' + transformation : '') + '.js';
    document.getElementsByTagName('head')[0].appendChild(script);
    // Transformation is not part of the name returned by epsg.io, so
    // the polling doesn't care.
    this._poll(authority, code, cb, context);
  },

  _poll: function(authority, code, cb, context) {
    var _this = this,
        name = authority + ':' + code;
    try {
      proj4.Proj(name);
      this._store(name, cb, context);
    } catch (e) {
      setTimeout(function() {
        _this._poll(authority, code, cb, context);
      }, 100);
    }
  },

  _store: function(name, cb, context) {
    var p = proj4.Proj(name);
    this.projections[name] = p;
    cb.call(context || cb, name, p);
  }
});
define(function(require) {
    "use strict";

    var filter = require('mout/array/filter');
    var forEach = require('mout/array/forEach');
    var L = require('leaflet');
    var pluck = require('mout/array/pluck');
    
    return L.Class.extend({
        /**
         * Initialize the trees layer
         *
         * @constructor
         * @param {Array[]} trees
         * @param {Popup} editMarkerPopup
         */
        initialize: function(trees, editMarkerPopup) {
            this.editMarkerPopup = editMarkerPopup;
            this.layerGroup = L.layerGroup();
            this.trees = trees;

            this.addTreeHandler = this.addTree.bind(this);
            this.onTreesChangeHandler = this.onTreesChange.bind(this);

            this.trees.subscribe(this.onTreesChangeHandler, null, 'arrayChange');
        },
        /**
         * On add
         *
         * @param {Object} map
         */
        onAdd: function(map) {
            this.layerGroup.addTo(map);
        },
        /**
         * On remove
         */
        onRemove: function(map) {
            map.removeLayer(this.layerGroup);
        },
        /**
         *
         */
        addTree: function(tree) {
            var marker = L.marker(
                [tree.latitude(), tree.longitude()],
                {
                    opacity: 0.75
                }
            );

            // this probably leaks memory, right?
            marker.on('click', function() {
                this.editMarkerPopup.setTree(tree);

                marker.bindPopup(this.editMarkerPopup)
                    .openPopup();
            }.bind(this));

            this.layerGroup
                .addLayer(marker);
        },
        /**
         * On trees change handler
         *
         * @param {Object[]} changes
         */
        onTreesChange: function(changes) {
            forEach( // call add tree on each
                pluck( // pluck the value of the change
                    filter( // filter non-added statuses
                        changes,
                        function(change) {
                            return change.status == 'added'
                        }
                    ),
                    'value'
                ),
                this.addTreeHandler
            );

            // TODO handle deletes
        }
    });
});
Example #11
0
  class: L.Class.extend({
    options: {
      geocodeUrl: 'http://geocoder.api.here.com/6.2/geocode.json',
      reverseGeocodeUrl: 'http://reverse.geocoder.api.here.com/6.2/reversegeocode.json',
      app_id: '<insert your app_id here>',
      app_code: '<insert your app_code here>',
      geocodingQueryParams: {},
      reverseQueryParams: {},
    },

    initialize: function(options) {
      L.setOptions(this, options);
    },

    geocode: function(query, cb, context) {
      var params = {
        searchtext: query,
        gen: 9,
        app_id: this.options.app_id,
        app_code: this.options.app_code,
        jsonattributes: 1,
      };
      params = L.Util.extend(params, this.options.geocodingQueryParams);
      this.getJSON(this.options.geocodeUrl, params, cb, context);
    },

    reverse: function(location, scale, cb, context) {
      var params = {
        prox: encodeURIComponent(location.lat) + ',' + encodeURIComponent(location.lng),
        mode: 'retrieveAddresses',
        app_id: this.options.app_id,
        app_code: this.options.app_code,
        gen: 9,
        jsonattributes: 1,
      };
      params = L.Util.extend(params, this.options.reverseQueryParams);
      this.getJSON(this.options.reverseGeocodeUrl, params, cb, context);
    },

    getJSON: function(url, params, cb, context) {
      getJSON(url, params, function(data) {
        var results = [],
          loc,
          latLng,
          latLngBounds;
        if (data.response.view && data.response.view.length) {
          for (var i = 0; i <= data.response.view[0].result.length - 1; i++) {
            loc = data.response.view[0].result[i].location;
            latLng = L.latLng(loc.displayPosition.latitude, loc.displayPosition.longitude);
            latLngBounds = L.latLngBounds(
              L.latLng(loc.mapView.topLeft.latitude, loc.mapView.topLeft.longitude),
              L.latLng(loc.mapView.bottomRight.latitude, loc.mapView.bottomRight.longitude)
            );
            results[i] = {
              name: loc.address.label,
              bbox: latLngBounds,
              center: latLng,
            };
          }
        }
        cb.call(context, results);
      });
    },
  }),
Example #12
0
  class: L.Class.extend({
    options: {
      serviceUrl: 'https://api.what3words.com/v2/',
    },

    initialize: function(accessToken) {
      this._accessToken = accessToken;
    },

    geocode: function(query, cb, context) {
      //get three words and make a dot based string
      getJSON(
        this.options.serviceUrl + 'forward',
        {
          key: this._accessToken,
          addr: query.split(/\s+/).join('.'),
        },
        function(data) {
          var results = [],
            latLng,
            latLngBounds;
          if (data.hasOwnProperty('geometry')) {
            latLng = L.latLng(data.geometry['lat'], data.geometry['lng']);
            latLngBounds = L.latLngBounds(latLng, latLng);
            results[0] = {
              name: data.words,
              bbox: latLngBounds,
              center: latLng,
            };
          }

          cb.call(context, results);
        }
      );
    },

    suggest: function(query, cb, context) {
      return this.geocode(query, cb, context);
    },

    reverse: function(location, scale, cb, context) {
      getJSON(
        this.options.serviceUrl + 'reverse',
        {
          key: this._accessToken,
          coords: [location.lat, location.lng].join(','),
        },
        function(data) {
          var results = [],
            latLng,
            latLngBounds;
          if (data.status.status === 200) {
            latLng = L.latLng(data.geometry['lat'], data.geometry['lng']);
            latLngBounds = L.latLngBounds(latLng, latLng);
            results[0] = {
              name: data.words,
              bbox: latLngBounds,
              center: latLng,
            };
          }
          cb.call(context, results);
        }
      );
    },
  }),
export var Renderer = L.Class.extend({
  options: {
    proportionalPolygon: false,
    clickable: true
  },

  initialize: function (rendererJson, options) {
    this._rendererJson = rendererJson;
    this._pointSymbols = false;
    this._symbols = [];
    this._visualVariables = this._parseVisualVariables(rendererJson.visualVariables);
    L.Util.setOptions(this, options);
  },

  _parseVisualVariables: function (visualVariables) {
    var visVars = {};
    if (visualVariables) {
      for (var i = 0; i < visualVariables.length; i++) {
        visVars[visualVariables[i].type] = visualVariables[i];
      }
    }
    return visVars;
  },

  _createDefaultSymbol: function () {
    if (this._rendererJson.defaultSymbol) {
      this._defaultSymbol = this._newSymbol(this._rendererJson.defaultSymbol);
      this._defaultSymbol._isDefault = true;
    }
  },

  _newSymbol: function (symbolJson) {
    if (symbolJson.type === 'esriSMS' || symbolJson.type === 'esriPMS') {
      this._pointSymbols = true;
      return pointSymbol(symbolJson, this.options);
    }
    if (symbolJson.type === 'esriSLS') {
      return lineSymbol(symbolJson, this.options);
    }
    if (symbolJson.type === 'esriSFS') {
      return polygonSymbol(symbolJson, this.options);
    }
  },

  _getSymbol: function () {
    // override
  },

  attachStylesToLayer: function (layer) {
    if (this._pointSymbols) {
      layer.options.pointToLayer = L.Util.bind(this.pointToLayer, this);
    } else {
      layer.options.style = L.Util.bind(this.style, this);
      layer._originalStyle = layer.options.style;
    }
  },

  pointToLayer: function (geojson, latlng, options) {
    var sym = this._getSymbol(geojson);
    if (sym && sym.pointToLayer) {
      return sym.pointToLayer(geojson, latlng, this._visualVariables, options);
    }
    // invisible symbology
    return L.circleMarker(latlng, {radius: 0, opacity: 0});
  },

  style: function (feature) {
    var userStyles;
    if (this.options.userDefinedStyle) {
      userStyles = this.options.userDefinedStyle(feature);
    }
    // find the symbol to represent this feature
    var sym = this._getSymbol(feature);
    if (sym) {
      return this.mergeStyles(sym.style(feature, this._visualVariables), userStyles);
    } else {
      // invisible symbology
      return this.mergeStyles({opacity: 0, fillOpacity: 0}, userStyles);
    }
  },

  mergeStyles: function (styles, userStyles) {
    var mergedStyles = {};
    var attr;
    // copy renderer style attributes
    for (attr in styles) {
      if (styles.hasOwnProperty(attr)) {
        mergedStyles[attr] = styles[attr];
      }
    }
    // override with user defined style attributes
    if (userStyles) {
      for (attr in userStyles) {
        if (userStyles.hasOwnProperty(attr)) {
          mergedStyles[attr] = userStyles[attr];
        }
      }
    }
    return mergedStyles;
  }
});
var InteractionLayer = L.Class.extend({

    includes : L.Mixin.Events,

    options : {
        resolution : 4,
        pointerCursor : true
    },

    /** Initializes this layer */
    initialize : function(options) {
        L.setOptions(this, options);
        // this._move = _.throttle(this._move, 20);
        // this._update = _.debounce(this._update, 10);
    },

    /**
     * This method is called when this layer is added to the map.
     */
    onAdd : function(map) {
        this._map = map;
        this._container = this._map._container;
        // this._update();
        // map.on('click', this._click, this);
        map.on('mousemove', this._move, this);
        // map.on('moveend', this._update, this);
    },

    /**
     * This method is called when this layer is removed from the map.
     */
    onRemove : function() {
        var map = this._map;
        map.off('click', this._click, this);
        map.off('mousemove', this._move, this);
        // map.off('moveend', this._update, this);
        this._removeMouseCursorStyle();
    },

    /** Map click handler */
    _click : function(e) {
        var on = this._objectForEvent(e);
        if (on.data) {
            this.fire('click', on);
        }
    },

    /** Map move handler */
    _move : function(e) {
        var on = this._objectForEvent(e);
        if (on.data !== this._mouseOn) {
            if (this._mouseOn) {
                this.fire('mouseout', {
                    latlng : e.latlng,
                    data : this._mouseOn
                });
                this._removeMouseCursorStyle();
            }
            if (on.data) {
                this.fire('mouseover', on);
                this._setMouseCursorStyle();
            }
            this._mouseOn = on.data;
        } else if (on.data) {
            this.fire('mousemove', on);
        }
    },

    /**
     * Checks if the cursor style of the container should be changed to pointer
     * cursor
     */
    _setMouseCursorStyle : function() {
        if (!this.options.pointerCursor)
            return;
        if (!this._container._pointerCursorCount) {
            this._container._pointerCursorCount = 1;
            this._container.style.cursor = 'pointer';
        } else {
            this._container._pointerCursorCount++;
        }
    },

    /** Removes cursor style from the container */
    _removeMouseCursorStyle : function() {
        if (!this.options.pointerCursor)
            return;
        if (this._container._pointerCursorCount) {
            this._container._pointerCursorCount--;
            if (this._container._pointerCursorCount === 0) {
                this._container.style.cursor = '';
                delete this._container._pointerCursorCount;
            }
        }
    },

    /**
     * Returns an object from UTF grid corresponding to the coordinates of the
     * mouse event.
     */
    _objectForEvent : function(e) {
        throw new Error('This method should be implemented ' + //
        'in subclasses.');
    },

});
export var Photon = L.Class.extend({
  options: {
    serviceUrl: 'https://photon.komoot.de/api/',
    reverseUrl: 'https://photon.komoot.de/reverse/',
    nameProperties: ['name', 'street', 'suburb', 'hamlet', 'town', 'city', 'state', 'country']
  },

  initialize: function(options) {
    L.setOptions(this, options);
  },

  geocode: function(query, cb, context) {
    var params = L.extend(
      {
        q: query
      },
      this.options.geocodingQueryParams
    );

    getJSON(
      this.options.serviceUrl,
      params,
      L.bind(function(data) {
        cb.call(context, this._decodeFeatures(data));
      }, this)
    );
  },

  suggest: function(query, cb, context) {
    return this.geocode(query, cb, context);
  },

  reverse: function(latLng, scale, cb, context) {
    var params = L.extend(
      {
        lat: latLng.lat,
        lon: latLng.lng
      },
      this.options.reverseQueryParams
    );

    getJSON(
      this.options.reverseUrl,
      params,
      L.bind(function(data) {
        cb.call(context, this._decodeFeatures(data));
      }, this)
    );
  },

  _decodeFeatures: function(data) {
    var results = [],
      i,
      f,
      c,
      latLng,
      extent,
      bbox;

    if (data && data.features) {
      for (i = 0; i < data.features.length; i++) {
        f = data.features[i];
        c = f.geometry.coordinates;
        latLng = L.latLng(c[1], c[0]);
        extent = f.properties.extent;

        if (extent) {
          bbox = L.latLngBounds([extent[1], extent[0]], [extent[3], extent[2]]);
        } else {
          bbox = L.latLngBounds(latLng, latLng);
        }

        results.push({
          name: this._decodeFeatureName(f),
          html: this.options.htmlTemplate ? this.options.htmlTemplate(f) : undefined,
          center: latLng,
          bbox: bbox,
          properties: f.properties
        });
      }
    }

    return results;
  },

  _decodeFeatureName: function(f) {
    return (this.options.nameProperties || [])
      .map(function(p) {
        return f.properties[p];
      })
      .filter(function(v) {
        return !!v;
      })
      .join(', ');
  }
});
var L = require('leaflet');

L.AbstractWorker = L.Class.extend({
    initialize: function () {
    },

    onAdd: function (map) {
    },

    onRemove: function (map) {
    },

    process: function(tile, callback) {
        callback(tile);
    },
    
    abort: function(tile) {
    },
    
    clear: function() {
    }
});

// dummy worker (= no worker) when used directly
L.noWorker = function () {
    return new L.AbstractWorker();
};
(function() {
	'use strict';

	var L = require('leaflet');

	L.Routing = L.Routing || {};

	L.extend(L.Routing, require('./L.Routing.Localization'));

	L.Routing.Formatter = L.Class.extend({
		options: {
			units: 'metric',
			unitNames: {
				meters: 'm',
				kilometers: 'km',
				yards: 'yd',
				miles: 'mi',
				hours: 'h',
				minutes: 'mín',
				seconds: 's'
			},
			language: 'en',
			roundingSensitivity: 1,
			distanceTemplate: '{value} {unit}'
		},

		initialize: function(options) {
			L.setOptions(this, options);
		},

		formatDistance: function(d /* Number (meters) */) {
			var un = this.options.unitNames,
			    v,
				data;

			if (this.options.units === 'imperial') {
				d = d / 1.609344;
				if (d >= 1000) {
					data = {
						value: (this._round(d) / 1000),
						unit: un.miles
					};
				} else {
					data = {
						value: this._round(d / 1.760),
						unit: un.yards
					};
				}
			} else {
				v = this._round(d);
				data = {
					value: v >= 1000 ? (v / 1000) : v,
					unit: v >= 1000 ? un.kilometers : un.meters
				};
			}

			return L.Util.template(this.options.distanceTemplate, data);
		},

		_round: function(d) {
			var pow10 = Math.pow(10, (Math.floor(d / this.options.roundingSensitivity) + '').length - 1),
				r = Math.floor(d / pow10),
				p = (r > 5) ? pow10 : pow10 / 2;

			return Math.round(d / p) * p;
		},

		formatTime: function(t /* Number (seconds) */) {
			if (t > 86400) {
				return Math.round(t / 3600) + ' h';
			} else if (t > 3600) {
				return Math.floor(t / 3600) + ' h ' +
					Math.round((t % 3600) / 60) + ' min';
			} else if (t > 300) {
				return Math.round(t / 60) + ' min';
			} else if (t > 60) {
				return Math.floor(t / 60) + ' min' +
					(t % 60 !== 0 ? ' ' + (t % 60) + ' s' : '');
			} else {
				return t + ' s';
			}
		},

		formatInstruction: function(instr, i) {
			if (instr.text === undefined) {
				return L.Util.template(this._getInstructionTemplate(instr, i),
					L.extend({
						exitStr: instr.exit ? L.Routing.Localization[this.options.language].formatOrder(instr.exit) : '',
						dir: L.Routing.Localization[this.options.language].directions[instr.direction]
					},
					instr));
			} else {
				return instr.text;
			}
		},

		getIconName: function(instr, i) {
			switch (instr.type) {
			case 'Straight':
				return (i === 0 ? 'depart' : 'continue');
			case 'SlightRight':
				return 'bear-right';
			case 'Right':
				return 'turn-right';
			case 'SharpRight':
				return 'sharp-right';
			case 'TurnAround':
				return 'u-turn';
			case 'SharpLeft':
				return 'sharp-left';
			case 'Left':
				return 'turn-left';
			case 'SlightLeft':
				return 'bear-left';
			case 'WaypointReached':
				return 'via';
			case 'Roundabout':
				return 'enter-roundabout';
			case 'DestinationReached':
				return 'arrive';
			}
		},

		_getInstructionTemplate: function(instr, i) {
			var type = instr.type === 'Straight' ? (i === 0 ? 'Head' : 'Continue') : instr.type,
				strings = L.Routing.Localization[this.options.language].instructions[type];

			return strings[0] + (strings.length > 1 && instr.road ? strings[1] : '');
		}
	});

	module.exports = L.Routing;
})();
(function() {
	'use strict';

	var L = require('leaflet');

	L.Routing = L.Routing || {};
	L.extend(L.Routing, require('./L.Routing.Util'));
	L.extend(L.Routing, require('./L.Routing.Waypoint'));

	L.Routing.GraphHopper = L.Class.extend({
		options: {
			serviceUrl: 'https://graphhopper.com/api/1/route',
			timeout: 30 * 1000
		},

		initialize: function(apiKey, options) {
			this._apiKey = apiKey;
			L.Util.setOptions(this, options);
		},

		route: function(waypoints, callback, context, options) {
			var timedOut = false,
				wps = [],
				url,
				timer,
				wp,
				i;

			options = options || {};
			url = this.buildRouteUrl(waypoints, options);

			timer = setTimeout(function() {
								timedOut = true;
								callback.call(context || callback, {
									status: -1,
									message: 'GraphHopper request timed out.'
								});
							}, this.options.timeout);

			// Create a copy of the waypoints, since they
			// might otherwise be asynchronously modified while
			// the request is being processed.
			for (i = 0; i < waypoints.length; i++) {
				wp = waypoints[i];
				wps.push(new L.Routing.Waypoint(wp.latLng, wp.name, wp.options));
			}

			L.Routing._jsonp(url, function(data) {
				clearTimeout(timer);
				if (!timedOut) {
					this._routeDone(data, wps, callback, context);
				}
			}, this, 'callback');

			return this;
		},

		_routeDone: function(response, inputWaypoints, callback, context) {
			var alts = [],
			    mappedWaypoints,
			    coordinates,
			    i,
			    path;

			context = context || callback;
			if (response.info.errors && response.info.errors.length) {
				callback.call(context, {
					// TODO: include all errors
					status: response.info.errors[0].details,
					message: response.info.errors[0].message
				});
				return;
			}

			for (i = 0; i < response.paths.length; i++) {
				path = response.paths[i];
				coordinates = L.Routing._decodePolyline(path.points, 5);
				mappedWaypoints =
					this._mapWaypointIndices(inputWaypoints, path.instructions, coordinates);

				alts.push({
					name: '',
					coordinates: coordinates,
					instructions: this._convertInstructions(path.instructions),
					summary: {
						totalDistance: path.distance,
						totalTime: path.time / 1000,
					},
					inputWaypoints: inputWaypoints,
					actualWaypoints: mappedWaypoints.waypoints,
					waypointIndices: mappedWaypoints.waypointIndices
				});
			}

			callback.call(context, null, alts);
		},

		_toWaypoints: function(inputWaypoints, vias) {
			var wps = [],
			    i;
			for (i = 0; i < vias.length; i++) {
				wps.push(L.Routing.waypoint(L.latLng(vias[i]),
				                            inputWaypoints[i].name,
				                            inputWaypoints[i].options));
			}

			return wps;
		},

		buildRouteUrl: function(waypoints, options) {
			var computeInstructions =
				!(options && options.geometryOnly),
				locs = [],
				i;

			for (i = 0; i < waypoints.length; i++) {
				locs.push('point=' + waypoints[i].latLng.lat + ',' + waypoints[i].latLng.lng);
			}

			return this.options.serviceUrl + '?' +
				locs.join('&') +
				'&instructions=' + computeInstructions +
				'&type=jsonp' +
				'&key=' + this._apiKey;
		},

		_convertInstructions: function(instructions) {
			var signToType = {
					'-3': 'SharpLeft',
					'-2': 'Left',
					'-1': 'SlightLeft',
					0: 'Straight',
					1: 'SlightRight',
					2: 'Right',
					3: 'SharpRight',
					4: 'DestinationReached',
					5: 'WaypointReached'
				},
				result = [],
			    i,
			    instr;

			for (i = 0; i < instructions.length; i++) {
				instr = instructions[i];
				result.push({
					type: signToType[instr.sign],
					text: instr.text,
					distance: instr.distance,
					time: instr.time / 1000,
					index: instr.interval[0]
				});
			}

			return result;
		},

		_mapWaypointIndices: function(waypoints, instructions, coordinates) {
			var wps = [],
				wpIndices = [],
			    i,
			    idx;

			wpIndices.push(0);
			wps.push(new L.Routing.Waypoint(coordinates[0], waypoints[0].name));

			for (i = 0; i < instructions.length; i++) {
				if (instructions[i].sign === 5) { // VIA_REACHED
					idx = instructions[i].interval[0];
					wpIndices.push(idx);
					wps.push(new L.Routing.Waypoint(coordinates[idx], waypoints[wps.length + 1].name));
				}
			}

			wpIndices.push(coordinates.length - 1);
			wps.push(new L.Routing.Waypoint(coordinates[coordinates.length - 1], waypoints[waypoints.length - 1].name));

			return {
				waypointIndices: wpIndices,
				waypoints: wps
			};
		}
	});

	L.Routing.graphHopper = function(options) {
		return new L.Routing.GraphHopper(options);
	};

	module.exports = L.Routing;
})();
(function() {
	'use strict';

	var L = require('leaflet'),
		corslite = require('@mapbox/corslite'),
		polyline = require('@mapbox/polyline'),
		osrmTextInstructions = require('osrm-text-instructions')('v5');

	// Ignore camelcase naming for this file, since OSRM's API uses
	// underscores.
	/* jshint camelcase: false */

	var Waypoint = require('./waypoint');

	/**
	 * Works against OSRM's new API in version 5.0; this has
	 * the API version v1.
	 */
	module.exports = L.Class.extend({
		options: {
			serviceUrl: 'https://router.project-osrm.org/route/v1',
			profile: 'driving',
			timeout: 30 * 1000,
			routingOptions: {
				alternatives: true,
				steps: true
			},
			polylinePrecision: 5,
			useHints: true,
			suppressDemoServerWarning: false,
			language: 'en'
		},

		initialize: function(options) {
			L.Util.setOptions(this, options);
			this._hints = {
				locations: {}
			};

			if (!this.options.suppressDemoServerWarning &&
				this.options.serviceUrl.indexOf('//router.project-osrm.org') >= 0) {
				console.warn('You are using OSRM\'s demo server. ' +
					'Please note that it is **NOT SUITABLE FOR PRODUCTION USE**.\n' +
					'Refer to the demo server\'s usage policy: ' +
					'https://github.com/Project-OSRM/osrm-backend/wiki/Api-usage-policy\n\n' +
					'To change, set the serviceUrl option.\n\n' +
					'Please do not report issues with this server to neither ' +
					'Leaflet Routing Machine or OSRM - it\'s for\n' +
					'demo only, and will sometimes not be available, or work in ' +
					'unexpected ways.\n\n' +
					'Please set up your own OSRM server, or use a paid service ' +
					'provider for production.');
			}
		},

		route: function(waypoints, callback, context, options) {
			var timedOut = false,
				wps = [],
				url,
				timer,
				wp,
				i,
				xhr;

			options = L.extend({}, this.options.routingOptions, options);
			url = this.buildRouteUrl(waypoints, options);
			if (this.options.requestParameters) {
				url += L.Util.getParamString(this.options.requestParameters, url);
			}

			timer = setTimeout(function() {
				timedOut = true;
				callback.call(context || callback, {
					status: -1,
					message: 'OSRM request timed out.'
				});
			}, this.options.timeout);

			// Create a copy of the waypoints, since they
			// might otherwise be asynchronously modified while
			// the request is being processed.
			for (i = 0; i < waypoints.length; i++) {
				wp = waypoints[i];
				wps.push(new Waypoint(wp.latLng, wp.name, wp.options));
			}

			return xhr = corslite(url, L.bind(function(err, resp) {
				var data,
					error =  {};

				clearTimeout(timer);
				if (!timedOut) {
					if (!err) {
						try {
							data = JSON.parse(resp.responseText);
							try {
								return this._routeDone(data, wps, options, callback, context);
							} catch (ex) {
								error.status = -3;
								error.message = ex.toString();
							}
						} catch (ex) {
							error.status = -2;
							error.message = 'Error parsing OSRM response: ' + ex.toString();
						}
					} else {
						var message = err.type + (err.target && err.target.status ? ' HTTP ' + err.target.status + ': ' + err.target.statusText : '');
						if (err.responseText) {
							try {
								data = JSON.parse(err.responseText);
								if (data.message)
									message = data.message;
							} catch (ex) {
							}
						}
						error.message = 'HTTP request failed: ' + message;
						error.url = url;
						error.status = -1;
						error.target = err;
					}

					callback.call(context || callback, error);
				} else {
					xhr.abort();
				}
			}, this));
		},

		requiresMoreDetail: function(route, zoom, bounds) {
			if (!route.properties.isSimplified) {
				return false;
			}

			var waypoints = route.inputWaypoints,
				i;
			for (i = 0; i < waypoints.length; ++i) {
				if (!bounds.contains(waypoints[i].latLng)) {
					return true;
				}
			}

			return false;
		},

		_routeDone: function(response, inputWaypoints, options, callback, context) {
			var alts = [],
			    actualWaypoints,
			    i,
			    route;

			context = context || callback;
			if (response.code !== 'Ok') {
				callback.call(context, {
					status: response.code
				});
				return;
			}

			actualWaypoints = this._toWaypoints(inputWaypoints, response.waypoints);

			for (i = 0; i < response.routes.length; i++) {
				route = this._convertRoute(response.routes[i]);
				route.inputWaypoints = inputWaypoints;
				route.waypoints = actualWaypoints;
				route.properties = {isSimplified: !options || !options.geometryOnly || options.simplifyGeometry};
				alts.push(route);
			}

			this._saveHintData(response.waypoints, inputWaypoints);

			callback.call(context, null, alts);
		},

		_convertRoute: function(responseRoute) {
			var result = {
					name: '',
					coordinates: [],
					instructions: [],
					summary: {
						totalDistance: responseRoute.distance,
						totalTime: responseRoute.duration
					}
				},
				legNames = [],
				waypointIndices = [],
				index = 0,
				legCount = responseRoute.legs.length,
				hasSteps = responseRoute.legs[0].steps.length > 0,
				i,
				j,
				leg,
				step,
				geometry,
				type,
				modifier,
				text,
				stepToText;

			if (this.options.stepToText) {
				stepToText = this.options.stepToText;
			} else {
				stepToText = L.bind(osrmTextInstructions.compile, osrmTextInstructions, this.options.language);
			}

			for (i = 0; i < legCount; i++) {
				leg = responseRoute.legs[i];
				legNames.push(leg.summary && leg.summary.charAt(0).toUpperCase() + leg.summary.substring(1));
				for (j = 0; j < leg.steps.length; j++) {
					step = leg.steps[j];
					geometry = this._decodePolyline(step.geometry);
					result.coordinates.push.apply(result.coordinates, geometry);
					type = this._maneuverToInstructionType(step.maneuver, i === legCount - 1);
					modifier = this._maneuverToModifier(step.maneuver);
					text = stepToText(step, {legCount: legCount, legIndex: i});

					if (type) {
						if ((i == 0 && step.maneuver.type == 'depart') || step.maneuver.type == 'arrive') {
							waypointIndices.push(index);
						}

						result.instructions.push({
							type: type,
							distance: step.distance,
							time: step.duration,
							road: step.name,
							direction: this._bearingToDirection(step.maneuver.bearing_after),
							exit: step.maneuver.exit,
							index: index,
							mode: step.mode,
							modifier: modifier,
							text: text
						});
					}

					index += geometry.length;
				}
			}

			result.name = legNames.join(', ');
			if (!hasSteps) {
				result.coordinates = this._decodePolyline(responseRoute.geometry);
			} else {
				result.waypointIndices = waypointIndices;
			}

			return result;
		},

		_bearingToDirection: function(bearing) {
			var oct = Math.round(bearing / 45) % 8;
			return ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'][oct];
		},

		_maneuverToInstructionType: function(maneuver, lastLeg) {
			switch (maneuver.type) {
			case 'new name':
				return 'Continue';
			case 'depart':
				return 'Head';
			case 'arrive':
				return lastLeg ? 'DestinationReached' : 'WaypointReached';
			case 'roundabout':
			case 'rotary':
				return 'Roundabout';
			case 'merge':
			case 'fork':
			case 'on ramp':
			case 'off ramp':
			case 'end of road':
				return this._camelCase(maneuver.type);
			// These are all reduced to the same instruction in the current model
			//case 'turn':
			//case 'ramp': // deprecated in v5.1
			default:
				return this._camelCase(maneuver.modifier);
			}
		},

		_maneuverToModifier: function(maneuver) {
			var modifier = maneuver.modifier;

			switch (maneuver.type) {
			case 'merge':
			case 'fork':
			case 'on ramp':
			case 'off ramp':
			case 'end of road':
				modifier = this._leftOrRight(modifier);
			}

			return modifier && this._camelCase(modifier);
		},

		_camelCase: function(s) {
			var words = s.split(' '),
				result = '';
			for (var i = 0, l = words.length; i < l; i++) {
				result += words[i].charAt(0).toUpperCase() + words[i].substring(1);
			}

			return result;
		},

		_leftOrRight: function(d) {
			return d.indexOf('left') >= 0 ? 'Left' : 'Right';
		},

		_decodePolyline: function(routeGeometry) {
			var cs = polyline.decode(routeGeometry, this.options.polylinePrecision),
				result = new Array(cs.length),
				i;
			for (i = cs.length - 1; i >= 0; i--) {
				result[i] = L.latLng(cs[i]);
			}

			return result;
		},

		_toWaypoints: function(inputWaypoints, vias) {
			var wps = [],
			    i,
			    viaLoc;
			for (i = 0; i < vias.length; i++) {
				viaLoc = vias[i].location;
				wps.push(new Waypoint(L.latLng(viaLoc[1], viaLoc[0]),
				                            inputWaypoints[i].name,
											inputWaypoints[i].options));
			}

			return wps;
		},

		buildRouteUrl: function(waypoints, options) {
			var locs = [],
				hints = [],
				wp,
				latLng,
			    computeInstructions,
			    computeAlternative = true;

			for (var i = 0; i < waypoints.length; i++) {
				wp = waypoints[i];
				latLng = wp.latLng;
				locs.push(latLng.lng + ',' + latLng.lat);
				hints.push(this._hints.locations[this._locationKey(latLng)] || '');
			}

			computeInstructions =
				true;

			return this.options.serviceUrl + '/' + this.options.profile + '/' +
				locs.join(';') + '?' +
				(options.geometryOnly ? (options.simplifyGeometry ? '' : 'overview=full') : 'overview=false') +
				'&alternatives=' + computeAlternative.toString() +
				'&steps=' + computeInstructions.toString() +
				(this.options.useHints ? '&hints=' + hints.join(';') : '') +
				(options.allowUTurns ? '&continue_straight=' + !options.allowUTurns : '');
		},

		_locationKey: function(location) {
			return location.lat + ',' + location.lng;
		},

		_saveHintData: function(actualWaypoints, waypoints) {
			var loc;
			this._hints = {
				locations: {}
			};
			for (var i = actualWaypoints.length - 1; i >= 0; i--) {
				loc = waypoints[i].latLng;
				this._hints.locations[this._locationKey(loc)] = actualWaypoints[i].hint;
			}
		},
	});
})();
Example #20
0
  class: L.Class.extend({
    initialize: function(key) {
      this.key = key;
    },

    geocode: function(query, cb, context) {
      jsonp(
        'https://dev.virtualearth.net/REST/v1/Locations',
        {
          query: query,
          key: this.key,
        },
        function(data) {
          var results = [];
          if (data.resourceSets.length > 0) {
            for (var i = data.resourceSets[0].resources.length - 1; i >= 0; i--) {
              var resource = data.resourceSets[0].resources[i],
                bbox = resource.bbox;
              results[i] = {
                name: resource.name,
                bbox: L.latLngBounds([bbox[0], bbox[1]], [bbox[2], bbox[3]]),
                center: L.latLng(resource.point.coordinates),
              };
            }
          }
          cb.call(context, results);
        },
        this,
        'jsonp'
      );
    },

    reverse: function(location, scale, cb, context) {
      jsonp(
        '//dev.virtualearth.net/REST/v1/Locations/' + location.lat + ',' + location.lng,
        {
          key: this.key,
        },
        function(data) {
          var results = [];
          for (var i = data.resourceSets[0].resources.length - 1; i >= 0; i--) {
            var resource = data.resourceSets[0].resources[i],
              bbox = resource.bbox;
            results[i] = {
              name: resource.name,
              bbox: L.latLngBounds([bbox[0], bbox[1]], [bbox[2], bbox[3]]),
              center: L.latLng(resource.point.coordinates),
            };
          }
          cb.call(context, results);
        },
        this,
        'jsonp'
      );
    },
  }),
	class: L.Class.extend({
		options: {
			serviceUrl: 'https://api.tiles.mapbox.com/v4/geocode/mapbox.places-v1/'
		},

		initialize: function(accessToken, options) {
			L.setOptions(this, options);
			this._accessToken = accessToken;
		},

		geocode: function(query, cb, context) {
			Util.getJSON(this.options.serviceUrl + encodeURIComponent(query) + '.json', {
				access_token: this._accessToken,
			}, function(data) {
				var results = [],
				loc,
				latLng,
				latLngBounds;
				if (data.features && data.features.length) {
					for (var i = 0; i <= data.features.length - 1; i++) {
						loc = data.features[i];
						latLng = L.latLng(loc.center.reverse());
						if(loc.hasOwnProperty('bbox'))
						{
							latLngBounds = L.latLngBounds(L.latLng(loc.bbox.slice(0, 2).reverse()), L.latLng(loc.bbox.slice(2, 4).reverse()));
						}
						else
						{
							latLngBounds = L.latLngBounds(latLng, latLng);
						}
						results[i] = {
							name: loc.place_name,
							bbox: latLngBounds,
							center: latLng
						};
					}
				}

				cb.call(context, results);
			});
		},

		suggest: function(query, cb, context) {
			return this.geocode(query, cb, context);
		},

		reverse: function(location, scale, cb, context) {
			Util.getJSON(this.options.serviceUrl + encodeURIComponent(location.lng) + ',' + encodeURIComponent(location.lat) + '.json', {
				access_token: this._accessToken,
			}, function(data) {
				var results = [],
				loc,
				latLng,
				latLngBounds;
				if (data.features && data.features.length) {
					for (var i = 0; i <= data.features.length - 1; i++) {
						loc = data.features[i];
						latLng = L.latLng(loc.center.reverse());
						if(loc.hasOwnProperty('bbox'))
						{
							latLngBounds = L.latLngBounds(L.latLng(loc.bbox.slice(0, 2).reverse()), L.latLng(loc.bbox.slice(2, 4).reverse()));
						}
						else
						{
							latLngBounds = L.latLngBounds(latLng, latLng);
						}
						results[i] = {
							name: loc.place_name,
							bbox: latLngBounds,
							center: latLng
						};
					}
				}

				cb.call(context, results);
			});
		}
	}),
	class: L.Class.extend({
		options: {
			serviceUrl: 'https://nominatim.openstreetmap.org/',
			geocodingQueryParams: {},
			reverseQueryParams: {},
			htmlTemplate: function(r) {
				var a = r.address,
					parts = [];
				if (a.road || a.building) {
					parts.push('{building} {road} {house_number}');
				}

				if (a.city || a.town || a.village || a.hamlet) {
					parts.push('<span class="' + (parts.length > 0 ? 'leaflet-control-geocoder-address-detail' : '') +
						'">{postcode} {city} {town} {village} {hamlet}</span>');
				}

				if (a.state || a.country) {
					parts.push('<span class="' + (parts.length > 0 ? 'leaflet-control-geocoder-address-context' : '') +
						'">{state} {country}</span>');
				}

				return Util.template(parts.join('<br/>'), a, true);
			}
		},

		initialize: function(options) {
			L.Util.setOptions(this, options);
		},

		geocode: function(query, cb, context) {
			Util.jsonp(this.options.serviceUrl + 'search', L.extend({
				q: query,
				limit: 5,
				format: 'json',
				addressdetails: 1
			}, this.options.geocodingQueryParams),
			function(data) {
				var results = [];
				for (var i = data.length - 1; i >= 0; i--) {
					var bbox = data[i].boundingbox;
					for (var j = 0; j < 4; j++) bbox[j] = parseFloat(bbox[j]);
					results[i] = {
						icon: data[i].icon,
						name: data[i].display_name,
						html: this.options.htmlTemplate ?
							this.options.htmlTemplate(data[i])
							: undefined,
						bbox: L.latLngBounds([bbox[0], bbox[2]], [bbox[1], bbox[3]]),
						center: L.latLng(data[i].lat, data[i].lon),
						properties: data[i]
					};
				}
				cb.call(context, results);
			}, this, 'json_callback');
		},

		reverse: function(location, scale, cb, context) {
			Util.jsonp(this.options.serviceUrl + 'reverse', L.extend({
				lat: location.lat,
				lon: location.lng,
				zoom: Math.round(Math.log(scale / 256) / Math.log(2)),
				addressdetails: 1,
				format: 'json'
			}, this.options.reverseQueryParams), function(data) {
				var result = [],
				    loc;

				if (data && data.lat && data.lon) {
					loc = L.latLng(data.lat, data.lon);
					result.push({
						name: data.display_name,
						html: this.options.htmlTemplate ?
							this.options.htmlTemplate(data)
							: undefined,
						center: loc,
						bounds: L.latLngBounds(loc, loc),
						properties: data
					});
				}

				cb.call(context, result);
			}, this, 'json_callback');
		}
	}),
(function() {
	'use strict';

	var L = require('leaflet'),
		corslite = require('corslite'),
		polyline = require('polyline');

	// Ignore camelcase naming for this file, since OSRM's API uses
	// underscores.
	/* jshint camelcase: false */

	L.Routing = L.Routing || {};
	L.extend(L.Routing, require('./L.Routing.Waypoint'));

	/**
	 * Works against OSRM's new API in version 5.0; this has
	 * the API version v1.
	 */
	L.Routing.OSRMv1 = L.Class.extend({
		options: {
			serviceUrl: 'https://router.project-osrm.org/route/v1',
			profile: 'driving',
			timeout: 30 * 1000,
			routingOptions: {
				alternatives: true,
				steps: true
			},
			polylinePrecision: 5
		},

		initialize: function(options) {
			L.Util.setOptions(this, options);
			this._hints = {
				locations: {}
			};
		},

		route: function(waypoints, callback, context, options) {
			var timedOut = false,
				wps = [],
				url,
				timer,
				wp,
				i;

			options = L.extend({}, this.options.routingOptions, options);
			url = this.buildRouteUrl(waypoints, options);

			timer = setTimeout(function() {
				timedOut = true;
				callback.call(context || callback, {
					status: -1,
					message: 'OSRM request timed out.'
				});
			}, this.options.timeout);

			// Create a copy of the waypoints, since they
			// might otherwise be asynchronously modified while
			// the request is being processed.
			for (i = 0; i < waypoints.length; i++) {
				wp = waypoints[i];
				wps.push(new L.Routing.Waypoint(wp.latLng, wp.name, wp.options));
			}

			corslite(url, L.bind(function(err, resp) {
				var data,
					errorMessage,
					statusCode;

				clearTimeout(timer);
				if (!timedOut) {
					errorMessage = 'HTTP request failed: ' + err;
					statusCode = -1;

					if (!err) {
						try {
							data = JSON.parse(resp.responseText);
							try {
								return this._routeDone(data, wps, options, callback, context);
							} catch (ex) {
								statusCode = -3;
								errorMessage = ex.toString();
							}
						} catch (ex) {
							statusCode = -2;
							errorMessage = 'Error parsing OSRM response: ' + ex.toString();
						}
					}

					callback.call(context || callback, {
						status: statusCode,
						message: errorMessage
					});
				}
			}, this));

			return this;
		},

		requiresMoreDetail: function(route, zoom, bounds) {
			if (!route.properties.isSimplified) {
				return false;
			}

			var waypoints = route.inputWaypoints,
				i;
			for (i = 0; i < waypoints.length; ++i) {
				if (!bounds.contains(waypoints[i].latLng)) {
					return true;
				}
			}

			return false;
		},

		_routeDone: function(response, inputWaypoints, options, callback, context) {
			var alts = [],
			    actualWaypoints,
			    i,
			    route;

			context = context || callback;
			if (response.code !== 'Ok') {
				callback.call(context, {
					status: response.code
				});
				return;
			}

			actualWaypoints = this._toWaypoints(inputWaypoints, response.waypoints);

			for (i = 0; i < response.routes.length; i++) {
				route = this._convertRoute(response.routes[i]);
				route.inputWaypoints = inputWaypoints;
				route.waypoints = actualWaypoints;
				route.properties = {isSimplified: !options || !options.geometryOnly || options.simplifyGeometry};
				alts.push(route);
			}

			this._saveHintData(response.waypoints, inputWaypoints);

			callback.call(context, null, alts);
		},

		_convertRoute: function(responseRoute) {
			var result = {
					name: '',
					coordinates: [],
					instructions: [],
					summary: {
						totalDistance: responseRoute.distance,
						totalTime: responseRoute.duration
					}
				},
				legNames = [],
				index = 0,
				legCount = responseRoute.legs.length,
				hasSteps = responseRoute.legs[0].steps.length > 0,
				i,
				j,
				leg,
				step,
				geometry,
				type;

			for (i = 0; i < legCount; i++) {
				leg = responseRoute.legs[i];
				legNames.push(leg.summary);
				for (j = 0; j < leg.steps.length; j++) {
					step = leg.steps[j];
					geometry = this._decodePolyline(step.geometry);
					result.coordinates.push.apply(result.coordinates, geometry);
					type = this._maneuverToInstructionType(step.maneuver, i === legCount - 1);
					if (type) {
						result.instructions.push({
							type: type,
							distance: step.distance,
							time: step.duration,
							road: step.name,
							direction: this._bearingToDirection(step.maneuver.bearing_after),
							exit: step.maneuver.exit,
							index: index,
							mode: step.mode
						});
					}

					index += geometry.length;
				}
			}

			result.name = legNames.join(', ');
			if (!hasSteps) {
				result.coordinates = this._decodePolyline(responseRoute.geometry);
			}

			return result;
		},

		_bearingToDirection: function(bearing) {
			var oct = Math.round(bearing / 45) % 8;
			return ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'][oct];
		},

		_maneuverToInstructionType: function(maneuver, lastLeg) {
			switch (maneuver.type) {
			case 'new name':
				return 'Continue';
			case 'arrive':
				return lastLeg ? 'DestinationReached' : 'WaypointReached';
			case 'roundabout':
			case 'rotary':
				return 'Roundabout';
			// These are all reduced to the same instruction in the current model
			//case 'turn':
			//case 'end of road':
			//case 'merge':
			//case 'on ramp': // new in v5.1
			//case 'off ramp': // new in v5.1
			//case 'ramp': // deprecated in v5.1
			//case 'fork':
			default:
				switch (maneuver.modifier) {
				case 'straight':
					return 'Straight';
				case 'slight right':
					return 'SlightRight';
				case 'right':
					return 'Right';
				case 'sharp right':
					return 'SharpRight';
				case 'sharp left':
					return 'SharpLeft';
				case 'left':
					return 'Left';
				case 'slight left':
					return 'SlightLeft';
				case 'uturn':
					return 'TurnAround';
				default:
					return null;
				}
				return null;
			}
		},

		_decodePolyline: function(routeGeometry) {
			var cs = polyline.decode(routeGeometry, this.options.polylinePrecision),
				result = new Array(cs.length),
				i;
			for (i = cs.length - 1; i >= 0; i--) {
				result[i] = L.latLng(cs[i]);
			}

			return result;
		},

		_toWaypoints: function(inputWaypoints, vias) {
			var wps = [],
			    i;
			for (i = 0; i < vias.length; i++) {
				wps.push(L.Routing.waypoint(L.latLng(vias[i].location),
				                            inputWaypoints[i].name,
											inputWaypoints[i].options));
			}

			return wps;
		},

		buildRouteUrl: function(waypoints, options) {
			var locs = [],
				hints = [],
				wp,
				latLng,
			    computeInstructions,
			    computeAlternative = true;

			for (var i = 0; i < waypoints.length; i++) {
				wp = waypoints[i];
				latLng = wp.latLng;
				locs.push(latLng.lng + ',' + latLng.lat);
				hints.push(this._hints.locations[this._locationKey(latLng)] || '');
			}

			computeInstructions =
				!(options && options.geometryOnly);

			return this.options.serviceUrl + '/' + this.options.profile + '/' +
				locs.join(';') + '?' +
				(options.geometryOnly ? (options.simplifyGeometry ? '' : 'overview=full') : 'overview=false') +
				'&alternatives=' + computeAlternative.toString() +
				'&steps=' + computeInstructions.toString() +
				'&hints=' + hints.join(';') +
				(options.allowUTurns ? '&continue_straight=' + !options.allowUTurns : '');
		},

		_locationKey: function(location) {
			return location.lat + ',' + location.lng;
		},

		_saveHintData: function(actualWaypoints, waypoints) {
			var loc;
			this._hints = {
				locations: {}
			};
			for (var i = actualWaypoints.length - 1; i >= 0; i--) {
				loc = waypoints[i].latLng;
				this._hints.locations[this._locationKey(loc)] = actualWaypoints[i].hint;
			}
		},
	});

	L.Routing.osrmv1 = function(options) {
		return new L.Routing.OSRMv1(options);
	};

	module.exports = L.Routing;
})();
	class: L.Class.extend({
		options: {
			serviceUrl: 'https://maps.googleapis.com/maps/api/geocode/json',
			geocodingQueryParams: {},
			reverseQueryParams: {}
		},

		initialize: function(key, options) {
			this._key = key;
			L.setOptions(this, options);
			// Backwards compatibility
			this.options.serviceUrl = this.options.service_url || this.options.serviceUrl;
		},

		geocode: function(query, cb, context) {
			var params = {
				address: query,
			};

			if (this._key && this._key.length) {
				params.key = this._key;
			}

			params = L.Util.extend(params, this.options.geocodingQueryParams);

			Util.getJSON(this.options.serviceUrl, params, function(data) {
				var results = [],
						loc,
						latLng,
						latLngBounds;
				if (data.results && data.results.length) {
					for (var i = 0; i <= data.results.length - 1; i++) {
						loc = data.results[i];
						latLng = L.latLng(loc.geometry.location);
						latLngBounds = L.latLngBounds(L.latLng(loc.geometry.viewport.northeast), L.latLng(loc.geometry.viewport.southwest));
						results[i] = {
							name: loc.formatted_address,
							bbox: latLngBounds,
							center: latLng,
							properties: loc.address_components
						};
					}
				}

				cb.call(context, results);
			});
		},

		reverse: function(location, scale, cb, context) {
			var params = {
				latlng: encodeURIComponent(location.lat) + ',' + encodeURIComponent(location.lng)
			};
			params = L.Util.extend(params, this.options.reverseQueryParams);
			if (this._key && this._key.length) {
				params.key = this._key;
			}

			Util.getJSON(this.options.serviceUrl, params, function(data) {
				var results = [],
						loc,
						latLng,
						latLngBounds;
				if (data.results && data.results.length) {
					for (var i = 0; i <= data.results.length - 1; i++) {
						loc = data.results[i];
						latLng = L.latLng(loc.geometry.location);
						latLngBounds = L.latLngBounds(L.latLng(loc.geometry.viewport.northeast), L.latLng(loc.geometry.viewport.southwest));
						results[i] = {
							name: loc.formatted_address,
							bbox: latLngBounds,
							center: latLng,
							properties: loc.address_components
						};
					}
				}

				cb.call(context, results);
			});
		}
	}),
Example #25
0
module.exports = L.Class.extend({
  includes: L.Mixin.Events,

  initialize: function(id) {
    var _this = this;

    this.map = L.map(id, { attributionControl: false });
    this.geojsonLayer = {};
    this.geomLayer = L.geoJson(null, {
      style: createStyle,
      pointToLayer: function(feature, latlng) {
        return L.circle(latlng, 24);
      },
      onEachFeature: function(f, layer) {
        _this.geojsonLayer[L.stamp(f)] = layer;
        featureControl(f, layer);
      }
    });

    L.tileLayer(config.tiles.url, {
      attribution: config.tiles.atttribution
    }).addTo(this.map);

    L.control.attribution({ position: 'bottomleft' }).addTo(this.map);

    this.geomLayer.addTo(this.map);
    this.map.setView([0, 0], 2);
    this.map.on('click', L.bind(function(e) { this.fire('click', e); }, this));
  },

  add: function(geojson) {
    this.geomLayer.addData(geojson);
    this.map.fitBounds(this.geomLayer.getBounds(), {maxZoom: 14});

    this.fire('added', {
      geojson: geojson,
      layer: this.geojsonLayer[L.stamp(geojson)]
    });
  },

  remove: function(geojson) {
    var id = L.stamp(geojson);
    this.geomLayer.removeLayer(this.geojsonLayer[id]);
    delete this.geomLayer[id];
  },

  highlightFeature: function(geojson) {
    var layer = this.geojsonLayer[L.stamp(geojson)];
    this.map.fitBounds(layer.getBounds(), {maxZoom: 15});
  }
});
Example #26
0
L.Google = L.Class.extend({
  includes: L.Mixin.Events,

  options: {
    minZoom: 0,
    maxZoom: 18,
    tileSize: 256,
    subdomains: '',
    errorTileUrl: '',
    attribution: '',
    opacity: 1,
    continuousWorld: false,
    noWrap: false,
  },

  // Possible types: SATELLITE, ROADMAP, HYBRID
  initialize: function(type, options) {
    L.Util.setOptions(this, options);

    this._type = google.maps.MapTypeId[type || 'SATELLITE'];
  },

  onAdd: function(map, insertAtTheBottom) {
    this._map = map;
    this._insertAtTheBottom = insertAtTheBottom;

    // create a container div for tiles
    this._initContainer();
    this._initMapObject();

    // set up events
    map.on('viewreset', this._resetCallback, this);

    this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this);
    map.on('move', this._update, this);
    //map.on('moveend', this._update, this);

    this._reset();
    this._update();
  },

  onRemove: function(map) {
    this._map._container.removeChild(this._container);
    //this._container = null;

    this._map.off('viewreset', this._resetCallback, this);

    this._map.off('move', this._update, this);
    //this._map.off('moveend', this._update, this);
  },

  getAttribution: function() {
    return this.options.attribution;
  },

  setOpacity: function(opacity) {
    this.options.opacity = opacity;
    if (opacity < 1) {
      L.DomUtil.setOpacity(this._container, opacity);
    }
  },

  _initContainer: function() {
    var tilePane = this._map._container
    var first = tilePane.firstChild;

    if (!this._container) {
      this._container = L.DomUtil.create('div', 'leaflet-google-layer leaflet-top leaflet-left');
      this._container.id = "_GMapContainer";
    }

    if (true) {
      tilePane.insertBefore(this._container, first);

      this.setOpacity(this.options.opacity);
      var size = this._map.getSize();
      this._container.style.width = size.x + 'px';
      this._container.style.height = size.y + 'px';
    }
  },

  _initMapObject: function() {
    this._google_center = new google.maps.LatLng(0, 0);
    var map = new google.maps.Map(this._container, {
        center: this._google_center,
        zoom: 0,
        mapTypeId: this._type,
        disableDefaultUI: true,
        keyboardShortcuts: false,
        draggable: false,
        disableDoubleClickZoom: true,
        scrollwheel: false,
        streetViewControl: false
    });

    var _this = this;
    this._reposition = google.maps.event.addListenerOnce(map, "center_changed",
      function() { _this.onReposition(); });

    map.backgroundColor = '#ff0000';
    this._google = map;
  },

  _resetCallback: function(e) {
    this._reset(e.hard);
  },

  _reset: function(clearOldContainer) {
    this._initContainer();
  },

  _update: function() {
    this._resize();

    var bounds = this._map.getBounds();
    var ne = bounds.getNorthEast();
    var sw = bounds.getSouthWest();
    var google_bounds = new google.maps.LatLngBounds(
      new google.maps.LatLng(sw.lat, sw.lng),
      new google.maps.LatLng(ne.lat, ne.lng)
    );
    var center = this._map.getCenter();
    var _center = new google.maps.LatLng(center.lat, center.lng);

    this._google.setCenter(_center);
    this._google.setZoom(this._map.getZoom());
    //this._google.fitBounds(google_bounds);
  },

  _resize: function() {
    var size = this._map.getSize();
    if (this._container.style.width == size.x &&
        this._container.style.height == size.y)
      return;
    this._container.style.width = size.x + 'px';
    this._container.style.height = size.y + 'px';
    google.maps.event.trigger(this._google, "resize");
  },

  onReposition: function() {}
});
Example #27
0
/*
 * Defines an interface for a single filter - for example, Filter By Aid Category.
 */

var L = require('leaflet');

var BaseFilter = L.Class.extend({
    includes: L.Mixin.Events,

    render: function () {
        this.fire('update');
    },

    update: function () {},

    reset: function () {}
});

module.exports = BaseFilter;
  load: function () {

    const LEAFLET_MAJOR_VERSION = parseInt(L.version.split('.')[0], 10)

    const googleParams = {
      includes: L.Mixin.Events,

      options: {
        minZoom: 0,
        maxZoom: 18,
        tileSize: 256,
        subdomains: 'abc',
        errorTileUrl: '',
        attribution: '',
        opacity: 1,
        continuousWorld: false,
        noWrap: false,
        mapOptions: {
          backgroundColor: '#dddddd',
        },
      },

      // Possible types: SATELLITE, ROADMAP, HYBRID, TERRAIN
      initialize: function (type = 'ROADMAP', options) {
        L.Util.setOptions(this, options)
        this._type = type
        this._ready = google.maps.Map !== undefined
        if (!this._ready) {
          L.Google.asyncWait.push(this)
        }
      },

      onAdd: function (map, insertAtTheBottom) {
        this._map = map
        this._insertAtTheBottom = insertAtTheBottom

        // create a container div for tiles
        this._initContainer()
        this._initMapObject()

        // set up events
        map.on('viewreset', this._resetCallback, this)

        if (LEAFLET_MAJOR_VERSION === 0) {
          this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this)
        } else {
          this._limitedUpdate = L.Util.throttle(this._update, 150, this)
        }
        map.on('move', this._update, this)

        map.on('zoomanim', this._handleZoomAnim, this)

        // 20px instead of 1em to avoid a slight overlap with google's attribution
        map._controlCorners.bottomright.style.marginBottom = '20px'

        this._reset()
        this._update()
      },

      onRemove: function (map) {
        map._container.removeChild(this._container)
        map.off('viewreset', this._resetCallback, this)
        map.off('move', this._update, this)
        map.off('zoomanim', this._handleZoomAnim, this)
        map._controlCorners.bottomright.style.marginBottom = '0em'
      },

      getAttribution: function () {
        return this.options.attribution
      },

      setOpacity: function (opacity) {
        this.options.opacity = opacity
        if (opacity < 1) {
          L.DomUtil.setOpacity(this._container, opacity)
        }
      },

      setElementSize: function (e, size) {
        e.style.width = size.x + 'px'
        e.style.height = size.y + 'px'
      },

      _initContainer: function () {
        let tilePane = this._map._container
        let first = tilePane.firstChild

        if (!this._container) {
          let gMapExtraContainerClasses = LEAFLET_MAJOR_VERSION === 0 ? ' leaflet-top leaflet-left' : ''
          this._container = L.DomUtil.create('div', 'leaflet-google-layer' + gMapExtraContainerClasses)
          this._container.id = '_GMapContainer_' + L.Util.stamp(this)
          this._container.style.zIndex = 'auto'
        }

        tilePane.insertBefore(this._container, first)

        this.setOpacity(this.options.opacity)
        this.setElementSize(this._container, this._map.getSize())
      },

      _initMapObject: function () {
        if (!this._ready) return
        this._google_center = new google.maps.LatLng(0, 0)
        let map = new google.maps.Map(this._container, {
          center: this._google_center,
          zoom: 0,
          tilt: 0,
          mapTypeId: google.maps.MapTypeId[this._type],
          disableDefaultUI: true,
          keyboardShortcuts: false,
          draggable: false,
          disableDoubleClickZoom: true,
          scrollwheel: false,
          streetViewControl: false,
          styles: this.options.mapOptions.styles,
          backgroundColor: this.options.mapOptions.backgroundColor,
        })

        let _this = this
        this._reposition = google.maps.event.addListenerOnce(map, 'center_changed',
          function () {
            _this.onReposition()
          })
        this._google = map

        google.maps.event.addListenerOnce(map, 'idle',
          function () {
            _this._checkZoomLevels()
          })
        google.maps.event.addListenerOnce(map, 'tilesloaded',
          function () {
            _this.fire('load')
          })
        // Reporting that map-object was initialized.
        this.fire('MapObjectInitialized', {
          mapObject: map,
        })
      },

      _checkZoomLevels: function () {
        // setting the zoom level on the Google map may result in a different zoom level than the one requested
        // (it won't go beyond the level for which they have data).
        // verify and make sure the zoom levels on both Leaflet and Google maps are consistent
        if (this._google.getZoom() !== this._map.getZoom()) {
          // zoom levels are out of sync. Set the leaflet zoom level to match the google one
          this._map.setZoom(this._google.getZoom())
        }
      },

      _resetCallback: function (e) {
        this._reset(e.hard)
      },

      _reset: function () {
        this._initContainer()
      },

      _update: function () {
        if (!this._google) return
        this._resize()

        let center = this._map.getCenter()
        let _center = new google.maps.LatLng(center.lat, center.lng)

        this._google.setCenter(_center)
        this._google.setZoom(Math.round(this._map.getZoom()))

        this._checkZoomLevels()
      },

      _resize: function () {
        let size = this._map.getSize()
        if (this._container.style.width === size.x && this._container.style.height === size.y) {
          return
        }
        this.setElementSize(this._container, size)
        this.onReposition()
      },

      _handleZoomAnim: function (e) {
        let center = e.center
        let _center = new google.maps.LatLng(center.lat, center.lng)

        this._google.setCenter(_center)
        this._google.setZoom(Math.round(e.zoom))
      },

      onReposition: function () {
        if (!this._google) return
        google.maps.event.trigger(this._google, 'resize')
      },
    }

    if (LEAFLET_MAJOR_VERSION === 0) {
      L.Google = L.Class.extend(googleParams)
    } else {
      L.Google = L.Layer.extend(googleParams)
    }

    L.Google.asyncWait = []
    L.Google.asyncInitialize = function () {
      for (let i = 0; i < L.Google.asyncWait.length; i++) {
        let o = L.Google.asyncWait[i]
        o._ready = true
        if (o._container) {
          o._initMapObject()
          o._update()
        }
      }
      L.Google.asyncWait = []
    }
  },
(function() {
	'use strict';

	var L = require('leaflet'),
		corslite = require('corslite'),
		polyline = require('polyline');

	// Ignore camelcase naming for this file, since OSRM's API uses
	// underscores.
	/* jshint camelcase: false */

	L.Routing = L.Routing || {};
	L.extend(L.Routing, require('./L.Routing.Waypoint'));

	L.Routing.OSRM = L.Class.extend({
		options: {
			serviceUrl: 'https://router.project-osrm.org/viaroute',
			timeout: 30 * 1000,
			routingOptions: {},
			polylinePrecision: 6
		},

		initialize: function(options) {
			L.Util.setOptions(this, options);
			this._hints = {
				locations: {}
			};
		},

		route: function(waypoints, callback, context, options) {
			var timedOut = false,
				wps = [],
				url,
				timer,
				wp,
				i;

			url = this.buildRouteUrl(waypoints, L.extend({}, this.options.routingOptions, options));

			timer = setTimeout(function() {
				timedOut = true;
				callback.call(context || callback, {
					status: -1,
					message: 'OSRM request timed out.'
				});
			}, this.options.timeout);

			// Create a copy of the waypoints, since they
			// might otherwise be asynchronously modified while
			// the request is being processed.
			for (i = 0; i < waypoints.length; i++) {
				wp = waypoints[i];
				wps.push(new L.Routing.Waypoint(wp.latLng, wp.name, wp.options));
			}

			corslite(url, L.bind(function(err, resp) {
				var data,
					errorMessage,
					statusCode;

				clearTimeout(timer);
				if (!timedOut) {
					errorMessage = 'HTTP request failed: ' + err;
					statusCode = -1;

					if (!err) {
						try {
							data = JSON.parse(resp.responseText);
							try {
								return this._routeDone(data, wps, callback, context);
							} catch (ex) {
								statusCode = -3;
								errorMessage = ex.toString();
							}
						} catch (ex) {
							statusCode = -2;
							errorMessage = 'Error parsing OSRM response: ' + ex.toString();
						}
					}

					callback.call(context || callback, {
						status: statusCode,
						message: errorMessage
					});
				}
			}, this));

			return this;
		},

		_routeDone: function(response, inputWaypoints, callback, context) {
			var coordinates,
			    alts,
			    actualWaypoints,
			    i;

			context = context || callback;
			if (response.status !== 0 && response.status !== 200) {
				callback.call(context, {
					status: response.status,
					message: response.status_message
				});
				return;
			}

			coordinates = this._decodePolyline(response.route_geometry);
			actualWaypoints = this._toWaypoints(inputWaypoints, response.via_points);
			alts = [{
				name: this._createName(response.route_name),
				coordinates: coordinates,
				instructions: response.route_instructions ? this._convertInstructions(response.route_instructions) : [],
				summary: response.route_summary ? this._convertSummary(response.route_summary) : [],
				inputWaypoints: inputWaypoints,
				waypoints: actualWaypoints,
				waypointIndices: this._clampIndices(response.via_indices, coordinates)
			}];

			if (response.alternative_geometries) {
				for (i = 0; i < response.alternative_geometries.length; i++) {
					coordinates = this._decodePolyline(response.alternative_geometries[i]);
					alts.push({
						name: this._createName(response.alternative_names[i]),
						coordinates: coordinates,
						instructions: response.alternative_instructions[i] ? this._convertInstructions(response.alternative_instructions[i]) : [],
						summary: response.alternative_summaries[i] ? this._convertSummary(response.alternative_summaries[i]) : [],
						inputWaypoints: inputWaypoints,
						waypoints: actualWaypoints,
						waypointIndices: this._clampIndices(response.alternative_geometries.length === 1 ?
							// Unsure if this is a bug in OSRM or not, but alternative_indices
							// does not appear to be an array of arrays, at least not when there is
							// a single alternative route.
							response.alternative_indices : response.alternative_indices[i],
							coordinates)
					});
				}
			}

			// only versions <4.5.0 will support this flag
			if (response.hint_data) {
				this._saveHintData(response.hint_data, inputWaypoints);
			}
			callback.call(context, null, alts);
		},

		_decodePolyline: function(routeGeometry) {
			var cs = polyline.decode(routeGeometry, this.options.polylinePrecision),
				result = new Array(cs.length),
				i;
			for (i = cs.length - 1; i >= 0; i--) {
				result[i] = L.latLng(cs[i]);
			}

			return result;
		},

		_toWaypoints: function(inputWaypoints, vias) {
			var wps = [],
			    i;
			for (i = 0; i < vias.length; i++) {
				wps.push(L.Routing.waypoint(L.latLng(vias[i]),
				                            inputWaypoints[i].name,
				                            inputWaypoints[i].options));
			}

			return wps;
		},

		_createName: function(nameParts) {
			var name = '',
				i;

			for (i = 0; i < nameParts.length; i++) {
				if (nameParts[i]) {
					if (name) {
						name += ', ';
					}
					name += nameParts[i].charAt(0).toUpperCase() + nameParts[i].slice(1);
				}
			}

			return name;
		},

		buildRouteUrl: function(waypoints, options) {
			var locs = [],
				wp,
			    computeInstructions,
			    computeAlternative,
			    locationKey,
			    hint;

			for (var i = 0; i < waypoints.length; i++) {
				wp = waypoints[i];
				locationKey = this._locationKey(wp.latLng);
				locs.push('loc=' + locationKey);

				hint = this._hints.locations[locationKey];
				if (hint) {
					locs.push('hint=' + hint);
				}

				if (wp.options && wp.options.allowUTurn) {
					locs.push('u=true');
				}
			}

			computeAlternative = computeInstructions =
				!(options && options.geometryOnly);

			return this.options.serviceUrl + '?' +
				'instructions=' + computeInstructions.toString() + '&' +
				'alt=' + computeAlternative.toString() + '&' +
				(options.z ? 'z=' + options.z + '&' : '') +
				locs.join('&') +
				(this._hints.checksum !== undefined ? '&checksum=' + this._hints.checksum : '') +
				(options.fileformat ? '&output=' + options.fileformat : '') +
				(options.allowUTurns ? '&uturns=' + options.allowUTurns : '');
		},

		_locationKey: function(location) {
			return location.lat + ',' + location.lng;
		},

		_saveHintData: function(hintData, waypoints) {
			var loc;
			this._hints = {
				checksum: hintData.checksum,
				locations: {}
			};
			for (var i = hintData.locations.length - 1; i >= 0; i--) {
				loc = waypoints[i].latLng;
				this._hints.locations[this._locationKey(loc)] = hintData.locations[i];
			}
		},

		_convertSummary: function(osrmSummary) {
			return {
				totalDistance: osrmSummary.total_distance,
				totalTime: osrmSummary.total_time
			};
		},

		_convertInstructions: function(osrmInstructions) {
			var result = [],
			    i,
			    instr,
			    type,
			    driveDir;

			for (i = 0; i < osrmInstructions.length; i++) {
				instr = osrmInstructions[i];
				type = this._drivingDirectionType(instr[0]);
				driveDir = instr[0].split('-');
				if (type) {
					result.push({
						type: type,
						distance: instr[2],
						time: instr[4],
						road: instr[1],
						direction: instr[6],
						exit: driveDir.length > 1 ? driveDir[1] : undefined,
						index: instr[3]
					});
				}
			}

			return result;
		},

		_drivingDirectionType: function(d) {
			switch (parseInt(d, 10)) {
			case 1:
				return 'Straight';
			case 2:
				return 'SlightRight';
			case 3:
				return 'Right';
			case 4:
				return 'SharpRight';
			case 5:
				return 'TurnAround';
			case 6:
				return 'SharpLeft';
			case 7:
				return 'Left';
			case 8:
				return 'SlightLeft';
			case 9:
				return 'WaypointReached';
			case 10:
				// TODO: "Head on"
				// https://github.com/DennisOSRM/Project-OSRM/blob/master/DataStructures/TurnInstructions.h#L48
				return 'Straight';
			case 11:
			case 12:
				return 'Roundabout';
			case 15:
				return 'DestinationReached';
			default:
				return null;
			}
		},

		_clampIndices: function(indices, coords) {
			var maxCoordIndex = coords.length - 1,
				i;
			for (i = 0; i < indices.length; i++) {
				indices[i] = Math.min(maxCoordIndex, Math.max(indices[i], 0));
			}
			return indices;
		}
	});

	L.Routing.osrm = function(options) {
		return new L.Routing.OSRM(options);
	};

	module.exports = L.Routing;
})();
Example #30
0
L.Google.TileLayer = L.Class.extend({
  includes: L.Mixin.Events,

  options: {
    minZoom: 0,
    maxZoom: 18,
    tileSize: 256,
    subdomains: 'abc',
    errorTileUrl: '',
    attribution: '',
    opacity: 1,
    continuousWorld: false,
    noWrap: false,
    mapOptions: {
      backgroundColor: '#fff'
    }
  },

  // Possible types: SATELLITE, ROADMAP, HYBRID, TERRAIN
  initialize: function(type, options) {
    L.Util.setOptions(this, options);

    this._ready = google.maps.Map !== undefined;
    if (!this._ready) L.Google.asyncWait.push(this);

    this._type = type || 'SATELLITE';
  },

  _layerAdd: function (e) {
    var map = e.target;

    // check in case layer gets added and then removed before the map is ready
    if (!map.hasLayer(this)) { return; }

    this._map = map;
    this._zoomAnimated = map._zoomAnimated;

    this.onAdd(map);

    if (this.getAttribution && this._map.attributionControl) {
      this._map.attributionControl.addAttribution(this.getAttribution());
    }

    if (this.getEvents) {
      map.on(this.getEvents(), this);
    }

    this.fire('add');
    map.fire('layeradd', {layer: this});
  },

  onAdd: function(map, insertAtTheBottom) {
    this._map = map;
    this._insertAtTheBottom = insertAtTheBottom;

    // create a container div for tiles
    this._initContainer();
    this._initMapObject();

    // set up events
    map.on('viewreset', this._resetCallback, this);

    this._limitedUpdate = L.Util.throttle(this._update, 150, this);
    map.on('move', this._update, this);

    map.on('zoomanim', this._handleZoomAnim, this);

    //20px instead of 1em to avoid a slight overlap with google's attribution
    map._controlCorners.bottomright.style.marginBottom = '20px';

    this._reset();
    this._update();
  },

  onRemove: function(map) {
    map._container.removeChild(this._container);

    map.off('viewreset', this._resetCallback, this);

    map.off('move', this._update, this);

    map.off('zoomanim', this._handleZoomAnim, this);

    map._controlCorners.bottomright.style.marginBottom = '0em';
  },

  getAttribution: function() {
    return this.options.attribution;
  },

  setOpacity: function(opacity) {
    this.options.opacity = opacity;
    if (opacity < 1) {
      L.DomUtil.setOpacity(this._container, opacity);
    }
  },

  setElementSize: function(e, size) {
    e.style.width = size.x + 'px';
    e.style.height = size.y + 'px';
  },

  _initContainer: function() {
    var tilePane = this._map._container,
      first = tilePane.firstChild;

    if (!this._container) {
      this._container = L.DomUtil.create('div', 'leaflet-google-layer leaflet-top leaflet-left');
      this._container.id = '_GMapContainer_' + L.Util.stamp(this);
      this._container.style.zIndex = 'auto';
    }

    tilePane.insertBefore(this._container, first);

    this.setOpacity(this.options.opacity);
    this.setElementSize(this._container, this._map.getSize());
  },

  _initMapObject: function() {
    if (!this._ready) return;
    this._google_center = new google.maps.LatLng(0, 0);
    var map = new google.maps.Map(this._container, {
      center: this._google_center,
      zoom: 0,
      tilt: 0,
      mapTypeId: google.maps.MapTypeId[this._type],
      disableDefaultUI: true,
      keyboardShortcuts: false,
      draggable: false,
      disableDoubleClickZoom: true,
      scrollwheel: false,
      streetViewControl: false,
      styles: this.options.mapOptions.styles,
      backgroundColor: this.options.mapOptions.backgroundColor
    });

    var _this = this;
    this._reposition = google.maps.event.addListenerOnce(map, 'center_changed',
      function() { _this.onReposition(); });
    this._google = map;

    google.maps.event.addListenerOnce(map, 'idle',
      function() { _this._checkZoomLevels(); });
    //Reporting that map-object was initialized.
    this.fire('MapObjectInitialized', { mapObject: map });
  },

  _checkZoomLevels: function() {
    //setting the zoom level on the Google map may result in a different zoom level than the one requested
    //(it won't go beyond the level for which they have data).
    // verify and make sure the zoom levels on both Leaflet and Google maps are consistent
    if (this._google.getZoom() !== this._map.getZoom()) {
      //zoom levels are out of sync. Set the leaflet zoom level to match the google one
      this._map.setZoom( this._google.getZoom() );
    }
  },

  _resetCallback: function(e) {
    this._reset(e.hard);
  },

  _reset: function(clearOldContainer) {
    this._initContainer();
  },

  _update: function(e) {
    if (!this._google) return;
    this._resize();

    var center = this._map.getCenter();
    var _center = new google.maps.LatLng(center.lat, center.lng);

    this._google.setCenter(_center);
    this._google.setZoom(Math.round(this._map.getZoom()));

    this._checkZoomLevels();
  },

  _resize: function() {
    var size = this._map.getSize();
    if (this._container.style.width === size.x &&
        this._container.style.height === size.y)
      return;
    this.setElementSize(this._container, size);
    this.onReposition();
  },


  _handleZoomAnim: function (e) {
    var center = e.center;
    var _center = new google.maps.LatLng(center.lat, center.lng);

    this._google.setCenter(_center);
    this._google.setZoom(Math.round(e.zoom));
  },


  onReposition: function() {
    if (!this._google) return;
    google.maps.event.trigger(this._google, 'resize');
  }
});