mapbox-taxi.html 8.1 KB
<!--
https://web1.capetown.gov.za/web1/opendataportal/AllDatasets
https://web1.capetown.gov.za/web1/opendataportal/DatasetDetail?DatasetName=Taxi%20routes
https://web1.capetown.gov.za/web1/opendataportal/DatasetDetail?DatasetName=Building%20footprints
-->
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Taxi routes in capetown - ECHARTS-GL</title>
        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
        <meta name="apple-mobile-web-app-capable" content="yes"> <!-- Fullscreen Landscape on iOS -->
        <link rel="stylesheet" href="./common.css">
    </head>
    <body>
        <div id="main"></div>
        <script src="../node_modules/echarts/dist/echarts.js"></script>
        <script src="../dist/echarts-gl.js"></script>
        <script src='lib/mapbox-gl.js'></script>
        <link href='lib/mapbox-gl.css' rel='stylesheet' />
        <script src="https://unpkg.com/shapefile@0.6"></script>
        <script src="lib/jquery.min.js"></script>
        <script src="lib/dat.gui.js"></script>
        <script src="js/commonUI.js"></script>
        <script>
            mapboxgl.accessToken = window.location.search.slice(1);
            var chart = echarts.init(document.getElementById('main'));

            var ENCODE_SCALE = 1e6;
            function decodeLine(line) {

                var result = [];
                var prevX = line[0];
                var prevY = line[1];

                for (var i = 0; i < line[2].length; i += 2) {
                    var x = line[2].charCodeAt(i) - 64;
                    var y = line[2].charCodeAt(i + 1) - 64;
                    // ZigZag decoding
                    x = (x >> 1) ^ (-(x & 1));
                    y = (y >> 1) ^ (-(y & 1));
                    // Delta deocding
                    x += prevX;
                    y += prevY;

                    prevX = x;
                    prevY = y;
                    // Dequantize
                    result.push([x / ENCODE_SCALE, y / ENCODE_SCALE]);
                }

                return result;
            }

            var geoJSON = {
                features: []
            };
            var regions = [];
            var readShp = new Promise(function (resolve, reject) {
                shapefile.open('data/buildings-capetown.shp', 'data/buildings-capetown.dbf')
                    .then(source => source.read()
                        .then(function append(result) {
                            if (result.done) {
                                resolve();
                                return;
                            }
                            var feature = result.value;
                            feature.properties.name = geoJSON.features.length + '';
                            regions.push({
                                name: geoJSON.features.length + '',
                                value: 1,
                                height: feature.properties.SHAPE_leng * 10000
                            })
                            geoJSON.features.push(feature);
                            return source.read().then(append);
                        })
                    );
            });

            Promise.all([$.getJSON('data/taxi-routes-capetown.json'), readShp])
                .then(function ([data, lastFeature]) {

                    var lines = data.map(function (track) {
                        return {
                            coords: decodeLine(track)
                        };
                    });

                    echarts.registerMap('buildings', geoJSON);

                    console.profile('setOption');
                    chart.setOption({
                        mapbox3D: {
                            center: [18.424552361777955, -33.92188144682616],
                            zoom: 14,
                            pitch: 50,
                            bearing: -10,
                            altitudeScale: 2,
                            style: 'mapbox://styles/mapbox/dark-v9',
                            postEffect: {
                                enable: true,
                                screenSpaceAmbientOcclusion: {
                                    enable: true,
                                    intensity: 1.2,
                                    radius: 6,
                                    quality: 'high'
                                },
                                screenSpaceReflection: {
                                    enable: true
                                },
                                depthOfField: {
                                    enable: false,
                                    focalDistance: 80,
                                    blurRadius: 5
                                }
                            },
                            light: {
                                main: {
                                    intensity: 1,
                                    shadow: true,
                                    shadowQuality: 'high'
                                },
                                ambient: {
                                    intensity: 0.
                                },
                                ambientCubemap: {
                                    texture: 'asset/pisa.hdr',
                                    exposure: 2,
                                    diffuseIntensity: 1,
                                    specularIntensity: 2
                                }
                            }
                        },
                        series: [{
                            type: 'lines3D',

                            coordinateSystem: 'mapbox3D',

                            effect: {
                                show: true,
                                constantSpeed: 5,
                                trailWidth: 2,
                                trailLength: 0.8,
                                trailOpacity: 1,
                                spotIntensity: 10
                            },

                            blendMode: 'lighter',

                            polyline: true,

                            lineStyle: {
                                width: 0.1,
                                color: 'rgb(200, 40, 0)',
                                opacity: 0.
                            },

                            data: {
                                count: function () {
                                    return lines.length;
                                },
                                getItem: function (idx) {
                                    return lines[idx]
                                }
                            }
                        }, {
                            type: 'map3D',
                            map: 'buildings',

                            coordinateSystem: 'mapbox3D',
                            shading: 'realistic',
                            silent: true,

                            data: regions,

                            itemStyle: {
                                color: '#444'
                            },

                            realisticMaterial: {
                                metalness: 1,
                                roughness: 0.2,
                            }
                        }]
                    });

                    console.profileEnd('setOption');
                });

            window.addEventListener('keydown', function () {
                chart.dispatchAction({
                    type: 'lines3DToggleEffect',
                    seriesIndex: 0
                });
            });

            window.addEventListener('resize', function () {
                chart.resize();
            });

            var gui = new dat.GUI();
            var config = {
                color: 'rgb(200, 40, 0)'
            };
            gui.addColor(config, 'color').onFinishChange(function () {
                chart.setOption({
                    series: [{
                        lineStyle: {
                            color: config.color
                        }
                    }]
                });
            })

        </script>
    </body>
</html>