opentraffic / tangram-viz-experiments

OTv2: work-in-progress to visualize anonymized and aggregated traffic statics using Tangram
http://opentraffic.io/tangram-viz-experiments/
MIT License
4 stars 1 forks source link

Open Traffic ~ Tangram Demo

This map can be used in two ways: against a live API or against a local cached copy of a GeoJSON extract.

To use against a live OTv2 API, you will need to specify two query parameters:

For example: http://opentraffic.io/tangram-viz-experiments/?server=host.opentraffic.io&secret=password

To use against a local cached copy of a GeoJSON extract:

  1. Construct a query to the OTv2 API using the available query parameters.
  2. Save the response as a .geojson file to a local copy of this repository.
  3. Update the data source within the Tangram scene file to reference that file: scene.yaml#L9-L12
  4. Update the initial map start position: index.html#L190

    How does it work?

    The pipeline for this is:

    1. Interaction on the map
    2. Get map BoundingBox
    3. Do HTTP request to OpenTraffic server
    4. Load the GeoJSON Reply as a Tangram data source
    5. In Tangram scene YAML file, filter the data into a layer where the speed, drive_on_right and oneway properties are mapped to RGB channels of the geometry
    6. That geometry use a custom shader style that draws arrows in the right direction, and mapped the speed to a palette defined by a .png file (that can be generated by Spectrum App or any other software.)

1. On map Interaction

When the map changes position...

    map.on('moveend', debounce(function() {
        // Update the displayed information
        update();
    }, 1000));

Note: the call is debounced to avoid unnecessary multiple calls

2, 3 & 4. Request and load OpenTraffic data

Get the bounding box and present time to construct a HTTP call to OpenTraffic.

NOTE: the call have to be change to ask for a year of data instead of an hour. Also the query should be made for only one day of the week (using dow) to reduce stream of data. (Check all this with Kevin)

function update() {

    // Get the current boundaries of the displayed area on the map
    var bbox = map.getBounds();
    var day = moment().format('YYYY-MM-DD')
    var hour = moment().format('HH:MM:SS')

    // Make the URL for OpenWeatherMaps API, asking for all stations inside that area (bounding box)
    var url = 'https://localhost:3000/query?';
    url += '&start_date_time=' + day + 'T'+ moment().subtract(1,'hour').format('HH:MM:SS');
    url += '&end_date_time=' + day + 'T' + moment().format('HH:MM:SS');
    url += '&boundingbox=' + bbox.getSouthWest().lng + ',' +bbox.getSouthWest().lat + ',' + bbox.getNorthEast().lng + ',' + bbox.getNorthEast().lat;

    console.log('Fake call to:', url);

    // Make the request and wait for the reply
    fetch(url)
        .then(function (response) {
            // If we get a positive response...
            if (response.status !== 200) {
                console.log('Error getting data: ' + response.status);
                return;
            }
            // ... parse it to JSON
            return response.json();
        })
        .then(function(json) {
            var data = { " opentraffic": json };
            // Pass the POIs as a GeoJSON FeaturesCollection to tangram
            scene.setDataSource('opentraffic', {type: 'GeoJSON', data: json});
        })
        .catch(function(error) {
            console.log('Error parsing the GeoJSON.', error)
        })
}

5. Encode the data as color

Warning: the data on the valhalla tile that Kevin send me have a single float for speed. THIS WILL CHANGE there going to be multiple speed according to

layers:
    opentraffic:
        data: { source: opentraffic }
        draw:
            ot-roads:
                order: 10001
                width: [[10,2px],[15,5px],[20,5m]]
                color: |
                    function () {
                        return [ feature.speed/255, feature.drive_on_right, feature.oneway ]; 
                    }

6. Style the data in the line

Use the color to draw an chevron arrow pattern in the right direction, and for the speed color use a regular .png (that can be generated by Spectrum App or any other software.)

textures:
    palette:
        url: assets/palette-01.png
styles:
    ot-roads:
        base: lines
        mix: [functions-zoom, functions-aastep, generative-random]
        texcoords: true
        animated: true
        lighting: false
        blend: inlay
        shaders:
            defines:
                ZOOM_START: 15.
                ZOOM_END: 20.
                ZOOM_IN: .0
                ZOOM_OUT: .5
            uniforms:
                u_palette: palette
            blocks:
                width: |
                    // One or two lanes
                    width = mix(width*v_texcoord.x, width, a_color.b);
                color: |
                    // Speed to color from palette LUT 
                    color = texture2D(u_palette, vec2(smoothstep(0.,.3,v_color.r),.5));

                    // Draw arrows
                    vec2 st = v_texcoord.xy+vec2(.5,0.);

                    // Flip direction if the the drive is not on the right.
                    st.y = mix(1.-fract(st.y),st.y,v_color.g);
                    // Adjust the speed to the speed
                    st.y -= u_time*10.*v_color.r;

                    // Make chrevone arrow
                    color.a *= aastep(zoom(),fract(st.y+abs(st.x*.5-.5)));