1. 程式人生 > >Openlayers3 軌跡回放,點在線上運動, 解決linestring座標顯示不全

Openlayers3 軌跡回放,點在線上運動, 解決linestring座標顯示不全

記錄基於geoserver地圖服務,Openlayers3在web前端實現車輛軌跡回放功能,並記錄和解決過程中出現的linestring只描繪部分經緯度座標問題。
參考Openlayers3 官網例子
這裡寫圖片描述

html

<!DOCTYPE html>
<html lang="en">
<head>
    <title>車輛軌跡回放</title>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"
/>
<link rel="stylesheet" href="../css/bootstrap.min.css"/> <link rel="stylesheet" href="../ol/ol.css"/> <style> #map { position: relative; } .popover{ min-width: 60px; } html{height:100%} body{height:100%;margin
:0px
;padding:0px
}
</style> </head> <body style="margin: 0px 0px 0px 0px;line-height:0px;"> <div id="content"> <!--<div id="map" style="height: 100%;width:100%"></div>--> <div class="row-fluid"> <div> <div id="map" class="map"
>
</div> </div> </div> <div class="row-fluid"> <div class="span3" style="position:absolute;top:0px;right:0px;"> <div class="accordion-group widget-box"> <div class="accordion-heading"> <div class="widget-title"><a data-parent="#collapse-group" href="#collapseGOne" data-toggle="collapse"><span class="icon"><i class="icon-map-marker"></i></span> <h5>軌跡查詢</h5> </a> </div> </div> <div class="accordion-body in collapse" id="collapseGOne"> <div class="form-actions"> <div class="control-group" style="margin-bottom: 0px"> <label class="control-label"><i class="icon-truck"></i>裝置</label> <div class="controls"> <select id="busSelect" class="span10"> <option value="*">請選擇裝置</option> </select> </div> </div> </div> <div class="form-actions"> <div class="control-group" style="margin-bottom: 0px"> <label class="control-label"><i class="icon-table"></i>日期</label> <div class="controls"> <div data-date="" class="input-append date datepicker"> <input id="traceday" type="text" data-date-format="yyyy-mm-dd" class="span10" disabled> <span class="add-on"><i class="icon-time"></i></span></div> </div> </div> </div> <div style="padding: 19px 20px 20px; margin-top: 20px; margin-bottom: 20px;"> <div class="control-group" style="margin-bottom: 0px"> <button id="queryBtn" class="btn btn-primary"><i class="icon-search"></i>&nbsp;軌跡查詢</button> <span class="remind"></span> </div> <div class="control-group" style="margin-top: 10px"> <button id="animateBtn" class="btn btn-info"><i class="icon-eye-open"></i>&nbsp;軌跡回放</button> <input id="speed" type="range" min="1" max="100" step="10" value="10">&nbsp;<span><i class="icon-cog">速度</i></span> </div> </div> </div> </div> </div> </div> </div> </div> <script src="../js/lib/jquery.min.js"></script> <script src="../js/lib/bootstrap.min.js"></script> <script src="../ol/ol-debug.js"></script> <script src="../ol/ol.js"></script> <script src="../js/globalVariable.js"></script> <script src="../js/gpsQueryAndroid.js"></script> </body> </html>

map初始化


$(document).ready(function () {
    map = new ol.Map({
        logo: false,
        target: document.getElementById('map'),
        layers: layers,
        view: view
    });
    initSelect();//裝置下拉框列表初始化
     //時間控制元件初始化
    $('#s-traceday').val(transfromTime(new Date(),false)+" 00:00:00");
    $('#e-traceday').val(transfromTime(new Date(),true));
    $('.datepicker').datetimepicker({
        minView:0,
        format: 'yyyy-MM-dd hh:mm:ss', 
        todayBtn : "linked",  
        autoclose : true,  
        todayHighlight : true,
        startDate: daylimit,
        endDate:'+1d'//結束時間,在這時間之後都不可選
    });
});

