pMap

Welcome to pMap (planningMap). It currently offers this service: take the previous 28 days’ planning applications to lbg, map those that can be geo-coded (by postcode), and list those that can’t. You can read a bit more about it and check the source code below.

pMap


The data is scraped and processed in a fairly long-winded way as the e-shootershill server side scripts (which are written in php) are not allowed to interact with servers in other domains (i.e. the council).

In the past, this site has worked around this obstacle by using JavaScript to access ‘Sponsor a brick for Severndroog‘ data directly by the browser using a proxy which homes the script and the sponsorship details, however that was not possible this time. Since JavaScript is historically limited by the Same Origin Policy, various workarounds are available for applications that need to live in one domain and obtain resources (such as planning data) from another – in this case a Yahoo pipe provides an intermediate service that can both a) get the planning data, and b) pass it on.

pipes-lbg-planning-screenscraper

A Yahoo pipe scrapes the data, ready for the browser to collect it

From this point, a JavaScript in the browser looks for a postcode in each application, and if it finds one, it uses it to request latitude and longitude co-ordinates from mapit, plotting the application details on the map. If no postcode is found, the application is listed below.

TODO

Forthcoming in future versions: There are a number of features that this could have, as the planning data is quite rich in information – probably the first things to do are to find access to a service that geocodes locations without a postcode; and to allow custom date ranges to be explored. Following that different markers for different types of work could be plotted and toggled on/off to make it quick and easy to see what kind of changes are happening… other data differences that could be highlighted include ward and conservation.

The html/javascript is available, it can be freely reused, or better still forked via open source sharing. Whilst it obtains google maps and jquery scripts remotely, it currently requires a local copy of gmap3, plus the Yahoo Pipe. It might be possible to replace the latter with functions provided by easyXDM, although that remains to be tested.

[javascript]
<!DOCTYPE html>
<html>
<head>
<title>pMap</title>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<!– need a local copy of jquery-gmap3 –>
<script type="text/javascript" src="jquery-gmap3-3.4/gmap3.min.js"></script>
<style type="text/css">
#gmap{
height: 450px;
width: 450px;
margin: 20px auto;
}
#gmapnot{
width: 450px;
margin: 20px auto;
}
.no-postcode-list{

}
table.caseprogress .highlight {
border: 3px solid #088AB2;
}
</style>
</head>
<body>

<div id="gmap"></div>
<div align="center"><button>Toggle Unmapped Applications (No Postcode)</button></div>
<div id="gmapnot" style="display:none"></div>

<script type="text/javascript" charset="utf-8">

$("button").click(function () {
// enable the toggling of unmapped applications
$("#gmapnot").toggle("slow");
});

// initialise the map, center it by lat/lon coordinates in the centre of the borough
$().gmap3(‘setDefault’, {init:{center:[51.4738989064778, 0.04119873046875],zoom:12}});

// create a date object
var regdate1 = new Date();
var regdate2 = new Date();
regdate1.setDate(regdate1.getDate() – 28);
regdate2.setDate(regdate1.getDate() + 28 );

// get the planning data via yahoo pipes
$.getJSON(‘http://pipes.yahoo.com/selondon/planning?regdate1=’+regdate1.getDate()+’%2F0’+(regdate1.getMonth()+1)+’%2F’+regdate1.getFullYear()+’&regdate2=’+regdate2.getDate()+’%2F0’+(regdate2.getMonth()+1)+’%2F’+regdate2.getFullYear()+’&_render=json&_callback=?’, function(apps) {
// loop through each application
$.each(apps.value.items, function(i, data) {

// container for html content extracted from the planning data
var items_loc = [];

// look for start the postcode
var start = data.content.search("[A-Z]{2}[0-9]{1,2} [0-9][A-Z][A-Z]{1} ");
// set postcode to string from that point
var postcode = data.content.substring(start);
// try to trim the postcode
var postcode = postcode.substring(0, postcode.search(" Statutory class"));
// if the postcode could not be trimmmed it was not there – can’t be mapped, and is added as text only
if (postcode.length > 8) {
postcode = ”;
items_loc.push(‘<li>’ + data.stringtokenizer[0].content + ‘<hr />’ + data.stringtokenizer[8].content + ‘<hr />’ + data.stringtokenizer[10].content + ‘</li>’);
$(‘<ul/>’, {
‘class’: ‘no-postcode-list’,
html: items_loc.join(‘,’)
}).appendTo(‘#gmapnot’);
}
// or else the postcode could be trimmed correctly, and hence is in a usable form
else {
// request the geo data for the postcode from mapit
$.getJSON(‘http://mapit.mysociety.org/postcode/’ + postcode + ‘?callback=?’, function(locations) {
// merge retrieved locations into planning data
$.extend(data, locations);
// once DOM has loaded…
$(document).ready(function(){
// display the map, with a marker and infowindow for each geocoded planning application using the gmap3 jquery plugin
$("#gmap").gmap3(
{ action: ‘addMarkers’,
markers:[
{lat:data.wgs84_lat, lng:data.wgs84_lon, data:data.stringtokenizer[0].content + ‘<hr />’ + data.stringtokenizer[8].content + ‘<hr />’ + data.stringtokenizer[10].content}
],
marker:{
options:{
draggable: false
},
events:{
click: function(marker, event, data){
var map = $(this).gmap3(‘get’),
infowindow = $(this).gmap3({action:’get’, name:’infowindow’});
if (infowindow){
infowindow.open(map, marker);
infowindow.setContent(data);
} else {
$(this).gmap3({action:’addinfowindow’, anchor:marker, options:{content: data}});
}
}
}
}
}
); // end – gmap3

}); // end – document.ready

}); // end – getJSON locations from mapit
}

}); // end – each application
}); // end – getJSON apps from yahoo pipes

</script>
</body>

</html>
[/javascript]

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.