Tag Archives: Leaflet

ESRI Geocoding Widget Using the REST API and JavaScript

20 Oct
Geocoder Widget with the result dislpayed.

Geocoder Widget with the result dislpayed.

I need to geocode in my web apps and I decided to try writing my own geocoder using my ArcServer geocoding service and the ESRI REST API. I have made two version: one that only requires including the css and js files and one that requires a line of code to initialize. The second one allows me to switch the geocoder I want to use. The geocoder requres a Leaflet.js map – only to add the marker. If you want to use a different mapping library, just change the code in the JavaScript file after the line if(http.readyState == 4 && http.status == 200) {. The http.responseText will contain a JSON string of the results. Do whatever you want with them.

To use the first one, the HTML looks as follows:
<html>
<head><title>DMDVIEW REST Services</title>
<link rel=”stylesheet” href=”geocoder.css” />
<link rel=”stylesheet” href=”http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css&#8221; />
<style>
html, body, #map {
padding: 0;
margin: 0;
height: 100%;
}

</style>
</head>
<body>
<div id=”map”></div>
<script src=”http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js”></script&gt;
<script src=”geocoderMap.js”></script>
<script>

var map = L.map(‘map’, {
center: [35.10418, -106.62987],
zoom: 9
});

L.tileLayer(‘http://{s}.tile.osm.org/{z}/{x}/{y}.png’).addTo(map);

</script>
</body>
</html>

 

The CSS:

#AddressSearchBox{
background-color: rgba(255, 255, 255, 0.5);
border: 1px solid #000;
-moz-border-radius: 15px;
border-radius: 15px;
height:40px;
width:350px;
padding-top:10px;
padding-left:5px;
position: absolute;
left: 40%;
top: 0px;
z-index: 100000;
}
#first{
text-align: center;
}
#second{
text-align: left;
margin: 0 auto;
width: 50%;
}

 

The JavaScript file does all the work. It creates the nested <div>’s to the HTML, formats them and then lets you enter an address and either puch the button or press enter. The result is a point on the map at the first result with the popup open, displaying the result name. Just add your ArcServer geocoding service URL and you can include a geocoder widget with 2 includes.

Here is the JavaScript:

(function() {

var b = document.getElementsByTagName(‘body’)[0];
var first = document.createElement(‘div’);
var second = document.createElement(‘div’);
var addressSearchBox = document.createElement(‘div’);

first.id = “first”;
second.id = “second”;
addressSearchBox.id = “AddressSearchBox”;

b.appendChild(first);
first.appendChild(second);
second.appendChild(addressSearchBox);

var text = “<center><b>Address:</b><input type=’text’ id=’addr’ name=’to’><button id=’search’ >Search</button><center>”
addressSearchBox.innerHTML=text;

var textbox = document.getElementById(“addr”);
var button = document.getElementById(“search”);

function GeocodeAddress(){
addressFromAddressSearchBox=document.getElementById(“addr”).value;
var params = “Street=”+addressFromAddressSearchBox+”&f=json&outSR=4326”;
var url = “http://YourArcServerName/ArcGIS/rest/services/YourGeolocatorServiceName/GeocodeServer/findAddressCandidates&#8221;;
if (window.XMLHttpRequest)
{
http=new XMLHttpRequest();
}
else
{
http=new ActiveXObject(“Msxml2.XMLHTTP”);
}

http.open(“POST”, url, true);
http.setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);
http.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
var thexy= JSON.parse(http.responseText);
var yousearchedfor = L.marker([thexy.candidates[0].location.y,thexy.candidates[0].location.x]).addTo(map).bindPopup(‘<h3>’+addressFromAddressSearchBox+'</h3>’).openPopup();
map.setView([thexy.candidates[0].location.y,thexy.candidates[0].location.x],18);
}//end if
}
http.send(params);
}
button.onclick=function geocode(){
GeocodeAddress();

}

textbox.onkeypress=function handleKeyPress(e){
var key=e.keyCode || e.which;
if (key==13){
GeocodeAddress();

}}

}
());

 

I mentioned that I had a second example that allowed you to switch the service at run time, or just use the default. This example requires a line of code in your HTML:

new geocoder();

or

new geocoder(“http://the service you want to use.com/arcgis/services/rest/….”);

 

the CSS is the same. The only change is in the JavaScript. Here is the code:

( function( window, undefined, url ) {

function geocoder(url) {
this.url=url;
url = typeof url !== ‘undefined’ ? url : “http://YourArcServer/ArcGIS/rest/services/YourServiceName/GeocodeServer/findAddressCandidates&#8221;;
var b = document.getElementsByTagName(‘body’)[0];
var first = document.createElement(‘div’);
var second = document.createElement(‘div’);
var addressSearchBox = document.createElement(‘div’);

first.id = “first”;
second.id = “second”;
addressSearchBox.id = “AddressSearchBox”;

b.appendChild(first);
first.appendChild(second);
second.appendChild(addressSearchBox);

var text = “<center><b>Address:</b><input type=’text’ id=’addr’ name=’to’><button id=’search’ >Search</button><center>”
addressSearchBox.innerHTML=text;

var textbox = document.getElementById(“addr”);
var button = document.getElementById(“search”);
function GeocodeAddress(){
addressFromAddressSearchBox=document.getElementById(“addr”).value;
var params = “Street=”+addressFromAddressSearchBox+”&f=json&outSR=4326”;

if (window.XMLHttpRequest)
{
http=new XMLHttpRequest();
}
else
{
http=new ActiveXObject(“Msxml2.XMLHTTP”);
}

http.open(“POST”, url, true);
http.setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);
http.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
var thexy= JSON.parse(http.responseText);
var yousearchedfor = L.marker([thexy.candidates[0].location.y,thexy.candidates[0].location.x]).addTo(map).bindPopup(‘<h3>’+addressFromAddressSearchBox+'</h3>’).openPopup();
map.setView([thexy.candidates[0].location.y,thexy.candidates[0].location.x],18);
}//end if
}
http.send(params);
}

button.onclick=function geocode(){
GeocodeAddress();
}

textbox.onkeypress=function handleKeyPress(e){
var key=e.keyCode || e.which;
if (key==13){
GeocodeAddress();
}}

}

window.geocoder = geocoder;

} )( window );

Leaflet.js Interactivity II: Allow Users to Add Points

29 Jun

In Part I, I showed how to use buttons to add and remove layers, and how to capture popup text and display it in a <DIV> element. In this post I will show how to allow users to create their own points with popups. Here is an image of the page with no input yet.

First, I created a blank map with just a Cloudemade Tile.

Second, I created a <DIV> to hold my form:

<div>
LAT:<input type=”text” id=”lat”>
LONG:<input type=”text” id=”long”>
POPUP:<input type=”text” id=”popuptext” value=”POPUPTEXT”>
<button onclick=”createPoint()”>Create Point</button>
</div>

Lastly, I create the function in the form:

function createPoint()
{
var lat = document.getElementById(‘lat’).value;
var long = document.getElementById(‘long’).value;
var pop = document.getElementById(‘popuptext’).value;
var latint = parseInt(lat);
var longint = parseInt(long);
var mora = new L.LatLng(latint, longint),
MSD = new L.Marker(mora);
map.addLayer(MSD);
MSD.bindPopup(pop);
}

To see it working go to EducationalFacilityPlanning.com/UserAddPoints.html

Try typing in 35, -106 for Lat and Long

This needs more work, like a function to allow the user to click on the map and get a long,lat pair:

map.on(‘click’, onMapClick);
var popup = new L.Popup();

function onMapClick(e) {
var latlngStr = ‘(‘ + e.latlng.lat.toFixed(3) + ‘, ‘ + e.latlng.lng.toFixed(3) + ‘)’;

popup.setLatLng(e.latlng);
popup.setContent(“You clicked the map at ” + latlngStr);

map.openPopup(popup);
}

But, more importantly, a function to save the points so the user can recreate their map.

 

Happy Hacking

 

Query Multiple WMS Layers in Leaflet.js

16 Apr

In an earlier post I imported GeoJSON in to Leaflet. One of the reasons I did this was to be able to assign a popup to each layer – which is something I could not do with WMS. I was finally able to make a popup for each of my WMS layers. Here is how I did it.

I have 2 layers -psfa:SchoolPoints and psfa:CityOfAztec – on my GeoServer at: http://localhost:8080/geoserver/psfa/wms.

I made a Leaflet map importing these two layers.

Image

The cloudmade layer that is added is my base map. With the layers showing up correctly, I found the website of Bryan McBride. I copied his WMS example and then modified it for my server and layers.

Image

var URL = the location of my GeoServer.

GetFeatureInfo&LAYERS=my layers seperated by a ,

Lastly, do the same for &QUERYLAYERS= seperaed by a ,

This is how I was able to get my map to popup the correct info when I clicked on any WMS layer in my map. Next, I need to clean up the popup box to fit my data without scrolling. It looks like if you want to change the formatting of the popup internals, GeoServer has some WMS templates. I am not that far yet.

Final Map

 

Leaflet.js and GeoJSON

12 Apr

Recently, I have been playing with a few different open source GIS tools and Leaflet.js has been one I really like – OpenLayers is next on my To-Do list. In this post, I will show a very simple example of loading GeoJSON point data in to a map and then adding a popup to the points. I modified the example from the Leaflet website, stripping out other ways of doing it and simplified the GeoJSON to one data object. I think for newbies like myself, this made it much easier to understand.

Here is a screen shot of the final map – 2 points with a popup.

The Final Leaflet.js Map.

The following is the GeoJSON I used – it contains 2 points.

GeoJSON file saved as .js

Now in the webpage, I create a Leaflet map and use the GeoJSON file. Here is the code:

Here is what’s happening:

Import the GeoJSON data: <script src=”MyGeoJSONforLightRail.js” type=”text/javascript”></script>

Create a place to put the map: <div id=”map” style=”width: 600px; height: 400px”></div>

Add a map named same as place we want to put it: var map = new L.Map(‘map’);

Add a base map, set the map zoom, add the base layer to the map:

var cloudmadeUrl = ‘http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/22677/256/{z}/{x}/{y}.png’, cloudmadeAttribution = ‘Map data &copy; 2011 OpenStreetMap contributors, Imagery &copy; 2011 CloudMade’,  cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution});

map.setView(new L.LatLng(39.747, -105), 14).addLayer(cloudmade);

Create and empty GeoJSON Layer: var lightRailGeojsonLayer = new L.GeoJSON();

Attach a popup: lightRailGeojsonLayer.on(“featureparse”, function (e) {
var popupContent = “<p>I started out as a GeoJSON ” + e.geometryType + “, but now I’m a Leaflet vector!</p>”;
popupContent += “<p>This is the default look of a GeoJSON Point.</p>”;
if (e.properties && e.properties.popupContent) {
popupContent += e.properties.popupContent;
}
e.layer.bindPopup(popupContent);
});

Note on Popup: The += following popupContent is appending to the string. You will see it 3 times.

Add the blank GeoJSON layer to the map: map.addLayer(lightRailGeojsonLayer);

Populate the layer with the .js file we included in the header (MyGeoJSONforLightRail.js):

lightRailGeojsonLayer.addGeoJSON(lightRailStop);

Note on populating: the (lightRailStop) is the name of the var in the MyGeoJSONLightRail.js file:

var lightRailStop = {
“type”: “FeatureCollection”,
“features”: [ blah blah blah…..

 

There you go. Change the GeoJSON to your file, modify the map setView, and edit the popup and you have your own map. For more examples go to the Leaflet page.