Network Tracing with Turf JS

A Client Side Solution for Simple Upstream and Downstream Linear Network Analysis

Posted

A primary focus of my day job is managing utility datasets for a small municipality. I am currently in the process of taking a simple database of lines and points and turning it into a true utility network. One of the benefits of having this new seamless database is to perform network traces. This is possible using a variety of desktop and server tools including geometric networks in ArcGIS Desktop, the ArcGIS Utility Network Management extension for ArcGIS Server/Enterprise, pgRouting, and via various QGIS plugins. However, the utility field crews and managers only have access to our web maps, so I wondered if I could program a Mapbox GL JS plugin to do some simple network tracing directly in the browser. Fortunately in my case the entire database is less than 3MB, so all the data can be loaded into the browser via GeoJSON. This data can then be visualized and analyzed using client-side libraries, in this instance Mapbox GL and Turf JS.

My first attempt at network tracing involved looping through all the linear features and checking for equal upstream and downstream asset IDs assigned to each feature. This seemed like a common sense approach, but it would mean these IDs would need to be calculated for each feature beforehand. This did work, but I wanted to find a way to eliminate the need to calculate these IDs and focus solely on the geometry. I found the answer in the Turf JS API.

The basic idea became quit simple: find all the connected lines to an origin point using turf.booleanPointOnLine() and then use these resulting lines to seed the network trace. By iterating over this method the tool could return the entire network.

function getIntersectingLines(point, lines) {
  var point = point;
  var network = {
    type: "FeatureCollection",
    features: []
  };
  lines.features.map(function(f) {
    if (turf.booleanPointOnLine(point, f)) {
      network.features.push(f)
    }
  });

  return network 
}

In the first iteration I focused solely on identifying all the intersecting lines of the origin point to test the turf.booleanPointOnLine() method. I ran into some issues with the points and lines not being coincident, possibly due to rounding of extremely long decimal places. I decided to borrow the method used by the geojson-equality package and limit the coordinate check to six decimals using .toFixed(6). The coordinates could also be trimmed before adding them to the browser using QGIS, in NodeJS using geojson-precision, or with the command-line mapshaper tool.

This method worked well, however it only returns the first set of intersecting lines, and it returns the lines in both directions. In the production version, to achieve the desired upstream or downstream network trace the tool simply uses either the first or last coordinate pair of the intersecting lines. The result can be found below. In this example the tool only uses the upstream trace, however in production the tool is deployed as a Mapbox GL JS plugin and has a toggle to switch between upstream and downstream traces. Running this tool on the entire utility network can take some time, up five seconds on a PC. Moving the most of the computation to a worker thread alleviated some of the issues associated with the UI-blocking JavaScript process.

To trace the upstream network simply click on a point.



Related Posts