//軌跡line layer
var vsource = new ol.source.Vector({
    type: 'LineString',
    features: []
});
var linelayers = new ol.layer.Vector({
    source: vsource,
    style: new ol.style.Style({
        fill: new ol.style.Fill({
            color: '#0044CC'
        }),
        stroke: new ol.style.Stroke({
            color: '#0044CC',
            width: 4
        })
    })
});
//地圖基礎引數
var map;
var center = [121.6606763113213, 31.14611063632111];
var lng, lat;
var source = new ol.source.Vector({
    wrapX: false
});;
var projection = new ol.proj.Projection({
    code: 'EPSG:4326',
    units: 'degrees',
    axisOrientation: 'neu'
});
var view = new ol.View({
    projection: projection,
    center: center,
    zoom: 16
});

var layers = [new ol.layer.Tile({
      title: '、地圖',
        visible: true,
        preload: Infinity,
        source: new ol.source.TileWMS({
            url: gisUrl,
            params: {
                'VERSION': '1.1.0',
                tiled: true,
                STYLES: '',
                LAYERS: 'shanghai:maptest',
            }
        })
    }),linelayers];

ajax獲取座標資料

    //軌跡查詢按鈕點選
var positions=[];
$("#queryBtn").click(function(){
    //清除之前的圖層
      if (centerSource.getFeatures != null) {
            centerSource.clear(); }
      linelayers.getSource().clear(true);
     positions=[];//清空
     //取值
    var busnum=$("#busSelect").val();
    var traceday=$("#traceday").val();
    if(busnum=="*"){
        $(".remind").html('<i class="icon-info-sign">請先選擇車輛</i>');
        return;
    }else{
        $(".remind").html('');
        busnum=busnum.slice(2);
    }
    if(transfromTime(new Date(),false)==traceday){//當天
        traceday="*";
    }else{
        traceday=traceday.replace(/(-)/g,"");
    }
    $(".remind").html('<i class="icon-cogs">  正在查詢...</i>');

    //請求
    $.getJSON(baseUrl+"trace/query/"+busnum+"/"+traceday,"",function(data){
          if(data.length==0){
              $(".remind").html('<i class="icon-info-sign">未查到gps資料</i>');return;
          }
        var position = [];
        for(var i = 0;i<data.length;i++){
                if(i!=0&&data[i].lon==data[i-1].lon&&data[i].lon==data[i-1].lon){//去除重複資料
                    continue;
                }
            position = [parseFloat(data[i].lon),parseFloat(data[i].lat)];
            positions.push(position);
        }
        console.log(positions);
        if(positions.length==1){
             $(".remind").html('<i class="icon-info-sign">該車輛當天停在該位置未啟動</i>');
             centerAt(positions[0]);
             return;
        }
        AddLayer(positions);
    });
});

顯示軌跡

//軌跡描繪
function AddLayer() {
    var lineFeature = new ol.Feature({//路線
        geometry: new ol.geom.LineString(positions,'XY'),
    });
    linelayers.getSource().addFeature(lineFeature);

    var startFeature = new ol.Feature({//起點
        geometry: new ol.geom.Point(positions[0]),
        population: 4000,
        rainfall: 500
    });
    startFeature.setStyle(startStyle);
    linelayers.getSource().addFeature(startFeature);
    var endFeature = new ol.Feature({//終點
        geometry: new ol.geom.Point(positions[positions.length-1]),
        population: 4000,
        rainfall: 500
    });
    endFeature.setStyle(endStyle);
    linelayers.getSource().addFeature(endFeature);


    carFeature = new ol.Feature({//車子
        geometry: new ol.geom.Point(positions[0]),
        population: 4000,
        rainfall: 500
    });
    carFeature.setStyle(carStyle);
    linelayers.getSource().addFeature(carFeature);
    var extent = linelayers.getSource().getExtent();//合適比例縮放居中
   view.fit(extent, map.getSize());
   }

顯示單點

//居中  車輛不運動時居中顯示圖示處理
var centerLayer = null;
var centerSource = new ol.source.Vector({
    features: null
});
//居中在一個位置
function centerAt(position) {
    var pan = ol.animation.pan({
        duration: 2000,
        source: (view.getCenter())
    });
    view.setCenter(position);

    var iconFeature = new ol.Feature({
        geometry: new ol.geom.Point(position),
        name: 'Null Island',
        population: 4000,
        rainfall: 500
    });
    iconFeature.setStyle(iconStyle);
    centerSource.addFeature(iconFeature);
    centerLayer = new ol.layer.Vector({
        source: centerSource
    });
    map.addLayer(centerLayer);
    centerLayer.setVisible(true);
}

