等时圈实现

作者: 上岸躲雨 | 来源:发表于2018-11-23 10:08 被阅读8次

    等时圈是指从某点出发,以某种交通方式在特定时间内能到达的距离覆盖的范围。前段时间看到一个站点,该站点能够计算自驾、骑行、步行三种方式的等时圈。效果如下图

    image

    mapbox出品的图还是相当漂亮的,但毕竟是别人的东西,能自己做出来当然是好的(这个功能还是学生的时候就想做)。那就试试呗。

    当然先看看mapbox是怎么做的,查看站点使用什么接口,如下图发生数据请求,接口连接

    image

    对所有接口坐标进行分析,发现所有坐标的分布如下图:

    image

    从这些点就能猜出mapbox实现思路

    image.png

    参照这个思路,借助mapbox的接口完全能够自己实现等时圈功能。

    1. 生成网格,使用turf实现,上代码:
    var centerPoint = turf.point([116.46, 39.92]);
    //生成缓冲区
    var buffered = turf.buffer(centerPoint, 12, {units: 'kilometers'});
    //根据缓冲区生成bbox
    var bbox = turf.bbox(buffered);
    var cellSide = 1;
    var options = {units: 'kilometers'};
    //生成网格
    var grid = turf.pointGrid(bbox, cellSide, options);
    
    1. 利用mapbox接口计算网格各点时间属性。
     /**
         * 
         * @param startPoint
         * @param endPoints
         * @param travelType  walking driving,cycling
         */
    function makeRequest(startPoint,endPoints,travelType){
            var url= "https://api.mapbox.com/directions-matrix/v1/mapbox/"+travelType+"/"+startPoint.geometry.coordinates[0].toFixed(4)+","+startPoint.geometry.coordinates[1].toFixed(4)+";"
            if(endPoints.length>0){
                for(var i=0;i<endPoints.length;i++){
                    url=url+endPoints[i].geometry.coordinates[0].toFixed(4)+","+endPoints[i].geometry.coordinates[1].toFixed(4)+";";
                }
                url=url+"?sources=0&destinations=all&access_token=pk.eyJ1IjoicGV0ZXJxbGl1IiwiYSI6ImpvZmV0UEEifQ._D4bRmVcGfJvo1wjuOpA1g";
                url=url.replace(";?","?")
                $.ajax({
                    type : "get",
                    async:false,
                    url : url,
                    dataType : "json",
                    success : function(json){
                        var destinations=json.destinations;
                        var durations=json.durations;
                        for(var i=1;i<destinations.length;i++){
                            var point = turf.point(destinations[i].location,{duration:durations[0][i]});
                            points.push(point)
                        }
                    },
                    error:function(){
                        console.log('fail');
                    }
                });
            }
    
        }
    
    1. 生成等值线
      turf有生成等值线的功能
    var collections = turf.featureCollection(features);
    var breaks = [0, 600,700,800,900, 1200,1500, 1800,2100, 2400,2700, 3000, 3600, 4200, 4800,5400, 6000];
    var lines = turf.isolines(collections, breaks, {zProperty: 'duration'});
    
    效果图
    看效果,虽然能实现,但是和mapbox效果感觉差了点什么,查看mapbox例子的代码,发现它使用该组件link进行等时线生成。
    //它是这么使用的,但是实在看不懂这些参数是个啥意思
    var data = [[0, 1, 0], [1, 2, 1], [0, 1, 0]];
    var c = new Conrec;
    c.contour(data, 0, 2, 0, 2, [1, 2, 3], [1, 2, 3], 3, [0, 1, 2]);
    

    但是貌似这个组件效果是蛮好的。

    image
        function getNearestPoint(x,y,pts){
            var ptsjson = turf.featureCollection(pts);
            var targetPoint = turf.point([x, y]);
            var nearest = turf.nearestPoint(targetPoint, ptsjson);
            return  nearest;
        }
    
    //这里为啥要这么写,琢磨了好久,就不解释了
       xs=[];
       ys=[];
       for(var i=0;i<grid.features.length;i++){
            if(xs.indexOf(parseFloat(grid.features[i].geometry.coordinates[0].toFixed(4)))==-1){
                xs.push(parseFloat(grid.features[i].geometry.coordinates[0].toFixed(4)))
            }
        
            if(ys.indexOf(parseFloat(grid.features[i].geometry.coordinates[1].toFixed(4)))==-1){
                ys.push(parseFloat(grid.features[i].geometry.coordinates[1].toFixed(4)))
            }
        }
        var zs = [0,300, 600,900, 1200,1500, 1800,2100, 2400,2700, 3000,3300, 3600,3900, 4200,4500, 4800, 5100,5400, 5700,6000];
        
      var data=[];
       for (var y=0;y<ys.length;y++){
            var rowData=[];
            for (var x=0;x<xs.length;x++){
                var nearest=getNearestPoint(xs[x],ys[y],points)
                temperature=nearest.properties.temperature;
                rowData.push(temperature);
            }
            data.push(rowData)
        }    
            
     var c = new Conrec();
     c.contour(data, 0, xs.length - 1, 0, ys.length - 1, xs, ys, zs.length, zs);
    
    1. 将等时线连成等时面
     function polygonize(contourList){
            var shapes = []
            var results=[];
            polygons = [];
            for(var cIndex=0;cIndex<contourList.length;cIndex++){
                var c=contourList[cIndex];
                var level=c.level;
                var shape=[];
                for(var k=0;k<c.length;k++){
                    shape.push([c[k].x, c[k].y])
                }
                shape.push(shape[0]);
                for (var p = shape.length; p<4; p++){
                    shape.push(shape[0]);
                }
                var polygon = turf.polygon([shape], { level: level });
                shapes.push(polygon);
            }
            return shapes;
    
        }
    
    image
    1. 等时圈生成,并可视化
      使用turf进行处理,将大圈内的小圈叠加掉。
    function polygonize(contourList){
            var shapes = []
            var results=[];
            polygons = [];
            for(var cIndex=0;cIndex<contourList.length;cIndex++){
                var c=contourList[cIndex];
                var level=c.level;
                var shape=[];
                for(var k=0;k<c.length;k++){
                    shape.push([c[k].x, c[k].y])
                }
                shape.push(shape[0]);
                for (var p = shape.length; p<4; p++){
                    shape.push(shape[0]);
                }
                var polygon = turf.polygon([shape], { level: level });
                shapes.push(polygon);
            }
            for(var i=1;i<shapes.length;i++){
                var level=shapes[i].properties.level;
                var difference = turf.difference(shapes[i], shapes[i-1]);
                if(difference!=null){
                    difference.properties.level=level;
                    results.push(difference);
                }
            }
            return results;
        }
        
    
    image

    没有正儿八经的进行可视化,但也能看到和mapbox的效果相差不多。但是这个方案存在一个问题,就是mapbox的接口由于网络问题太不稳定。为了保证稳定性需要自己开发该接口,当然可以使用高德的接口 link

    相关文章

      网友评论

        本文标题:等时圈实现

        本文链接:https://www.haomeiwen.com/subject/rnwlqqtx.html