Road Orientations Map

A visualization of road orientations for the current map view. Explore the map to see the chart for your city!

by Lorenzo Brutti

HTML

<script src="https://unpkg.com/[email protected]/cheap-ruler.js"></script>
<script src="https://bundle.run/[email protected]"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v2.3.0/mapbox-gl-geocoder.min.js"></script>
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v2.3.0/mapbox-gl-geocoder.css">
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.52.0/mapbox-gl.js"></script>
<link rel="stylesheet" href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.52.0/mapbox-gl.css">
<div id="map"></div>
<canvas id="canvas"></canvas>

CSS

body { margin: 0; padding: 0; }
#map { position: absolute; width: 100%; height: 100%; }
#canvas { position: absolute; top: 10px; right: 10px; }

JavaScript

// my personal token - please generate your own at https://www.mapbox.com/studio/
mapboxgl.accessToken = 'pk.eyJ1IjoibW91cm5lciIsImEiOiJWWnRiWG1VIn0.j6eccFHpE3Q04XPLI7JxbA';

// initialize a Mapbox map with the Basic style, centered in New York
var map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/cjf4m44iw0uza2spb3q0a7s41',
    center: [-73.992, 40.734],
    zoom: 12,
    hash: true
});

map.addControl(new MapboxGeocoder({accessToken: mapboxgl.accessToken}), 'bottom-right');
map.addControl(new mapboxgl.NavigationControl(), 'top-left');

var h = 300; // size of the chart canvas
var r = h / 2; // radius of the polar histogram
var numBins = 64; // number of orientation bins spread around 360 deg.

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

canvas.style.width = canvas.style.height = h + 'px';
canvas.width = canvas.height = h;

if (window.devicePixelRatio > 1) {
    canvas.width = canvas.height = h * 2;
    ctx.scale(2, 2);
}

function updateOrientations() {
    ctx.clearRect(0, 0, h, h);

    var bearing = map.getBearing();

    ctx.save();
    ctx.translate(r, r);
    ctx.rotate(-bearing * Math.PI / 180);

    ctx.fillStyle = 'rgba(255,255,255,0.8)';
    ctx.beginPath();
    ctx.arc(0, 0, r, 0, 2 * Math.PI, false);
    ctx.fill();

    ctx.strokeStyle = 'rgba(0,0,0,0.15)';
    ctx.beginPath();
    ctx.moveTo(-r, 0);
    ctx.lineTo(r, 0);
    ctx.moveTo(0, -r);
    ctx.lineTo(0, r);
    ctx.stroke();

    var features = map.queryRenderedFeatures({layers: ['road']});
    if (features.length === 0) {
        ctx.restore();
        return;
    }

    var ruler = cheapRuler(map.getCenter().lat);
    var bounds = map.getBounds();
    var bbox = [bounds.getWest(), bounds.getSouth(), bounds.getEast(), bounds.getNorth()];
    var bins = new Float64Array(numBins);

    for (var i = 0; i < features.length; i++) {
        var geom = features[i].geometry;
        var lines = geom.type === 'LineString' ?...