七章-85-路径回放

2020-03-27  本文已影响0人  彩云飘过

本文基于腾讯课堂老胡的课《跟我学Openlayers--基础实例详解》做的学习笔记,使用的openlayers 5.3.x api。

源码 见 1085.html ,对应的 官网示例 https://openlayers.org/en/latest/examples/feature-move-animation.html?q=animation

image.png
核心技术点:
通过frameState.time和speed计算得到当前点位的index
根据index渲染对应的feature

image.png

<!DOCTYPE html>
<html>

<head>
 <title>路径回放</title>
 <link rel="stylesheet" href="../include/ol.css" type="text/css" />
 <script src="../include/ol.js"></script>
</head>
<style></style>

<body>
 <label for="speed">
   速度:&nbsp;
   <input id="speed" type="range" min="10" max="999" step="10" value="60">
 </label>
 <button id="start-animation">开始移动</button>
 <div id="map" class="map"></div>
 <div id="info">&nbsp;</div>
 <script>
   var polyline = [
     'hldhx@lnau`BCG_EaC??cFjAwDjF??uBlKMd@}@z@??aC^yk@z_@se@b[wFdE??wFfE}N',
     'fIoGxB_I\\gG}@eHoCyTmPqGaBaHOoD\\??yVrGotA|N??o[N_STiwAtEmHGeHcAkiA}^',
     'aMyBiHOkFNoI`CcVvM??gG^gF_@iJwC??eCcA]OoL}DwFyCaCgCcCwDcGwHsSoX??wI_E',
     'kUFmq@hBiOqBgTwS??iYse@gYq\\cp@ce@{vA}s@csJqaE}{@iRaqE{lBeRoIwd@_T{]_',
     'Ngn@{PmhEwaA{SeF_u@kQuyAw]wQeEgtAsZ}LiCarAkVwI}D??_}RcjEinPspDwSqCgs@',
     'sPua@_OkXaMeT_Nwk@ob@gV}TiYs[uTwXoNmT{Uyb@wNg]{Nqa@oDgNeJu_@_G}YsFw]k',
     'DuZyDmm@i_@uyIJe~@jCg|@nGiv@zUi_BfNqaAvIow@dEed@dCcf@r@qz@Egs@{Acu@mC',
     'um@yIey@gGig@cK_m@aSku@qRil@we@{mAeTej@}Tkz@cLgr@aHko@qOmcEaJw~C{w@ka',
     'i@qBchBq@kmBS{kDnBscBnFu_Dbc@_~QHeU`IuyDrC_}@bByp@fCyoA?qMbD}{AIkeAgB',
     'k_A_A{UsDke@gFej@qH{o@qGgb@qH{`@mMgm@uQus@kL{_@yOmd@ymBgwE}x@ouBwtA__',
     'DuhEgaKuWct@gp@cnBii@mlBa_@}|Asj@qrCg^eaC}L{dAaJ_aAiOyjByH{nAuYu`GsAw',
     'Xyn@ywMyOyqD{_@cfIcDe}@y@aeBJmwA`CkiAbFkhBlTgdDdPyiB`W}xDnSa}DbJyhCrX',
     'itAhT}x@bE}Z_@qW_Kwv@qKaaAiBgXvIm}A~JovAxCqW~WanB`XewBbK{_A`K}fBvAmi@',
     'xBycBeCauBoF}}@qJioAww@gjHaPopA_NurAyJku@uGmi@cDs[eRaiBkQstAsQkcByNma',
     'CsK_uBcJgbEw@gkB_@ypEqDoqSm@eZcDwjBoGw`BoMegBaU_`Ce_@_uBqb@ytBwkFqiT_',
     'fAqfEwe@mfCka@_eC_UmlB}MmaBeWkkDeHwqAoX}~DcBsZmLcxBqOwqE_DkyAuJmrJ\\o',
     '~CfIewG|YibQxBssB?es@qGciA}RorAoVajA_nAodD{[y`AgPqp@mKwr@ms@umEaW{dAm',
     'b@umAw|@ojBwzDaaJsmBwbEgdCsrFqhAihDquAi`Fux@}_Dui@_eB_u@guCuyAuiHukA_',
     'lKszAu|OmaA{wKm}@clHs_A_rEahCssKo\\sgBsSglAqk@yvDcS_wAyTwpBmPc|BwZknF',
     'oFscB_GsaDiZmyMyLgtHgQonHqT{hKaPg}Dqq@m~Hym@c`EuiBudIabB{hF{pWifx@snA',
     'w`GkFyVqf@y~BkoAi}Lel@wtc@}`@oaXi_C}pZsi@eqGsSuqJ|Lqeb@e]kgPcaAu}SkDw',
     'zGhn@gjYh\\qlNZovJieBqja@ed@siO{[ol\\kCmjMe\\isHorCmec@uLebB}EqiBaCg}',
     '@m@qwHrT_vFps@kkI`uAszIrpHuzYxx@e{Crw@kpDhN{wBtQarDy@knFgP_yCu\\wyCwy',
     'A{kHo~@omEoYmoDaEcPiuAosDagD}rO{{AsyEihCayFilLaiUqm@_bAumFo}DgqA_uByi',
     '@swC~AkzDlhA}xEvcBa}Cxk@ql@`rAo|@~bBq{@``Bye@djDww@z_C_cAtn@ye@nfC_eC',
     '|gGahH~s@w}@``Fi~FpnAooC|u@wlEaEedRlYkrPvKerBfYs}Arg@m}AtrCkzElw@gjBb',
     'h@woBhR{gCwGkgCc[wtCuOapAcFoh@uBy[yBgr@c@iq@o@wvEv@sp@`FajBfCaq@fIipA',
     'dy@ewJlUc`ExGuaBdEmbBpBssArAuqBBg}@s@g{AkB{bBif@_bYmC}r@kDgm@sPq_BuJ_',
     's@{X_{AsK_d@eM{d@wVgx@oWcu@??aDmOkNia@wFoSmDyMyCkPiBePwAob@XcQ|@oNdCo',
     'SfFwXhEmOnLi\\lbAulB`X_d@|k@au@bc@oc@bqC}{BhwDgcD`l@ed@??bL{G|a@eTje@',
     'oS~]cLr~Bgh@|b@}Jv}EieAlv@sPluD{z@nzA_]`|KchCtd@sPvb@wSb{@ko@f`RooQ~e',
     '[upZbuIolI|gFafFzu@iq@nMmJ|OeJn^{Qjh@yQhc@uJ~j@iGdd@kAp~BkBxO{@|QsAfY',
     'gEtYiGd]}Jpd@wRhVoNzNeK`j@ce@vgK}cJnSoSzQkVvUm^rSgc@`Uql@xIq\\vIgg@~k',
     'Dyq[nIir@jNoq@xNwc@fYik@tk@su@neB}uBhqEesFjoGeyHtCoD|D}Ed|@ctAbIuOzqB',
     '_}D~NgY`\\um@v[gm@v{Cw`G`w@o{AdjAwzBh{C}`Gpp@ypAxn@}mAfz@{bBbNia@??jI',
     'ab@`CuOlC}YnAcV`@_^m@aeB}@yk@YuTuBg^uCkZiGk\\yGeY}Lu_@oOsZiTe[uWi[sl@',
     'mo@soAauAsrBgzBqgAglAyd@ig@asAcyAklA}qAwHkGi{@s~@goAmsAyDeEirB_{B}IsJ',
     'uEeFymAssAkdAmhAyTcVkFeEoKiH}l@kp@wg@sj@ku@ey@uh@kj@}EsFmG}Jk^_r@_f@m',
     '~@ym@yjA??a@cFd@kBrCgDbAUnAcBhAyAdk@et@??kF}D??OL'
   ].join('');

   var route = (new ol.format.Polyline({
     factor: 1e6
   }).readGeometry(polyline, {
     dataProjection: 'EPSG:4326',
     featureProjection: 'EPSG:3857'
   }));

   console.dir(route)

   //获取轨迹上的所有点坐标
   var routeCoords = route.getCoordinates();
   var routeLength = routeCoords.length;
   console.log('routeLength = '+routeLength) //routeLength = 542

   var routeFeature = new ol.Feature({
     type: 'route',
     geometry: route
   });
   var geoMarker = new ol.Feature({
     type: 'geoMarker',
     geometry: new ol.geom.Point(routeCoords[0])
   });
   var startMarker = new ol.Feature({
     type: 'icon',
     geometry: new ol.geom.Point(routeCoords[0])
   });
   var endMarker = new ol.Feature({
     type: 'icon',
     geometry: new ol.geom.Point(routeCoords[routeLength - 1])
   });

   var styles = {
     'route': new ol.style.Style({
       stroke: new ol.style.Stroke({
         width: 6, color: [237, 212, 0, 0.8]
       })
     }),
     'icon': new ol.style.Style({
       image: new ol.style.Icon({
         anchor: [0.5, 1],
         src: '../data/icon.png'
       })
     }),
     'geoMarker': new ol.style.Style({
       image: new ol.style.Circle({
         radius: 7,
         fill: new ol.style.Fill({ color: 'black' }),
         stroke: new ol.style.Stroke({
           color: 'white', width: 2
         })
       })
     })
   };

   var animating = false; //标记当时是否执行动画
   var speed, now;
   var speedInput = document.getElementById('speed');
   var startButton = document.getElementById('start-animation');

   var vectorLayer = new ol.layer.Vector({
     source: new ol.source.Vector({
       features: [routeFeature, geoMarker, startMarker, endMarker]
     }),
     style: function (feature) {

       if (animating && feature.get('type') === 'geoMarker') {
         return null;
       }
       return styles[feature.get('type')];
     }
   });

   var center = [-5639523.95, -3501274.52];
   var map = new ol.Map({
     target: document.getElementById('map'),
     loadTilesWhileAnimating: true,
     view: new ol.View({
       center: center,
       zoom: 10,
       minZoom: 2,
       maxZoom: 19
     }),
     layers: [
       new ol.layer.Tile({
         source: new ol.source.BingMaps({
           imagerySet: 'AerialWithLabels',
           key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5'
         })
       }),
       vectorLayer
     ]
   });

   var moveFeature = function (event) {
     var vectorContext = event.vectorContext;
     var frameState = event.frameState;
     
     
     if (animating) {
       var elapsedTime = frameState.time - now; //获取动画已经执行的时间

       var index = Math.round(speed * elapsedTime / 1000); //获取到当前应画到的点的索引,index = (当前选中速度 * 已经执行的时间 / 最大速度值)
       console.log(' 已经动画时间 = '+elapsedTime) //
       console.log(' 当前index = '+index +'  ,speed = '+speed) //
       
       if (index >= routeLength) {
         stopAnimation(true); //动画结束条件
         return;
       }

       var currentPoint = new ol.geom.Point(routeCoords[index]);
       var feature = new ol.Feature(currentPoint);
       vectorContext.drawFeature(feature, styles.geoMarker);
     }

     map.render();//执行此函数时,又会触发postcompose事件;触发postcompose事件后,会执行函数moveFeature
   };

   function startAnimation() {
     if (animating) {
       stopAnimation(false);
     } else {
       animating = true;
       now = new Date().getTime();
       speed = speedInput.value;
       startButton.textContent = '停止移动';
       geoMarker.setStyle(null);//把动画的样式先隐藏,一会为了让它有动画的效果

       map.getView().setCenter(center);
       map.on('postcompose', moveFeature);
       map.render();
     }
   }

   //若动画结束为终点,则把移动点设置到终点;否则把移动点设置到起点。
   function stopAnimation(ended) {
     animating = false;
     startButton.textContent = '开始移动';


     var coord = ended ? routeCoords[routeLength - 1] : routeCoords[0];
     geoMarker.getGeometry().setCoordinates(coord);

     map.un('postcompose', moveFeature);
   }

   startButton.addEventListener('click', startAnimation, false);


 </script>
</body>

</html>
上一篇下一篇

猜你喜欢

热点阅读