基于Openlayers3的地图轨迹及其优化

一、背景
项目线上系统经常出现一个问题,当地图轨迹点较多后者出现跨度较大的跳跃点时,地图缩放轨迹计算会导致浏览器比较卡,非常影响用户体验,根本原因是因为地图轨迹在进行缩放时,会在前端重新计算轨迹箭头图层的位置信息,当看到计算入口代码时,发现计算比较暴力,计算时间复杂度太高,需要进行优化,通过网上查询,发现一个博主的做法能有效降低计算的时间复杂度(https://blog.csdn.net/freeland1/article/details/82113809),但实践后发现其存在一个问题,当存在两个点间来回的轨迹时,其做法只能显示一个方向的箭头,没有展示反向的箭头。

二、轨迹绘制及优化

组件 地址
openlayers https://openlayers.org/
rbush https://unpkg.com/[email protected]/rbush.min.js

注意:openlayers版本需v3.13.0及以上,低版本不支持不支持getCoordinateAt方法

附地图缩放时,轨迹箭头更新逻辑代码:

	/**
    *地图缩放时,更新轨迹箭头
    */
    updateTrackArrowStyle: function (geometry, lineWidth, lineColor, arrowIcon) {
    	var _this = this;
    	var trackLine = geometry;
        var zoom = window.map.getView().getZoom();
        var distance = 57*(19-zoom)*(19-zoom);//箭头间隔随地图层级变化
        var styles = [
           new ol.style.Style({
             stroke: new ol.style.Stroke({
               color: lineColor,
               width: lineWidth
             })
           })
        ];
        var length = _this.getLineLength(trackLine);
        if(length < 2 * distance){
	       	if(length < distance){
	       		distance = length / 3;
	       	}else{
	       		distance = length / 4;
	       	}
        }
        //对segments建立btree索引
        var tree = rbush();//路段数
        var max_num = 1;
        var geomLength = 0;
        trackLine.forEachSegment(function(start, end) {
            var dx = end[0] - start[0];
            var dy = end[1] - start[1];
            var rotation = Math.atan2(dy, dx);
            var geom = new ol.geom.LineString([start,end]);
            var extent = geom.getExtent();
            geomLength += _this.getLineLength(geom);
            var min_num = max_num;
            max_num = parseInt(geomLength / distance);//计算每一段轨迹上箭头在整段轨迹中的索引
            var item = {
                minX: extent[0],
                minY: extent[1],
                maxX: extent[2],
                maxY: extent[3],
                geom: geom,
                min_num: min_num,
                max_num: max_num,
                rotation_o : null,
                rotation_n : null,
                rotation: rotation
            };
            tree.insert(item);
         });
         
         var recExtent = map.getView().calculateExtent(map.getSize());
         //箭头总数
         var arrowsNum = parseInt(length / distance);
         var isRepeat = true;
         for(var i = 1;i < arrowsNum;i++){
        	 var arrowIcon = arrowIcon;
        	 var arraw_coor = trackLine.getCoordinateAt(i*1.0/arrowsNum);
        	 var tol = 0.1;
        	 var 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]
             });
             var arrow_rotation;
             if(treeSearch.length == 1){
            	isRepeat = true;
            	arrow_rotation = treeSearch[0].rotation;
             }else if(treeSearch.length > 1){
            	 var results = treeSearch.filter(function(item){
            		 var _tol = 0.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){
                	 for(var j = 0;j < results.length;j++){
                		 if(i >= results[j].min_num && i <= results[j].max_num){//判断箭头是否在该段轨迹上
                			 if(i == results[j].min_num + 1){
                				 if(!results[j].rotation_o){
                					 isRepeat = true;
                					 for(var k=0;k<results.length;k++){
                						 results[k].rotation_o = results[j].rotation;
                					 }
                				 }else if(results[j].rotation_o == results[j].rotation){
                					 isRepeat = false;
                				 }else if(!results[j].rotation_n){
                					 isRepeat = true;
                					 for(var k=0;k<results.length;k++){
                						 results[k].rotation_n = results[j].rotation;
                					 }
                				 }else if(results[j].rotation_n == results[j].rotation){
                					 isRepeat = false;
                				 }
                			 }
                			 arrow_rotation = results[j].rotation;
                			 break;
                		 }
                	 }
                 }
             }
             if(isRepeat){//判断是否已显示,当轨迹来回次数比较多时,如果不去冲,会在轨迹上堆积很多箭头
            	 styles.push(new ol.style.Style({
            		 geometry: new ol.geom.Point(arraw_coor),
            		 image: new ol.style.Icon({
            			 src: arrowIcon,
            			 anchor: [0.75, 0.5],
            			 rotateWithView: false,
            			 rotation: -arrow_rotation
            		 })
            	 }));
             }
         }
         return styles;
    },
    /**
    *计算轨迹长度
    */
    getLineLength : function(line){
    	 var coordinates = line.getCoordinates();
         var length = 0;
         var sourceProj = map.getView().getProjection();
         for (var i = 0, ii = coordinates.length - 1; i < ii; ++i) {
             var c1 = ol.proj.transform(coordinates[i], sourceProj, 'EPSG:4326');
             var c2 = ol.proj.transform(coordinates[i + 1], sourceProj, 'EPSG:4326');
             length += new ol.Sphere(6378137).haversineDistance(c1, c2);
         }
         return (Math.round(length * 100) / 100);
    }

三、效果图
1、无来回点

2、有来回点

如果您有好的改进建议,还请留言,不吝赐教!

你可能感兴趣的:(Openlayer3)