Skip to content

Instantly share code, notes, and snippets.

@ramiroaznar
Last active September 26, 2024 02:03
Show Gist options
  • Save ramiroaznar/44f8de5ab7db081cae19db4e67bf6d74 to your computer and use it in GitHub Desktop.
Save ramiroaznar/44f8de5ab7db081cae19db4e67bf6d74 to your computer and use it in GitHub Desktop.
How to make your markers move with Leaflet.js
L.AnimatedMarker = L.Marker.extend({
options: {
// meters
distance: 200,
// ms
interval: 1000,
// animate on add?
autoStart: true,
// callback onend
onEnd: function(){},
clickable: false
},
initialize: function (latlngs, options) {
this.setLine(latlngs);
L.Marker.prototype.initialize.call(this, latlngs[0], options);
},
// Breaks the line up into tiny chunks (see options) ONLY if CSS3 animations
// are not supported.
_chunk: function(latlngs) {
var i,
len = latlngs.length,
chunkedLatLngs = [];
for (i=1;i<len;i++) {
var cur = latlngs[i-1],
next = latlngs[i],
dist = cur.distanceTo(next),
factor = this.options.distance / dist,
dLat = factor * (next.lat - cur.lat),
dLng = factor * (next.lng - cur.lng);
if (dist > this.options.distance) {
while (dist > this.options.distance) {
cur = new L.LatLng(cur.lat + dLat, cur.lng + dLng);
dist = cur.distanceTo(next);
chunkedLatLngs.push(cur);
}
} else {
chunkedLatLngs.push(cur);
}
}
chunkedLatLngs.push(latlngs[len-1]);
return chunkedLatLngs;
},
onAdd: function (map) {
L.Marker.prototype.onAdd.call(this, map);
// Start animating when added to the map
if (this.options.autoStart) {
this.start();
}
},
animate: function() {
var self = this,
len = this._latlngs.length,
speed = this.options.interval;
// Normalize the transition speed from vertex to vertex
if (this._i < len && this.i > 0) {
speed = this._latlngs[this._i-1].distanceTo(this._latlngs[this._i]) / this.options.distance * this.options.interval;
}
// Only if CSS3 transitions are supported
if (L.DomUtil.TRANSITION) {
if (this._icon) { this._icon.style[L.DomUtil.TRANSITION] = ('all ' + speed + 'ms linear'); }
if (this._shadow) { this._shadow.style[L.DomUtil.TRANSITION] = 'all ' + speed + 'ms linear'; }
}
// Move to the next vertex
this.setLatLng(this._latlngs[this._i]);
this._i++;
// Queue up the animation to the next next vertex
this._tid = setTimeout(function(){
if (self._i === len) {
self.options.onEnd.apply(self, Array.prototype.slice.call(arguments));
} else {
self.animate();
}
}, speed);
},
// Start the animation
start: function() {
this.animate();
},
// Stop the animation in place
stop: function() {
if (this._tid) {
clearTimeout(this._tid);
}
},
setLine: function(latlngs){
if (L.DomUtil.TRANSITION) {
// No need to to check up the line if we can animate using CSS3
this._latlngs = latlngs;
} else {
// Chunk up the lines into options.distance bits
this._latlngs = this._chunk(latlngs);
this.options.distance = 10;
this.options.interval = 30;
}
this._i = 0;
}
});
L.animatedMarker = function (latlngs, options) {
return new L.AnimatedMarker(latlngs, options);
};
<html>
<head>
<title>How to make your markers move with Leaflet.js</title>
<meta charset="utf-8">
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.js"></script>
<script src="AnimatedMarker.js"></script>
<style type="text/css">
html, body, #map{
height: 100%;
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<div id="map"></map>
<script type="text/javascript">
var map = L.map('map').setView([40.68576, -73.94149], 18);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {attribution: 'OSM'})
.addTo(map);
var line = L.polyline([[40.68510, -73.94136], [40.68576, -73.94149], [40.68649, -73.94165]]);
map.addLayer(line);
var animatedMarker = L.animatedMarker(line.getLatLngs());
map.addLayer(animatedMarker);
</script>
</body>
</html>
@ahmetilgin
Copy link

how to set icon angle ?

@APalau82
Copy link

APalau82 commented Jun 17, 2019

Hey Ramiro,
Is the function compatible with CircleMarker ? I would like to use the circle marker instead of the default icon.
Thanks

@thekoko89
Copy link

thekoko89 commented Nov 9, 2021

Hello,
Why with more then 100 coordinates it does not work?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment