Search This Blog

Monday, 31 August 2015

Integrating your map service and Wikipedia using JavaScript and PHP



Wikipedia contains a huge amount of information that has a geographic reference. For example, coordinates of cities, tourist attractions, urban infrastructure - railway stations, airports, bridges, etc. And no doubt many developers of online map services (or GIS) and their users would like to have a quick access to this information and if needed to have it automatically added on the map with the attribute information. In this article you will get the information on how to do it yourself with the help of JavaScript and PHP languages.


Since in OpenWebGIS  selecting of information from Wikipedia and adding it on the map have already been implemented, and I am a developer of this system, so this process we will look at the example of OpenWebGIS.
First you need to create an input element in which the users will insert the names of the objects that they want to find in Wikipedia.
Its creation using HTML looks like this:
<input id="Id_WikipediaMapId" size="35" 
title="insert name of the object to find it on the map" type="text" value="" >
<button class="Searchclass" onclick="SearchWikipediaOnMap"
type="button">Search</button> 

Below creating block "div" will contain the results of the search in Wikipedia. As long as the user has not clicked on the "Search" button, this block is invisible, so it has the property "display: none":

<div id =
"ResultSearchWikipedia_id" style = "position: relative; top: 0;
left: 0px; display: none; height: 10px; font-size: 10px; overflow: auto;
border: solid 1px; black; background: # ffffff; "> </div>

The result of the creation of the necessary buttons and inputs for user`s data inserting in OpenWebGIS looks as shown in Figure 1.
Figure 1
Pay attention to the identifiers of the input element (id="Id_WikipediaMapId") and block with the search results (id="ResultSearchWikipedia_id"). They will be useful to us repeatedly. To the "Search" button on the event "onclick" the function "SearchWikipediaOnMap()" is bound . The whole code you can see in the function "SearchWikipediaOnMap()" in the file "opengis_eng.html" or "Start_OpenWebGIS_en.html", if you download the JavaScript and HTML code using the menu item of OpenWebGIS "JavascriptSourceCode".
Consider this function. In this function, we create a XMLHttpRequest with the help of which via request method "GET" turn to the PHP script "wikimap.php". This script have to be created by yourselves and put in the appropriate folder on your server. If on your server you use Apache in the Windows operating system (OS), this file should be placed in the folder "Apache\htdocs", but if in the Ubuntu OS then it is put in folder "/var/www". But it all depends on settings of your operating system and the way you have installed Apache and PHP. Start of the function SearchWikipediaOnMap():
try {var xmlhttp2 = new XMLHttpRequest();}
catch (e) {alert("error");}
var qVal = document.getElementById("Id_WikipediaMapId").value;

// variable c = qVal, contains what the user inserted for searching
// variable lan = en, contains the 
//language in which you want to search (in our case - English)

xmlhttp2.open ('GET', '/wikimap.php?' + 'c=' + qVal + '&lan=en', true);
xmlhttp2.setRequestHeader ("Cache-Control", "no-cache");
xmlhttp2.setRequestHeader ("Content-type", "text/xml");

After getting the request result, it is processed  and added into previously created element "div" with id="ResultSearchWikipedia_id". After receiving the response the event fires (triggers) "onreadystatechange" Event .When a request to a server is sent, we want to perform some actions based on the response.The onreadystatechange event is triggered every time the readyState changes.
Сontinuation of the function SearchWikipediaOnMap():
xmlhttp2.onreadystatechange = function ()
{if (xmlhttp2.readyState == 4 && xmlhttp2.status == 200) {
if (xmlhttp2 == '') {alert("no data"); return;}
var varSearch = xmlhttp2.responseText;
if (varSearch.split ("<! DOCTYPE html PUBLIC") [1]) {alert ("no data"); return;}
if (varSearch == '') {alert ("no data"); return;}
 var oXmlDoc = null;
 if (window.DOMParser) {
 var oXmlParser = new DOMParser ();
 oXmlDoc = oXmlParser.parseFromString (varSearch, "text/xml");
 } else {

// If user has older versions of IE browser

 oXmlDoc = new ActiveXObject ("Microsoft.XMLDOM");
 oXmlDoc.async = "false";
 oXmlDoc.loadXML (varSearch);
 }
 var s1 = []; var s2 = []; var s3 = [];
var ListNameWiki = oXmlDoc.getElementsByTagName('Text');
for (var i = 0; i <ListNameWiki.length; i++)
{s1.push (ListNameWiki[i].childNodes[0].nodeValue)}
var ListNameWiki = oXmlDoc.getElementsByTagName('Description');
for (var i = 0; i <ListNameWiki.length; i++)
{s2.push (ListNameWiki[i].childNodes[0].nodeValue)}
var ListNameWiki = oXmlDoc.getElementsByTagName('Url');
for (var i = 0; i <ListNameWiki.length; i++)
{s3.push(ListNameWiki[i].childNodes[0].nodeValue)}
var textDiv = '';

// to each row in the "div" with the results it is needed
// to tie the event "onclick" by name "zoomToSelectWiki":

for (var i = 0; i <s1.length; i ++)
{textDiv + = '<a title = "'+s2[i]+'" id="'+s3[i]+';.,'+i+
'SelOpenWikiStrClick __ ;;'+s1[i]+
'" style="cursor: pointer" onclick="zoomToSelectWiki(this)"'+
' onmouseout = "outPunktWiki (this);"'+
' onmouseover = "overPunktWiki (this);"> '+
s1[i]+' </a> <br> ';
document.getElementById ("ResultSearchWikipedia_id"). innerHTML = textDiv;
}
document.getElementById ("ResultSearchWikipedia_id"). style.display = 'block';
document.getElementById ("ResultSearchWikipedia_id"). style.height = "100px";
document.getElementById ("ResultSearchWikipedia_id"). style.width = "360px";
}} 

Let's say a user searches the famous sight of Berlin: Brandenburg gate. After clicking the "Search" button and fulfilling function "SearchWikipediaOnMap()" the user will see the result as shown in Figure 2.
Figure 2
Now let`s have a look at the file wikimap.php:

<? php
function test ()
{
$city=addslashes($_GET['c']);
$lan=addslashes($_GET['lan']);
// Form a request string to Wikipedia:
$url="http://".$lan.".wikipedia.org/w/api.php?action=opensearch&search=".
urlencode($city)."&format=xml&limit=100";
// The request to the Wikipedia server will be executed using cURL.
// initialize a cURL session:
$ch=curl_init();
// Specify the URL, where to send POST-request method. The URL to fetch. 
//This can also be set when initializing a session with curl_init():
curl_setopt($ch,CURLOPT_URL, $ url);
curl_setopt($ch,CURLOPT_FAILONERROR, 1);
// allow redirection:
curl_setopt($ch,CURLOPT_FOLLOWLOCATION, 1);
// indicate that TRUE (1) to return the transfer  //as a string of the return value of curl_exec() instead of outputting //it out directly:   curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
// The maximum number of seconds to allow cURL functions to execute:
curl_setopt($ch,CURLOPT_TIMEOUT, 3);
// when requesting for data from Wikipedia
// you must comply with "User-Agent_policy” 
//ie in the request  your service and email address must be indicated:   
curl_setopt($ch, CURLOPT_USERAGENT,' MyCoolTool/1.1(http://example.com/MyCoolTool/; MyCoolTool@example.com) BasedOnGeoserver_OpenLayers');
// if your server is running under Windows OS,
// most likely the file with Root certificate  //(collection of trusted root certification authorities) is needed.  //You can download it (cacert.pem) here.
//for Linux OS (like Ubuntu), this row is not needed:
  curl_setopt($ ch, CURLOPT_CAINFO, "Path_to/cacert.pem");
// Execute request:
$ result=curl_exec ($ ch);
  if (!$result) {
    exit ('cURL Error:' .curl_error ($ ch));}      echo $ result;
// Close session:
    curl_close($ch);
}
test ();
?>

A more detailed description of the curl_setopt parameters see here.
String "$url" of Wikipedia request is formed according to the standards of API Wikipedia. Wikipedia has a powerful API. Be sure to read about it here.

Let's look at rows of search results shown in Figure 2. As it has already been mentioned, to each row the function "zoomToSelectWiki(tr)" is tied, which is triggered when the users click on the row of interest to them. See the source code of this function:

function zoomToSelectWiki (tr)
{
var strS =tr.id.split ('__ ;;') [1];
var qVal =strS;
try {varxmlhttp2 = new XMLHttpRequest();}
catch (e) {alert ("error");}
var qVal =strS;
xmlhttp2.open ('GET', '/wikimap2.php?'+'c ='+qVal+'&lan=en', true);
xmlhttp2.setRequestHeader("Cache-Control", "no-cache");
xmlhttp2.setRequestHeader ("Content-type", "text / xml");
xmlhttp2.onreadystatechange= function ()
{if (xmlhttp2.readyState == 4 && xmlhttp2.status == 200) {
if (xmlhttp2 == '') {alert ("no data"); return;}
varvarSearch = xmlhttp2.responseText;
getcoordinatesAddLayer(varSearch);
}}
xmlhttp2.send(null);
}

In zoomToSelectWiki(tr) we again form the request to the PHP script on your server, and as variables to the content of the row is passed there, on which the user clicked and language (English) of Wikipedia. When "onreadystatechange" event is triggered we need to get the object coordinates, create a corresponding layer and add it to the map. In the code of the file "opengis_eng.html" or "Start_OpenWebGIS_en.html" all these actions are in the same function "zoomToSelectWiki", but here we put them in a separate function "getcoordinatesAddLayer(varSearch)". We'll look at it more closely later, now we will examine a PHP file wikimap2.php. Its structure is almost the same as the wikimap.php. Pay attention to the formation of the request string "$url" to the Wikipedia. It is important that we spesify the need for the response to contain the coordinates of the object:
<? php
function test ()
{
$city =addslashes ($_GET['c']);
$lan=addslashes ($_GET['lan']);
$url="http://".$lan.".wikipedia.org/w/api.php?format=json&action=query&titles=".
urlencode($city)."&prop=revisions|coordinates|images|categories";
$ch =curl_init ();
curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch,CURLOPT_FAILONERROR, 1); curl_setopt($ch,CURLOPT_FOLLOWLOCATION, 1);  curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);  curl_setopt($ch,CURLOPT_TIMEOUT, 3);
curl_setopt($ch,CURLOPT_USERAGENT,' MyCoolTool / 1.1 (http://example.com/MyCoolTool/; MyCoolTool@example.com) BasedOnGeoserver_OpenLayers' );
curl_setopt($ch, CURLOPT_CAINFO, "Path_to/cacert.pem");
$result=curl_exec($ch);
  if (!$result) {
    exit ('cURL Error:' .curl_error ($ch));}
    echo $result;
}
curl_close($ch);
test ();
?>

Before proceeding to the study of the function "getcoordinatesAddLayer (varSearch)", it is necessary to bear in mind that in OpenWebGIS to create maps and layers on the map, JavaScript OpenLayers library (version 2.11) is used. More about this you can see in the article "Heatmap, JavaScript, Openlayers and canvas" and "Maps, hurricanes and linear regression equation (correlation) inOpenWebGIS using JavaScript". 
function  getcoordinatesAddLayer (varSearch)
{
if (varSearch.split ("<! DOCTYPE html PUBLIC") [1]) {alert("no data"); return;}
if(varSearch == '') {alert("no data"); return;}
varSearch =JSON.parse(varSearch);
var lat =''; var lon = '';
for (h in varSearch.query.pages)
{for (hh in varSearch.query.pages [h]) {
// get the coordinates of the object:
if (hh =='coordinates')
{var r =varSearch.query.pages[h]; lat = r.coordinates[0].lat;
 lon = r.coordinates[0].lon;}
}} if (lat =='') {alert ('no coordinates'); return;}
lon =parseFloat (lon);
lat =parseFloat (lat);
var strS =tr.id.split ('__ ;;') [1];
// create a new layer that contains points with the selected coordinates
// and attributes to add on the map: var new_layer_Wiki = new OpenLayers.Layer.Vector (strS, {renderers: ["Canvas", "SVG", "VML"]});
var points;
var new_pos2= new OpenLayers.LonLat(lon,lat).transform(new  OpenLayers.Projection ("EPSG: 4326"),map.getProjectionObject());
points =new OpenLayers.Geometry.Point (new_pos2.lon, new_pos2.lat);
var first_point = new OpenLayers.Feature.Vector (points); new_layer_Wiki.addFeatures(first_point);
var new_style_layer = new OpenLayers.Style ({
pointRadius: 3, fillColor: "#FF9000", strokeColor: "#FF9000", strokeWidth: 1
fillOpacity: 1, strokeOpacity: 1});
 var selStyle = new OpenLayers.Style({pointRadius: 5, fillColor: "#ffaa00",
 strokeColor:"#00DDFF", strokeWidth: 2, fillOpacity: 1, strokeOpacity:1});
new_layer_Wiki.styleMap=
new OpenLayers.StyleMap({'default': new_style_layer, 'select': selStyle});
new_layer_Wiki.projection= new OpenLayers.Projection("EPSG: 900913");
var strS =tr.id.split('__ ;;')[1];
var strS2 = tr.id.split (';.,')[0]; var strS3=tr.title;
// to the point with the object coordinates attributes 
//of the object (name, description,etc.) are added:
first_point.attributes['placeWiki'] = strS;
first_point.attributes['urlWiki'] = '<a href="'+strS2+'" target="_blank">'+ strS+'</a>';
if(checkDiscrWiki == true)
{first_point.attributes['descrWiki'] = strS3;} // Add the newly created layer on the map:
map.addLayer(new_layer_Wiki);
// Add the name of the newly created layer in the list of "Editable Layer": var t = document.createElement ('option');
t.value =new_layer_Wiki.name;
t.text =new_layer_Wiki.name;
document.getElementById("editL1"). appendChild (t);
}

Here, in the "map.getProjectionObject()" and "map.addLayer (new_layer_Wiki)" expression, "map" is an OpenLayers map object, created using the OpenLayers.Map function.
In the code above there are functions and objects: OpenLayers.Layer.Vector, OpenLayers.LonLat, OpenLayers.Projection, getProjectionObject(), OpenLayers.Geometry.Point, OpenLayers.Feature.Vector, addFeatures, OpenLayers.Style, OpenLayers.StyleMap, OpenLayers.Projection  - they are functions and objects of OpenLayers library. Therefore for better understanding of the code and the fact what these functions make it is desirable to examine their descriptions in these links.

If you look in the file "opengis_eng.html" or "Start_OpenWebGIS_en.html" the function code "zoomToSelectWiki" , you will see there that the code has additional blocks that start working, depending on the availability of the element with the id="WikiLayerAdd_id" and a global variable "WikiLayerOpenWebGIS". In this article, we do not describe these blocks since they are triggered when a user opens an additional window with options of request to Wikipedia (it is shown in Figure 3), but this is not the topic of this article.
Figure 3
So after the complete execution of the function "zoomToSelectWiki" the point  with coordinates and attributes of the object in our case "Brandenburg gate" will be added on the map. At the same time the name of the layer containing this point will appear in the layers list on the left of the map. All this will look as it is shown in Figure 4.
Figure 4
Further, the user can select the layer name "Brandenburg gate" in the list of "Editable Layer" and make a zoom in to the extent layer (using the menu item   "Layers-> Zoom to Layer"). Then the user can hover the cursor over a point, click on it and see its attributes. As a result, the user will see what is shown in Figure 5.

Figure 5


That is all for now. Good luck in creating beautiful and comfortable online GIS services.

1 comment: