diff --git a/dist/esri-leaflet.js b/dist/esri-leaflet.js new file mode 100644 index 000000000..5e4e33ec6 --- /dev/null +++ b/dist/esri-leaflet.js @@ -0,0 +1,7 @@ +/* esri-leaflet - v2.0.0-beta.4 - Fri Jul 24 2015 10:44:18 GMT-0700 (PDT) + * Copyright (c) 2015 Environmental Systems Research Institute, Inc. + * Apache-2.0 */ +(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?factory(exports,require("leaflet")):typeof define==="function"&&define.amd?define(["exports","leaflet"],factory):factory(global.L.esri={},L)})(this,function(exports,L){"use strict";var cors=window.XMLHttpRequest&&"withCredentials"in new window.XMLHttpRequest;var pointerEvents=document.documentElement.style.pointerEvents==="";exports.Support={cors:cors,pointerEvents:pointerEvents};function pointsEqual(a,b){for(var i=0;i=0}function vertexIntersectsVertex(a1,a2,b1,b2){var uaT=(b2[0]-b1[0])*(a1[1]-b1[1])-(b2[1]-b1[1])*(a1[0]-b1[0]);var ubT=(a2[0]-a1[0])*(a1[1]-b1[1])-(a2[1]-a1[1])*(a1[0]-b1[0]);var uB=(b2[1]-b1[1])*(a2[0]-a1[0])-(b2[0]-b1[0])*(a2[1]-a1[1]);if(uB!==0){var ua=uaT/uB;var ub=ubT/uB;if(ua>=0&&ua<=1&&ub>=0&&ub<=1){return true}}return false}function arrayIntersectsArray(a,b){for(var i=0;i=0;x--){outerRing=outerRings[x][0];if(coordinatesContainCoordinates(outerRing,hole)){outerRings[x].push(hole);contained=true;break}}if(!contained){uncontainedHoles.push(hole)}}while(uncontainedHoles.length){hole=uncontainedHoles.pop();var intersects=false;for(x=outerRings.length-1;x>=0;x--){outerRing=outerRings[x][0];if(arrayIntersectsArray(outerRing,hole)){outerRings[x].push(hole);intersects=true;break}}if(!intersects){outerRings.push([hole.reverse()])}}if(outerRings.length===1){return{type:"Polygon",coordinates:outerRings[0]}}else{return{type:"MultiPolygon",coordinates:outerRings}}}function orientRings(poly){var output=[];var polygon=poly.slice(0);var outerRing=closeRing(polygon.shift().slice(0));if(outerRing.length>=4){if(!ringIsClockwise(outerRing)){outerRing.reverse()}output.push(outerRing);for(var i=0;i=4){if(ringIsClockwise(hole)){hole.reverse()}output.push(hole)}}}return output}function flattenMultiPolygonRings(rings){var output=[];for(var i=0;i=0;x--){var ring=polygon[x].slice(0);output.push(ring)}}return output}function shallowClone(obj){var target={};for(var i in obj){if(obj.hasOwnProperty(i)){target[i]=obj[i]}}return target}function extentToBounds(extent){var sw=L.latLng(extent.ymin,extent.xmin);var ne=L.latLng(extent.ymax,extent.xmax);return L.latLngBounds(sw,ne)}function boundsToExtent(bounds){bounds=L.latLngBounds(bounds);return{xmin:bounds.getSouthWest().lng,ymin:bounds.getSouthWest().lat,xmax:bounds.getNorthEast().lng,ymax:bounds.getNorthEast().lat,spatialReference:{wkid:4326}}}function arcgisToGeojson(arcgis,idAttribute){var geojson={};if(typeof arcgis.x==="number"&&typeof arcgis.y==="number"){geojson.type="Point";geojson.coordinates=[arcgis.x,arcgis.y]}if(arcgis.points){geojson.type="MultiPoint";geojson.coordinates=arcgis.points.slice(0)}if(arcgis.paths){if(arcgis.paths.length===1){geojson.type="LineString";geojson.coordinates=arcgis.paths[0].slice(0)}else{geojson.type="MultiLineString";geojson.coordinates=arcgis.paths.slice(0)}}if(arcgis.rings){geojson=convertRingsToGeoJSON(arcgis.rings.slice(0))}if(arcgis.geometry||arcgis.attributes){geojson.type="Feature";geojson.geometry=arcgis.geometry?arcgisToGeojson(arcgis.geometry):null;geojson.properties=arcgis.attributes?shallowClone(arcgis.attributes):null;if(arcgis.attributes){geojson.id=arcgis.attributes[idAttribute]||arcgis.attributes.OBJECTID||arcgis.attributes.FID}}return geojson}function geojsonToArcGIS(geojson,idAttribute){idAttribute=idAttribute||"OBJECTID";var spatialReference={wkid:4326};var result={};var i;switch(geojson.type){case"Point":result.x=geojson.coordinates[0];result.y=geojson.coordinates[1];result.spatialReference=spatialReference;break;case"MultiPoint":result.points=geojson.coordinates.slice(0);result.spatialReference=spatialReference;break;case"LineString":result.paths=[geojson.coordinates.slice(0)];result.spatialReference=spatialReference;break;case"MultiLineString":result.paths=geojson.coordinates.slice(0);result.spatialReference=spatialReference;break;case"Polygon":result.rings=orientRings(geojson.coordinates.slice(0));result.spatialReference=spatialReference;break;case"MultiPolygon":result.rings=flattenMultiPolygonRings(geojson.coordinates.slice(0));result.spatialReference=spatialReference;break;case"Feature":if(geojson.geometry){result.geometry=geojsonToArcGIS(geojson.geometry,idAttribute)}result.attributes=geojson.properties?shallowClone(geojson.properties):{};if(geojson.id){result.attributes[idAttribute]=geojson.id}break;case"FeatureCollection":result=[];for(i=0;i=0;i--){featureCollection.features.push(arcgisToGeojson(features[i],objectIdField))}}return featureCollection}function cleanUrl(url){url=L.Util.trim(url);if(url[url.length-1]!=="/"){url+="/"}return url}function isArcgisOnline(url){return/\.arcgis\.com.*?FeatureServer/g.test(url)}function geojsonTypeToArcGIS(geoJsonType){var arcgisGeometryType;switch(geoJsonType){case"Point":arcgisGeometryType="esriGeometryPoint";break;case"MultiPoint":arcgisGeometryType="esriGeometryMultipoint";break;case"LineString":arcgisGeometryType="esriGeometryPolyline";break;case"MultiLineString":arcgisGeometryType="esriGeometryPolyline";break;case"Polygon":arcgisGeometryType="esriGeometryPolygon";break;case"MultiPolygon":arcgisGeometryType="esriGeometryPolygon";break}return arcgisGeometryType}function warn(){if(console&&console.warn){console.warn.apply(console,arguments)}}exports.Util={shallowClone:shallowClone,warn:warn,cleanUrl:cleanUrl,isArcgisOnline:isArcgisOnline,geojsonTypeToArcGIS:geojsonTypeToArcGIS,responseToFeatureCollection:responseToFeatureCollection,geojsonToArcGIS:geojsonToArcGIS,arcgisToGeojson:arcgisToGeojson,boundsToExtent:boundsToExtent,extentToBounds:extentToBounds};var callbacks=0;function serialize(params){var data="";params.f=params.f||"json";for(var key in params){if(params.hasOwnProperty(key)){var param=params[key];var type=Object.prototype.toString.call(param);var value;if(data.length){data+="&"}if(type==="[object Array]"){value=Object.prototype.toString.call(param[0])==="[object Object]"?JSON.stringify(param):param.join(",")}else if(type==="[object Object]"){value=JSON.stringify(param)}else if(type==="[object Date]"){value=param.valueOf()}else{value=param}data+=encodeURIComponent(key)+"="+encodeURIComponent(value)}}return data}function createRequest(callback,context){var httpRequest=new window.XMLHttpRequest;httpRequest.onerror=function(e){httpRequest.onreadystatechange=L.Util.falseFn;callback.call(context,{error:{code:500,message:"XMLHttpRequest error"}},null)};httpRequest.onreadystatechange=function(){var response;var error;if(httpRequest.readyState===4){try{response=JSON.parse(httpRequest.responseText)}catch(e){response=null;error={code:500,message:"Could not parse response as JSON. This could also be caused by a CORS or XMLHttpRequest error."}}if(!error&&response.error){error=response.error;response=null}httpRequest.onerror=L.Util.falseFn;callback.call(context,error,response)}};return httpRequest}function xmlHttpPost(url,params,callback,context){var httpRequest=createRequest(callback,context);httpRequest.open("POST",url);httpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");httpRequest.send(serialize(params));return httpRequest}function xmlHttpGet(url,params,callback,context){var httpRequest=createRequest(callback,context);httpRequest.open("GET",url+"?"+serialize(params),true);httpRequest.send(null);return httpRequest}function request(url,params,callback,context){var paramString=serialize(params);var httpRequest=createRequest(callback,context);var requestLength=(url+"?"+paramString).length;if(requestLength<=2e3&&exports.Support.cors){httpRequest.open("GET",url+"?"+paramString);httpRequest.send(null)}else if(requestLength>2e3&&exports.Support.cors){httpRequest.open("POST",url);httpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");httpRequest.send(paramString)}else if(requestLength<=2e3&&!exports.Support.cors){return jsonp(url,params,callback,context)}else{warn("a request to "+url+" was longer then 2000 characters and this browser cannot make a cross-domain post request. Please use a proxy http://esri.github.io/esri-leaflet/api-reference/request.html");return}return httpRequest}function jsonp(url,params,callback,context){window._EsriLeafletCallbacks=window._EsriLeafletCallbacks||{};var callbackId="c"+callbacks;params.callback="window._EsriLeafletCallbacks."+callbackId;var script=L.DomUtil.create("script",null,document.body);script.type="text/javascript";script.src=url+"?"+serialize(params);script.id=callbackId;window._EsriLeafletCallbacks[callbackId]=function(response){if(window._EsriLeafletCallbacks[callbackId]!==true){var error;var responseType=Object.prototype.toString.call(response);if(!(responseType==="[object Object]"||responseType==="[object Array]")){error={error:{code:500,message:"Expected array or object as JSONP response"}};response=null}if(!error&&response.error){error=response;response=null}callback.call(context,error,response);window._EsriLeafletCallbacks[callbackId]=true}};callbacks++;return{id:callbackId,url:script.src,abort:function(){window._EsriLeafletCallbacks._callback[callbackId]({code:0,message:"Request aborted."})}}}exports.get=exports.Support.cors?xmlHttpGet:jsonp;exports.get.CORS=xmlHttpGet;exports.get.JSONP=jsonp;var Request={request:request,get:exports.get,post:xmlHttpPost};exports.Task=L.Class.extend({options:{proxy:false,useCors:cors},generateSetter:function(param,context){return L.Util.bind(function(value){this.params[param]=value;return this},context)},initialize:function(endpoint){if(endpoint.request&&endpoint.options){this._service=endpoint;L.Util.setOptions(this,endpoint.options)}else{L.Util.setOptions(this,endpoint);this.options.url=cleanUrl(endpoint.url)}this.params=L.Util.extend({},this.params||{});if(this.setters){for(var setter in this.setters){var param=this.setters[setter];this[setter]=this.generateSetter(param,this)}}},token:function(token){if(this._service){this._service.authenticate(token)}else{this.params.token=token}return this},request:function(callback,context){if(this._service){return this._service.request(this.path,this.params,callback,context)}return this._request("request",this.path,this.params,callback,context)},_request:function(method,path,params,callback,context){var url=this.options.proxy?this.options.proxy+"?"+this.options.url+path:this.options.url+path;if((method==="get"||method==="request")&&!this.options.useCors){return Request.get.JSONP(url,params,callback,context)}return Request[method](url,params,callback,context)}});function task(options){return new exports.Task(options)}exports.Query=exports.Task.extend({setters:{offset:"offset",limit:"limit",fields:"outFields",precision:"geometryPrecision",featureIds:"objectIds",returnGeometry:"returnGeometry",token:"token"},path:"query",params:{returnGeometry:true,where:"1=1",outSr:4326,outFields:"*"},within:function(geometry){this._setGeometry(geometry);this.params.spatialRel="esriSpatialRelContains";return this},intersects:function(geometry){this._setGeometry(geometry);this.params.spatialRel="esriSpatialRelIntersects";return this},contains:function(geometry){this._setGeometry(geometry);this.params.spatialRel="esriSpatialRelWithin";return this},crosses:function(geometry){this._setGeometry(geometry);this.params.spatialRel="esriSpatialRelCrosses";return this},touches:function(geometry){this._setGeometry(geometry);this.params.spatialRel="esriSpatialRelTouches";return this},overlaps:function(geometry){this._setGeometry(geometry);this.params.spatialRel="esriSpatialRelOverlaps";return this},nearby:function(latlng,radius){latlng=L.latLng(latlng);this.params.geometry=[latlng.lng,latlng.lat];this.params.geometryType="esriGeometryPoint";this.params.spatialRel="esriSpatialRelIntersects";this.params.units="esriSRUnit_Meter";this.params.distance=radius;this.params.inSr=4326;return this},where:function(string){this.params.where=string;return this},between:function(start,end){this.params.time=[start.valueOf(),end.valueOf()];return this},simplify:function(map,factor){var mapWidth=Math.abs(map.getBounds().getWest()-map.getBounds().getEast());this.params.maxAllowableOffset=mapWidth/map.getSize().y*factor;return this},orderBy:function(fieldName,order){order=order||"ASC";this.params.orderByFields=this.params.orderByFields?this.params.orderByFields+",":"";this.params.orderByFields+=[fieldName,order].join(" ");return this},run:function(callback,context){this._cleanParams();if(exports.Util.isArcgisOnline(this.options.url)){this.params.f="geojson";return this.request(function(error,response){this._trapSQLerrors(error);callback.call(context,error,response,response)},this)}else{return this.request(function(error,response){this._trapSQLerrors(error);callback.call(context,error,response&&exports.Util.responseToFeatureCollection(response),response)},this)}},count:function(callback,context){this._cleanParams();this.params.returnCountOnly=true;return this.request(function(error,response){callback.call(this,error,response&&response.count,response)},context)},ids:function(callback,context){this._cleanParams();this.params.returnIdsOnly=true;return this.request(function(error,response){callback.call(this,error,response&&response.objectIds,response)},context)},bounds:function(callback,context){this._cleanParams();this.params.returnExtentOnly=true;return this.request(function(error,response){callback.call(context,error,response&&response.extent&&exports.Util.extentToBounds(response.extent),response)},context)},pixelSize:function(point){point=L.point(point);this.params.pixelSize=[point.x,point.y];return this},layer:function(layer){this.path=layer+"/query";return this},_trapSQLerrors:function(error){if(error){if(error.code==="400"){exports.Util.warn("one common syntax error in query requests is encasing string values in double quotes instead of single quotes")}}},_cleanParams:function(){delete this.params.returnIdsOnly;delete this.params.returnExtentOnly;delete this.params.returnCountOnly},_setGeometry:function(geometry){this.params.inSr=4326;if(geometry instanceof L.LatLngBounds){this.params.geometry=exports.Util.boundsToExtent(geometry);this.params.geometryType="esriGeometryEnvelope";return}if(geometry.getLatLng){geometry=geometry.getLatLng()}if(geometry instanceof L.LatLng){geometry={type:"Point",coordinates:[geometry.lng,geometry.lat]}}if(geometry instanceof L.GeoJSON){geometry=geometry.getLayers()[0].feature.geometry;this.params.geometry=exports.Util.geojsonToArcGIS(geometry);this.params.geometryType=exports.Util.geojsonTypeToArcGIS(geometry.type)}if(geometry.toGeoJSON){geometry=geometry.toGeoJSON()}if(geometry.type==="Feature"){geometry=geometry.geometry}if(geometry.type==="Point"||geometry.type==="LineString"||geometry.type==="Polygon"){this.params.geometry=exports.Util.geojsonToArcGIS(geometry);this.params.geometryType=exports.Util.geojsonTypeToArcGIS(geometry.type);return}exports.Util.warn("invalid geometry passed to spatial query. Should be an L.LatLng, L.LatLngBounds or L.Marker or a GeoJSON Point Line or Polygon object");return}});function query(options){return new exports.Query(options)}exports.Find=exports.Task.extend({setters:{contains:"contains",text:"searchText",fields:"searchFields",spatialReference:"sr",sr:"sr",layers:"layers",returnGeometry:"returnGeometry",maxAllowableOffset:"maxAllowableOffset",precision:"geometryPrecision",dynamicLayers:"dynamicLayers",returnZ:"returnZ",returnM:"returnM",gdbVersion:"gdbVersion",token:"token"},path:"find",params:{sr:4326,contains:true,returnGeometry:true,returnZ:true,returnM:false},layerDefs:function(id,where){this.params.layerDefs=this.params.layerDefs?this.params.layerDefs+";":"";this.params.layerDefs+=[id,where].join(":");return this},simplify:function(map,factor){var mapWidth=Math.abs(map.getBounds().getWest()-map.getBounds().getEast());this.params.maxAllowableOffset=mapWidth/map.getSize().y*factor;return this},run:function(callback,context){return this.request(function(error,response){callback.call(context,error,response&&exports.Util.responseToFeatureCollection(response),response)},context)}});function find(options){return new exports.Find(options)}exports.Identify=exports.Task.extend({path:"identify",between:function(start,end){this.params.time=[start.valueOf(),end.valueOf()];return this}});function identify(options){return new exports.Identify(options)}exports.IdentifyFeatures=exports.Identify.extend({setters:{layers:"layers",precision:"geometryPrecision",tolerance:"tolerance",returnGeometry:"returnGeometry"},params:{sr:4326,layers:"all",tolerance:3,returnGeometry:true},on:function(map){var extent=exports.Util.boundsToExtent(map.getBounds());var size=map.getSize();this.params.imageDisplay=[size.x,size.y,96];this.params.mapExtent=[extent.xmin,extent.ymin,extent.xmax,extent.ymax];return this},at:function(latlng){latlng=L.latLng(latlng);this.params.geometry=[latlng.lng,latlng.lat];this.params.geometryType="esriGeometryPoint";return this},layerDef:function(id,where){this.params.layerDefs=this.params.layerDefs?this.params.layerDefs+";":"";this.params.layerDefs+=[id,where].join(":");return this},simplify:function(map,factor){var mapWidth=Math.abs(map.getBounds().getWest()-map.getBounds().getEast());this.params.maxAllowableOffset=mapWidth/map.getSize().y*(1-factor);return this},run:function(callback,context){return this.request(function(error,response){if(error){callback.call(context,error,undefined,response);return}else{var featureCollection=exports.Util.responseToFeatureCollection(response);response.results=response.results.reverse();for(var i=0;i=0;i--){geoJSON.catalogItems.features[i].properties.catalogItemVisibility=catalogItemVisibilities[i]}}}return geoJSON}});function identifyImage(params){return new exports.IdentifyImage(params)}exports.Service=L.Evented.extend({options:{proxy:false,useCors:cors},initialize:function(options){options=options||{};this._requestQueue=[];this._authenticating=false;L.Util.setOptions(this,options);this.options.url=cleanUrl(this.options.url)},get:function(path,params,callback,context){return this._request("get",path,params,callback,context)},post:function(path,params,callback,context){return this._request("post",path,params,callback,context)},request:function(path,params,callback,context){return this._request("request",path,params,callback,context)},metadata:function(callback,context){return this._request("get","",{},callback,context)},authenticate:function(token){this._authenticating=false;this.options.token=token;this._runQueue();return this},_request:function(method,path,params,callback,context){this.fire("requeststart",{url:this.options.url+path,params:params,method:method},true);var wrappedCallback=this._createServiceCallback(method,path,params,callback,context);if(this.options.token){params.token=this.options.token}if(this._authenticating){this._requestQueue.push([method,path,params,callback,context]);return}else{var url=this.options.proxy?this.options.proxy+"?"+this.options.url+path:this.options.url+path;if((method==="get"||method==="request")&&!this.options.useCors){return Request.get.JSONP(url,params,wrappedCallback)}else{return Request[method](url,params,wrappedCallback)}}},_createServiceCallback:function(method,path,params,callback,context){return L.Util.bind(function(error,response){if(error&&(error.code===499||error.code===498)){this._authenticating=true;this._requestQueue.push([method,path,params,callback,context]);this.fire("authenticationrequired",{authenticate:L.Util.bind(this.authenticate,this)},true);error.authenticate=L.Util.bind(this.authenticate,this)}callback.call(context,error,response);if(error){this.fire("requesterror",{url:this.options.url+path,params:params,message:error.message,code:error.code,method:method},true)}else{this.fire("requestsuccess",{url:this.options.url+path,params:params,response:response,method:method},true)}this.fire("requestend",{url:this.options.url+path,params:params,method:method},true)},this)},_runQueue:function(){for(var i=this._requestQueue.length-1;i>=0;i--){var request=this._requestQueue[i];var method=request.shift();this[method].apply(this,request)}this._requestQueue=[]}});function service(options){return new exports.Service(options)}exports.MapService=exports.Service.extend({identify:function(){return identifyFeatures(this)},find:function(){return find(this)},query:function(){return query(this)}});function mapService(options){return new exports.MapService(options)}exports.ImageService=exports.Service.extend({query:function(){return query(this)},identify:function(){return identifyImage(this)}});function imageService(options){return new exports.ImageService(options)}exports.FeatureLayerService=exports.Service.extend({options:{idAttribute:"OBJECTID"},query:function(){return query(this)},addFeature:function(feature,callback,context){delete feature.id;feature=geojsonToArcGIS(feature);return this.post("addFeatures",{features:[feature]},function(error,response){var result=response&&response.addResults?response.addResults[0]:undefined;if(callback){callback.call(context,error||response.addResults[0].error,result)}},context)},updateFeature:function(feature,callback,context){feature=geojsonToArcGIS(feature,this.options.idAttribute);return this.post("updateFeatures",{features:[feature]},function(error,response){var result=response&&response.updateResults?response.updateResults[0]:undefined;if(callback){callback.call(context,error||response.updateResults[0].error,result)}},context)},deleteFeature:function(id,callback,context){return this.post("deleteFeatures",{objectIds:id},function(error,response){var result=response&&response.deleteResults?response.deleteResults[0]:undefined;if(callback){callback.call(context,error||response.deleteResults[0].error,result)}},context)},deleteFeatures:function(ids,callback,context){return this.post("deleteFeatures",{objectIds:ids},function(error,response){var result=response&&response.deleteResults?response.deleteResults:undefined;if(callback){callback.call(context,error||response.deleteResults[0].error,result)}},context)}});function featureLayerService(options){return new exports.FeatureLayerService(options)}var Logo=L.Control.extend({options:{position:"bottomright",marginTop:0,marginLeft:0,marginBottom:0,marginRight:0},onAdd:function(){var div=L.DomUtil.create("div","esri-leaflet-logo");div.style.marginTop=this.options.marginTop;div.style.marginLeft=this.options.marginLeft;div.style.marginBottom=this.options.marginBottom;div.style.marginRight=this.options.marginRight;div.innerHTML=this._adjustLogo(this._map._size);this._map.on("resize",function(e){div.innerHTML=this._adjustLogo(e.newSize)},this);return div},_adjustLogo:function(mapSize){if(mapSize.x<=600||mapSize.y<=600){return'Powered by Esri'}else{return'Powered by Esri'}}});function logo(options){return new Logo(options)}var tileProtocol=window.location.protocol!=="https:"?"http:":"https:";exports.BasemapLayer=L.TileLayer.extend({statics:{TILES:{Streets:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}",attributionUrl:"https://static.arcgis.com/attribution/World_Street_Map",options:{hideLogo:false,logoPosition:"bottomright",minZoom:1,maxZoom:19,subdomains:["server","services"],attribution:"Esri"}},Topographic:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}",attributionUrl:"https://static.arcgis.com/attribution/World_Topo_Map",options:{hideLogo:false,logoPosition:"bottomright",minZoom:1,maxZoom:19,subdomains:["server","services"],attribution:"Esri"}},Oceans:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/arcgis/rest/services/Ocean/World_Ocean_Base/MapServer/tile/{z}/{y}/{x}",attributionUrl:"https://static.arcgis.com/attribution/Ocean_Basemap",options:{hideLogo:false,logoPosition:"bottomright",minZoom:1,maxZoom:16,subdomains:["server","services"],attribution:"Esri"}},OceansLabels:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/arcgis/rest/services/Ocean/World_Ocean_Reference/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:true,logoPosition:"bottomright",minZoom:1,maxZoom:16,subdomains:["server","services"],pane:pointerEvents?"esri-labels":"tilePane"}},NationalGeographic:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:false,logoPosition:"bottomright",minZoom:1,maxZoom:16,subdomains:["server","services"],attribution:"Esri"}},DarkGray:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Dark_Gray_Base/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:false,logoPosition:"bottomright",minZoom:1,maxZoom:16,subdomains:["server","services"],attribution:"Esri, DeLorme, HERE"}},DarkGrayLabels:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Dark_Gray_Reference/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:true,logoPosition:"bottomright",minZoom:1,maxZoom:16,subdomains:["server","services"],pane:pointerEvents?"esri-labels":"tilePane"}},Gray:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:false,logoPosition:"bottomright",minZoom:1,maxZoom:16,subdomains:["server","services"],attribution:"Esri, NAVTEQ, DeLorme"}},GrayLabels:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Reference/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:true,logoPosition:"bottomright",minZoom:1,maxZoom:16,subdomains:["server","services"],pane:pointerEvents?"esri-labels":"tilePane"}},Imagery:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:false,logoPosition:"bottomright",minZoom:1,maxZoom:19,subdomains:["server","services"],attribution:"Esri, DigitalGlobe, GeoEye, i-cubed, USDA, USGS, AEX, Getmapping, Aerogrid, IGN, IGP, swisstopo, and the GIS User Community"}},ImageryLabels:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:true,logoPosition:"bottomright",minZoom:1,maxZoom:19,subdomains:["server","services"],pane:pointerEvents?"esri-labels":"tilePane"}},ImageryTransportation:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:true,logoPosition:"bottomright",minZoom:1,maxZoom:19,subdomains:["server","services"],pane:pointerEvents?"esri-labels":"tilePane"}},ShadedRelief:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:false,logoPosition:"bottomright",minZoom:1,maxZoom:13,subdomains:["server","services"],attribution:"Esri, NAVTEQ, DeLorme"}},ShadedReliefLabels:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places_Alternate/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:true,logoPosition:"bottomright",minZoom:1,maxZoom:12,subdomains:["server","services"],pane:pointerEvents?"esri-labels":"tilePane"}},Terrain:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/World_Terrain_Base/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:false,logoPosition:"bottomright",minZoom:1,maxZoom:13,subdomains:["server","services"], +attribution:"Esri, USGS, NOAA"}},TerrainLabels:{urlTemplate:tileProtocol+"//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Reference_Overlay/MapServer/tile/{z}/{y}/{x}",options:{hideLogo:true,logoPosition:"bottomright",minZoom:1,maxZoom:13,subdomains:["server","services"],pane:pointerEvents?"esri-labels":"tilePane"}}}},initialize:function(key,options){var config;if(typeof key==="object"&&key.urlTemplate&&key.options){config=key}else if(typeof key==="string"&&exports.BasemapLayer.TILES[key]){config=exports.BasemapLayer.TILES[key]}else{throw new Error('L.esri.BasemapLayer: Invalid parameter. Use one of "Streets", "Topographic", "Oceans", "OceansLabels", "NationalGeographic", "Gray", "GrayLabels", "DarkGray", "DarkGrayLabels", "Imagery", "ImageryLabels", "ImageryTransportation", "ShadedRelief", "ShadedReliefLabels", "Terrain" or "TerrainLabels"')}var tileOptions=L.Util.extend(config.options,options);L.TileLayer.prototype.initialize.call(this,config.urlTemplate,L.Util.setOptions(this,tileOptions));if(config.attributionUrl){this._getAttributionData(config.attributionUrl)}this._logo=logo({position:this.options.logoPosition})},onAdd:function(map){if(!this.options.hideLogo&&!map._hasEsriLogo){this._logo.addTo(map);map._hasEsriLogo=true}if(this.options.pane==="esri-labels"){this._initPane()}L.TileLayer.prototype.onAdd.call(this,map);map.on("moveend",this._updateMapAttribution,this)},onRemove:function(map){if(this._logo&&this._logo._container){map.removeControl(this._logo);map._hasEsriLogo=false}L.TileLayer.prototype.onRemove.call(this,map);map.off("moveend",this._updateMapAttribution,this)},getAttribution:function(){var attribution=''+this.options.attribution+"";return attribution},_initPane:function(){if(!this._map.getPane(this.options.pane)){var pane=this._map.createPane(this.options.pane);pane.style.pointerEvents="none";pane.style.zIndex=500}},_getAttributionData:function(url){jsonp(url,{},L.Util.bind(function(error,attributions){if(error){return}this._attributions=[];for(var c=0;c=attribution.minZoom&&zoom<=attribution.maxZoom){newAttributions+=", "+text}}newAttributions=newAttributions.substr(2);var attributionElement=this._map.attributionControl._container.querySelector(".esri-attributions");attributionElement.innerHTML=newAttributions;attributionElement.style.maxWidth=this._map.getSize().x*.65+"px";this.fire("attributionupdated",{attribution:newAttributions})}}});function basemapLayer(key,options){return new exports.BasemapLayer(key,options)}exports.TiledMapLayer=L.TileLayer.extend({options:{zoomOffsetAllowance:.1,correctZoomLevels:true},statics:{MercatorZoomLevels:{0:156543.033928,1:78271.5169639999,2:39135.7584820001,3:19567.8792409999,4:9783.93962049996,5:4891.96981024998,6:2445.98490512499,7:1222.99245256249,8:611.49622628138,9:305.748113140558,10:152.874056570411,11:76.4370282850732,12:38.2185141425366,13:19.1092570712683,14:9.55462853563415,15:4.77731426794937,16:2.38865713397468,17:1.19432856685505,18:.597164283559817,19:.298582141647617,20:.14929107082381,21:.07464553541191,22:.0373227677059525,23:.0186613838529763}},initialize:function(options){options.url=cleanUrl(options.url);options=L.Util.setOptions(this,options);this.tileUrl=options.url+"tile/{z}/{y}/{x}";this.service=mapService(options);this.service.addEventParent(this);if(this.tileUrl.match("://tiles.arcgisonline.com")){this.tileUrl=this.tileUrl.replace("://tiles.arcgisonline.com","://tiles{s}.arcgisonline.com");options.subdomains=["1","2","3","4"]}if(this.options.token){this.tileUrl+="?token="+this.options.token}L.TileLayer.prototype.initialize.call(this,this.tileUrl,options)},getTileUrl:function(tilePoint){return L.Util.template(this.tileUrl,L.extend({s:this._getSubdomain(tilePoint),z:this._lodMap[tilePoint.z]||tilePoint.z,x:tilePoint.x,y:tilePoint.y},this.options))},onAdd:function(map){if(!this._lodMap&&this.options.correctZoomLevels){this._lodMap={};this.metadata(function(error,metadata){if(!error){var sr=metadata.spatialReference.latestWkid||metadata.spatialReference.wkid;if(sr===102100||sr===3857){var arcgisLODs=metadata.tileInfo.lods;var correctResolutions=exports.TiledMapLayer.MercatorZoomLevels;for(var i=0;ithis.options.maxZoom||zoom0||bottom.ythis.options.maxZoom||zoombounds.max.x)||!crs.wrapLat&&(coords.ybounds.max.y)){return false}}if(!this.options.bounds){return true}var cellBounds=this._cellCoordsToBounds(coords);return L.latLngBounds(this.options.bounds).intersects(cellBounds)},_cellCoordsToBounds:function(coords){var map=this._map;var cellSize=this.options.cellSize;var nwPoint=coords.multiplyBy(cellSize);var sePoint=nwPoint.add([cellSize,cellSize]);var nw=map.wrapLatLng(map.unproject(nwPoint,coords.z));var se=map.wrapLatLng(map.unproject(sePoint,coords.z));return L.latLngBounds(nw,se)},_cellCoordsToKey:function(coords){return coords.x+":"+coords.y},_keyToCellCoords:function(key){var kArr=key.split(":");var x=parseInt(kArr[0],10);var y=parseInt(kArr[1],10);return L.point(x,y)},_removeOtherCells:function(bounds){for(var key in this._cells){if(!bounds.contains(this._keyToCellCoords(key))){this._removeCell(key)}}},_removeCell:function(key){var cell=this._activeCells[key];if(cell){delete this._activeCells[key];if(this.cellLeave){this.cellLeave(cell.bounds,cell.coords)}this.fire("cellleave",{bounds:cell.bounds,coords:cell.coords})}},_removeCells:function(){for(var key in this._cells){var bounds=this._cells[key].bounds;var coords=this._cells[key].coords;if(this.cellLeave){this.cellLeave(bounds,coords)}this.fire("cellleave",{bounds:bounds,coords:coords})}},_addCell:function(coords){this._wrapCoords(coords);var key=this._cellCoordsToKey(coords);var cell=this._cells[key];if(cell&&!this._activeCells[key]){if(this.cellEnter){this.cellEnter(cell.bounds,coords)}this.fire("cellenter",{bounds:cell.bounds,coords:coords});this._activeCells[key]=cell}if(!cell){cell={coords:coords,bounds:this._cellCoordsToBounds(coords)};this._cells[key]=cell;this._activeCells[key]=cell;if(this.createCell){this.createCell(cell.bounds,coords)}this.fire("cellcreate",{bounds:cell.bounds,coords:coords})}},_wrapCoords:function(coords){coords.x=this._wrapLng?L.Util.wrapNum(coords.x,this._wrapLng):coords.x;coords.y=this._wrapLat?L.Util.wrapNum(coords.y,this._wrapLat):coords.y},_getCellNumBounds:function(){var bounds=this._map.getPixelWorldBounds();var size=this._getCellSize();return bounds?L.bounds(bounds.min.divideBy(size).floor(),bounds.max.divideBy(size).ceil().subtract([1,1])):null}});exports.FeatureManager=exports.FeatureGrid.extend({options:{attribution:null,where:"1=1",fields:["*"],from:false,to:false,timeField:false,timeFilterMode:"server",simplifyFactor:0,precision:6},initialize:function(options){exports.FeatureGrid.prototype.initialize.call(this,options);options.url=cleanUrl(options.url);options=L.setOptions(this,options);this.service=featureLayerService(options);this.service.addEventParent(this);if(this.options.fields[0]!=="*"){var oidCheck=false;for(var i=0;i=0;i--){var id=features[i].id;this._currentSnapshot.push(id);this._cache[key].push(id)}if(this.options.timeField){this._buildTimeIndexes(features)}var zoom=this._map.getZoom();if(zoom>this.options.maxZoom||zoom=0;i--){newSnapshot.push(featureCollection.features[i].id)}}pendingRequests--;if(pendingRequests<=0){this._currentSnapshot=newSnapshot;L.Util.requestAnimFrame(L.Util.bind(function(){this.removeLayers(oldSnapshot);this.addLayers(newSnapshot);if(callback){callback.call(context,requestError)}},this))}},this);for(var i=this._currentSnapshot.length-1;i>=0;i--){oldSnapshot.push(this._currentSnapshot[i])}for(var key in this._activeCells){pendingRequests++;var coords=this._keyToCellCoords(key);var bounds=this._cellCoordsToBounds(coords);this._requestFeatures(bounds,key,requestCallback)}return this},getWhere:function(){return this.options.where},getTimeRange:function(){return[this.options.from,this.options.to]},setTimeRange:function(from,to,callback,context){var oldFrom=this.options.from;var oldTo=this.options.to;var pendingRequests=0;var requestError=null;var requestCallback=L.Util.bind(function(error){if(error){requestError=error}this._filterExistingFeatures(oldFrom,oldTo,from,to);pendingRequests--;if(callback&&pendingRequests<=0){callback.call(context,requestError)}},this);this.options.from=from;this.options.to=to;this._filterExistingFeatures(oldFrom,oldTo,from,to);if(this.options.timeFilterMode==="server"){for(var key in this._activeCells){pendingRequests++;var coords=this._keyToCellCoords(key);var bounds=this._cellCoordsToBounds(coords);this._requestFeatures(bounds,key,requestCallback)}}return this},refresh:function(){for(var key in this._activeCells){var coords=this._keyToCellCoords(key);var bounds=this._cellCoordsToBounds(coords);this._requestFeatures(bounds,key)}if(this.redraw){this.once("load",function(){this.eachFeature(function(layer){this._redraw(layer.feature.id)},this)},this)}},_filterExistingFeatures:function(oldFrom,oldTo,newFrom,newTo){var layersToRemove=oldFrom&&oldTo?this._getFeaturesInTimeRange(oldFrom,oldTo):this._currentSnapshot;var layersToAdd=this._getFeaturesInTimeRange(newFrom,newTo);if(layersToAdd.indexOf){for(var i=0;i=0){layersToRemove.splice(shouldRemoveLayer,1)}}}L.Util.requestAnimFrame(L.Util.bind(function(){this.removeLayers(layersToRemove);this.addLayers(layersToAdd)},this))},_getFeaturesInTimeRange:function(start,end){var ids=[];var search;if(this.options.timeField.start&&this.options.timeField.end){var startTimes=this._startTimeIndex.between(start,end);var endTimes=this._endTimeIndex.between(start,end);search=startTimes.concat(endTimes)}else{search=this._timeIndex.between(start,end)}for(var i=search.length-1;i>=0;i--){ids.push(search[i].id)}return ids},_buildTimeIndexes:function(geojson){var i;var feature;if(this.options.timeField.start&&this.options.timeField.end){var startTimeEntries=[];var endTimeEntries=[];for(i=geojson.length-1;i>=0;i--){feature=geojson[i];startTimeEntries.push({id:feature.id,value:new Date(feature.properties[this.options.timeField.start])});endTimeEntries.push({id:feature.id,value:new Date(feature.properties[this.options.timeField.end])})}this._startTimeIndex.bulkAdd(startTimeEntries);this._endTimeIndex.bulkAdd(endTimeEntries)}else{var timeEntries=[];for(i=geojson.length-1;i>=0;i--){feature=geojson[i];timeEntries.push({id:feature.id,value:new Date(feature.properties[this.options.timeField])})}this._timeIndex.bulkAdd(timeEntries)}},_featureWithinTimeRange:function(feature){if(!this.options.from||!this.options.to){return true}var from=+this.options.from.valueOf();var to=+this.options.to.valueOf();if(typeof this.options.timeField==="string"){var date=+feature.properties[this.options.timeField];return date>=from&&date<=to}if(this.options.timeField.start&&this.options.timeField.end){var startDate=+feature.properties[this.options.timeField.start];var endDate=+feature.properties[this.options.timeField.end];return startDate>=from&&startDate<=to||endDate>=from&&endDate<=to}},authenticate:function(token){this.service.authenticate(token);return this},metadata:function(callback,context){this.service.metadata(callback,context);return this},query:function(){return this.service.query()},_getMetadata:function(callback){if(this._metadata){var error;callback(error,this._metadata)}else{this.metadata(L.Util.bind(function(error,response){this._metadata=response;callback(error,this._metadata)},this))}},addFeature:function(feature,callback,context){this._getMetadata(L.Util.bind(function(error,metadata){if(error){if(callback){callback.call(this,error,null)}return}this.service.addFeature(feature,L.Util.bind(function(error,response){if(!error){feature.properties[metadata.objectIdField]=response.objectId;feature.id=response.objectId;this.createLayers([feature])}if(callback){callback.call(context,error,response)}},this))},this))},updateFeature:function(feature,callback,context){this.service.updateFeature(feature,function(error,response){if(!error){this.removeLayers([feature.id],true);this.createLayers([feature])}if(callback){callback.call(context,error,response)}},this)},deleteFeature:function(id,callback,context){this.service.deleteFeature(id,function(error,response){if(!error&&response.objectId){this.removeLayers([response.objectId],true)}if(callback){callback.call(context,error,response)}},this)},deleteFeatures:function(ids,callback,context){return this.service.deleteFeatures(ids,function(error,response){if(!error&&response.length>0){for(var i=0;i+query){maxIndex=currentIndex-1}else{return currentIndex}}return~maxIndex};BinarySearchIndex.prototype.sort=function(){this.values.sort(function(a,b){return+b.value-+a.value}).reverse();this.dirty=false};BinarySearchIndex.prototype.between=function(start,end){if(this.dirty){this.sort()}var startIndex=this._query(start);var endIndex=this._query(end);if(startIndex===0&&endIndex===0){return[]}startIndex=Math.abs(startIndex);endIndex=endIndex<0?Math.abs(endIndex):endIndex+1;return this.values.slice(startIndex,endIndex)};BinarySearchIndex.prototype.bulkAdd=function(items){this.dirty=true;this.values=this.values.concat(items)};exports.FeatureLayer=exports.FeatureManager.extend({options:{cacheLayers:true},initialize:function(options){exports.FeatureManager.prototype.initialize.call(this,options);this._originalStyle=this.options.style;this._layers={}},onRemove:function(map){for(var i in this._layers){map.removeLayer(this._layers[i])}return exports.FeatureManager.prototype.onRemove.call(this,map)},createNewLayer:function(geojson){ +var layer=L.GeoJSON.geometryToLayer(geojson,this.options);layer.defaultOptions=layer.options;return layer},_updateLayer:function(layer,geojson){var latlngs=[];var coordsToLatLng=this.options.coordsToLatLng||L.GeoJSON.coordsToLatLng;if(geojson.properties){layer.feature.properties=geojson.properties}switch(geojson.geometry.type){case"Point":latlngs=L.GeoJSON.coordsToLatLng(geojson.geometry.coordinates);layer.setLatLng(latlngs);break;case"LineString":latlngs=L.GeoJSON.coordsToLatLngs(geojson.geometry.coordinates,0,coordsToLatLng);layer.setLatLngs(latlngs);break;case"MultiLineString":latlngs=L.GeoJSON.coordsToLatLngs(geojson.geometry.coordinates,1,coordsToLatLng);layer.setLatLngs(latlngs);break;case"Polygon":latlngs=L.GeoJSON.coordsToLatLngs(geojson.geometry.coordinates,1,coordsToLatLng);layer.setLatLngs(latlngs);break;case"MultiPolygon":latlngs=L.GeoJSON.coordsToLatLngs(geojson.geometry.coordinates,2,coordsToLatLng);layer.setLatLngs(latlngs);break}},createLayers:function(features){for(var i=features.length-1;i>=0;i--){var geojson=features[i];var layer=this._layers[geojson.id];var newLayer;if(layer&&!this._map.hasLayer(layer)){this._map.addLayer(layer)}if(layer&&this.options.simplifyFactor>0&&(layer.setLatLngs||layer.setLatLng)){this._updateLayer(layer,geojson)}if(!layer){newLayer=this.createNewLayer(geojson);newLayer.feature=geojson;newLayer.addEventParent(this);if(this.options.onEachFeature){this.options.onEachFeature(newLayer.feature,newLayer)}this._layers[newLayer.feature.id]=newLayer;this.setFeatureStyle(newLayer.feature.id,this.options.style);this.fire("createfeature",{feature:newLayer.feature},true);if(!this.options.timeField||this.options.timeField&&this._featureWithinTimeRange(geojson)){this._map.addLayer(newLayer)}}}},addLayers:function(ids){for(var i=ids.length-1;i>=0;i--){var layer=this._layers[ids[i]];if(layer){this.fire("addfeature",{feature:layer.feature},true);this._map.addLayer(layer)}}},removeLayers:function(ids,permanent){for(var i=ids.length-1;i>=0;i--){var id=ids[i];var layer=this._layers[id];if(layer){this.fire("removefeature",{feature:layer.feature,permanent:permanent},true);this._map.removeLayer(layer)}if(layer&&permanent){delete this._layers[id]}}},cellEnter:function(bounds,coords){console.log(this._zooming);if(!this._zooming){L.Util.requestAnimFrame(L.Util.bind(function(){var cacheKey=this._cacheKey(coords);var cellKey=this._cellCoordsToKey(coords);var layers=this._cache[cacheKey];if(this._activeCells[cellKey]&&layers){this.addLayers(layers)}},this))}},cellLeave:function(bounds,coords){console.log(this._zooming);if(!this._zooming){L.Util.requestAnimFrame(L.Util.bind(function(){var cacheKey=this._cacheKey(coords);var cellKey=this._cellCoordsToKey(coords);var layers=this._cache[cacheKey];var mapBounds=this._map.getBounds();if(!this._activeCells[cellKey]&&layers){var removable=true;for(var i=0;i= 0);\n}\n\n// ported from terraformer.js https://github.com/Esri/Terraformer/blob/master/terraformer.js#L504-L519\nfunction vertexIntersectsVertex (a1, a2, b1, b2) {\n var uaT = (b2[0] - b1[0]) * (a1[1] - b1[1]) - (b2[1] - b1[1]) * (a1[0] - b1[0]);\n var ubT = (a2[0] - a1[0]) * (a1[1] - b1[1]) - (a2[1] - a1[1]) * (a1[0] - b1[0]);\n var uB = (b2[1] - b1[1]) * (a2[0] - a1[0]) - (b2[0] - b1[0]) * (a2[1] - a1[1]);\n\n if (uB !== 0) {\n var ua = uaT / uB;\n var ub = ubT / uB;\n\n if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) {\n return true;\n }\n }\n\n return false;\n}\n\n// ported from terraformer.js https://github.com/Esri/Terraformer/blob/master/terraformer.js#L521-L531\nfunction arrayIntersectsArray (a, b) {\n for (var i = 0; i < a.length - 1; i++) {\n for (var j = 0; j < b.length - 1; j++) {\n if (vertexIntersectsVertex(a[i], a[i + 1], b[j], b[j + 1])) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n// ported from terraformer.js https://github.com/Esri/Terraformer/blob/master/terraformer.js#L470-L480\nfunction coordinatesContainPoint (coordinates, point) {\n var contains = false;\n for (var i = -1, l = coordinates.length, j = l - 1; ++i < l; j = i) {\n if (((coordinates[i][1] <= point[1] && point[1] < coordinates[j][1]) ||\n (coordinates[j][1] <= point[1] && point[1] < coordinates[i][1])) &&\n (point[0] < (coordinates[j][0] - coordinates[i][0]) * (point[1] - coordinates[i][1]) / (coordinates[j][1] - coordinates[i][1]) + coordinates[i][0])) {\n contains = !contains;\n }\n }\n return contains;\n}\n\n// ported from terraformer-arcgis-parser.js https://github.com/Esri/terraformer-arcgis-parser/blob/master/terraformer-arcgis-parser.js#L106-L113\nfunction coordinatesContainCoordinates (outer, inner) {\n var intersects = arrayIntersectsArray(outer, inner);\n var contains = coordinatesContainPoint(outer, inner[0]);\n if (!intersects && contains) {\n return true;\n }\n return false;\n}\n\n// do any polygons in this array contain any other polygons in this array?\n// used for checking for holes in arcgis rings\n// ported from terraformer-arcgis-parser.js https://github.com/Esri/terraformer-arcgis-parser/blob/master/terraformer-arcgis-parser.js#L117-L172\nfunction convertRingsToGeoJSON (rings) {\n var outerRings = [];\n var holes = [];\n var x; // iterator\n var outerRing; // current outer ring being evaluated\n var hole; // current hole being evaluated\n\n // for each ring\n for (var r = 0; r < rings.length; r++) {\n var ring = closeRing(rings[r].slice(0));\n if (ring.length < 4) {\n continue;\n }\n // is this ring an outer ring? is it clockwise?\n if (ringIsClockwise(ring)) {\n var polygon = [ ring ];\n outerRings.push(polygon); // push to outer rings\n } else {\n holes.push(ring); // counterclockwise push to holes\n }\n }\n\n var uncontainedHoles = [];\n\n // while there are holes left...\n while (holes.length) {\n // pop a hole off out stack\n hole = holes.pop();\n\n // loop over all outer rings and see if they contain our hole.\n var contained = false;\n for (x = outerRings.length - 1; x >= 0; x--) {\n outerRing = outerRings[x][0];\n if (coordinatesContainCoordinates(outerRing, hole)) {\n // the hole is contained push it into our polygon\n outerRings[x].push(hole);\n contained = true;\n break;\n }\n }\n\n // ring is not contained in any outer ring\n // sometimes this happens https://github.com/Esri/esri-leaflet/issues/320\n if (!contained) {\n uncontainedHoles.push(hole);\n }\n }\n\n // if we couldn't match any holes using contains we can try intersects...\n while (uncontainedHoles.length) {\n // pop a hole off out stack\n hole = uncontainedHoles.pop();\n\n // loop over all outer rings and see if any intersect our hole.\n var intersects = false;\n\n for (x = outerRings.length - 1; x >= 0; x--) {\n outerRing = outerRings[x][0];\n if (arrayIntersectsArray(outerRing, hole)) {\n // the hole is contained push it into our polygon\n outerRings[x].push(hole);\n intersects = true;\n break;\n }\n }\n\n if (!intersects) {\n outerRings.push([hole.reverse()]);\n }\n }\n\n if (outerRings.length === 1) {\n return {\n type: 'Polygon',\n coordinates: outerRings[0]\n };\n } else {\n return {\n type: 'MultiPolygon',\n coordinates: outerRings\n };\n }\n}\n\n// This function ensures that rings are oriented in the right directions\n// outer rings are clockwise, holes are counterclockwise\n// used for converting GeoJSON Polygons to ArcGIS Polygons\nfunction orientRings (poly) {\n var output = [];\n var polygon = poly.slice(0);\n var outerRing = closeRing(polygon.shift().slice(0));\n if (outerRing.length >= 4) {\n if (!ringIsClockwise(outerRing)) {\n outerRing.reverse();\n }\n\n output.push(outerRing);\n\n for (var i = 0; i < polygon.length; i++) {\n var hole = closeRing(polygon[i].slice(0));\n if (hole.length >= 4) {\n if (ringIsClockwise(hole)) {\n hole.reverse();\n }\n output.push(hole);\n }\n }\n }\n\n return output;\n}\n\n// This function flattens holes in multipolygons to one array of polygons\n// used for converting GeoJSON Polygons to ArcGIS Polygons\nfunction flattenMultiPolygonRings (rings) {\n var output = [];\n for (var i = 0; i < rings.length; i++) {\n var polygon = orientRings(rings[i]);\n for (var x = polygon.length - 1; x >= 0; x--) {\n var ring = polygon[x].slice(0);\n output.push(ring);\n }\n }\n return output;\n}\n\n// shallow object clone for feature properties and attributes\n// from http://jsperf.com/cloning-an-object/2\nexport function shallowClone (obj) {\n var target = {};\n for (var i in obj) {\n if (obj.hasOwnProperty(i)) {\n target[i] = obj[i];\n }\n }\n return target;\n}\n\n// convert an extent (ArcGIS) to LatLngBounds (Leaflet)\nexport function extentToBounds (extent) {\n var sw = L.latLng(extent.ymin, extent.xmin);\n var ne = L.latLng(extent.ymax, extent.xmax);\n return L.latLngBounds(sw, ne);\n}\n\n// convert an LatLngBounds (Leaflet) to extent (ArcGIS)\nexport function boundsToExtent (bounds) {\n bounds = L.latLngBounds(bounds);\n return {\n 'xmin': bounds.getSouthWest().lng,\n 'ymin': bounds.getSouthWest().lat,\n 'xmax': bounds.getNorthEast().lng,\n 'ymax': bounds.getNorthEast().lat,\n 'spatialReference': {\n 'wkid': 4326\n }\n };\n}\n\nexport function arcgisToGeojson (arcgis, idAttribute) {\n var geojson = {};\n\n if (typeof arcgis.x === 'number' && typeof arcgis.y === 'number') {\n geojson.type = 'Point';\n geojson.coordinates = [arcgis.x, arcgis.y];\n }\n\n if (arcgis.points) {\n geojson.type = 'MultiPoint';\n geojson.coordinates = arcgis.points.slice(0);\n }\n\n if (arcgis.paths) {\n if (arcgis.paths.length === 1) {\n geojson.type = 'LineString';\n geojson.coordinates = arcgis.paths[0].slice(0);\n } else {\n geojson.type = 'MultiLineString';\n geojson.coordinates = arcgis.paths.slice(0);\n }\n }\n\n if (arcgis.rings) {\n geojson = convertRingsToGeoJSON(arcgis.rings.slice(0));\n }\n\n if (arcgis.geometry || arcgis.attributes) {\n geojson.type = 'Feature';\n geojson.geometry = (arcgis.geometry) ? arcgisToGeojson(arcgis.geometry) : null;\n geojson.properties = (arcgis.attributes) ? shallowClone(arcgis.attributes) : null;\n if (arcgis.attributes) {\n geojson.id = arcgis.attributes[idAttribute] || arcgis.attributes.OBJECTID || arcgis.attributes.FID;\n }\n }\n\n return geojson;\n}\n\n// GeoJSON -> ArcGIS\nexport function geojsonToArcGIS (geojson, idAttribute) {\n idAttribute = idAttribute || 'OBJECTID';\n var spatialReference = { wkid: 4326 };\n var result = {};\n var i;\n\n switch (geojson.type) {\n case 'Point':\n result.x = geojson.coordinates[0];\n result.y = geojson.coordinates[1];\n result.spatialReference = spatialReference;\n break;\n case 'MultiPoint':\n result.points = geojson.coordinates.slice(0);\n result.spatialReference = spatialReference;\n break;\n case 'LineString':\n result.paths = [geojson.coordinates.slice(0)];\n result.spatialReference = spatialReference;\n break;\n case 'MultiLineString':\n result.paths = geojson.coordinates.slice(0);\n result.spatialReference = spatialReference;\n break;\n case 'Polygon':\n result.rings = orientRings(geojson.coordinates.slice(0));\n result.spatialReference = spatialReference;\n break;\n case 'MultiPolygon':\n result.rings = flattenMultiPolygonRings(geojson.coordinates.slice(0));\n result.spatialReference = spatialReference;\n break;\n case 'Feature':\n if (geojson.geometry) {\n result.geometry = geojsonToArcGIS(geojson.geometry, idAttribute);\n }\n result.attributes = (geojson.properties) ? shallowClone(geojson.properties) : {};\n if (geojson.id) {\n result.attributes[idAttribute] = geojson.id;\n }\n break;\n case 'FeatureCollection':\n result = [];\n for (i = 0; i < geojson.features.length; i++) {\n result.push(geojsonToArcGIS(geojson.features[i], idAttribute));\n }\n break;\n case 'GeometryCollection':\n result = [];\n for (i = 0; i < geojson.geometries.length; i++) {\n result.push(geojsonToArcGIS(geojson.geometries[i], idAttribute));\n }\n break;\n }\n\n return result;\n}\n\nexport function responseToFeatureCollection (response, idAttribute) {\n var objectIdField;\n\n if (idAttribute) {\n objectIdField = idAttribute;\n } else if (response.objectIdFieldName) {\n objectIdField = response.objectIdFieldName;\n } else if (response.fields) {\n for (var j = 0; j <= response.fields.length - 1; j++) {\n if (response.fields[j].type === 'esriFieldTypeOID') {\n objectIdField = response.fields[j].name;\n break;\n }\n }\n } else {\n objectIdField = 'OBJECTID';\n }\n\n var featureCollection = {\n type: 'FeatureCollection',\n features: []\n };\n var features = response.features || response.results;\n if (features.length) {\n for (var i = features.length - 1; i >= 0; i--) {\n featureCollection.features.push(arcgisToGeojson(features[i], objectIdField));\n }\n }\n\n return featureCollection;\n}\n\n // trim url whitespace and add a trailing slash if needed\nexport function cleanUrl (url) {\n // trim leading and trailing spaces, but not spaces inside the url\n url = L.Util.trim(url);\n\n // add a trailing slash to the url if the user omitted it\n if (url[url.length - 1] !== '/') {\n url += '/';\n }\n\n return url;\n}\n\nexport function isArcgisOnline (url) {\n /* hosted feature services can emit geojson natively.\n our check for 'geojson' support will need to be revisted\n once the functionality makes its way to ArcGIS Server*/\n return (/\\.arcgis\\.com.*?FeatureServer/g).test(url);\n}\n\nexport function geojsonTypeToArcGIS (geoJsonType) {\n var arcgisGeometryType;\n switch (geoJsonType) {\n case 'Point':\n arcgisGeometryType = 'esriGeometryPoint';\n break;\n case 'MultiPoint':\n arcgisGeometryType = 'esriGeometryMultipoint';\n break;\n case 'LineString':\n arcgisGeometryType = 'esriGeometryPolyline';\n break;\n case 'MultiLineString':\n arcgisGeometryType = 'esriGeometryPolyline';\n break;\n case 'Polygon':\n arcgisGeometryType = 'esriGeometryPolygon';\n break;\n case 'MultiPolygon':\n arcgisGeometryType = 'esriGeometryPolygon';\n break;\n }\n\n return arcgisGeometryType;\n}\n\nexport function warn () {\n if (console && console.warn) {\n console.warn.apply(console, arguments);\n }\n}\n\nexport var Util = {\n shallowClone: shallowClone,\n warn: warn,\n cleanUrl: cleanUrl,\n isArcgisOnline: isArcgisOnline,\n geojsonTypeToArcGIS: geojsonTypeToArcGIS,\n responseToFeatureCollection: responseToFeatureCollection,\n geojsonToArcGIS: geojsonToArcGIS,\n arcgisToGeojson: arcgisToGeojson,\n boundsToExtent: boundsToExtent,\n extentToBounds: extentToBounds\n};\n\nexport default Util;\n","import L from 'leaflet';\nimport Support from './Support';\nimport {warn} from './Util';\n\nvar callbacks = 0;\n\nfunction serialize (params) {\n var data = '';\n\n params.f = params.f || 'json';\n\n for (var key in params) {\n if (params.hasOwnProperty(key)) {\n var param = params[key];\n var type = Object.prototype.toString.call(param);\n var value;\n\n if (data.length) {\n data += '&';\n }\n\n if (type === '[object Array]') {\n value = (Object.prototype.toString.call(param[0]) === '[object Object]') ? JSON.stringify(param) : param.join(',');\n } else if (type === '[object Object]') {\n value = JSON.stringify(param);\n } else if (type === '[object Date]') {\n value = param.valueOf();\n } else {\n value = param;\n }\n\n data += encodeURIComponent(key) + '=' + encodeURIComponent(value);\n }\n }\n\n return data;\n}\n\nfunction createRequest (callback, context) {\n var httpRequest = new window.XMLHttpRequest();\n\n httpRequest.onerror = function (e) {\n httpRequest.onreadystatechange = L.Util.falseFn;\n\n callback.call(context, {\n error: {\n code: 500,\n message: 'XMLHttpRequest error'\n }\n }, null);\n };\n\n httpRequest.onreadystatechange = function () {\n var response;\n var error;\n\n if (httpRequest.readyState === 4) {\n try {\n response = JSON.parse(httpRequest.responseText);\n } catch(e) {\n response = null;\n error = {\n code: 500,\n message: 'Could not parse response as JSON. This could also be caused by a CORS or XMLHttpRequest error.'\n };\n }\n\n if (!error && response.error) {\n error = response.error;\n response = null;\n }\n\n httpRequest.onerror = L.Util.falseFn;\n\n callback.call(context, error, response);\n }\n };\n\n return httpRequest;\n}\n\nfunction xmlHttpPost (url, params, callback, context) {\n var httpRequest = createRequest(callback, context);\n httpRequest.open('POST', url);\n httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n httpRequest.send(serialize(params));\n\n return httpRequest;\n}\n\nfunction xmlHttpGet (url, params, callback, context) {\n var httpRequest = createRequest(callback, context);\n\n httpRequest.open('GET', url + '?' + serialize(params), true);\n httpRequest.send(null);\n\n return httpRequest;\n}\n\n// AJAX handlers for CORS (modern browsers) or JSONP (older browsers)\nexport function request (url, params, callback, context) {\n var paramString = serialize(params);\n var httpRequest = createRequest(callback, context);\n var requestLength = (url + '?' + paramString).length;\n\n // request is less then 2000 characters and the browser supports CORS, make GET request with XMLHttpRequest\n if (requestLength <= 2000 && Support.cors) {\n httpRequest.open('GET', url + '?' + paramString);\n httpRequest.send(null);\n\n // request is less more then 2000 characters and the browser supports CORS, make POST request with XMLHttpRequest\n } else if (requestLength > 2000 && Support.cors) {\n httpRequest.open('POST', url);\n httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n httpRequest.send(paramString);\n\n // request is less more then 2000 characters and the browser does not support CORS, make a JSONP request\n } else if (requestLength <= 2000 && !Support.cors) {\n return jsonp(url, params, callback, context);\n\n // request is longer then 2000 characters and the browser does not support CORS, log a warning\n } else {\n warn('a request to ' + url + ' was longer then 2000 characters and this browser cannot make a cross-domain post request. Please use a proxy http://esri.github.io/esri-leaflet/api-reference/request.html');\n return;\n }\n\n return httpRequest;\n}\n\nexport function jsonp (url, params, callback, context) {\n window._EsriLeafletCallbacks = window._EsriLeafletCallbacks || {};\n var callbackId = 'c' + callbacks;\n\n params.callback = 'window._EsriLeafletCallbacks.' + callbackId;\n\n var script = L.DomUtil.create('script', null, document.body);\n script.type = 'text/javascript';\n script.src = url + '?' + serialize(params);\n script.id = callbackId;\n\n window._EsriLeafletCallbacks[callbackId] = function (response) {\n if (window._EsriLeafletCallbacks[callbackId] !== true) {\n var error;\n var responseType = Object.prototype.toString.call(response);\n\n if (!(responseType === '[object Object]' || responseType === '[object Array]')) {\n error = {\n error: {\n code: 500,\n message: 'Expected array or object as JSONP response'\n }\n };\n response = null;\n }\n\n if (!error && response.error) {\n error = response;\n response = null;\n }\n\n callback.call(context, error, response);\n window._EsriLeafletCallbacks[callbackId] = true;\n }\n };\n\n callbacks++;\n\n return {\n id: callbackId,\n url: script.src,\n abort: function () {\n window._EsriLeafletCallbacks._callback[callbackId]({\n code: 0,\n message: 'Request aborted.'\n });\n }\n };\n}\n\nvar get = ((Support.cors) ? xmlHttpGet : jsonp);\nget.CORS = xmlHttpGet;\nget.JSONP = jsonp;\n\n// choose the correct AJAX handler depending on CORS support\nexport { get };\n\n// always use XMLHttpRequest for posts\nexport { xmlHttpPost as post };\n\n// export the Request object to call the different handlers for debugging\nexport var Request = {\n request: request,\n get: get,\n post: xmlHttpPost\n};\n\nexport default Request;\n","import L from 'leaflet';\nimport {cors} from '../Support';\nimport {cleanUrl} from '../Util';\nimport Request from '../Request';\n\nexport var Task = L.Class.extend({\n\n options: {\n proxy: false,\n useCors: cors\n },\n\n // Generate a method for each methodName:paramName in the setters for this task.\n generateSetter: function (param, context) {\n return L.Util.bind(function (value) {\n this.params[param] = value;\n return this;\n }, context);\n },\n\n initialize: function (endpoint) {\n // endpoint can be either a url (and options) for an ArcGIS Rest Service or an instance of EsriLeaflet.Service\n if (endpoint.request && endpoint.options) {\n this._service = endpoint;\n L.Util.setOptions(this, endpoint.options);\n } else {\n L.Util.setOptions(this, endpoint);\n this.options.url = cleanUrl(endpoint.url);\n }\n\n // clone default params into this object\n this.params = L.Util.extend({}, this.params || {});\n\n // generate setter methods based on the setters object implimented a child class\n if (this.setters) {\n for (var setter in this.setters) {\n var param = this.setters[setter];\n this[setter] = this.generateSetter(param, this);\n }\n }\n },\n\n token: function (token) {\n if (this._service) {\n this._service.authenticate(token);\n } else {\n this.params.token = token;\n }\n return this;\n },\n\n request: function (callback, context) {\n if (this._service) {\n return this._service.request(this.path, this.params, callback, context);\n }\n\n return this._request('request', this.path, this.params, callback, context);\n },\n\n _request: function (method, path, params, callback, context) {\n var url = (this.options.proxy) ? this.options.proxy + '?' + this.options.url + path : this.options.url + path;\n\n if ((method === 'get' || method === 'request') && !this.options.useCors) {\n return Request.get.JSONP(url, params, callback, context);\n }\n\n return Request[method](url, params, callback, context);\n }\n});\n\nexport function task (options) {\n return new Task(options);\n}\n\nexport default task;\n","import L from 'leaflet';\nimport { Task } from './Task';\nimport Util from '../Util';\n\nexport var Query = Task.extend({\n setters: {\n 'offset': 'offset',\n 'limit': 'limit',\n 'fields': 'outFields',\n 'precision': 'geometryPrecision',\n 'featureIds': 'objectIds',\n 'returnGeometry': 'returnGeometry',\n 'token': 'token'\n },\n\n path: 'query',\n\n params: {\n returnGeometry: true,\n where: '1=1',\n outSr: 4326,\n outFields: '*'\n },\n\n within: function (geometry) {\n this._setGeometry(geometry);\n this.params.spatialRel = 'esriSpatialRelContains'; // will make code read layer within geometry, to the api this will reads geometry contains layer\n return this;\n },\n\n intersects: function (geometry) {\n this._setGeometry(geometry);\n this.params.spatialRel = 'esriSpatialRelIntersects';\n return this;\n },\n\n contains: function (geometry) {\n this._setGeometry(geometry);\n this.params.spatialRel = 'esriSpatialRelWithin'; // will make code read layer contains geometry, to the api this will reads geometry within layer\n return this;\n },\n\n crosses: function (geometry) {\n this._setGeometry(geometry);\n this.params.spatialRel = 'esriSpatialRelCrosses';\n return this;\n },\n\n touches: function (geometry) {\n this._setGeometry(geometry);\n this.params.spatialRel = 'esriSpatialRelTouches';\n return this;\n },\n\n overlaps: function (geometry) {\n this._setGeometry(geometry);\n this.params.spatialRel = 'esriSpatialRelOverlaps';\n return this;\n },\n\n // only valid for Feature Services running on ArcGIS Server 10.3 or ArcGIS Online\n nearby: function (latlng, radius) {\n latlng = L.latLng(latlng);\n this.params.geometry = [latlng.lng, latlng.lat];\n this.params.geometryType = 'esriGeometryPoint';\n this.params.spatialRel = 'esriSpatialRelIntersects';\n this.params.units = 'esriSRUnit_Meter';\n this.params.distance = radius;\n this.params.inSr = 4326;\n return this;\n },\n\n where: function (string) {\n // instead of converting double-quotes to single quotes, pass as is, and provide a more informative message if a 400 is encountered\n this.params.where = string;\n return this;\n },\n\n between: function (start, end) {\n this.params.time = [start.valueOf(), end.valueOf()];\n return this;\n },\n\n simplify: function (map, factor) {\n var mapWidth = Math.abs(map.getBounds().getWest() - map.getBounds().getEast());\n this.params.maxAllowableOffset = (mapWidth / map.getSize().y) * factor;\n return this;\n },\n\n orderBy: function (fieldName, order) {\n order = order || 'ASC';\n this.params.orderByFields = (this.params.orderByFields) ? this.params.orderByFields + ',' : '';\n this.params.orderByFields += ([fieldName, order]).join(' ');\n return this;\n },\n\n run: function (callback, context) {\n this._cleanParams();\n\n // if the service is hosted on arcgis online request geojson directly\n if (Util.isArcgisOnline(this.options.url)) {\n this.params.f = 'geojson';\n\n return this.request(function (error, response) {\n this._trapSQLerrors(error);\n callback.call(context, error, response, response);\n }, this);\n\n // otherwise convert it in the callback then pass it on\n } else {\n return this.request(function (error, response) {\n this._trapSQLerrors(error);\n callback.call(context, error, (response && Util.responseToFeatureCollection(response)), response);\n }, this);\n }\n },\n\n count: function (callback, context) {\n this._cleanParams();\n this.params.returnCountOnly = true;\n return this.request(function (error, response) {\n callback.call(this, error, (response && response.count), response);\n }, context);\n },\n\n ids: function (callback, context) {\n this._cleanParams();\n this.params.returnIdsOnly = true;\n return this.request(function (error, response) {\n callback.call(this, error, (response && response.objectIds), response);\n }, context);\n },\n\n // only valid for Feature Services running on ArcGIS Server 10.3 or ArcGIS Online\n bounds: function (callback, context) {\n this._cleanParams();\n this.params.returnExtentOnly = true;\n return this.request(function (error, response) {\n callback.call(context, error, (response && response.extent && Util.extentToBounds(response.extent)), response);\n }, context);\n },\n\n // only valid for image services\n pixelSize: function (point) {\n point = L.point(point);\n this.params.pixelSize = [point.x, point.y];\n return this;\n },\n\n // only valid for map services\n layer: function (layer) {\n this.path = layer + '/query';\n return this;\n },\n\n _trapSQLerrors: function (error) {\n if (error) {\n if (error.code === '400') {\n Util.warn('one common syntax error in query requests is encasing string values in double quotes instead of single quotes');\n }\n }\n },\n\n _cleanParams: function () {\n delete this.params.returnIdsOnly;\n delete this.params.returnExtentOnly;\n delete this.params.returnCountOnly;\n },\n\n _setGeometry: function (geometry) {\n this.params.inSr = 4326;\n\n // convert bounds to extent and finish\n if (geometry instanceof L.LatLngBounds) {\n // set geometry + geometryType\n this.params.geometry = Util.boundsToExtent(geometry);\n this.params.geometryType = 'esriGeometryEnvelope';\n return;\n }\n\n // convert L.Marker > L.LatLng\n if (geometry.getLatLng) {\n geometry = geometry.getLatLng();\n }\n\n // convert L.LatLng to a geojson point and continue;\n if (geometry instanceof L.LatLng) {\n geometry = {\n type: 'Point',\n coordinates: [geometry.lng, geometry.lat]\n };\n }\n\n // handle L.GeoJSON, pull out the first geometry\n if (geometry instanceof L.GeoJSON) {\n // reassign geometry to the GeoJSON value (we are assuming that only one feature is present)\n geometry = geometry.getLayers()[0].feature.geometry;\n this.params.geometry = Util.geojsonToArcGIS(geometry);\n this.params.geometryType = Util.geojsonTypeToArcGIS(geometry.type);\n }\n\n // Handle L.Polyline and L.Polygon\n if (geometry.toGeoJSON) {\n geometry = geometry.toGeoJSON();\n }\n\n // handle GeoJSON feature by pulling out the geometry\n if (geometry.type === 'Feature') {\n // get the geometry of the geojson feature\n geometry = geometry.geometry;\n }\n\n // confirm that our GeoJSON is a point, line or polygon\n if (geometry.type === 'Point' || geometry.type === 'LineString' || geometry.type === 'Polygon') {\n this.params.geometry = Util.geojsonToArcGIS(geometry);\n this.params.geometryType = Util.geojsonTypeToArcGIS(geometry.type);\n return;\n }\n\n // warn the user if we havn't found a\n /* global console */\n Util.warn('invalid geometry passed to spatial query. Should be an L.LatLng, L.LatLngBounds or L.Marker or a GeoJSON Point Line or Polygon object');\n\n return;\n }\n});\n\nexport function query (options) {\n return new Query(options);\n}\n\nexport default query;\n","import { Task } from './Task';\nimport Util from '../Util';\n\nexport var Find = Task.extend({\n setters: {\n // method name > param name\n 'contains': 'contains',\n 'text': 'searchText',\n 'fields': 'searchFields', // denote an array or single string\n 'spatialReference': 'sr',\n 'sr': 'sr',\n 'layers': 'layers',\n 'returnGeometry': 'returnGeometry',\n 'maxAllowableOffset': 'maxAllowableOffset',\n 'precision': 'geometryPrecision',\n 'dynamicLayers': 'dynamicLayers',\n 'returnZ': 'returnZ',\n 'returnM': 'returnM',\n 'gdbVersion': 'gdbVersion',\n 'token': 'token'\n },\n\n path: 'find',\n\n params: {\n sr: 4326,\n contains: true,\n returnGeometry: true,\n returnZ: true,\n returnM: false\n },\n\n layerDefs: function (id, where) {\n this.params.layerDefs = (this.params.layerDefs) ? this.params.layerDefs + ';' : '';\n this.params.layerDefs += ([id, where]).join(':');\n return this;\n },\n\n simplify: function (map, factor) {\n var mapWidth = Math.abs(map.getBounds().getWest() - map.getBounds().getEast());\n this.params.maxAllowableOffset = (mapWidth / map.getSize().y) * factor;\n return this;\n },\n\n run: function (callback, context) {\n return this.request(function (error, response) {\n callback.call(context, error, (response && Util.responseToFeatureCollection(response)), response);\n }, context);\n }\n});\n\nexport function find (options) {\n return new Find(options);\n}\n\nexport default find;\n","import { Task } from './Task';\n\nexport var Identify = Task.extend({\n path: 'identify',\n\n between: function (start, end) {\n this.params.time = [start.valueOf(), end.valueOf()];\n return this;\n }\n});\n\nexport function identify (options) {\n return new Identify(options);\n}\n\nexport default identify;\n","import L from 'leaflet';\nimport { Identify } from './Identify';\nimport Util from '../Util';\n\nexport var IdentifyFeatures = Identify.extend({\n setters: {\n 'layers': 'layers',\n 'precision': 'geometryPrecision',\n 'tolerance': 'tolerance',\n 'returnGeometry': 'returnGeometry'\n },\n\n params: {\n sr: 4326,\n layers: 'all',\n tolerance: 3,\n returnGeometry: true\n },\n\n on: function (map) {\n var extent = Util.boundsToExtent(map.getBounds());\n var size = map.getSize();\n this.params.imageDisplay = [size.x, size.y, 96];\n this.params.mapExtent = [extent.xmin, extent.ymin, extent.xmax, extent.ymax];\n return this;\n },\n\n at: function (latlng) {\n latlng = L.latLng(latlng);\n this.params.geometry = [latlng.lng, latlng.lat];\n this.params.geometryType = 'esriGeometryPoint';\n return this;\n },\n\n layerDef: function (id, where) {\n this.params.layerDefs = (this.params.layerDefs) ? this.params.layerDefs + ';' : '';\n this.params.layerDefs += ([id, where]).join(':');\n return this;\n },\n\n simplify: function (map, factor) {\n var mapWidth = Math.abs(map.getBounds().getWest() - map.getBounds().getEast());\n this.params.maxAllowableOffset = (mapWidth / map.getSize().y) * (1 - factor);\n return this;\n },\n\n run: function (callback, context) {\n return this.request(function (error, response) {\n // immediately invoke with an error\n if (error) {\n callback.call(context, error, undefined, response);\n return;\n\n // ok no error lets just assume we have features...\n } else {\n var featureCollection = Util.responseToFeatureCollection(response);\n response.results = response.results.reverse();\n for (var i = 0; i < featureCollection.features.length; i++) {\n var feature = featureCollection.features[i];\n feature.layerId = response.results[i].layerId;\n }\n callback.call(context, undefined, featureCollection, response);\n }\n });\n }\n});\n\nexport function identifyFeatures (options) {\n return new IdentifyFeatures(options);\n}\n\nexport default identifyFeatures;\n","import L from 'leaflet';\nimport { Identify } from './Identify';\nimport Util from '../Util';\n\nexport var IdentifyImage = Identify.extend({\n setters: {\n 'setMosaicRule': 'mosaicRule',\n 'setRenderingRule': 'renderingRule',\n 'setPixelSize': 'pixelSize',\n 'returnCatalogItems': 'returnCatalogItems',\n 'returnGeometry': 'returnGeometry'\n },\n\n params: {\n returnGeometry: false\n },\n\n at: function (latlng) {\n latlng = L.latLng(latlng);\n this.params.geometry = JSON.stringify({\n x: latlng.lng,\n y: latlng.lat,\n spatialReference: {\n wkid: 4326\n }\n });\n this.params.geometryType = 'esriGeometryPoint';\n return this;\n },\n\n getMosaicRule: function () {\n return this.params.mosaicRule;\n },\n\n getRenderingRule: function () {\n return this.params.renderingRule;\n },\n\n getPixelSize: function () {\n return this.params.pixelSize;\n },\n\n run: function (callback, context) {\n return this.request(function (error, response) {\n callback.call(context, error, (response && this._responseToGeoJSON(response)), response);\n }, this);\n },\n\n // get pixel data and return as geoJSON point\n // populate catalog items (if any)\n // merging in any catalogItemVisibilities as a propery of each feature\n _responseToGeoJSON: function (response) {\n var location = response.location;\n var catalogItems = response.catalogItems;\n var catalogItemVisibilities = response.catalogItemVisibilities;\n var geoJSON = {\n 'pixel': {\n 'type': 'Feature',\n 'geometry': {\n 'type': 'Point',\n 'coordinates': [location.x, location.y]\n },\n 'crs': {\n 'type': 'EPSG',\n 'properties': {\n 'code': location.spatialReference.wkid\n }\n },\n 'properties': {\n 'OBJECTID': response.objectId,\n 'name': response.name,\n 'value': response.value\n },\n 'id': response.objectId\n }\n };\n\n if (response.properties && response.properties.Values) {\n geoJSON.pixel.properties.values = response.properties.Values;\n }\n\n if (catalogItems && catalogItems.features) {\n geoJSON.catalogItems = Util.responseToFeatureCollection(catalogItems);\n if (catalogItemVisibilities && catalogItemVisibilities.length === geoJSON.catalogItems.features.length) {\n for (var i = catalogItemVisibilities.length - 1; i >= 0; i--) {\n geoJSON.catalogItems.features[i].properties.catalogItemVisibility = catalogItemVisibilities[i];\n }\n }\n }\n return geoJSON;\n }\n\n});\n\nexport function identifyImage (params) {\n return new IdentifyImage(params);\n}\n\nexport default identifyImage;\n","import L from 'leaflet';\nimport {cors} from '../Support';\nimport {cleanUrl} from '../Util';\nimport Request from '../Request';\n\nexport var Service = L.Evented.extend({\n\n options: {\n proxy: false,\n useCors: cors\n },\n\n initialize: function (options) {\n options = options || {};\n this._requestQueue = [];\n this._authenticating = false;\n L.Util.setOptions(this, options);\n this.options.url = cleanUrl(this.options.url);\n },\n\n get: function (path, params, callback, context) {\n return this._request('get', path, params, callback, context);\n },\n\n post: function (path, params, callback, context) {\n return this._request('post', path, params, callback, context);\n },\n\n request: function (path, params, callback, context) {\n return this._request('request', path, params, callback, context);\n },\n\n metadata: function (callback, context) {\n return this._request('get', '', {}, callback, context);\n },\n\n authenticate: function (token) {\n this._authenticating = false;\n this.options.token = token;\n this._runQueue();\n return this;\n },\n\n _request: function (method, path, params, callback, context) {\n this.fire('requeststart', {\n url: this.options.url + path,\n params: params,\n method: method\n }, true);\n\n var wrappedCallback = this._createServiceCallback(method, path, params, callback, context);\n\n if (this.options.token) {\n params.token = this.options.token;\n }\n\n if (this._authenticating) {\n this._requestQueue.push([method, path, params, callback, context]);\n return;\n } else {\n var url = (this.options.proxy) ? this.options.proxy + '?' + this.options.url + path : this.options.url + path;\n\n if ((method === 'get' || method === 'request') && !this.options.useCors) {\n return Request.get.JSONP(url, params, wrappedCallback);\n } else {\n return Request[method](url, params, wrappedCallback);\n }\n }\n },\n\n _createServiceCallback: function (method, path, params, callback, context) {\n return L.Util.bind(function (error, response) {\n if (error && (error.code === 499 || error.code === 498)) {\n this._authenticating = true;\n\n this._requestQueue.push([method, path, params, callback, context]);\n\n // fire an event for users to handle and re-authenticate\n this.fire('authenticationrequired', {\n authenticate: L.Util.bind(this.authenticate, this)\n }, true);\n\n // if the user has access to a callback they can handle the auth error\n error.authenticate = L.Util.bind(this.authenticate, this);\n }\n\n callback.call(context, error, response);\n\n if (error) {\n this.fire('requesterror', {\n url: this.options.url + path,\n params: params,\n message: error.message,\n code: error.code,\n method: method\n }, true);\n } else {\n this.fire('requestsuccess', {\n url: this.options.url + path,\n params: params,\n response: response,\n method: method\n }, true);\n }\n\n this.fire('requestend', {\n url: this.options.url + path,\n params: params,\n method: method\n }, true);\n }, this);\n },\n\n _runQueue: function () {\n for (var i = this._requestQueue.length - 1; i >= 0; i--) {\n var request = this._requestQueue[i];\n var method = request.shift();\n this[method].apply(this, request);\n }\n this._requestQueue = [];\n }\n});\n\nexport function service (options) {\n return new Service(options);\n}\n\nexport default service;\n","import { Service } from './Service';\nimport identifyFeatures from '../Tasks/IdentifyFeatures';\nimport query from '../Tasks/Query';\nimport find from '../Tasks/Find';\n\nexport var MapService = Service.extend({\n\n identify: function () {\n return identifyFeatures(this);\n },\n\n find: function () {\n return find(this);\n },\n\n query: function () {\n return query(this);\n }\n\n});\n\nexport function mapService (options) {\n return new MapService(options);\n}\n\nexport default mapService;\n","import { Service } from './Service';\nimport identifyImage from '../Tasks/IdentifyImage';\nimport query from '../Tasks/Query';\n\nexport var ImageService = Service.extend({\n\n query: function () {\n return query(this);\n },\n\n identify: function () {\n return identifyImage(this);\n }\n});\n\nexport function imageService (options) {\n return new ImageService(options);\n}\n\nexport default imageService;\n","import { Service } from './Service';\nimport query from '../Tasks/Query';\nimport { geojsonToArcGIS } from '../Util';\n\nexport var FeatureLayerService = Service.extend({\n\n options: {\n idAttribute: 'OBJECTID'\n },\n\n query: function () {\n return query(this);\n },\n\n addFeature: function (feature, callback, context) {\n delete feature.id;\n\n feature = geojsonToArcGIS(feature);\n\n return this.post('addFeatures', {\n features: [feature]\n }, function (error, response) {\n var result = (response && response.addResults) ? response.addResults[0] : undefined;\n if (callback) {\n callback.call(context, error || response.addResults[0].error, result);\n }\n }, context);\n },\n\n updateFeature: function (feature, callback, context) {\n feature = geojsonToArcGIS(feature, this.options.idAttribute);\n\n return this.post('updateFeatures', {\n features: [feature]\n }, function (error, response) {\n var result = (response && response.updateResults) ? response.updateResults[0] : undefined;\n if (callback) {\n callback.call(context, error || response.updateResults[0].error, result);\n }\n }, context);\n },\n\n deleteFeature: function (id, callback, context) {\n return this.post('deleteFeatures', {\n objectIds: id\n }, function (error, response) {\n var result = (response && response.deleteResults) ? response.deleteResults[0] : undefined;\n if (callback) {\n callback.call(context, error || response.deleteResults[0].error, result);\n }\n }, context);\n },\n\n deleteFeatures: function (ids, callback, context) {\n return this.post('deleteFeatures', {\n objectIds: ids\n }, function (error, response) {\n // pass back the entire array\n var result = (response && response.deleteResults) ? response.deleteResults : undefined;\n if (callback) {\n callback.call(context, error || response.deleteResults[0].error, result);\n }\n }, context);\n }\n});\n\nexport function featureLayerService (options) {\n return new FeatureLayerService(options);\n}\n\nexport default featureLayerService;\n","import L from 'leaflet';\n\nexport var Logo = L.Control.extend({\n options: {\n position: 'bottomright',\n marginTop: 0,\n marginLeft: 0,\n marginBottom: 0,\n marginRight: 0\n },\n\n onAdd: function () {\n var div = L.DomUtil.create('div', 'esri-leaflet-logo');\n div.style.marginTop = this.options.marginTop;\n div.style.marginLeft = this.options.marginLeft;\n div.style.marginBottom = this.options.marginBottom;\n div.style.marginRight = this.options.marginRight;\n div.innerHTML = this._adjustLogo(this._map._size);\n\n this._map.on('resize', function (e) {\n div.innerHTML = this._adjustLogo(e.newSize);\n }, this);\n\n return div;\n },\n\n _adjustLogo: function (mapSize) {\n if (mapSize.x <= 600 || mapSize.y <= 600) {\n return '\"Powered';\n } else {\n return '\"Powered';\n }\n }\n});\n\nexport default function logo (options) {\n return new Logo(options);\n}\n","import L from 'leaflet';\nimport logo from '../Controls/Logo';\nimport { jsonp } from '../Request';\nimport { pointerEvents } from '../Support';\n\nvar tileProtocol = (window.location.protocol !== 'https:') ? 'http:' : 'https:';\n\nexport var BasemapLayer = L.TileLayer.extend({\n statics: {\n TILES: {\n Streets: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}',\n attributionUrl: 'https://static.arcgis.com/attribution/World_Street_Map',\n options: {\n hideLogo: false,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 19,\n subdomains: ['server', 'services'],\n attribution: 'Esri'\n }\n },\n Topographic: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}',\n attributionUrl: 'https://static.arcgis.com/attribution/World_Topo_Map',\n options: {\n hideLogo: false,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 19,\n subdomains: ['server', 'services'],\n attribution: 'Esri'\n }\n },\n Oceans: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/arcgis/rest/services/Ocean/World_Ocean_Base/MapServer/tile/{z}/{y}/{x}',\n attributionUrl: 'https://static.arcgis.com/attribution/Ocean_Basemap',\n options: {\n hideLogo: false,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 16,\n subdomains: ['server', 'services'],\n attribution: 'Esri'\n }\n },\n OceansLabels: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/arcgis/rest/services/Ocean/World_Ocean_Reference/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: true,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 16,\n subdomains: ['server', 'services'],\n pane: (pointerEvents) ? 'esri-labels' : 'tilePane'\n }\n },\n NationalGeographic: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: false,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 16,\n subdomains: ['server', 'services'],\n attribution: 'Esri'\n }\n },\n DarkGray: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Dark_Gray_Base/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: false,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 16,\n subdomains: ['server', 'services'],\n attribution: 'Esri, DeLorme, HERE'\n }\n },\n DarkGrayLabels: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Dark_Gray_Reference/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: true,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 16,\n subdomains: ['server', 'services'],\n pane: (pointerEvents) ? 'esri-labels' : 'tilePane'\n }\n },\n Gray: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: false,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 16,\n subdomains: ['server', 'services'],\n attribution: 'Esri, NAVTEQ, DeLorme'\n }\n },\n GrayLabels: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Reference/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: true,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 16,\n subdomains: ['server', 'services'],\n pane: (pointerEvents) ? 'esri-labels' : 'tilePane'\n }\n },\n Imagery: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: false,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 19,\n subdomains: ['server', 'services'],\n attribution: 'Esri, DigitalGlobe, GeoEye, i-cubed, USDA, USGS, AEX, Getmapping, Aerogrid, IGN, IGP, swisstopo, and the GIS User Community'\n }\n },\n ImageryLabels: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: true,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 19,\n subdomains: ['server', 'services'],\n pane: (pointerEvents) ? 'esri-labels' : 'tilePane'\n }\n },\n ImageryTransportation: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: true,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 19,\n subdomains: ['server', 'services'],\n pane: (pointerEvents) ? 'esri-labels' : 'tilePane'\n }\n },\n ShadedRelief: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: false,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 13,\n subdomains: ['server', 'services'],\n attribution: 'Esri, NAVTEQ, DeLorme'\n }\n },\n ShadedReliefLabels: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places_Alternate/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: true,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 12,\n subdomains: ['server', 'services'],\n pane: (pointerEvents) ? 'esri-labels' : 'tilePane'\n }\n },\n Terrain: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/World_Terrain_Base/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: false,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 13,\n subdomains: ['server', 'services'],\n attribution: 'Esri, USGS, NOAA'\n }\n },\n TerrainLabels: {\n urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/Reference/World_Reference_Overlay/MapServer/tile/{z}/{y}/{x}',\n options: {\n hideLogo: true,\n logoPosition: 'bottomright',\n minZoom: 1,\n maxZoom: 13,\n subdomains: ['server', 'services'],\n pane: (pointerEvents) ? 'esri-labels' : 'tilePane'\n }\n }\n }\n },\n initialize: function (key, options) {\n var config;\n\n // set the config variable with the appropriate config object\n if (typeof key === 'object' && key.urlTemplate && key.options) {\n config = key;\n } else if (typeof key === 'string' && BasemapLayer.TILES[key]) {\n config = BasemapLayer.TILES[key];\n } else {\n throw new Error('L.esri.BasemapLayer: Invalid parameter. Use one of \"Streets\", \"Topographic\", \"Oceans\", \"OceansLabels\", \"NationalGeographic\", \"Gray\", \"GrayLabels\", \"DarkGray\", \"DarkGrayLabels\", \"Imagery\", \"ImageryLabels\", \"ImageryTransportation\", \"ShadedRelief\", \"ShadedReliefLabels\", \"Terrain\" or \"TerrainLabels\"');\n }\n\n // merge passed options into the config options\n var tileOptions = L.Util.extend(config.options, options);\n\n // call the initialize method on L.TileLayer to set everything up\n L.TileLayer.prototype.initialize.call(this, config.urlTemplate, L.Util.setOptions(this, tileOptions));\n\n // if this basemap requires dynamic attribution set it up\n if (config.attributionUrl) {\n this._getAttributionData(config.attributionUrl);\n }\n\n this._logo = logo({\n position: this.options.logoPosition\n });\n },\n onAdd: function (map) {\n if (!this.options.hideLogo && !map._hasEsriLogo) {\n this._logo.addTo(map);\n map._hasEsriLogo = true;\n }\n\n if (this.options.pane === 'esri-labels') {\n this._initPane();\n }\n\n L.TileLayer.prototype.onAdd.call(this, map);\n\n map.on('moveend', this._updateMapAttribution, this);\n },\n onRemove: function (map) {\n // check to make sure the logo hasn't already been removed\n if (this._logo && this._logo._container) {\n map.removeControl(this._logo);\n map._hasEsriLogo = false;\n }\n\n L.TileLayer.prototype.onRemove.call(this, map);\n\n map.off('moveend', this._updateMapAttribution, this);\n },\n getAttribution: function () {\n var attribution = '' + this.options.attribution + '';\n return attribution;\n },\n _initPane: function () {\n if (!this._map.getPane(this.options.pane)) {\n var pane = this._map.createPane(this.options.pane);\n pane.style.pointerEvents = 'none';\n pane.style.zIndex = 500;\n }\n },\n _getAttributionData: function (url) {\n jsonp(url, {}, L.Util.bind(function (error, attributions) {\n if (error) { return; }\n this._attributions = [];\n\n for (var c = 0; c < attributions.contributors.length; c++) {\n var contributor = attributions.contributors[c];\n for (var i = 0; i < contributor.coverageAreas.length; i++) {\n var coverageArea = contributor.coverageAreas[i];\n var southWest = L.latLng(coverageArea.bbox[0], coverageArea.bbox[1]);\n var northEast = L.latLng(coverageArea.bbox[2], coverageArea.bbox[3]);\n this._attributions.push({\n attribution: contributor.attribution,\n score: coverageArea.score,\n bounds: L.latLngBounds(southWest, northEast),\n minZoom: coverageArea.zoomMin,\n maxZoom: coverageArea.zoomMax\n });\n }\n }\n\n this._attributions.sort(function (a, b) {\n return b.score - a.score;\n });\n\n this._updateMapAttribution();\n }, this));\n },\n _updateMapAttribution: function () {\n if (this._map && this._map.attributionControl && this._attributions) {\n var newAttributions = '';\n var bounds = this._map.getBounds();\n var zoom = this._map.getZoom();\n\n for (var i = 0; i < this._attributions.length; i++) {\n var attribution = this._attributions[i];\n var text = attribution.attribution;\n if (!newAttributions.match(text) && bounds.intersects(attribution.bounds) && zoom >= attribution.minZoom && zoom <= attribution.maxZoom) {\n newAttributions += (', ' + text);\n }\n }\n newAttributions = newAttributions.substr(2);\n var attributionElement = this._map.attributionControl._container.querySelector('.esri-attributions');\n\n attributionElement.innerHTML = newAttributions;\n attributionElement.style.maxWidth = (this._map.getSize().x * 0.65) + 'px';\n\n this.fire('attributionupdated', {\n attribution: newAttributions\n });\n }\n }\n});\n\nexport function basemapLayer (key, options) {\n return new BasemapLayer(key, options);\n}\n\nexport default basemapLayer;\n","import L from 'leaflet';\nimport {warn, cleanUrl} from '../Util';\nimport mapService from '../Services/MapService';\n\nexport var TiledMapLayer = L.TileLayer.extend({\n options: {\n zoomOffsetAllowance: 0.1,\n correctZoomLevels: true\n },\n\n statics: {\n MercatorZoomLevels: {\n '0': 156543.03392799999,\n '1': 78271.516963999893,\n '2': 39135.758482000099,\n '3': 19567.879240999901,\n '4': 9783.9396204999593,\n '5': 4891.9698102499797,\n '6': 2445.9849051249898,\n '7': 1222.9924525624899,\n '8': 611.49622628138002,\n '9': 305.74811314055802,\n '10': 152.874056570411,\n '11': 76.437028285073197,\n '12': 38.218514142536598,\n '13': 19.109257071268299,\n '14': 9.5546285356341496,\n '15': 4.7773142679493699,\n '16': 2.38865713397468,\n '17': 1.1943285668550501,\n '18': 0.59716428355981699,\n '19': 0.29858214164761698,\n '20': 0.14929107082381,\n '21': 0.07464553541191,\n '22': 0.0373227677059525,\n '23': 0.0186613838529763\n }\n },\n\n initialize: function (options) {\n options.url = cleanUrl(options.url);\n options = L.Util.setOptions(this, options);\n\n // set the urls\n this.tileUrl = options.url + 'tile/{z}/{y}/{x}';\n this.service = mapService(options);\n this.service.addEventParent(this);\n\n // if this is looking at the AGO tiles subdomain insert the subdomain placeholder\n if (this.tileUrl.match('://tiles.arcgisonline.com')) {\n this.tileUrl = this.tileUrl.replace('://tiles.arcgisonline.com', '://tiles{s}.arcgisonline.com');\n options.subdomains = ['1', '2', '3', '4'];\n }\n\n if (this.options.token) {\n this.tileUrl += ('?token=' + this.options.token);\n }\n\n // init layer by calling TileLayers initialize method\n L.TileLayer.prototype.initialize.call(this, this.tileUrl, options);\n },\n\n getTileUrl: function (tilePoint) {\n return L.Util.template(this.tileUrl, L.extend({\n s: this._getSubdomain(tilePoint),\n z: this._lodMap[tilePoint.z] || tilePoint.z, // try lod map first, then just defualt to zoom level\n x: tilePoint.x,\n y: tilePoint.y\n }, this.options));\n },\n\n onAdd: function (map) {\n if (!this._lodMap && this.options.correctZoomLevels) {\n this._lodMap = {}; // make sure we always have an lod map even if its empty\n this.metadata(function (error, metadata) {\n if (!error) {\n var sr = metadata.spatialReference.latestWkid || metadata.spatialReference.wkid;\n\n if (sr === 102100 || sr === 3857) {\n // create the zoom level data\n var arcgisLODs = metadata.tileInfo.lods;\n var correctResolutions = TiledMapLayer.MercatorZoomLevels;\n\n for (var i = 0; i < arcgisLODs.length; i++) {\n var arcgisLOD = arcgisLODs[i];\n for (var ci in correctResolutions) {\n var correctRes = correctResolutions[ci];\n\n if (this._withinPercentage(arcgisLOD.resolution, correctRes, this.options.zoomOffsetAllowance)) {\n this._lodMap[ci] = arcgisLOD.level;\n break;\n }\n }\n }\n } else {\n warn('L.esri.TiledMapLayer is using a non-mercator spatial reference. Support may be available through Proj4Leaflet http://esri.github.io/esri-leaflet/examples/non-mercator-projection.html');\n }\n }\n\n L.TileLayer.prototype.onAdd.call(this, map);\n }, this);\n } else {\n L.TileLayer.prototype.onAdd.call(this, map);\n }\n },\n\n metadata: function (callback, context) {\n this.service.metadata(callback, context);\n return this;\n },\n\n identify: function () {\n return this.service.identify();\n },\n\n find: function () {\n return this.service.find();\n },\n\n query: function () {\n return this.service.query();\n },\n\n authenticate: function (token) {\n var tokenQs = '?token=' + token;\n this.tileUrl = (this.options.token) ? this.tileUrl.replace(/\\?token=(.+)/g, tokenQs) : this.tileUrl + tokenQs;\n this.options.token = token;\n this.service.authenticate(token);\n return this;\n },\n\n _withinPercentage: function (a, b, percentage) {\n var diff = Math.abs((a / b) - 1);\n return diff < percentage;\n }\n});\n\nexport function tiledMapLayer (url, options) {\n return new TiledMapLayer(url, options);\n}\n\nexport default tiledMapLayer;\n","import L from 'leaflet';\nimport {cors} from '../Support';\n\nexport var RasterLayer = L.Layer.extend({\n\n options: {\n opacity: 1,\n position: 'front',\n f: 'image',\n useCors: cors,\n attribution: null,\n interactive: false,\n alt: ''\n },\n\n onAdd: function (map) {\n this._update = L.Util.throttle(this._update, this.options.updateInterval, this);\n\n if (map.options.crs && map.options.crs.code) {\n var sr = map.options.crs.code.split(':')[1];\n this.options.bboxSR = sr;\n this.options.imageSR = sr;\n }\n\n map.on('moveend', this._update, this);\n\n // if we had an image loaded and it matches the\n // current bounds show the image otherwise remove it\n if (this._currentImage && this._currentImage._bounds.equals(this._map.getBounds())) {\n map.addLayer(this._currentImage);\n } else if (this._currentImage) {\n this._map.removeLayer(this._currentImage);\n this._currentImage = null;\n }\n\n this._update();\n\n if (this._popup) {\n this._map.on('click', this._getPopupData, this);\n this._map.on('dblclick', this._resetPopupState, this);\n }\n },\n\n onRemove: function (map) {\n if (this._currentImage) {\n this._map.removeLayer(this._currentImage);\n }\n\n if (this._popup) {\n this._map.off('click', this._getPopupData, this);\n this._map.off('dblclick', this._resetPopupState, this);\n }\n\n this._map.off('moveend', this._update, this);\n },\n\n getEvents: function () {\n return {\n moveend: this._update\n };\n },\n\n bindPopup: function (fn, popupOptions) {\n this._shouldRenderPopup = false;\n this._lastClick = false;\n this._popup = L.popup(popupOptions);\n this._popupFunction = fn;\n if (this._map) {\n this._map.on('click', this._getPopupData, this);\n this._map.on('dblclick', this._resetPopupState, this);\n }\n return this;\n },\n\n unbindPopup: function () {\n if (this._map) {\n this._map.closePopup(this._popup);\n this._map.off('click', this._getPopupData, this);\n this._map.off('dblclick', this._resetPopupState, this);\n }\n this._popup = false;\n return this;\n },\n\n bringToFront: function () {\n this.options.position = 'front';\n if (this._currentImage) {\n this._currentImage.bringToFront();\n }\n return this;\n },\n\n bringToBack: function () {\n this.options.position = 'back';\n if (this._currentImage) {\n this._currentImage.bringToBack();\n }\n return this;\n },\n\n getAttribution: function () {\n return this.options.attribution;\n },\n\n getOpacity: function () {\n return this.options.opacity;\n },\n\n setOpacity: function (opacity) {\n this.options.opacity = opacity;\n this._currentImage.setOpacity(opacity);\n return this;\n },\n\n getTimeRange: function () {\n return [this.options.from, this.options.to];\n },\n\n setTimeRange: function (from, to) {\n this.options.from = from;\n this.options.to = to;\n this._update();\n return this;\n },\n\n metadata: function (callback, context) {\n this.service.metadata(callback, context);\n return this;\n },\n\n authenticate: function (token) {\n this.service.authenticate(token);\n return this;\n },\n\n _renderImage: function (url, bounds) {\n if (this._map) {\n // create a new image overlay and add it to the map\n // to start loading the image\n // opacity is 0 while the image is loading\n var image = L.imageOverlay(url, bounds, {\n opacity: 0,\n crossOrigin: this.options.useCors,\n alt: this.options.alt,\n pane: this.options.pane || this.getPane(),\n interactive: this.options.interactive\n }).addTo(this._map);\n\n // once the image loads\n image.once('load', function (e) {\n if (this._map) {\n var newImage = e.target;\n var oldImage = this._currentImage;\n\n // if the bounds of this image matches the bounds that\n // _renderImage was called with and we have a map with the same bounds\n // hide the old image if there is one and set the opacity\n // of the new image otherwise remove the new image\n if (newImage._bounds.equals(bounds) && newImage._bounds.equals(this._map.getBounds())) {\n this._currentImage = newImage;\n\n if (this.options.position === 'front') {\n this.bringToFront();\n } else {\n this.bringToBack();\n }\n\n if (this._map && this._currentImage._map) {\n this._currentImage.setOpacity(this.options.opacity);\n } else {\n this._currentImage._map.removeLayer(this._currentImage);\n }\n\n if (oldImage && this._map) {\n this._map.removeLayer(oldImage);\n }\n\n if (oldImage && oldImage._map) {\n oldImage._map.removeLayer(oldImage);\n }\n } else {\n this._map.removeLayer(newImage);\n }\n }\n\n this.fire('load', {\n bounds: bounds\n });\n }, this);\n\n this.fire('loading', {\n bounds: bounds\n });\n }\n },\n\n _update: function () {\n if (!this._map) {\n return;\n }\n\n var zoom = this._map.getZoom();\n var bounds = this._map.getBounds();\n\n if (this._animatingZoom) {\n return;\n }\n\n if (this._map._panTransition && this._map._panTransition._inProgress) {\n return;\n }\n\n if (zoom > this.options.maxZoom || zoom < this.options.minZoom) {\n return;\n }\n var params = this._buildExportParams();\n\n this._requestExport(params, bounds);\n },\n\n _renderPopup: function (latlng, error, results, response) {\n latlng = L.latLng(latlng);\n if (this._shouldRenderPopup && this._lastClick.equals(latlng)) {\n // add the popup to the map where the mouse was clicked at\n var content = this._popupFunction(error, results, response);\n if (content) {\n this._popup.setLatLng(latlng).setContent(content).openOn(this._map);\n }\n }\n },\n\n _resetPopupState: function (e) {\n this._shouldRenderPopup = false;\n this._lastClick = e.latlng;\n }\n});\n","import L from 'leaflet';\nimport { RasterLayer } from './RasterLayer';\nimport { cleanUrl } from '../Util';\nimport imageService from '../Services/ImageService';\n\nexport var ImageMapLayer = RasterLayer.extend({\n\n options: {\n updateInterval: 150,\n format: 'jpgpng',\n transparent: true,\n f: 'json'\n },\n\n query: function () {\n return this.service.query();\n },\n\n identify: function () {\n return this.service.identify();\n },\n\n initialize: function (options) {\n options.url = cleanUrl(options.url);\n this.service = imageService(options);\n this.service.addEventParent(this);\n\n L.Util.setOptions(this, options);\n },\n\n setPixelType: function (pixelType) {\n this.options.pixelType = pixelType;\n this._update();\n return this;\n },\n\n getPixelType: function () {\n return this.options.pixelType;\n },\n\n setBandIds: function (bandIds) {\n if (L.Util.isArray(bandIds)) {\n this.options.bandIds = bandIds.join(',');\n } else {\n this.options.bandIds = bandIds.toString();\n }\n this._update();\n return this;\n },\n\n getBandIds: function () {\n return this.options.bandIds;\n },\n\n setNoData: function (noData, noDataInterpretation) {\n if (L.Util.isArray(noData)) {\n this.options.noData = noData.join(',');\n } else {\n this.options.noData = noData.toString();\n }\n if (noDataInterpretation) {\n this.options.noDataInterpretation = noDataInterpretation;\n }\n this._update();\n return this;\n },\n\n getNoData: function () {\n return this.options.noData;\n },\n\n getNoDataInterpretation: function () {\n return this.options.noDataInterpretation;\n },\n\n setRenderingRule: function (renderingRule) {\n this.options.renderingRule = renderingRule;\n this._update();\n },\n\n getRenderingRule: function () {\n return this.options.renderingRule;\n },\n\n setMosaicRule: function (mosaicRule) {\n this.options.mosaicRule = mosaicRule;\n this._update();\n },\n\n getMosaicRule: function () {\n return this.options.mosaicRule;\n },\n\n _getPopupData: function (e) {\n var callback = L.Util.bind(function (error, results, response) {\n if (error) { return; } // we really can't do anything here but authenticate or requesterror will fire\n setTimeout(L.Util.bind(function () {\n this._renderPopup(e.latlng, error, results, response);\n }, this), 300);\n }, this);\n\n var identifyRequest = this.identify().at(e.latlng);\n\n // set mosaic rule for identify task if it is set for layer\n if (this.options.mosaicRule) {\n identifyRequest.setMosaicRule(this.options.mosaicRule);\n // @TODO: force return catalog items too?\n }\n\n // @TODO: set rendering rule? Not sure,\n // sometimes you want raw pixel values\n // if (this.options.renderingRule) {\n // identifyRequest.setRenderingRule(this.options.renderingRule);\n // }\n\n identifyRequest.run(callback);\n\n // set the flags to show the popup\n this._shouldRenderPopup = true;\n this._lastClick = e.latlng;\n },\n\n _buildExportParams: function () {\n var bounds = this._map.getBounds();\n var size = this._map.getSize();\n var ne = this._map.options.crs.project(bounds._northEast);\n var sw = this._map.options.crs.project(bounds._southWest);\n\n var params = {\n bbox: [sw.x, sw.y, ne.x, ne.y].join(','),\n size: size.x + ',' + size.y,\n format: this.options.format,\n transparent: this.options.transparent,\n bboxSR: this.options.bboxSR,\n imageSR: this.options.imageSR\n };\n\n if (this.options.from && this.options.to) {\n params.time = this.options.from.valueOf() + ',' + this.options.to.valueOf();\n }\n\n if (this.options.pixelType) {\n params.pixelType = this.options.pixelType;\n }\n\n if (this.options.interpolation) {\n params.interpolation = this.options.interpolation;\n }\n\n if (this.options.compressionQuality) {\n params.compressionQuality = this.options.compressionQuality;\n }\n\n if (this.options.bandIds) {\n params.bandIds = this.options.bandIds;\n }\n\n if (this.options.noData) {\n params.noData = this.options.noData;\n }\n\n if (this.options.noDataInterpretation) {\n params.noDataInterpretation = this.options.noDataInterpretation;\n }\n\n if (this.service.options.token) {\n params.token = this.service.options.token;\n }\n\n if (this.options.renderingRule) {\n params.renderingRule = JSON.stringify(this.options.renderingRule);\n }\n\n if (this.options.mosaicRule) {\n params.mosaicRule = JSON.stringify(this.options.mosaicRule);\n }\n\n return params;\n },\n\n _requestExport: function (params, bounds) {\n if (this.options.f === 'json') {\n this.service.get('exportImage', params, function (error, response) {\n if (error) { return; } // we really can't do anything here but authenticate or requesterror will fire\n this._renderImage(response.href, bounds);\n }, this);\n } else {\n params.f = 'image';\n this._renderImage(this.options.url + 'exportImage' + L.Util.getParamString(params), bounds);\n }\n }\n});\n\nexport function imageMapLayer (url, options) {\n return new ImageMapLayer(url, options);\n}\n\nexport default imageMapLayer;\n","import L from 'leaflet';\nimport { RasterLayer } from './RasterLayer';\nimport { cleanUrl } from '../Util';\nimport mapService from '../Services/MapService';\n\nexport var DynamicMapLayer = RasterLayer.extend({\n\n options: {\n updateInterval: 150,\n layers: false,\n layerDefs: false,\n timeOptions: false,\n format: 'png24',\n transparent: true,\n f: 'json'\n },\n\n initialize: function (options) {\n options.url = cleanUrl(options.url);\n this.service = mapService(options);\n this.service.addEventParent(this);\n\n if ((options.proxy || options.token) && options.f !== 'json') {\n options.f = 'json';\n }\n L.Util.setOptions(this, options);\n },\n\n getDynamicLayers: function () {\n return this.options.dynamicLayers;\n },\n\n setDynamicLayers: function (dynamicLayers) {\n this.options.dynamicLayers = dynamicLayers;\n this._update();\n return this;\n },\n\n getLayers: function () {\n return this.options.layers;\n },\n\n setLayers: function (layers) {\n this.options.layers = layers;\n this._update();\n return this;\n },\n\n getLayerDefs: function () {\n return this.options.layerDefs;\n },\n\n setLayerDefs: function (layerDefs) {\n this.options.layerDefs = layerDefs;\n this._update();\n return this;\n },\n\n getTimeOptions: function () {\n return this.options.timeOptions;\n },\n\n setTimeOptions: function (timeOptions) {\n this.options.timeOptions = timeOptions;\n this._update();\n return this;\n },\n\n query: function () {\n return this.service.query();\n },\n\n identify: function () {\n return this.service.identify();\n },\n\n find: function () {\n return this.service.find();\n },\n\n _getPopupData: function (e) {\n var callback = L.Util.bind(function (error, featureCollection, response) {\n if (error) { return; } // we really can't do anything here but authenticate or requesterror will fire\n setTimeout(L.Util.bind(function () {\n this._renderPopup(e.latlng, error, featureCollection, response);\n }, this), 300);\n }, this);\n\n var identifyRequest = this.identify().on(this._map).at(e.latlng);\n\n if (this.options.layers) {\n identifyRequest.layers('visible:' + this.options.layers.join(','));\n } else {\n identifyRequest.layers('visible');\n }\n\n identifyRequest.run(callback);\n\n // set the flags to show the popup\n this._shouldRenderPopup = true;\n this._lastClick = e.latlng;\n },\n\n _buildExportParams: function () {\n var bounds = this._map.getBounds();\n var size = this._map.getSize();\n var ne = this._map.options.crs.project(bounds._northEast);\n var sw = this._map.options.crs.project(bounds._southWest);\n\n // ensure that we don't ask ArcGIS Server for a taller image than we have actual map displaying\n var top = this._map.latLngToLayerPoint(bounds._northEast);\n var bottom = this._map.latLngToLayerPoint(bounds._southWest);\n\n if (top.y > 0 || bottom.y < size.y) {\n size.y = bottom.y - top.y;\n }\n\n var params = {\n bbox: [sw.x, sw.y, ne.x, ne.y].join(','),\n size: size.x + ',' + size.y,\n dpi: 96,\n format: this.options.format,\n transparent: this.options.transparent,\n bboxSR: this.options.bboxSR,\n imageSR: this.options.imageSR\n };\n\n if (this.options.dynamicLayers) {\n params.dynamicLayers = this.options.dynamicLayers;\n }\n\n if (this.options.layers) {\n params.layers = 'show:' + this.options.layers.join(',');\n }\n\n if (this.options.layerDefs) {\n params.layerDefs = JSON.stringify(this.options.layerDefs);\n }\n\n if (this.options.timeOptions) {\n params.timeOptions = JSON.stringify(this.options.timeOptions);\n }\n\n if (this.options.from && this.options.to) {\n params.time = this.options.from.valueOf() + ',' + this.options.to.valueOf();\n }\n\n if (this.service.options.token) {\n params.token = this.service.options.token;\n }\n\n return params;\n },\n\n _requestExport: function (params, bounds) {\n if (this.options.f === 'json') {\n this.service.get('export', params, function (error, response) {\n if (error) { return; } // we really can't do anything here but authenticate or requesterror will fire\n this._renderImage(response.href, bounds);\n }, this);\n } else {\n params.f = 'image';\n this._renderImage(this.options.url + 'export' + L.Util.getParamString(params), bounds);\n }\n }\n});\n\nexport function dynamicMapLayer (url, options) {\n return new DynamicMapLayer(url, options);\n}\n\nexport default dynamicMapLayer;\n","import L from 'leaflet';\n\nexport var FeatureGrid = L.Layer.extend({\n\n options: {\n cellSize: 512,\n updateInterval: 150\n },\n\n initialize: function (options) {\n options = L.setOptions(this, options);\n this._zooming = false;\n },\n\n onAdd: function (map) {\n this._map = map;\n this._update = L.Util.throttle(this._update, this.options.updateInterval, this);\n this._reset();\n this._update();\n },\n\n onRemove: function () {\n this._map.removeEventListener(this.getEvents(), this);\n this._removeCells();\n },\n\n getEvents: function () {\n var events = {\n moveend: this._update,\n zoomstart: this._zoomstart,\n zoomend: this._reset\n };\n\n return events;\n },\n\n addTo: function (map) {\n map.addLayer(this);\n return this;\n },\n\n removeFrom: function (map) {\n map.removeLayer(this);\n return this;\n },\n\n _zoomstart: function () {\n this._zooming = true;\n },\n\n _reset: function () {\n this._removeCells();\n\n this._cells = {};\n this._activeCells = {};\n this._cellsToLoad = 0;\n this._cellsTotal = 0;\n this._cellNumBounds = this._getCellNumBounds();\n\n this._resetWrap();\n this._zooming = false;\n },\n\n _resetWrap: function () {\n var map = this._map;\n var crs = map.options.crs;\n\n if (crs.infinite) { return; }\n\n var cellSize = this._getCellSize();\n\n if (crs.wrapLng) {\n this._wrapLng = [\n Math.floor(map.project([0, crs.wrapLng[0]]).x / cellSize),\n Math.ceil(map.project([0, crs.wrapLng[1]]).x / cellSize)\n ];\n }\n\n if (crs.wrapLat) {\n this._wrapLat = [\n Math.floor(map.project([crs.wrapLat[0], 0]).y / cellSize),\n Math.ceil(map.project([crs.wrapLat[1], 0]).y / cellSize)\n ];\n }\n },\n\n _getCellSize: function () {\n return this.options.cellSize;\n },\n\n _update: function () {\n if (!this._map) { return; }\n\n var bounds = this._map.getPixelBounds();\n var zoom = this._map.getZoom();\n var cellSize = this._getCellSize();\n\n if (zoom > this.options.maxZoom ||\n zoom < this.options.minZoom) { return; }\n\n // cell coordinates range for the current view\n var cellBounds = L.bounds(\n bounds.min.divideBy(cellSize).floor(),\n bounds.max.divideBy(cellSize).floor());\n\n this._removeOtherCells(cellBounds);\n this._addCells(cellBounds);\n },\n\n _addCells: function (bounds) {\n var queue = [];\n var center = bounds.getCenter();\n var zoom = this._map.getZoom();\n\n var j, i, coords;\n // create a queue of coordinates to load cells from\n for (j = bounds.min.y; j <= bounds.max.y; j++) {\n for (i = bounds.min.x; i <= bounds.max.x; i++) {\n coords = L.point(i, j);\n coords.z = zoom;\n\n if (this._isValidCell(coords)) {\n queue.push(coords);\n }\n }\n }\n\n var cellsToLoad = queue.length;\n\n if (cellsToLoad === 0) { return; }\n\n this._cellsToLoad += cellsToLoad;\n this._cellsTotal += cellsToLoad;\n\n // sort cell queue to load cells in order of their distance to center\n queue.sort(function (a, b) {\n return a.distanceTo(center) - b.distanceTo(center);\n });\n\n for (i = 0; i < cellsToLoad; i++) {\n this._addCell(queue[i]);\n }\n },\n\n _isValidCell: function (coords) {\n var crs = this._map.options.crs;\n\n if (!crs.infinite) {\n // don't load cell if it's out of bounds and not wrapped\n var bounds = this._cellNumBounds;\n if (\n (!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||\n (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))\n ) {\n return false;\n }\n }\n\n if (!this.options.bounds) {\n return true;\n }\n\n // don't load cell if it doesn't intersect the bounds in options\n var cellBounds = this._cellCoordsToBounds(coords);\n return L.latLngBounds(this.options.bounds).intersects(cellBounds);\n },\n\n // converts cell coordinates to its geographical bounds\n _cellCoordsToBounds: function (coords) {\n var map = this._map;\n var cellSize = this.options.cellSize;\n var nwPoint = coords.multiplyBy(cellSize);\n var sePoint = nwPoint.add([cellSize, cellSize]);\n var nw = map.wrapLatLng(map.unproject(nwPoint, coords.z));\n var se = map.wrapLatLng(map.unproject(sePoint, coords.z));\n\n return L.latLngBounds(nw, se);\n },\n\n // converts cell coordinates to key for the cell cache\n _cellCoordsToKey: function (coords) {\n return coords.x + ':' + coords.y;\n },\n\n // converts cell cache key to coordiantes\n _keyToCellCoords: function (key) {\n var kArr = key.split(':');\n var x = parseInt(kArr[0], 10);\n var y = parseInt(kArr[1], 10);\n\n return L.point(x, y);\n },\n\n // remove any present cells that are off the specified bounds\n _removeOtherCells: function (bounds) {\n for (var key in this._cells) {\n if (!bounds.contains(this._keyToCellCoords(key))) {\n this._removeCell(key);\n }\n }\n },\n\n _removeCell: function (key) {\n var cell = this._activeCells[key];\n\n if (cell) {\n delete this._activeCells[key];\n\n if (this.cellLeave) {\n this.cellLeave(cell.bounds, cell.coords);\n }\n\n this.fire('cellleave', {\n bounds: cell.bounds,\n coords: cell.coords\n });\n }\n },\n\n _removeCells: function () {\n for (var key in this._cells) {\n var bounds = this._cells[key].bounds;\n var coords = this._cells[key].coords;\n\n if (this.cellLeave) {\n this.cellLeave(bounds, coords);\n }\n\n this.fire('cellleave', {\n bounds: bounds,\n coords: coords\n });\n }\n },\n\n _addCell: function (coords) {\n // wrap cell coords if necessary (depending on CRS)\n this._wrapCoords(coords);\n\n // generate the cell key\n var key = this._cellCoordsToKey(coords);\n\n // get the cell from the cache\n var cell = this._cells[key];\n // if this cell should be shown as isnt active yet (enter)\n\n if (cell && !this._activeCells[key]) {\n if (this.cellEnter) {\n this.cellEnter(cell.bounds, coords);\n }\n\n this.fire('cellenter', {\n bounds: cell.bounds,\n coords: coords\n });\n\n this._activeCells[key] = cell;\n }\n\n // if we dont have this cell in the cache yet (create)\n if (!cell) {\n cell = {\n coords: coords,\n bounds: this._cellCoordsToBounds(coords)\n };\n\n this._cells[key] = cell;\n this._activeCells[key] = cell;\n\n if (this.createCell) {\n this.createCell(cell.bounds, coords);\n }\n\n this.fire('cellcreate', {\n bounds: cell.bounds,\n coords: coords\n });\n }\n },\n\n _wrapCoords: function (coords) {\n coords.x = this._wrapLng ? L.Util.wrapNum(coords.x, this._wrapLng) : coords.x;\n coords.y = this._wrapLat ? L.Util.wrapNum(coords.y, this._wrapLat) : coords.y;\n },\n\n // get the global cell coordinates range for the current zoom\n _getCellNumBounds: function () {\n var bounds = this._map.getPixelWorldBounds();\n var size = this._getCellSize();\n\n return bounds ? L.bounds(\n bounds.min.divideBy(size).floor(),\n bounds.max.divideBy(size).ceil().subtract([1, 1])) : null;\n }\n});\n","import L from 'leaflet';\nimport { FeatureGrid } from './FeatureGrid';\nimport featureLayerService from '../../Services/FeatureLayerService';\nimport { cleanUrl, warn } from '../../Util';\n\nexport var FeatureManager = FeatureGrid.extend({\n /**\n * Options\n */\n\n options: {\n attribution: null,\n where: '1=1',\n fields: ['*'],\n from: false,\n to: false,\n timeField: false,\n timeFilterMode: 'server',\n simplifyFactor: 0,\n precision: 6\n },\n\n /**\n * Constructor\n */\n\n initialize: function (options) {\n FeatureGrid.prototype.initialize.call(this, options);\n\n options.url = cleanUrl(options.url);\n options = L.setOptions(this, options);\n\n this.service = featureLayerService(options);\n this.service.addEventParent(this);\n\n // use case insensitive regex to look for common fieldnames used for indexing\n if (this.options.fields[0] !== '*') {\n var oidCheck = false;\n for (var i = 0; i < this.options.fields.length; i++) {\n if (this.options.fields[i].match(/^(OBJECTID|FID|OID|ID)$/i)) {\n oidCheck = true;\n }\n }\n if (oidCheck === false) {\n warn('no known esriFieldTypeOID field detected in fields Array. Please add an attribute field containing unique IDs to ensure the layer can be drawn correctly.');\n }\n }\n\n if (this.options.timeField.start && this.options.timeField.end) {\n this._startTimeIndex = new BinarySearchIndex();\n this._endTimeIndex = new BinarySearchIndex();\n } else if (this.options.timeField) {\n this._timeIndex = new BinarySearchIndex();\n }\n\n this._cache = {};\n this._currentSnapshot = []; // cache of what layers should be active\n this._activeRequests = 0;\n },\n\n /**\n * Layer Interface\n */\n\n onAdd: function (map) {\n return FeatureGrid.prototype.onAdd.call(this, map);\n },\n\n onRemove: function (map) {\n return FeatureGrid.prototype.onRemove.call(this, map);\n },\n\n getAttribution: function () {\n return this.options.attribution;\n },\n\n /**\n * Feature Managment\n */\n\n createCell: function (bounds, coords) {\n this._requestFeatures(bounds, coords);\n },\n\n _requestFeatures: function (bounds, coords, callback) {\n this._activeRequests++;\n\n // our first active request fires loading\n if (this._activeRequests === 1) {\n this.fire('loading', {\n bounds: bounds\n }, true);\n }\n\n return this._buildQuery(bounds).run(function (error, featureCollection, response) {\n if (response && response.exceededTransferLimit) {\n this.fire('drawlimitexceeded');\n }\n\n // no error, features\n if (!error && featureCollection && featureCollection.features.length) {\n // schedule adding features until the next animation frame\n L.Util.requestAnimFrame(L.Util.bind(function () {\n this._addFeatures(featureCollection.features, coords);\n this._postProcessFeatures(bounds);\n }, this));\n }\n\n // no error, no features\n if (!error && featureCollection && !featureCollection.features.length) {\n this._postProcessFeatures(bounds);\n }\n\n if (callback) {\n callback.call(this, error, featureCollection);\n }\n }, this);\n },\n\n _postProcessFeatures: function (bounds) {\n // deincriment the request counter now that we have processed features\n this._activeRequests--;\n\n // if there are no more active requests fire a load event for this view\n if (this._activeRequests <= 0) {\n this.fire('load', {\n bounds: bounds\n });\n }\n },\n\n _cacheKey: function (coords) {\n return coords.z + ':' + coords.x + ':' + coords.y;\n },\n\n _addFeatures: function (features, coords) {\n var key = this._cacheKey(coords);\n this._cache[key] = this._cache[key] || [];\n\n for (var i = features.length - 1; i >= 0; i--) {\n var id = features[i].id;\n this._currentSnapshot.push(id);\n this._cache[key].push(id);\n }\n\n if (this.options.timeField) {\n this._buildTimeIndexes(features);\n }\n\n var zoom = this._map.getZoom();\n\n if (zoom > this.options.maxZoom ||\n zoom < this.options.minZoom) { return; }\n\n this.createLayers(features);\n },\n\n _buildQuery: function (bounds) {\n var query = this.service.query()\n .intersects(bounds)\n .where(this.options.where)\n .fields(this.options.fields)\n .precision(this.options.precision);\n\n if (this.options.simplifyFactor) {\n query.simplify(this._map, this.options.simplifyFactor);\n }\n\n if (this.options.timeFilterMode === 'server' && this.options.from && this.options.to) {\n query.between(this.options.from, this.options.to);\n }\n\n return query;\n },\n\n /**\n * Where Methods\n */\n\n setWhere: function (where, callback, context) {\n this.options.where = (where && where.length) ? where : '1=1';\n\n var oldSnapshot = [];\n var newSnapshot = [];\n var pendingRequests = 0;\n var requestError = null;\n var requestCallback = L.Util.bind(function (error, featureCollection) {\n if (error) {\n requestError = error;\n }\n\n if (featureCollection) {\n for (var i = featureCollection.features.length - 1; i >= 0; i--) {\n newSnapshot.push(featureCollection.features[i].id);\n }\n }\n\n pendingRequests--;\n\n if (pendingRequests <= 0) {\n this._currentSnapshot = newSnapshot;\n // schedule adding features until the next animation frame\n L.Util.requestAnimFrame(L.Util.bind(function () {\n this.removeLayers(oldSnapshot);\n this.addLayers(newSnapshot);\n if (callback) {\n callback.call(context, requestError);\n }\n }, this));\n }\n }, this);\n\n for (var i = this._currentSnapshot.length - 1; i >= 0; i--) {\n oldSnapshot.push(this._currentSnapshot[i]);\n }\n\n for (var key in this._activeCells) {\n pendingRequests++;\n var coords = this._keyToCellCoords(key);\n var bounds = this._cellCoordsToBounds(coords);\n this._requestFeatures(bounds, key, requestCallback);\n }\n\n return this;\n },\n\n getWhere: function () {\n return this.options.where;\n },\n\n /**\n * Time Range Methods\n */\n\n getTimeRange: function () {\n return [this.options.from, this.options.to];\n },\n\n setTimeRange: function (from, to, callback, context) {\n var oldFrom = this.options.from;\n var oldTo = this.options.to;\n var pendingRequests = 0;\n var requestError = null;\n var requestCallback = L.Util.bind(function (error) {\n if (error) {\n requestError = error;\n }\n this._filterExistingFeatures(oldFrom, oldTo, from, to);\n\n pendingRequests--;\n\n if (callback && pendingRequests <= 0) {\n callback.call(context, requestError);\n }\n }, this);\n\n this.options.from = from;\n this.options.to = to;\n\n this._filterExistingFeatures(oldFrom, oldTo, from, to);\n\n if (this.options.timeFilterMode === 'server') {\n for (var key in this._activeCells) {\n pendingRequests++;\n var coords = this._keyToCellCoords(key);\n var bounds = this._cellCoordsToBounds(coords);\n this._requestFeatures(bounds, key, requestCallback);\n }\n }\n\n return this;\n },\n\n refresh: function () {\n for (var key in this._activeCells) {\n var coords = this._keyToCellCoords(key);\n var bounds = this._cellCoordsToBounds(coords);\n this._requestFeatures(bounds, key);\n }\n\n if (this.redraw) {\n this.once('load', function () {\n this.eachFeature(function (layer) {\n this._redraw(layer.feature.id);\n }, this);\n }, this);\n }\n },\n\n _filterExistingFeatures: function (oldFrom, oldTo, newFrom, newTo) {\n var layersToRemove = (oldFrom && oldTo) ? this._getFeaturesInTimeRange(oldFrom, oldTo) : this._currentSnapshot;\n var layersToAdd = this._getFeaturesInTimeRange(newFrom, newTo);\n\n if (layersToAdd.indexOf) {\n for (var i = 0; i < layersToAdd.length; i++) {\n var shouldRemoveLayer = layersToRemove.indexOf(layersToAdd[i]);\n if (shouldRemoveLayer >= 0) {\n layersToRemove.splice(shouldRemoveLayer, 1);\n }\n }\n }\n\n // schedule adding features until the next animation frame\n L.Util.requestAnimFrame(L.Util.bind(function () {\n this.removeLayers(layersToRemove);\n this.addLayers(layersToAdd);\n }, this));\n },\n\n _getFeaturesInTimeRange: function (start, end) {\n var ids = [];\n var search;\n\n if (this.options.timeField.start && this.options.timeField.end) {\n var startTimes = this._startTimeIndex.between(start, end);\n var endTimes = this._endTimeIndex.between(start, end);\n search = startTimes.concat(endTimes);\n } else {\n search = this._timeIndex.between(start, end);\n }\n\n for (var i = search.length - 1; i >= 0; i--) {\n ids.push(search[i].id);\n }\n\n return ids;\n },\n\n _buildTimeIndexes: function (geojson) {\n var i;\n var feature;\n if (this.options.timeField.start && this.options.timeField.end) {\n var startTimeEntries = [];\n var endTimeEntries = [];\n for (i = geojson.length - 1; i >= 0; i--) {\n feature = geojson[i];\n startTimeEntries.push({\n id: feature.id,\n value: new Date(feature.properties[this.options.timeField.start])\n });\n endTimeEntries.push({\n id: feature.id,\n value: new Date(feature.properties[this.options.timeField.end])\n });\n }\n this._startTimeIndex.bulkAdd(startTimeEntries);\n this._endTimeIndex.bulkAdd(endTimeEntries);\n } else {\n var timeEntries = [];\n for (i = geojson.length - 1; i >= 0; i--) {\n feature = geojson[i];\n timeEntries.push({\n id: feature.id,\n value: new Date(feature.properties[this.options.timeField])\n });\n }\n\n this._timeIndex.bulkAdd(timeEntries);\n }\n },\n\n _featureWithinTimeRange: function (feature) {\n if (!this.options.from || !this.options.to) {\n return true;\n }\n\n var from = +this.options.from.valueOf();\n var to = +this.options.to.valueOf();\n\n if (typeof this.options.timeField === 'string') {\n var date = +feature.properties[this.options.timeField];\n return (date >= from) && (date <= to);\n }\n\n if (this.options.timeField.start && this.options.timeField.end) {\n var startDate = +feature.properties[this.options.timeField.start];\n var endDate = +feature.properties[this.options.timeField.end];\n return ((startDate >= from) && (startDate <= to)) || ((endDate >= from) && (endDate <= to));\n }\n },\n\n /**\n * Service Methods\n */\n\n authenticate: function (token) {\n this.service.authenticate(token);\n return this;\n },\n\n metadata: function (callback, context) {\n this.service.metadata(callback, context);\n return this;\n },\n\n query: function () {\n return this.service.query();\n },\n\n _getMetadata: function (callback) {\n if (this._metadata) {\n var error;\n callback(error, this._metadata);\n } else {\n this.metadata(L.Util.bind(function (error, response) {\n this._metadata = response;\n callback(error, this._metadata);\n }, this));\n }\n },\n\n addFeature: function (feature, callback, context) {\n this._getMetadata(L.Util.bind(function (error, metadata) {\n if (error) {\n if (callback) { callback.call(this, error, null); }\n return;\n }\n\n this.service.addFeature(feature, L.Util.bind(function (error, response) {\n if (!error) {\n // assign ID from result to appropriate objectid field from service metadata\n feature.properties[metadata.objectIdField] = response.objectId;\n\n // we also need to update the geojson id for createLayers() to function\n feature.id = response.objectId;\n this.createLayers([feature]);\n }\n\n if (callback) {\n callback.call(context, error, response);\n }\n }, this));\n }, this));\n },\n\n updateFeature: function (feature, callback, context) {\n this.service.updateFeature(feature, function (error, response) {\n if (!error) {\n this.removeLayers([feature.id], true);\n this.createLayers([feature]);\n }\n\n if (callback) {\n callback.call(context, error, response);\n }\n }, this);\n },\n\n deleteFeature: function (id, callback, context) {\n this.service.deleteFeature(id, function (error, response) {\n if (!error && response.objectId) {\n this.removeLayers([response.objectId], true);\n }\n if (callback) {\n callback.call(context, error, response);\n }\n }, this);\n },\n\n deleteFeatures: function (ids, callback, context) {\n return this.service.deleteFeatures(ids, function (error, response) {\n if (!error && response.length > 0) {\n for (var i = 0; i < response.length; i++) {\n this.removeLayers([response[i].objectId], true);\n }\n }\n if (callback) {\n callback.call(context, error, response);\n }\n }, this);\n }\n});\n\n/**\n * Temporal Binary Search Index\n */\n\nfunction BinarySearchIndex (values) {\n this.values = values || [];\n}\n\nBinarySearchIndex.prototype._query = function (query) {\n var minIndex = 0;\n var maxIndex = this.values.length - 1;\n var currentIndex;\n var currentElement;\n\n while (minIndex <= maxIndex) {\n currentIndex = (minIndex + maxIndex) / 2 | 0;\n currentElement = this.values[Math.round(currentIndex)];\n if (+currentElement.value < +query) {\n minIndex = currentIndex + 1;\n } else if (+currentElement.value > +query) {\n maxIndex = currentIndex - 1;\n } else {\n return currentIndex;\n }\n }\n\n return ~maxIndex;\n};\n\nBinarySearchIndex.prototype.sort = function () {\n this.values.sort(function (a, b) {\n return +b.value - +a.value;\n }).reverse();\n this.dirty = false;\n};\n\nBinarySearchIndex.prototype.between = function (start, end) {\n if (this.dirty) {\n this.sort();\n }\n\n var startIndex = this._query(start);\n var endIndex = this._query(end);\n\n if (startIndex === 0 && endIndex === 0) {\n return [];\n }\n\n startIndex = Math.abs(startIndex);\n endIndex = (endIndex < 0) ? Math.abs(endIndex) : endIndex + 1;\n\n return this.values.slice(startIndex, endIndex);\n};\n\nBinarySearchIndex.prototype.bulkAdd = function (items) {\n this.dirty = true;\n this.values = this.values.concat(items);\n};\n","import L from 'leaflet';\nimport { FeatureManager } from './FeatureManager';\n\nexport var FeatureLayer = FeatureManager.extend({\n\n options: {\n cacheLayers: true\n },\n\n /**\n * Constructor\n */\n initialize: function (options) {\n FeatureManager.prototype.initialize.call(this, options);\n this._originalStyle = this.options.style;\n this._layers = {};\n },\n\n /**\n * Layer Interface\n */\n\n onRemove: function (map) {\n for (var i in this._layers) {\n map.removeLayer(this._layers[i]);\n }\n\n return FeatureManager.prototype.onRemove.call(this, map);\n },\n\n createNewLayer: function (geojson) {\n var layer = L.GeoJSON.geometryToLayer(geojson, this.options);\n layer.defaultOptions = layer.options;\n return layer;\n },\n\n _updateLayer: function (layer, geojson) {\n // convert the geojson coordinates into a Leaflet LatLng array/nested arrays\n // pass it to setLatLngs to update layer geometries\n var latlngs = [];\n var coordsToLatLng = this.options.coordsToLatLng || L.GeoJSON.coordsToLatLng;\n\n // copy new attributes, if present\n if (geojson.properties) {\n layer.feature.properties = geojson.properties;\n }\n\n switch (geojson.geometry.type) {\n case 'Point':\n latlngs = L.GeoJSON.coordsToLatLng(geojson.geometry.coordinates);\n layer.setLatLng(latlngs);\n break;\n case 'LineString':\n latlngs = L.GeoJSON.coordsToLatLngs(geojson.geometry.coordinates, 0, coordsToLatLng);\n layer.setLatLngs(latlngs);\n break;\n case 'MultiLineString':\n latlngs = L.GeoJSON.coordsToLatLngs(geojson.geometry.coordinates, 1, coordsToLatLng);\n layer.setLatLngs(latlngs);\n break;\n case 'Polygon':\n latlngs = L.GeoJSON.coordsToLatLngs(geojson.geometry.coordinates, 1, coordsToLatLng);\n layer.setLatLngs(latlngs);\n break;\n case 'MultiPolygon':\n latlngs = L.GeoJSON.coordsToLatLngs(geojson.geometry.coordinates, 2, coordsToLatLng);\n layer.setLatLngs(latlngs);\n break;\n }\n },\n\n /**\n * Feature Management Methods\n */\n\n createLayers: function (features) {\n for (var i = features.length - 1; i >= 0; i--) {\n var geojson = features[i];\n\n var layer = this._layers[geojson.id];\n var newLayer;\n\n if (layer && !this._map.hasLayer(layer)) {\n this._map.addLayer(layer);\n }\n\n // update geometry if neccessary\n if (layer && this.options.simplifyFactor > 0 && (layer.setLatLngs || layer.setLatLng)) {\n this._updateLayer(layer, geojson);\n }\n\n if (!layer) {\n newLayer = this.createNewLayer(geojson);\n newLayer.feature = geojson;\n\n // bubble events from individual layers to the feature layer\n newLayer.addEventParent(this);\n\n if (this.options.onEachFeature) {\n this.options.onEachFeature(newLayer.feature, newLayer);\n }\n\n // cache the layer\n this._layers[newLayer.feature.id] = newLayer;\n\n // style the layer\n this.setFeatureStyle(newLayer.feature.id, this.options.style);\n\n this.fire('createfeature', {\n feature: newLayer.feature\n }, true);\n\n // add the layer if it is within the time bounds or our layer is not time enabled\n if (!this.options.timeField || (this.options.timeField && this._featureWithinTimeRange(geojson))) {\n this._map.addLayer(newLayer);\n }\n }\n }\n },\n\n addLayers: function (ids) {\n for (var i = ids.length - 1; i >= 0; i--) {\n var layer = this._layers[ids[i]];\n if (layer) {\n this.fire('addfeature', {\n feature: layer.feature\n }, true);\n this._map.addLayer(layer);\n }\n }\n },\n\n removeLayers: function (ids, permanent) {\n for (var i = ids.length - 1; i >= 0; i--) {\n var id = ids[i];\n var layer = this._layers[id];\n if (layer) {\n this.fire('removefeature', {\n feature: layer.feature,\n permanent: permanent\n }, true);\n this._map.removeLayer(layer);\n }\n if (layer && permanent) {\n delete this._layers[id];\n }\n }\n },\n\n cellEnter: function (bounds, coords) {\n console.log(this._zooming);\n if (!this._zooming) {\n L.Util.requestAnimFrame(L.Util.bind(function () {\n var cacheKey = this._cacheKey(coords);\n var cellKey = this._cellCoordsToKey(coords);\n var layers = this._cache[cacheKey];\n if (this._activeCells[cellKey] && layers) {\n this.addLayers(layers);\n }\n }, this));\n }\n },\n\n cellLeave: function (bounds, coords) {\n console.log(this._zooming);\n if (!this._zooming) {\n L.Util.requestAnimFrame(L.Util.bind(function () {\n var cacheKey = this._cacheKey(coords);\n var cellKey = this._cellCoordsToKey(coords);\n var layers = this._cache[cacheKey];\n var mapBounds = this._map.getBounds();\n if (!this._activeCells[cellKey] && layers) {\n var removable = true;\n\n for (var i = 0; i < layers.length; i++) {\n var layer = this._layers[layers[i]];\n if (layer && layer.getBounds && mapBounds.intersects(layer.getBounds())) {\n removable = false;\n }\n }\n\n if (removable) {\n this.removeLayers(layers, !this.options.cacheLayers);\n }\n\n if (!this.options.cacheLayers && removable) {\n delete this._cache[cacheKey];\n delete this._cells[cellKey];\n delete this._activeCells[cellKey];\n }\n }\n }, this));\n }\n },\n\n /**\n * Styling Methods\n */\n\n resetStyle: function () {\n this.options.style = this._originalStyle;\n this.eachFeature(function (layer) {\n this.resetFeatureStyle(layer.feature.id);\n }, this);\n return this;\n },\n\n setStyle: function (style) {\n this.options.style = style;\n this.eachFeature(function (layer) {\n this.setFeatureStyle(layer.feature.id, style);\n }, this);\n return this;\n },\n\n resetFeatureStyle: function (id) {\n var layer = this._layers[id];\n var style = this._originalStyle || L.Path.prototype.options;\n if (layer) {\n L.Util.extend(layer.options, layer.defaultOptions);\n this.setFeatureStyle(id, style);\n }\n return this;\n },\n\n setFeatureStyle: function (id, style) {\n var layer = this._layers[id];\n if (typeof style === 'function') {\n style = style(layer.feature);\n }\n if (layer.setStyle) {\n layer.setStyle(style);\n }\n return this;\n },\n\n /**\n * Utility Methods\n */\n\n eachFeature: function (fn, context) {\n for (var i in this._layers) {\n fn.call(context, this._layers[i]);\n }\n return this;\n },\n\n getFeature: function (id) {\n return this._layers[id];\n },\n\n bringToBack: function () {\n this.eachFeature(function (layer) {\n if (layer.bringToBack) {\n layer.bringToBack();\n }\n });\n },\n\n bringToFront: function () {\n this.eachFeature(function (layer) {\n if (layer.bringToFront) {\n layer.bringToFront();\n }\n });\n },\n\n redraw: function (id) {\n if (id) {\n this._redraw(id);\n }\n return this;\n },\n\n _redraw: function (id) {\n var layer = this._layers[id];\n var geojson = layer.feature;\n\n // if this looks like a marker\n if (layer && layer.setIcon && this.options.pointToLayer) {\n // update custom symbology, if necessary\n if (this.options.pointToLayer) {\n var getIcon = this.options.pointToLayer(geojson, L.latLng(geojson.geometry.coordinates[1], geojson.geometry.coordinates[0]));\n var updatedIcon = getIcon.options.icon;\n layer.setIcon(updatedIcon);\n }\n }\n\n // looks like a vector marker (circleMarker)\n if (layer && layer.setStyle && this.options.pointToLayer) {\n var getStyle = this.options.pointToLayer(geojson, L.latLng(geojson.geometry.coordinates[1], geojson.geometry.coordinates[0]));\n var updatedStyle = getStyle.options;\n this.setFeatureStyle(geojson.id, updatedStyle);\n }\n\n // looks like a path (polygon/polyline)\n if (layer && layer.setStyle && this.options.style) {\n this.resetStyle(geojson.id);\n }\n }\n});\n\nexport function featureLayer (options) {\n return new FeatureLayer(options);\n}\n\nexport default featureLayer;\n","export var VERSION = '2.0.0-beta.4';\n\n// import base\nexport { Support } from './Support';\nexport { Util } from './Util';\nexport { get, post, request } from './Request';\n\n// export tasks\nexport { Task, task } from './Tasks/Task';\nexport { Query, query } from './Tasks/Query';\nexport { Find, find } from './Tasks/Find';\nexport { Identify, identify } from './Tasks/Identify';\nexport { IdentifyFeatures, identifyFeatures } from './Tasks/IdentifyFeatures';\nexport { IdentifyImage, identifyImage } from './Tasks/IdentifyImage';\n\n// export services\nexport { Service, service } from './Services/Service';\nexport { MapService, mapService } from './Services/MapService';\nexport { ImageService, imageService } from './Services/ImageService';\nexport { FeatureLayerService, featureLayerService } from './Services/FeatureLayerService';\n\n// export layers\nexport { BasemapLayer, basemapLayer } from './Layers/BasemapLayer';\nexport { TiledMapLayer, tiledMapLayer } from './Layers/TiledMapLayer';\nexport { RasterLayer } from './Layers/RasterLayer';\nexport { ImageMapLayer, imageMapLayer } from './Layers/ImageMapLayer';\nexport { DynamicMapLayer, dynamicMapLayer } from './Layers/DynamicMapLayer';\nexport { FeatureGrid } from './Layers/FeatureLayer/FeatureGrid';\nexport { FeatureManager } from './Layers/FeatureLayer/FeatureManager';\nexport { FeatureLayer, featureLayer } from './Layers/FeatureLayer/FeatureLayer';\n"]} \ No newline at end of file