Code
/** Animation loop / drawing and moving (and shaking :) that happens between each segment on the route (A > B)
@param {L.LatLng} latlng data|array for the particular animation part
@param {L.Marker} startMarker is a starting position for this animation part - A
@param {L.Marker} targetMarker is target position for this animation part - B
@param {Integer} currentIndex a current requested animation part index
*/
animatePolyline: function (latlng, startMarker, targetMarker, currentIndex) {
if (latlng && latlng.length > 0) {
// Define start and end positions
var start = startMarker ? startMarker : self.markers.moving; //photos[0];
var end = targetMarker ? new L.LatLng(targetMarker.getLatLng().lat,
targetMarker.getLatLng().lng) : {};
// "End" marker should never be visible during the animation
self.markers.end.setOpacity('0');
// And make sure that target marker is visible during the animation, if it's not "end" one
if (targetMarker != self.markers.end) {
targetMarker.setOpacity('1');
}
// Here we create an array of each nth item (panDividerFactor property) in the current polyline array in order to run camera that often
var indexes = [];
for (e = 0; e &
#60; latlng.length; e++) {
if (latlng[e]) {
if ((e % self.panDividerFactor) = =
0) {
indexes.push(latlng[e]);
}
}
}
// Listen for ongoing animation
document.addEventListener('mapAnimation', self.listeners.mapAnimation);
// Current animation was interrupted with the other one; most likely user interaction / slide prev/next navigation
if (self.timeout.delay._default == self.timeout.delay.broken) {
// If there was a previous animation make sure to remove vector(svg) and draw canvas polyline (so the line does not "fly" together with flyToBounds() below
if (self.polylineSlides[currentIndex - 1] && self.polylineSlides[currentIndex -
1].polyline) {
self.map.removeLayer(self.polylineSlides[currentIndex - 1].polyline);
self.polylineSlides[currentIndex - 1].polyline = self.setPolyline(self.polylineSlides[
currentIndex - 1].data, {
renderer: L.canvas({
padding: 0
})
});
}
// Make sure image/marker becomes visible in this case too
if (startMarker && startMarker != targetMarker) {
startMarker.setZIndexOffset(1);
$(startMarker._icon).addClass('slide-active dirty');
}
// Place marker on the requested destination/slide
self.markers.moving.setLatLng(latlng[0]);
// And flyTo requested destination/slide
self.map.flyTo(latlng[0], self.zoom, {
animate: true,
duration: self.timeout.delay.brokenFly
});
// Broadcast this event, declare this animation as complete
var event = new CustomEvent('mapAnimationComplete', {
'detail': {
broken: true,
currentIndex: parseInt(currentIndex) - 1
}
});
// Dispatch/Trigger/Fire the event
document.dispatchEvent(event);
}
var zoom = self.map.getZoom();
setTimeout(function () {
// Define timeout array for this animation part; This is to be cleared on interruption or if animation completed
self.polylineSlides[currentIndex].timeout = [];
// Define polyline for this animation part (A > B) to be "filled" progressively in a loop below
self.polylineSlides[currentIndex].polyline = self.setPolyline([latlng[0]], {
renderer: L.svg({
padding: 0
})
});
// Our glorious loop starts here
for (i = 0; i &
#60; latlng.length; i++) {
// Broadcast this event, tell everyone that animation is ongoing
var animateEvent = new CustomEvent(
'mapAnimation', {
'detail': {
currentIndex: parseInt(currentIndex),
index: i
}
}); document.dispatchEvent(animateEvent);
// Each polyline segment needs to be packed into timeout array so that we can safely clear it per need
self.polylineSlides[currentIndex].timeout[i] = setTimeout(function (
coords, index) {
var currPolyline = self.polylineSlides[currentIndex].polyline;
// The main magic, progressively draw polyline and move "moving" marker
if (!coords[index].equals(end)) {
// Move marker
self.markers.moving.setLatLng(coords[index]);
// Populate polyline with points (drawing it)
self.polylineSlides[currentIndex].polyline.addLatLng(coords[index]);
}
// Camera move during the animation; each nth (panDividerFactor property) time of the whole loop
if (indexes.indexOf(coords[index])) {
// Currently we use flyToBound() which makes the whole animation kind of fancy
var startCoords = self.polylineSlides[currentIndex].polyline.getLatLngs()[
index];;
var endCoords = targetMarker.getLatLng()
if (startCoords && endCoords) {
var p1 = new L.latLng(startCoords.lat, startCoords.lng);
var p2 = new L.latLng(endCoords.lat, endCoords.lng);
var bounds = new L.latLngBounds(p1, p2);
self.map.flyToBounds(bounds, {
maxZoom: 15,
duration: self.panDuration,
easeLinearity: 1.25
});
}
}
// Animation reached its last point (targetMarker)
if (coords.length - 1 == index) {
// Revert animation delay value to default, from "flying" one to a "moving" one
self.timeout.delay._default = self.timeout.delay.linear;
//self.map.flyTo(coords[index], newZoom, {animate: true, duration: 1.55, easeLinearity: 0.55}); //2.32
// Broadcast this event, declare this animation as complete
var event = new CustomEvent('mapAnimationComplete', {
'detail': {
currentIndex: parseInt(currentIndex)
}
});
document.dispatchEvent(event);
// Since animation for this very polyline, part of the route, was completed, make sure that line is canvas now rather than vector (svg)
// Canvas line does not "fly" together with flyToBounds() above
self.map.removeLayer(self.polylineSlides[currentIndex].polyline);
self.polylineSlides[currentIndex].polyline = self.setPolyline(
self.polylineSlides[currentIndex].data, {
renderer: L.canvas({
padding: 0
})
});
// self.map.addLayer(self.polylineSlides[currentIndex].polyline);
// Make target marker visible (if not "end" marker)
if (targetMarker !== self.markers.end) {
targetMarker.setZIndexOffset(1);
$(targetMarker._icon).addClass('slide-active dirty');
} else { // Last portion, do some specific changes
self.markers.end.setOpacity('1');
$(self.markers.end._icon).addClass('slide-active');
self.markers.moving.setOpacity('0');
// Once the "end" slide is reached fly to bounds of entire route
setTimeout(function () {
//self.map.setMaxBounds([currentPath[0], currentMarkerCoord]);
self.map.flyToBounds(self.polyline.getBounds(), {
animate: true,
duration: self.endSlideBounds.duration
});
}, self.endSlideBounds.delay);
}
}
}, self.drawingSpeed._default * i, latlng, i);
}
}, self.timeout.delay._default);
}
}