From 5541e9a2368caa9b38bf898ac9d3f904fbc76c94 Mon Sep 17 00:00:00 2001 From: jonataswalker Date: Mon, 19 Oct 2015 07:54:06 -0200 Subject: [PATCH 1/3] Add 'Move a feature along a line' example --- examples/feature-move-animation.html | 24 ++++ examples/feature-move-animation.js | 198 +++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 examples/feature-move-animation.html create mode 100644 examples/feature-move-animation.js diff --git a/examples/feature-move-animation.html b/examples/feature-move-animation.html new file mode 100644 index 0000000000..e75b4d7450 --- /dev/null +++ b/examples/feature-move-animation.html @@ -0,0 +1,24 @@ +--- +template: example.html +title: Animate a feature movement +shortdesc: Demonstrates how to move a feature along a line. +docs: > + This example shows how to use postcompose and vectorContext to + animate a (marker) feature along a line. In this example an encoded polyline + is being used. +tags: "animation, feature, postcompose, polyline" +--- +
+
+
+
+
+
+
+ + +
+
diff --git a/examples/feature-move-animation.js b/examples/feature-move-animation.js new file mode 100644 index 0000000000..79f2dcda11 --- /dev/null +++ b/examples/feature-move-animation.js @@ -0,0 +1,198 @@ +goog.require('ol.Feature'); +goog.require('ol.Map'); +goog.require('ol.View'); +goog.require('ol.format.Polyline'); +goog.require('ol.geom.Point'); +goog.require('ol.layer.Tile'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.BingMaps'); +goog.require('ol.source.Vector'); +goog.require('ol.style.Circle'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Icon'); +goog.require('ol.style.Stroke'); +goog.require('ol.style.Style'); + +// This long string is placed here due to jsFiddle limitations. +// It is usually loaded with AJAX. +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' +}); + +var routeCoords = route.getCoordinates(); +var routeLength = routeCoords.length; + +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, + snapToPixel: false, + fill: new ol.style.Fill({color: 'black'}), + stroke: new ol.style.Stroke({ + color: 'white', width: 2 + }) + }) + }) +}; + +var vectorLayer = new ol.layer.Vector({ + source: new ol.source.Vector({ + features: [routeFeature, geoMarker, startMarker, endMarker] + }), + style: function(feature, resolution) { + // hide geoMarker if animation is active + if (animating && feature.get('type') === 'geoMarker') { + return []; + } + 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: 'Ak-dzM4wZjSqTlzveKz5u0d4IQ4bRzVI309GxmkgSVr1ewS6iPSrOvOKhA-CJlm3' + }) + }), + vectorLayer + ] +}); + +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 >= routeLength) { + stopAnimation(true); + return; + } + + var currentPoint = new ol.geom.Point(routeCoords[index]); + var feature = new ol.Feature(currentPoint); + vectorContext.drawFeature(feature, styles.geoMarker); + } + // tell OL3 to continue the postcompose animation + frameState.animate = true; +}; + +function startAnimation() { + if (animating) { + stopAnimation(); + } else { + animating = true; + now = new Date().getTime(); + speed = speedInput.value; + startButton.textContent = 'Cancel Animation'; + // 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; + startButton.textContent = 'Start Animation'; + + // if animation cancelled set the marker at the beginning + var coord = ended ? routeCoords[routeLength - 1] : routeCoords[0]; + geoMarker.getGeometry().setCoordinates(coord); + map.un('postcompose', moveFeature); +} + +var speed, now; +var animating = false; +var speedInput = document.getElementById('speed'); +var startButton = document.getElementById('start-animation'); +startButton.addEventListener('click', startAnimation, false); From e5c2a226dd23b986e4f261de8dc031b021520834 Mon Sep 17 00:00:00 2001 From: jonataswalker Date: Mon, 19 Oct 2015 08:40:59 -0200 Subject: [PATCH 2/3] Add 'Move a feature along a line' example --- examples/feature-move-animation.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/feature-move-animation.js b/examples/feature-move-animation.js index 79f2dcda11..184db9b9e7 100644 --- a/examples/feature-move-animation.js +++ b/examples/feature-move-animation.js @@ -57,12 +57,12 @@ var polyline = [ '~@ym@yjA??a@cFd@kBrCgDbAUnAcBhAyAdk@et@??kF}D??OL' ].join(''); -var route = new ol.format.Polyline({ +var route = /** @type {ol.geom.LineString} */ (new ol.format.Polyline({ factor: 1e6 }).readGeometry(polyline, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' -}); +})); var routeCoords = route.getCoordinates(); var routeLength = routeCoords.length; @@ -167,7 +167,7 @@ var moveFeature = function(event) { function startAnimation() { if (animating) { - stopAnimation(); + stopAnimation(false); } else { animating = true; now = new Date().getTime(); @@ -181,13 +181,20 @@ function startAnimation() { map.render(); } } + + +/** + * @param {boolean} ended end of animation. + */ function stopAnimation(ended) { animating = false; startButton.textContent = 'Start Animation'; // if animation cancelled set the marker at the beginning var coord = ended ? routeCoords[routeLength - 1] : routeCoords[0]; - geoMarker.getGeometry().setCoordinates(coord); + /** @type {ol.geom.Point} */ (geoMarker.getGeometry()) + .setCoordinates(coord); + //remove listener map.un('postcompose', moveFeature); } From 9e252518918fc3fb0246d0b84c18c013be77ede9 Mon Sep 17 00:00:00 2001 From: jonataswalker Date: Fri, 30 Oct 2015 18:50:04 -0200 Subject: [PATCH 3/3] Add 'Move a feature along a line' example --- examples/feature-move-animation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/feature-move-animation.js b/examples/feature-move-animation.js index 184db9b9e7..e1b803448b 100644 --- a/examples/feature-move-animation.js +++ b/examples/feature-move-animation.js @@ -162,7 +162,7 @@ var moveFeature = function(event) { vectorContext.drawFeature(feature, styles.geoMarker); } // tell OL3 to continue the postcompose animation - frameState.animate = true; + map.render(); }; function startAnimation() {