├── LICENSE ├── README.md ├── markerAnimate.js └── demo ├── markermove.html └── jquery_easing.js /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012 Robert Gerlach 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Animated marker movement in Google Maps 2 | 3 | **For a much nicer and unobtrusive marker animation library based on this one, check out [marker-animate-unobtrusive](https://github.com/terikon/marker-animate-unobtrusive)** 4 | 5 | A nice alternative to `marker.setPosition(latLng)`. Include jQuery and jQuery Easing Plugin for more easing options. 6 | 7 | Demo: http://robsite.net/static/markermove/markermove.html (click on the map) 8 | 9 | ## Usage 10 | 11 | Include `markerAnimate.js` after Google Maps and call `animateTo` on a `google.maps.Marker`: 12 | 13 | // params: 14 | // newPosition - the new Position as google.maps.LatLng() 15 | // options.duration - animation duration in ms (default 1000) 16 | // options.easing - easing function from jQuery and/or the jQuery easing plugin (default 'linear') 17 | // options.complete - callback function. Gets called, after the animation has finished 18 | 19 | marker.animateTo(newPosition [, {easing: 'easeOutBounce', duration: 1000, complete: function(){}}]); 20 | 21 | ## Example 22 | 23 | var marker = new google.maps.Marker({position: new google.maps.LatLng(0,0), map: myMap, title: 'Hello World!'}); 24 | var newPosition = new google.maps.LatLng(13,42); 25 | 26 | // move marker in 1000ms and with linear animation. 27 | marker.animateTo(newPosition); 28 | 29 | // or with callback and options for easing and duration in milliseconds. Needs jQuery Easing Plugin. 30 | marker.animateTo(newPosition, { easing: "easeOutBounce", 31 | duration: 1000, 32 | complete: function() { 33 | alert("animation complete"); 34 | } 35 | }); 36 | -------------------------------------------------------------------------------- /markerAnimate.js: -------------------------------------------------------------------------------- 1 | // Animated Marker Movement. Robert Gerlach 2012-2013 https://github.com/combatwombat/marker-animate 2 | // MIT license 3 | // 4 | // params: 5 | // newPosition - the new Position as google.maps.LatLng() 6 | // options - optional options object (optional) 7 | // options.duration - animation duration in ms (default 1000) 8 | // options.easing - easing function from jQuery and/or the jQuery easing plugin (default 'linear') 9 | // options.complete - callback function. Gets called, after the animation has finished 10 | // options.pan - can be 'center', 'inbounds', or null. center keeps marker centered, in bounds keeps it in bounds (default null) 11 | google.maps.Marker.prototype.animateTo = function(newPosition, options) { 12 | defaultOptions = { 13 | duration: 1000, 14 | easing: 'linear', 15 | complete: null, 16 | pan: null 17 | } 18 | options = options || {}; 19 | 20 | // complete missing options 21 | for (key in defaultOptions) { 22 | options[key] = options[key] || defaultOptions[key]; 23 | } 24 | 25 | // throw exception if easing function doesn't exist 26 | if (options.easing != 'linear') { 27 | if (typeof jQuery == 'undefined' || !jQuery.easing[options.easing]) { 28 | throw '"' + options.easing + '" easing function doesn\'t exist. Include jQuery and/or the jQuery easing plugin and use the right function name.'; 29 | return; 30 | } 31 | } 32 | 33 | // make sure the pan option is valid 34 | if (options.pan !== null) { 35 | if (options.pan !== 'center' && options.pan !== 'inbounds') { 36 | return; 37 | } 38 | } 39 | 40 | window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; 41 | window.cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame; 42 | 43 | // save current position. prefixed to avoid name collisions. separate for lat/lng to avoid calling lat()/lng() in every frame 44 | this.AT_startPosition_lat = this.getPosition().lat(); 45 | this.AT_startPosition_lng = this.getPosition().lng(); 46 | var newPosition_lat = newPosition.lat(); 47 | var newPosition_lng = newPosition.lng(); 48 | var newPoint = new google.maps.LatLng(newPosition.lat(), newPosition.lng()); 49 | 50 | if (options.pan === 'center') { 51 | this.map.setCenter(newPoint); 52 | } 53 | 54 | if (options.pan === 'inbounds') { 55 | if (!this.map.getBounds().contains(newPoint)) { 56 | var mapbounds = this.map.getBounds(); 57 | mapbounds.extend(newPoint); 58 | this.map.fitBounds(mapbounds); 59 | } 60 | } 61 | 62 | // crossing the 180° meridian and going the long way around the earth? 63 | if (Math.abs(newPosition_lng - this.AT_startPosition_lng) > 180) { 64 | if (newPosition_lng > this.AT_startPosition_lng) { 65 | newPosition_lng -= 360; 66 | } else { 67 | newPosition_lng += 360; 68 | } 69 | } 70 | 71 | var animateStep = function(marker, startTime) { 72 | var ellapsedTime = (new Date()).getTime() - startTime; 73 | var durationRatio = ellapsedTime / options.duration; // 0 - 1 74 | var easingDurationRatio = durationRatio; 75 | 76 | // use jQuery easing if it's not linear 77 | if (options.easing !== 'linear') { 78 | easingDurationRatio = jQuery.easing[options.easing](durationRatio, ellapsedTime, 0, 1, options.duration); 79 | } 80 | 81 | if (durationRatio < 1) { 82 | var deltaPosition = new google.maps.LatLng(marker.AT_startPosition_lat + (newPosition_lat - marker.AT_startPosition_lat) * easingDurationRatio, 83 | marker.AT_startPosition_lng + (newPosition_lng - marker.AT_startPosition_lng) * easingDurationRatio); 84 | marker.setPosition(deltaPosition); 85 | 86 | // use requestAnimationFrame if it exists on this browser. If not, use setTimeout with ~60 fps 87 | if (window.requestAnimationFrame) { 88 | marker.AT_animationHandler = window.requestAnimationFrame(function() { 89 | animateStep(marker, startTime) 90 | }); 91 | } else { 92 | marker.AT_animationHandler = setTimeout(function() { 93 | animateStep(marker, startTime) 94 | }, 17); 95 | } 96 | 97 | } else { 98 | 99 | marker.setPosition(newPosition); 100 | 101 | if (typeof options.complete === 'function') { 102 | options.complete(); 103 | } 104 | 105 | } 106 | } 107 | 108 | // stop possibly running animation 109 | if (window.cancelAnimationFrame) { 110 | window.cancelAnimationFrame(this.AT_animationHandler); 111 | } else { 112 | clearTimeout(this.AT_animationHandler); 113 | } 114 | 115 | animateStep(this, (new Date()).getTime()); 116 | } -------------------------------------------------------------------------------- /demo/markermove.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Google Maps Animated Marker Move Demo 8 | 9 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 114 | 115 | 116 |
117 | 118 |
119 |
120 | 121 | 155 |
156 |
157 | 158 | 159 |
160 | 163 | 164 |
165 | 166 | 167 | -------------------------------------------------------------------------------- /demo/jquery_easing.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ 3 | * 4 | * Uses the built in easing capabilities added In jQuery 1.1 5 | * to offer multiple easing options 6 | * 7 | * TERMS OF USE - jQuery Easing 8 | * 9 | * Open source under the BSD License. 10 | * 11 | * Copyright © 2008 George McGinley Smith 12 | * All rights reserved. 13 | * 14 | * Redistribution and use in source and binary forms, with or without modification, 15 | * are permitted provided that the following conditions are met: 16 | * 17 | * Redistributions of source code must retain the above copyright notice, this list of 18 | * conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this list 20 | * of conditions and the following disclaimer in the documentation and/or other materials 21 | * provided with the distribution. 22 | * 23 | * Neither the name of the author nor the names of contributors may be used to endorse 24 | * or promote products derived from this software without specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 27 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 28 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 30 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 31 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 34 | * OF THE POSSIBILITY OF SUCH DAMAGE. 35 | * 36 | */ 37 | 38 | // t: current time, b: begInnIng value, c: change In value, d: duration 39 | jQuery.easing['jswing'] = jQuery.easing['swing']; 40 | 41 | jQuery.extend( jQuery.easing, 42 | { 43 | def: 'easeOutQuad', 44 | swing: function (x, t, b, c, d) { 45 | //alert(jQuery.easing.default); 46 | return jQuery.easing[jQuery.easing.def](x, t, b, c, d); 47 | }, 48 | easeInQuad: function (x, t, b, c, d) { 49 | return c*(t/=d)*t + b; 50 | }, 51 | easeOutQuad: function (x, t, b, c, d) { 52 | return -c *(t/=d)*(t-2) + b; 53 | }, 54 | easeInOutQuad: function (x, t, b, c, d) { 55 | if ((t/=d/2) < 1) return c/2*t*t + b; 56 | return -c/2 * ((--t)*(t-2) - 1) + b; 57 | }, 58 | easeInCubic: function (x, t, b, c, d) { 59 | return c*(t/=d)*t*t + b; 60 | }, 61 | easeOutCubic: function (x, t, b, c, d) { 62 | return c*((t=t/d-1)*t*t + 1) + b; 63 | }, 64 | easeInOutCubic: function (x, t, b, c, d) { 65 | if ((t/=d/2) < 1) return c/2*t*t*t + b; 66 | return c/2*((t-=2)*t*t + 2) + b; 67 | }, 68 | easeInQuart: function (x, t, b, c, d) { 69 | return c*(t/=d)*t*t*t + b; 70 | }, 71 | easeOutQuart: function (x, t, b, c, d) { 72 | return -c * ((t=t/d-1)*t*t*t - 1) + b; 73 | }, 74 | easeInOutQuart: function (x, t, b, c, d) { 75 | if ((t/=d/2) < 1) return c/2*t*t*t*t + b; 76 | return -c/2 * ((t-=2)*t*t*t - 2) + b; 77 | }, 78 | easeInQuint: function (x, t, b, c, d) { 79 | return c*(t/=d)*t*t*t*t + b; 80 | }, 81 | easeOutQuint: function (x, t, b, c, d) { 82 | return c*((t=t/d-1)*t*t*t*t + 1) + b; 83 | }, 84 | easeInOutQuint: function (x, t, b, c, d) { 85 | if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; 86 | return c/2*((t-=2)*t*t*t*t + 2) + b; 87 | }, 88 | easeInSine: function (x, t, b, c, d) { 89 | return -c * Math.cos(t/d * (Math.PI/2)) + c + b; 90 | }, 91 | easeOutSine: function (x, t, b, c, d) { 92 | return c * Math.sin(t/d * (Math.PI/2)) + b; 93 | }, 94 | easeInOutSine: function (x, t, b, c, d) { 95 | return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; 96 | }, 97 | easeInExpo: function (x, t, b, c, d) { 98 | return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; 99 | }, 100 | easeOutExpo: function (x, t, b, c, d) { 101 | return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; 102 | }, 103 | easeInOutExpo: function (x, t, b, c, d) { 104 | if (t==0) return b; 105 | if (t==d) return b+c; 106 | if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; 107 | return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; 108 | }, 109 | easeInCirc: function (x, t, b, c, d) { 110 | return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; 111 | }, 112 | easeOutCirc: function (x, t, b, c, d) { 113 | return c * Math.sqrt(1 - (t=t/d-1)*t) + b; 114 | }, 115 | easeInOutCirc: function (x, t, b, c, d) { 116 | if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; 117 | return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; 118 | }, 119 | easeInElastic: function (x, t, b, c, d) { 120 | var s=1.70158;var p=0;var a=c; 121 | if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 122 | if (a < Math.abs(c)) { a=c; var s=p/4; } 123 | else var s = p/(2*Math.PI) * Math.asin (c/a); 124 | return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 125 | }, 126 | easeOutElastic: function (x, t, b, c, d) { 127 | var s=1.70158;var p=0;var a=c; 128 | if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 129 | if (a < Math.abs(c)) { a=c; var s=p/4; } 130 | else var s = p/(2*Math.PI) * Math.asin (c/a); 131 | return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; 132 | }, 133 | easeInOutElastic: function (x, t, b, c, d) { 134 | var s=1.70158;var p=0;var a=c; 135 | if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); 136 | if (a < Math.abs(c)) { a=c; var s=p/4; } 137 | else var s = p/(2*Math.PI) * Math.asin (c/a); 138 | if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 139 | return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; 140 | }, 141 | easeInBack: function (x, t, b, c, d, s) { 142 | if (s == undefined) s = 1.70158; 143 | return c*(t/=d)*t*((s+1)*t - s) + b; 144 | }, 145 | easeOutBack: function (x, t, b, c, d, s) { 146 | if (s == undefined) s = 1.70158; 147 | return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; 148 | }, 149 | easeInOutBack: function (x, t, b, c, d, s) { 150 | if (s == undefined) s = 1.70158; 151 | if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; 152 | return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; 153 | }, 154 | easeInBounce: function (x, t, b, c, d) { 155 | return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b; 156 | }, 157 | easeOutBounce: function (x, t, b, c, d) { 158 | if ((t/=d) < (1/2.75)) { 159 | return c*(7.5625*t*t) + b; 160 | } else if (t < (2/2.75)) { 161 | return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; 162 | } else if (t < (2.5/2.75)) { 163 | return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; 164 | } else { 165 | return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; 166 | } 167 | }, 168 | easeInOutBounce: function (x, t, b, c, d) { 169 | if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; 170 | return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; 171 | } 172 | }); 173 | 174 | /* 175 | * 176 | * TERMS OF USE - EASING EQUATIONS 177 | * 178 | * Open source under the BSD License. 179 | * 180 | * Copyright © 2001 Robert Penner 181 | * All rights reserved. 182 | * 183 | * Redistribution and use in source and binary forms, with or without modification, 184 | * are permitted provided that the following conditions are met: 185 | * 186 | * Redistributions of source code must retain the above copyright notice, this list of 187 | * conditions and the following disclaimer. 188 | * Redistributions in binary form must reproduce the above copyright notice, this list 189 | * of conditions and the following disclaimer in the documentation and/or other materials 190 | * provided with the distribution. 191 | * 192 | * Neither the name of the author nor the names of contributors may be used to endorse 193 | * or promote products derived from this software without specific prior written permission. 194 | * 195 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 196 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 197 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 198 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 199 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 200 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 201 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 202 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 203 | * OF THE POSSIBILITY OF SUCH DAMAGE. 204 | * 205 | */ --------------------------------------------------------------------------------