點在線上運動,軌跡回放

//軌跡回放start  參考官網
var carFeature = null;
var speed, now;
var animating = false;
$("#animateBtn").click(function(){
    if(positions.length==0){
         $(".remind").html('<i class="icon-info-sign">請先查詢軌跡</i>');
            return;
    }
     if (animating) {
            stopAnimation(false);
          } else {
            animating = true;
            now = new Date().getTime();
            speed = $("#speed").val();//速度
            $("#animateBtn").html('<i class="icon-eye-close"></i>&nbsp;取消回放');
            carFeature.setStyle(null);
           // map.getView().setCenter(center);
            map.on('postcompose', moveFeature);
            map.render();
          }
});

var moveFeature = function(event) {
      var vectorContext = event.vectorContext;
      var frameState = event.frameState;

      if (animating) {
        var elapsedTime = frameState.time - now;
        // here the trick to increase speed is to jump some indexes
        // on lineString coordinates
        var index = Math.round(speed * elapsedTime / 1000);

        if (index >= positions.length) {
          stopAnimation(true);
          return;
        }

        var currentPoint = new ol.geom.Point(positions[index]);
        var feature = new ol.Feature(currentPoint);
        vectorContext.drawFeature(feature, carStyle);
      }
      // tell OL3 to continue the postcompose animation
      map.render();
    };

    function startAnimation() {
      if (animating) {
        stopAnimation(false);
      } else {
        animating = true;
        now = new Date().getTime();
        speed = speedInput.value;
        $("#animateBtn").html('<i class="icon-eye-close"></i>&nbsp;取消回放');
        // hide geoMarker
        geoMarker.setStyle(null);
        // just in case you pan somewhere else
        map.getView().setCenter(center);
        map.on('postcompose', moveFeature);
        map.render();
      }
    }

    function stopAnimation(ended) {
          animating = false;
          $("#animateBtn").html('<i class="icon-eye-open"></i>&nbsp;軌跡回放');

          // if animation cancelled set the marker at the beginning
          var coord = ended ? positions[positions.length - 1] : positions[0];
          /** @type {ol.geom.Point} */ (carFeature.getGeometry())
            .setCoordinates(coord);
          //remove listener
          map.un('postcompose', moveFeature);
        }
//軌跡回放end

解決linestring座標顯示不全

期間碰到一個問題,

 var lineFeature = new ol.Feature({//路線
        geometry: new ol.geom.LineString(positions,'XY'),
    });
    linelayers.getSource().addFeature(lineFeature);

呼叫這段程式碼顯示軌跡時,從資料庫取到20個座標,就可能只顯示4個座標,本來是彎曲的軌跡,但是實際上就是折線,很尷尬。
誤打誤撞,和同學 交流過程中發現問題所在,特此感謝。
在ajax獲取座標資料中發現問題所在:
原先錯誤程式碼

position = [data[i].lon,data[i].lat];
            positions.push(position);

正確程式碼

position = [parseFloat(data[i].lon),parseFloat(data[i].lat)];
            positions.push(position);

原因就是沒有把float型別的座標利用parseFloat強轉,導致預設的泛資料型別精確度不夠,經緯度小數點後末尾幾位就會被忽略,於是造成資料失效,描出的線就會有問題。

附上icon、起點、終點、車輛等地圖樣式

//樣式,供上述程式碼呼叫
var iconStyle = new ol.style.Style({
    image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({
        anchor: [0.5, 0.8],
        anchorXUnits: 'fraction',
        anchorYUnits: 'pixels',
        opacity: 0.75,
        src: 'img/iconfont-weizhi-red.png'
    }))
});
var startStyle = new ol.style.Style({
    image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({
         anchor: [0.5, 0.8],
         opacity: 0.8,
         src: 'img/start.png'
        /*anchorXUnits: 'fraction',
        anchorYUnits: 'pixels',
        opacity: 0.75,*/

    }))
});
var endStyle = new ol.style.Style({
    image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({
        src: 'img/end.png',
        anchor: [0.5, 0.8],
    }))
});
var carStyle = new ol.style.Style({
    image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({
        src: 'img/car.png',
        anchor: [0.5, 0.8],
    }))
});