Openlayers3實現車輛軌跡回放功能
阿新 • • 發佈:2020-10-03
記錄基於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> 軌跡查詢</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> 軌跡回放</button> <input id="speed" type="range" min="1" max="100" step="10" value="10"> <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]),rainfall: 500 }); endFeature.setStyle(endStyle); linelayers.getSource().addFeature(endFeature); carFeature = new ol.Feature({//車子 geometry: new ol.geom.Point(positions[0]),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',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> 取消回放'); 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> 取消回放'); // 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> 軌跡回放'); // 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,}); 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,opacity: 0.8,src: 'img/start.png' /*anchorXUnits: 'fraction',*/ })) }); var endStyle = new ol.style.Style({ image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({ src: 'img/end.png',anchor: [0.5,})) }); var carStyle = new ol.style.Style({ image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({ src: 'img/car.png',})) });
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。