基于OpenLayers+rbush+turf实现高德轨迹样式

<!DOCTYPE html>
<html>
<head>
    <title>基于OpenLayers+rbush+turf实现高德轨迹样式</title>
    <link rel="stylesheet" href="https://openlayers.org/en/v4.6.5/css/ol.css" type="text/css">
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
    <script src="https://openlayers.org/en/v4.6.5/build/ol.js"></script>
    <script src="https://unpkg.com/rbush@2.0.1/rbush.js"></script>
    <script src='https://npmcdn.com/@turf/turf/turf.min.js'></script>
</head>
<body>
<div id="map" class="map"></div>
<canvas id="canvas" width="5" height="10"></canvas>
<script>
    var canvas = document.getElementById("canvas");
    drawArrowImage(canvas,9,5);
    var raster = new ol.layer.Tile({
        source: new ol.source.OSM()
    });
    
    var map = new ol.Map({
        layers: [raster],
        target: 'map',
        view: new ol.View({
            center: [-0, 0],
            zoom: 4
        })
    });
    
    var source = new ol.source.Vector({wrapX: false});
    var vector = new ol.layer.Vector();
    map.addLayer(vector);
    vector.setStyle(styleFunction);
    vector.setSource(source);
    
    
    function drawArrowImage(canvas,height,width){
        canvas.width = width;
        canvas.height = height;
        let ctx = canvas.getContext("2d");
        if(height<2)return;
        if(width<1)return;
        ctx.lineWidth = 2;
        ctx.strokeStyle = "#faf4ff";
        ctx.beginPath();
        ctx.moveTo(0,0);
        ctx.lineTo(width,height/2.0);
        ctx.lineTo(0,height);
        ctx.stroke();
    }

    function styleFunction(feature,res){
        let styles = [];

        styles = [
            new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: '#393bff',
                    width: 10
                })
            })
        ];

        let trackLine= feature.getGeometry();
        if(trackLine instanceof ol.geom.LineString){
            //对segments建立btree索引
            let tree= rbush();//路段数
            trackLine.forEachSegment(function(start, end) {
                var dx = end[0] - start[0];
                var dy = end[1] - start[1];
                //计算每个segment的方向,即箭头旋转方向
                let rotation = Math.atan2(dy, dx);
                let geom=new ol.geom.LineString([start,end]);
                let extent=geom.getExtent();
                let item = {
                    minX: extent[0],
                    minY: extent[1],
                    maxX: extent[2],
                    maxY: extent[3],
                    geom: geom,
                    rotation:rotation
                };
                tree.insert(item);
            });
            //轨迹地理长度
            let length=trackLine.getLength();
            //像素间隔步长
            let stpes=40;//像素步长间隔
            //将像素步长转实际地理距离步长
            let geo_steps=stpes*res;
            //箭头总数
            let arrowsNum=parseInt(length/geo_steps);
            for(let i=1;i<arrowsNum;i++){
                let arraw_coor=trackLine.getCoordinateAt(i*1.0/arrowsNum);
                let tol=10;//查询设置的点的容差,测试地图单位是米。如果是4326坐标系单位为度的话,改成0.0001.
                let arraw_coor_buffer=[arraw_coor[0]-tol,arraw_coor[1]-tol,arraw_coor[0]+tol,arraw_coor[1]+tol];
                //进行btree查询
                var treeSearch = tree.search({
                    minX: arraw_coor_buffer[0],
                    minY: arraw_coor_buffer[1],
                    maxX: arraw_coor_buffer[2],
                    maxY: arraw_coor_buffer[3]
                });
                let arrow_rotation;
                //只查询一个,那么肯定是它了,直接返回
                if(treeSearch.length==1)
                    arrow_rotation=treeSearch[0].rotation;
                else if(treeSearch.length>1){
                    let results=treeSearch.filter(function(item){
                        //换一种方案,设置一个稍小的容差,消除精度问题
                        let _tol=1;//消除精度误差的容差
                        if(item.geom.intersectsExtent([arraw_coor[0]-_tol,arraw_coor[1]-_tol,arraw_coor[0]+_tol,arraw_coor[1]+_tol]))
                            return true;
                    })
                    if(results.length>0)
                        arrow_rotation=results[0].rotation;
                }
                styles.push(new ol.style.Style({
                    geometry: new ol.geom.Point(arraw_coor),
                    image: new ol.style.Icon({
                        img: canvas,
                        imgSize:[canvas.width,canvas.height],
                        rotation: -arrow_rotation
                    })
                }));
            }
        }

        return styles;
    }

    
    function createLine(){
        var coords = [[-1000000,1000000],[0,0],[100000,1000000]];
        var mLine = new ol.geom.LineString(coords);
        var mFeatrue = new ol.Feature({
            geometry:mLine
        })
        mFeatrue.set("type","arrow");
        source.addFeature(mFeatrue);
    }
    
    function clipByRect(oLine,oRect) {
        let lineResult ;
        if(oLine && oRect)
        {
            let coords = oLine.getCoordinates();
            oLine = turf.lineString(coords);
            lineResult = turf.bboxClip(oLine,oRect);
            let temp = lineResult.geometry.coordinates;
            lineResult = new ol.geom.LineString(temp);

        }
        return lineResult;
    }
    
    createLine();
</script>
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小蝇工作室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值