The first step is to include arcgislink.js
or arcgislink_packed.js
in your document header, after the Google Maps API has loaded. You can use the
hosted release version if you do not want to download the script.
<script src="/path/to/extargis_packed.js" type="text/javascript"></script>
In the simplest form, you can add an ArcGIS map with the add-on method
GMap2.addArcGISMap(url) to
the core GMap2
class.
You can optionally use a callback function to do extra things with the result.
function init(){ var map = new GMap2(document.getElementById("map")); map.setCenter(new GLatLng(45.5, -122.7), 14); var base = 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services'; var tiled = base + '/Portland/Portland_ESRI_LandBase_AGO/MapServer'; var dyna = base + '/Demographics/ESRI_Census_USA/MapServer'; map.addArcGISMap(tiled); map.addArcGISMap(dyna); }
ArcGIS Server provides map services to generate map images on the fly,
also known as "dynamic map". Dynamic services are implemented as
ArcGISMapOverlay,
a subclass of GOverlay
, and hence can be
added with map.addOverlay()
. This class is similar
to the GGoundOverlay
in the core API, as it essentially draws a
single image over the map. Any map service can be added as an ArcGISMapOverlay,
regardless of whether it's tiled or not.
function init(){ var map = new GMap2(document.getElementById("map")); map.setCenter(new GLatLng(40, -100), 4); var url = 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer'; map.addOverlay(new ArcGISMapOverlay(url)); }
If a map service is pre-rendered as tiles, the application
will have a better response time if added as
ArcGISTileLayer.
If the map service is tiled using the same tiling scheme as Google Maps
(WebMercator in ArcGIS), it can be added as a map type directly.
The following example constructs a new GMap2
with only an ArcGIS map type and no Google map types.
function init(){ var url = 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Portland/ESRI_LandBase_WebMercator/MapServer'; var agsType = new ArcGISMapType(url); var map = new GMap2(document.getElementById("map"),{mapTypes:[agsType]}); map.setCenter(new GLatLng(45.5, -122.7), 15); }
If the map service is not cached using the same tiling scheme as Google maps,
then it can not be loaded directly because the system does not know how to
request the tiles. It must instead be added asynchronously,
after it's received information about the scheme.
The following example adds a map service created in
ArcGIS online scheme after the "load"
event:
function init(){ var map = new GMap2(document.getElementById("map")); map.setCenter(new GLatLng(45.5, -122.7), 15); var url = 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Portland/Portland_ESRI_LandBase_AGO/MapServer'; var agsType = new ArcGISMapType(url); GEvent.addListener(agsType,'load', function(){ map.addMapType(agsType); map.setMapType(agsType); }); }
If you do not want to wait until the 'load' event, and you already know how the tiles are built, you can pass an ArcGISProjection to the constructor of ArcGISTileLayer. Note, you still must make sure the ArcGISSpatialReference is in the system already. This is a useful technique when you have many tiled maps a nd they are all using the same tile scheme.
var tileInfo = { "rows": 512, "cols": 512, "dpi": 96, "origin": { "x": -180, "y": 90 }, "spatialReference": { "wkid": 4326 }, "lods": [ {"level" : 0, "resolution" : 0.351562499999999, "scale" : 147748799.285417}, {"level" : 1, "resolution" : 0.17578125, "scale" : 73874399.6427087}, {"level" : 2, "resolution" : 0.0878906250000001, "scale" : 36937199.8213544}, {"level" : 3, "resolution" : 0.0439453125, "scale" : 18468599.9106772}, {"level" : 4, "resolution" : 0.02197265625, "scale" : 9234299.95533859}, {"level" : 5, "resolution" : 0.010986328125, "scale" : 4617149.97766929}, {"level" : 6, "resolution" : 0.0054931640625, "scale" : 2308574.98883465}, {"level" : 7, "resolution" : 0.00274658203124999, "scale" : 1154287.49441732}, {"level" : 8, "resolution" : 0.001373291015625, "scale" : 577143.747208662}, {"level" : 9, "resolution" : 0.0006866455078125, "scale" : 288571.873604331}, {"level" : 10, "resolution" : 0.000343322753906249, "scale" : 144285.936802165}, {"level" : 11, "resolution" : 0.000171661376953125, "scale" : 72142.9684010827}, {"level" : 12, "resolution" : 8.58306884765626E-05, "scale" : 36071.4842005414}, {"level" : 13, "resolution" : 4.29153442382813E-05, "scale" : 18035.7421002707}, {"level" : 14, "resolution" : 2.14576721191406E-05, "scale" : 9017.87105013534}, {"level" : 15, "resolution" : 1.07288360595703E-05, "scale" : 4508.93552506767} ]}; var url = 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Portland/Portland_ESRI_LandBase_AGO/MapServer'; var agsType = new ArcGISMapType(url,{projection: new ArcGISProjection(tileInfo)}); // note no load event listener. var map = new GMap2(document.getElementById("map"), { mapTypes: [agsType]}); map.setCenter(new GLatLng(45.5, -122.7), 15);
Tile layers can also be added as
ArcGISTileLayerOverlay,
a subclass of GTileLayerOverlay
in the core API.
If the tile is created with "WebMercator", it can be added on top of
the default Google map types. If it is not in "WebMercator", it can only be
added as an ArcGISTileLayerOverlay
on top of map types with
the same tiling scheme. In this case, it's best to initialize the map
with only the ArcGIS map types.
var url = 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Portland/ESRI_LandBase_WebMercator/MapServer'; var tileoverlay = new ArcGISTileLayerOverlay(new ArcGISTileLayer(url,{opacity:0.4})); map.addOverlay(tileoverlay);
View example (Mercator) | Packed (Mercator) | View example (Load) | Packed (Load) | Back to top
In many situations, it's ideal to combined a tiled map as a background, with a dynamic layer on top of it. The following example loads the default Google map types (Normal, Satellite, Hybrid), then a tiled map service built on WGS84(4326) with 521x512 pixel tile size, then a tiled map service built on Web-Mercator(102113) with 256x256 pixel tile size, and finally, a dynamic map service whose own spatial reference system is NAD83 GCS(4269) on top of all. As map type changes, the dynamic map will refresh itself to match the underlying spatial reference.
function init(){ // first init a normal map var map = new GMap2(document.getElementById("map")); map.setCenter(new GLatLng(45.5, -122.7), 15); // now add ArcGIS maps var baseUrl = 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services'; var wgs84Url = baseUrl + '/Portland/Portland_ESRI_LandBase_AGO/MapServer'; var webMercatorUrl = baseUrl + '/Portland/ESRI_LandBase_WebMercator/MapServer'; var dynaUrl = baseUrl + '/Demographics/ESRI_Census_USA/MapServer'; var wgs84 = new ArcGISMapType(wgs84Url); GEvent.addListener(wgs84,'load',function(){map.addMapType(wgs84);}); var webMercator = new ArcGISMapType(webMercatorUrl); GEvent.addListener(webMercator,'load',function(){ map.addMapType(webMercator); }); var dynaOverlay = new ArcGISMapOverlay(dynaUrl); map.addOverlay(dynaOverlay); }
ArcGISOnline is an online geo-spatial service provided by ESRI, Inc. All the tiled map services are based on WGS84 Spatial Reference System with tile size of 512x512.
Check Licensing before you use these services.
The following example creates and loads one ArcGIS base map type, sets that as the maptype for the map, then adds additional services using the GMap2.addArcGISMap(url)
function init(){ var base = 'http://server.arcgisonline.com/ArcGIS/rest/services'; var type = new ArcGISMapType(base + '/ESRI_StreetMap_World_2D/MapServer'); GEvent.addListener(type,'load', function(){ var map = new GMap2(document.getElementById("map"), {mapTypes: [type]}); map.setCenter(new GLatLng(40,-95), 4); // now add more services map.addArcGISMap(base + "/ESRI_Imagery_World_2D/MapServer"); map.addArcGISMap(base + "/ESRI_ShadedRelief_World_2D/MapServer"); map.addArcGISMap(base + "/I3_Imagery_Prime_World_2D/MapServer"); map.addArcGISMap(base + "/NGS_Topo_US_2D/MapServer"); map.addArcGISMap(base + "/NPS_Physical_World_2D/MapServer"); map.addArcGISMap(base + "/Demographics/ESRI_00-08PopGrwth_US_2D/MapServer"); map.addArcGISMap(base + "/Demographics/ESRI_Diversity_US_2D/MapServer"); map.addArcGISMap(base + "/Demographics/ESRI_MedianIncome_US_2D/MapServer"); map.addArcGISMap(base + "/Specialty/EVC_Topo_World_2D/MapServer"); }); }
ArcGIS Map Services contains a backend geospatial database that can answer spatial queries about geographic features located at a certain location. The simplest way to use this feature is by calling the add-on method GMap2.enableArcGISClick(). That will cause an infowindow to pop up after the user clicks the map.
function init(){ var url = 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Portland/Portland_ESRI_LandBase_AGO/MapServer'; var agsType = new ArcGISMapType([new ArcGISTileLayer(url)]); GEvent.addListener(agsType,'load', function(){ var map = new GMap2(document.getElementById("map"), {mapTypes: [agsType]}); map.setCenter(new GLatLng(45.5, -122.7), 15); // simply enable MapClick map.enableArcGISClick(); //... }); }
The library supports virtually all types of ArcGIS Server map service, with rare exceptions:
function addMap(url){ map.addArcGISMap(url, function(o){ if (o instanceof ArcGISMapType) { map.setMapType(o); map.setBounds(o.getTileLayers()[0].getInitialBounds()); } else if (o instanceof ArcGISMapOverlay) { map.setBounds(o.getInitialBounds()); o.setOpacity(document.getElementById("opacity").value); map.zoomIn(); } updateTOC(); }); }
Using namespaced libraries can avoid potential class conflicts.
The Google AJAX API loader originally introduced the namespace "google.maps
" and
since v2.86 you can also use that namespace with
the normal loader.
This library can be used in the namespace "google.maputils.arcgis
".
To use any of the classes from the library with that namespace,
the basic rule is to replace the "ArcGIS" prefix with the namespace.
// first init a normal map var map = new google.maps.Map2(document.getElementById("map")); map.setCenter(new google.maps.LatLng(45.5, -122.7), 15); map.addControl(new google.maps.MapTypeControl()); map.addControl(new google.maps.LargeMapControl()); map.addControl(new google.maps.ScaleControl()); var wgs84Url = baseUrl + '/Portland/Portland_ESRI_LandBase_AGO/MapServer'; var wgs84 = new google.maputils.arcgis.MapType(wgs84Url); google.maps.Event.addListener(wgs84,'load',function(s){ map.addMapType(wgs84); }); var dynaOverlay = new google.maputils.arcgis.MapOverlay(dynaUrl); map.addOverlay(dynaOverlay);
Virtually all GIS data collected by State or Local Governments in Unite States are stored in one of the State Plane Coordinate Systems. In real-world operations, map services (both tiled and dynamic) are published using the native coordinate system the data uses.
When adding an ArcGISTileLayer from a tiled map service, the spatial reference of the map service must be loaded into the internal SpatialReferences collections before it can be used. The library has 3 built-in spatial references: NAD GCS (4269), WGS84 (4326) and "Web Mercator" (102113). It also supports any spatial references based on Lambert Conformal Conic Projection or Transverse Mercator Projection. They can be added either with one line of code by its Well_known_text format or constructed directly with correct parameters. Please use the WKT value from ESRI documentation. Spatial references based on other projections can be used by implementing the ArcGISSpatialReference interface
ArcGISSpatialReferences.addSpatialReference(2264, 'PROJCS["NAD_1983_StatePlane_....UNIT["Foot_US",0.3048006096012192]]'); function init(){ var url = 'http://maps.ci.charlotte.nc.us/ArcGIS/rest/services/GET/BaseMap/MapServer'; var agsLayer = new ArcGISTileLayer(url); var agsType = new ArcGISMapType([agsLayer]); GEvent.addListener(agsType, 'load', function(){ var map = new GMap2(document.getElementById("map"), { mapTypes: [agsType]}); //this is a add-on method to use in place of GMap2.setCenter() without knowning the actual latlng; map.setBounds(agsLayer.getInitialBounds()); }); }
Some browsers has default limitations on how many concurrent connections can
be made to a give host based on URL name, so that when many tiles are being
downloaded, some of them have to wait in the queue. One workaround for this
issue is to create multiple DNS names with numbers as suffix.
There is an option in the ArcGISTileLayer
constructor to allow you
to specify an 'host pattern', for example, "mt[4].google.com" means
to rotate hosts across mt0.google.com, mt1.google.com, mt2.google.com,
mt3.google.com (4 hosts)
function init(){ var url = 'http://maps.ci.charlotte.nc.us/ArcGIS/rest/services/GET/BaseMap/MapServer'; var agsLayer = new ArcGISTileLayer(url, { hosts: "mt[4].ci.charlotte.nc.us" }); var agsType = new ArcGISMapType([agsLayer]); GEvent.addListener(agsType, 'load', function(){ var map = new GMap2(document.getElementById("map"), { mapTypes: [agsType] }); }
This library also include a simple class FlatSpatialReference. Strictly speaking, this is not a true spatial reference, but can be used as a workaround without implementing a real projection class. This class assumes latitude and longitude values are increased evenly. The following example works as if the spatial reference 4326 is not added as an instance of LambertConformalConic. You can add tiled maps service without actually doing anything with ArcGISSpatialReference.
var url = 'http://.../MapServer'; var agsLayer = new ArcGISTileLayer(url); var agsType = new ArcGISMapType([agsLayer]); GEvent.addListener(agsType, 'load', function(){ var map = new GMap2(document.getElementById("map"), { mapTypes: [agsType] }); map.setBounds(agsLayer.getInitialBounds()); });
You can draw a subset of a feature layer inside a dynamic map service
(ArcGISMapOverlay) by setting a
SQL expression as its definition
property.
You will have to use the ArcGISLayer
class in the REST part of the libarary.
var service = dynaLayer.getMapService(); service.getLayer("Coarse Counties").definition="STATE_NAME='Kansas' and POP2007 > 25000"; service.getLayer("Detailed Counties").definition="STATE_NAME='Kansas' and POP2007 > 25000"; service.getLayer("states").definition="STATE_NAME='Kansas'";
You can control visibility of a layer inside a dynamic map service
(ArcGISMapOverlay)
by setting its visible
property. There are some limitations on
the scale threshold on layers in the REST API.
You will have to load the layer resource individually if you
want to do a TOC that handles scales.
var service = dynaLayer.getMapService(); service.getLayer("states").visible = true; dynaLayer.refresh();
A dynamic map image may take some time to render.
When a intensive server request like map rendering is running in the
background, it's helpful to let the user know about it.
You can display some sort of hourglass animation image or simply a
message such as "loading...".
You can accomplish this by handling different "***start
"
and "***end
" events, or use ArcGISUtil#jsonpstart
and ArcGISUtil#jsonpend
event to monitor all server requests
GEvent.addListener(dynaLayer, 'drawstart', function(){ document.getElementById('drawing').style.visibility = 'visible'; }); GEvent.addListener(dynaLayer, 'drawend', function(){ document.getElementById('drawing').style.visibility = 'hidden'; }); GEvent.addListener(ArcGISUtil, 'jsonpstart', function(){ document.getElementById('working').innerHTML = "working...."; }); GEvent.addListener(ArcGISUtil, 'jsonpend', function(){ document.getElementById('working').innerHTML = ''; });
You can query a layer with a SQL statement and spatial filters. The result can be displayed as overlays, like markers or polys. You can also attach mouse events to those overlays to make the application more interactive.
function initFunctionality(){ var layer = dyna.getMapService().getLayer(3); var params = { returnGeometry: true, where: "STATE_NAME = 'South Carolina'", outFields: ["NAME", "POP2000", "POP2007", "POP00_SQMI", "POP07_SQMI"], outSR: 4326 }; layer.query(params, processResultSet); } function processResultSet(rs){ var fs = rs.features; for (var i = 0, c = fs.length; i < c; i++) { var ovs = createGPolys(fs[i], rs.spatialReference); for (var j = 0; j < ovs.length; j++) { gmap.addOverlay(ovs[j]); } } } function createGPolys(feat, sr){ var ovs = ArcGISUtil.fromFeatureToOverlays(feat,sr, style); var ov = ovs[j]; GEvent.addListener(ov, 'mouseover', function(){ for (var i = 0, ic = ovs.length; i < ic; i++) { ovs[i].setStrokeStyle({color: hStyle.outlineColor,weight: hStyle.outlineWeight}); ovs[i].setFillStyle({ color: hStyle.fillColor,opacity: hStyle.fillOpacity}); } var latlng = ov.getBounds().getCenter(); gmap.openInfoWindowHtml(latlng, html); }); return ovs; }
Find is an operation supported by a map service to query features based on a single String. It will search the attribute columns of the map layers inside the map service and return matching features.
var params = { returnGeometry: true, searchText: q, contains:!exact, layers:['Cities','Rivers','States'], searchFields:["CITY_NAME","NAME","SYSTEM","STATE_ABBR","STATE_NAME"], sr: 4326 }; service.find(params, processFindResults); function processFindResults(rs) { var fs = rs.results; for (var i = 0, c = fs.length; i < c; i++) { processFindResult(fs[i]); } } function processFindResult(res) { var ovs = ArcGISUtil.fromFeatureToOverlays(res); gmap.addOverlays(ovs); }
You can get the coordinates of a location by passing itss address
or other descriptions. You can use
ArcGISGeocodeService's
findAddressCandidates
method. You can dynamically construct
an input form based on the meta data of the GeocodeService such as
'addressFields' property.
var inputs = { }; var fields=geocoder.addressFields; for (var i=0; i < fields.length; i++){ inputs[fields[i].name]=document.getElementById(fields[i].name).value; } geocoder.findAddressCandidates({inputs: inputs}, function(results) { var markers = []; if (results.candidates) { for (var i = 0, c = results.candidates.length; i < c; i++) { var marker=createMarker(results.candidates[i]); map.addOverlay(marker); markers.push(marker); if (i == 0) { map.setCenter(marker.getLatLng(),15); GEvent.trigger(marker, 'click'); } } } });
You can also find the address of a given geographic coordinates
(reverse geocode), using
GeocodeService's
reverseGeocode
method.
function reverseGeocode(latlng){ if (latlng){ var point = ArcGISUtil.fromLatLngToPoint(latlng); var params = { location: point, distance: 100 }; geocoder.reverseGeocode(params, function(result) { if (result.address) { var html = ''; var attrs = result.address; for (var x in attrs) { if (attrs.hasOwnProperty(x)) { html += x +': '+ attrs[x] + '<br/>'; } } var loc=ArcGISUtil.fromPointToLatLng(result.location); marker.setLatLng(loc); marker.openInfoWindowHtml(html); } else { alert('can not find address for point:'+latlng.toString()); } }); } }