Web development: Percent built on
Last updated
Last updated
Website
Ordnance SurveyData
OS Data HubIn this tutorial we'll develop a web app that lets users draw a polygon, then calculates what percentage of the geometry is built on. This technique is useful for determining land cover of any number of layers - green space, buildings, road surface and so on.
We'll be using the OS Maps API for basemaps and the Features API to fetch vector building footprint geometries.
We'll also use Mapbox GL JS as our JavaScript mapping library, the Mapbox Draw package for drawing geometries, and Turf.js for spatial analysis in the browser. We'll also use jQuery to manipulate the DOM.
Spatial analysis is a powerful way to understand the world. The insights derived from analysis of points, lines, polygons and raster data can serve as the evidence to inform intelligent decision-making. Let's look at how to build a web interface capable of sophisticated spatial analytics.
<iframe style="width:100%;height:400px;max-width:1200px;border:1px solid #f5f5f5;" src="/public/os-data-hub-tutorials/dist/web-development/percent-built-on/"></iframe>
Most of this tutorial will focus on the JavaScript required to create this app, but we do need to set up our HTML page so we have the right libraries loaded, and elements with the appropriate classes and IDs.
Have a skim through our index.html
: you'll notice we load mapbox-gl.css
, mapbox-gl-draw.css
, turf.js
and local stylesheets in the head, and jquery.js
, mapbox-gl.js
, mapbox-gl-draw.js
and local scripts before the closing </body>
tag.
Other than loading these assets, index.html
includes elements for the code in tutorial.js
to interact with, most notably a #map
div element, a #percent-built
p element to hold the computed result and a #fetch-and-calculate
button element.
Alright - on to the JavaScript.
First, head to osdatahub.os.uk and copy your API key from a project with both the Maps and Features APIs added. We'll start by assigning this string to a constant variable. We'll do the same with the service endpoint urls:
We won't go over setting up the basemap in detail here - you can find code on how to connect a mapboxgl.Map
instance to the OS Maps API on our Examples page. Since we'll be overlaying features, the Light cartographic style is a good choice.
MapboxDraw
The mapbox-gl-draw package lets users draw polygons on a Mapbox GL basemap by clicking points. We create a new instance of MapboxDraw
- for this app we configured the Draw tool with OS colours and customised user interaction modes on the drawn polygon. (We set up these options in js/config.js to keep code clean.)
We don't want the user to be able to fetch data from the OS Features API until we have a polygon to find intersecting features, so we only activate that button's functionality if a polygon is drawn on the map. We define these functions toward the bottom of tutorial.js
, knowing they'll be hoisted and available for the 'draw.create'
and 'draw.delete'
event listeners:
Mapbox GL JS works by visualising styled layers, which reference a data source.
We'll be adding two sources and layers to visualise in addition to the query polygon the user draws on the map: buildings
and buildings-intersection
. Our users might draw a polygon that cuts through a building footprint, and we only want to count the section of the footprint that intersects the query polygon. The buildings
source / layer will hold and visualise polygons from the OS Features API, and buildings-intersection
will hold polygon intersections computed in the browser.
Until we have a query to analyse we will just add the sources to the map:
Most of the logic in this app will be executed once the user has drawn a polygon and clicks Fetch and Calculate.
The things that need to happen:
Generate a Features API query to request building features intersecting the drawn geometry - and send the request.
Loop through the array of returned building features, creating another array of the building footprints intersecting the query polygon.
Calculate the percent built on by dividing the area of the building intersection features by the total area of the query polygon.
Add buildings and intersection features to the map, and update the HTML to show the percent built on.
We'll walk through this step by step.
But, of course, all this code only needs to run when the user clicks "Fetch and Run", so we'll start by adding a "click" event listener to that button element. The callback function we define will be executed when the button is clicked - we'll be writing an async
function to help us write clean code handling asynchronous API calls.
First step: fetch buildings that intersect the query polygon the user drew.
The OS Features API is a Web Features Service. Users can query the API with spatial parameters, including making requests for features that intersect a polygon. Within the callback, we take the geometry of the drawn polygon, geom
, and call getIntersectingFeatures(geom)
, which builds the request with the spatial filter and fetches features from the API.
Let's look closely at the getIntersectingFeatures
function:
So, a call to getIntersectingFeatures()
with a query geometry will return a GeoJSON FeatureCollection with an array of features representing building polygons from the OS Features API's Topography_TopographicArea
feature type. With this information we can proceed to the in-client spatial analysis step.
Here we loop through each building feature returned, finding the part of its geometry that is intersecting the query polygon. With this we'll create another GeoJSON FeatureCollection, intersections
.
We'll use a few functions in the Turf.js library for spatial analysis.
With that we have a GeoJSON FeatureCollection of all the building areas inside the query polygon. We're just ready to work out the percent built on!
If any building intersections were detected, we calculate the percent built on and add the buildings and intersections to the map, to visualise the output.
Last but not least, show the answer by updating the righthand panel with the float value of the percentage built on. We'll also fit map bounds to the target area.
That's it! We've written code that let's a user draw a polygon on an OS Maps API raster basemap, fetch features representing building polygons from the OS Features API, and calculate the percentage of the query geometry that is covered by building footprints.
We used Mapbox GL JS, MapboxDraw, Turf.js, and jQuery to help us with map visualisation, map interactivity, spatial analysis and DOM manipulation.
Let us know what you think - or show us what you build! Tweet @OrdnanceSurvey and tag #OSDeveloper.