Open Layer 3 Animation - javascript

i want to animate a marker in Ol3. I used this example from Ol.
The Animation works but with a little bug an i dont know how to fix it.
//main animating loop
var moveFeature = function(event) {
var vectorContext = event.vectorContext;
var frameState = event.frameState;
if (animating) {
var elapsedTime = frameState.time - now;
var now1 = new Date().getTime();
if((now1 - lastTime) > 100){
// stop if end reached
if(curIndex >= coordinates.length){
stopAnimation(true);
requestData(true);
// console.log(" end ");
return;
}
var newPoint = coordinates[curIndex];
var lastP = newPoint;
if(curIndex>=1)
lastP = coordinates[curIndex-1];
if(newPoint !== null & typeof newPoint != " undefined "){
curPoint = ol.proj.fromLonLat(newPoint);
lastCourse = course;
// calculate azimuth between two coordinates
course = calcBearing(lastP,newPoint);
lastTime = now1;
}
curIndex++;
lastTime = now1;
}
//every time render marker position ?? needed ? or only when new one
geoMarker.getGeometry().setCoordinates(curPoint);
//styles.geoMarker.getImage().setRotation(course); //rotates the feature
debugger;
lastCourse = course;
vectorContext.drawFeature(geoMarker, styles.geoMarker);
// do we need follow the bus due to rendering out of current extend =
calcExtend();
}
// tell OL3 to continue the postcompose animation
map.render();
};
I draw the new pos of the marger with vectorContext.drawFeature(geoMarker, styles.geoMarker);
Every time the new position is plotted the vectorlayer is new generated. I dont know why.
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [geoMarker]
//features: [pointFeature]
}),
style: function(feature) {
// hide geoMarker if animation is active
if (animating && feature.get('type') === 'geoMarker') {
// TODOBug
return styles[feature.get('type')];
}
return styles[feature.get('type')];
}
});
With this example above i get the following problem on the map. If the map is clicked, the marker duplicates, one marker stays at the old position and the other one is moving forwoard. Thats a problem.
When i change the code of the vectorlayer like this.
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [geoMarker]
//features: [pointFeature]
}),
style: function(feature) {
// hide geoMarker if animation is active
if (animating && feature.get('type') === 'geoMarker') {
debugger;
console.log("return null")
// TODOBug
return null;
}
return styles[feature.get('type')];
}
});
The problem with the duplicate marker is solved but then the marker isnt clickable while the animation is in progess.
The Question is: How can i achieve that the marker doesen´t duplicates and is clickable while animating???

Related

Markers image are not displaying, only the last one because of css

I have a google map which was working well until a few weeks ago.
My problem is that now, all the label markers appears in the right place but only the last image appears.
I see in the generated html code that all images are here but all of them have the same position (that's why i can just see the last one).
I say again : it was working before, i'm sure! Maybe google has changed something (i'm calling the script : https://maps.googleapis.com/maps/api/js?sensor=false).
Here is my code :
jQuery(function() {
var stops = [];
var nbPoints = $('#nbPoints').val();
for (var i = 1; i <= nbPoints; i++) {
if($('#latitude'+i).val() && $('#longitude'+i).val())
stops.push({"Geometry":{"Latitude":$('#latitude'+i).val(),"Longitude":$('#longitude'+i).val()}});
}
var map = new window.google.maps.Map(document.getElementById("map_canvas"));
// new up complex objects before passing them around
var directionsDisplay = new window.google.maps.DirectionsRenderer({suppressMarkers: true});
var directionsService = new window.google.maps.DirectionsService();
Tour_startUp(stops);
window.tour.loadMap(map, directionsDisplay);
window.tour.fitBounds(map);
if (stops.length > 1)
window.tour.calcRoute(directionsService, directionsDisplay);
else $("#message").html("Erreur : Aucune coordonnée renseignée!");
});
function Tour_startUp(stops) {
if (!window.tour) window.tour = {
updateStops: function (newStops) {
stops = newStops;
},
// map: google map object
// directionsDisplay: google directionsDisplay object (comes in empty)
loadMap: function (map, directionsDisplay) {
var myOptions = {
zoom: 13,
center: new window.google.maps.LatLng($('#latitudeInit').val(),$('#longitudeInit').val()),
mapTypeId: window.google.maps.MapTypeId.ROADMAP
};
map.setOptions(myOptions);
directionsDisplay.setMap(map);
},
fitBounds: function (map) {
var bounds = new window.google.maps.LatLngBounds();
// extend bounds for each record
jQuery.each(stops, function (key, val) {
var myLatlng = new window.google.maps.LatLng(val.Geometry.Latitude, val.Geometry.Longitude);
bounds.extend(myLatlng);
});
map.fitBounds(bounds);
},
calcRoute: function (directionsService, directionsDisplay) {
var batches = [];
var itemsPerBatch = 10; // google API max = 10 - 1 start, 1 stop, and 8 waypoints
var itemsCounter = 0;
var wayptsExist = stops.length > 0;
while (wayptsExist) {
var subBatch = [];
var subitemsCounter = 0;
for (var j = itemsCounter; j < stops.length; j++) {
subitemsCounter++;
subBatch.push({
location: new window.google.maps.LatLng(stops[j].Geometry.Latitude, stops[j].Geometry.Longitude),
stopover: true
});
if (subitemsCounter == itemsPerBatch)
break;
}
itemsCounter += subitemsCounter;
batches.push(subBatch);
wayptsExist = itemsCounter < stops.length;
// If it runs again there are still points. Minus 1 before continuing to
// start up with end of previous tour leg
itemsCounter--;
}
// now we should have a 2 dimensional array with a list of a list of waypoints
var combinedResults;
var unsortedResults = [{}]; // to hold the counter and the results themselves as they come back, to later sort
//var directionsResultsReturned = 0;
var directionsResultsReturned = new Array();
directionsResultsReturned[0]=0;
for (var k = 0; k < batches.length; k++) {
var lastIndex = batches[k].length - 1;
var start = batches[k][0].location;
var end = batches[k][lastIndex].location;
// trim first and last entry from array
var waypts = [];
waypts = batches[k];
waypts.splice(0, 1);
waypts.splice(waypts.length - 1, 1);
var request = {
origin: start,
destination: end,
waypoints: waypts,
travelMode: window.google.maps.TravelMode.DRIVING
};
creerRoute(k,request,batches,directionsService,unsortedResults,combinedResults,directionsResultsReturned,directionsDisplay);
}
}
};
}
var infowindow = new google.maps.InfoWindow(
{
size: new google.maps.Size(150,50)
});
var icons = new Array();
icons["red"] = new google.maps.MarkerImage("mapIcons/marker_red.png",
// This marker is 20 pixels wide by 34 pixels tall.
new google.maps.Size(20, 34),
// The origin for this image is 0,0.
new google.maps.Point(0,0),
// The anchor for this image is at 9,34.
new google.maps.Point(9, 34));
function getMarkerImage(numero, type, anomalie) {
var url_img = "../img/";
var type = new String(type);
if(anomalie) url_img+="anomalie.png";
else{
switch(type.toUpperCase()){
case "LAVAGE" : url_img+="shower.png"; break;
case "EAU" : url_img+="waterdrop.png"; break;
default : url_img+="stop.png"; break;
}
}
icons[numero] = new google.maps.MarkerImage(url_img,
new google.maps.Size(34, 34),
new google.maps.Point(0,0),
new google.maps.Point(9, 34));
return icons[numero];
}
// Marker sizes are expressed as a Size of X,Y
// where the origin of the image (0,0) is located
// in the top left of the image.
// Origins, anchor positions and coordinates of the marker
// increase in the X direction to the right and in
// the Y direction down.
var iconImage = new google.maps.MarkerImage('mapIcons/marker_red.png',
// This marker is 20 pixels wide by 34 pixels tall.
new google.maps.Size(34, 34),
// The origin for this image is 0,0.
new google.maps.Point(0,0),
// The anchor for this image is at 9,34.
new google.maps.Point(9, 34));
var iconShadow = new google.maps.MarkerImage('http://www.google.com/mapfiles/shadow50.png',
// The shadow image is larger in the horizontal dimension
// while the position and offset are the same as for the main image.
new google.maps.Size(37, 34),
new google.maps.Point(0,0),
new google.maps.Point(9, 34));
// Shapes define the clickable region of the icon.
// The type defines an HTML <area> element 'poly' which
// traces out a polygon as a series of X,Y points. The final
// coordinate closes the poly by connecting to the first
// coordinate.
var iconShape = {
coord: [9,0,6,1,4,2,2,4,0,8,0,12,1,14,2,16,5,19,7,23,8,26,9,30,9,34,11,34,11,30,12,26,13,24,14,21,16,18,18,16,20,12,20,8,18,4,16,2,15,1,13,0],
type: 'poly'
};
function createMarker(map, latlng, label, html, numero, type, anomalie) {
var contentString = '<b>'+label+'</b><br>'+html;
var marker = new MarkerWithLabel({
position: latlng,
map: map,
draggable: false,
raiseOnDrag: true,
icon : getMarkerImage(numero,type,anomalie),
labelContent: numero,
labelAnchor: new google.maps.Point(0, 0),
labelClass: "labels",
labelInBackground: false
});
marker.myname = label;
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(contentString);
infowindow.open(map,marker);
});
return marker;
}
function creerRoute(kk,request,batches,directionsService,unsortedResults,combinedResults,directionsResultsReturned,directionsDisplay) {
directionsService.route(request, function (result, status) {
if (status == window.google.maps.DirectionsStatus.OK) {
var unsortedResult = { order: kk, result: result };
unsortedResults.push(unsortedResult);
directionsResultsReturned[0]++;
if (directionsResultsReturned[0] == batches.length) // we've received all the results. put to map
{
// sort the returned values into their correct order
unsortedResults.sort(function (a, b) { return parseFloat(a.order) - parseFloat(b.order); });
var count = 0;
for (var key in unsortedResults) {
if (unsortedResults[key].result != null) {
if (unsortedResults.hasOwnProperty(key)) {
if (count == 0) // first results. new up the combinedResults object
combinedResults = unsortedResults[key].result;
else {
// only building up legs, overview_path, and bounds in my consolidated object. This is not a complete
// directionResults object, but enough to draw a path on the map, which is all I need
combinedResults.routes[0].legs = combinedResults.routes[0].legs.concat(unsortedResults[key].result.routes[0].legs);
combinedResults.routes[0].overview_path = combinedResults.routes[0].overview_path.concat(unsortedResults[key].result.routes[0].overview_path);
combinedResults.routes[0].bounds = combinedResults.routes[0].bounds.extend(unsortedResults[key].result.routes[0].bounds.getNorthEast());
combinedResults.routes[0].bounds = combinedResults.routes[0].bounds.extend(unsortedResults[key].result.routes[0].bounds.getSouthWest());
}
count++;
}
}
}
directionsDisplay.setDirections(combinedResults);
var legs = combinedResults.routes[0].legs;
for (var i=0; i < legs.length;i++){
var j = i + 1;
var markerletter = $('#ordre'+j).val();
var anomalie=false;
var html = $('#infospoint'+j).val();
if($('#infoschocspoint'+j).length){
anomalie = true;
html+="<br/>"+$('#infoschocspoint'+j).val();
}
createMarker(directionsDisplay.getMap(),legs[i].start_location,$('#titrepoint'+j).val(),html,markerletter,$('#type'+j).val(),anomalie);
}
var i=legs.length + 1;
var markerletter = $('#ordre'+i).val();
var anomalie=false;
var html = $('#infospoint'+i).val();
if($('#infoschocspoint'+i).length){
anomalie = true;
html+="<br/>"+$('#infoschocspoint'+i).val();
}
createMarker(directionsDisplay.getMap(),legs[legs.length-1].end_location,$('#titrepoint'+i).val(),html,markerletter,$('#type'+i).val(),anomalie);
}
}else {
if (status == window.google.maps.DirectionsStatus.OVER_QUERY_LIMIT) {
setTimeout( function(){
creerRoute(kk,request,batches,directionsService,unsortedResults,combinedResults,directionsResultsReturned,directionsDisplay);
}, 200);
}else{
$("#message").html("Erreur : Code "+status);
}
}
});
}
Has anyone the same problem?
Thanks for your help!
You can use new one
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&v=3.3"></script>

Remove markers out of viewport

I have to manage a map of about 80.000 markers concentrated in France.
To do that, I decided to get the bounds of the viewport and call a dynamic-JSON (with PHP) which contains the markers inside the viewport. And this on the "idle" event.
I faced a problem with this solution. Indeed, the markers which already exist was re-plotted (at the same position), which consequently weigh the map for nothing...
To solve it, the markers list before and after the JSON query are compared (thanks to jQuery), in order to plot only the new markers. And it works!
Now, I would want to remove the markers which are not currently shown on the map. Or a list of markers (I get it thanks to jQuery) designated by an ID which is also the title of the marker. So, how can a delete markers like that ? I specify that I am using MarkerManager.
Otherwise, you guess that if I do not remove these markers, they will be re-plotted in some cases... For example, you are viewing the city A, you move the map to view the city B, and you get back to the city A...
Here is the code:
var map;
var mgr;
var markers = [];
function initialize(){
var mapOptions = {
zoom: 6,
center: new google.maps.LatLng(46.679594, 2.109375)
};
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
var mgrOptions = { borderPadding: 50, maxZoom: 15, trackMarkers: false };
mgr = new MarkerManager(map, mgrOptions);
google.maps.event.addListener(map, 'idle', function() {
mapEvent();
});
}
function mapEvent(){
if( map.getZoom() >= 8 ){
var bounds = map.getBounds();
getSupports(bounds.getNorthEast(), bounds.getSouthWest());
} else {
// Todo
}
}
var markerslistID = new Array();
var markerslistData = {};
function getSupports(ne, sw){
newMarkerslistID = new Array();
newMarkerslistData = {};
// Getting the markers of the current view
$.getJSON('./markerslist.php?nelat='+ne.lat()+'&nelng='+ne.lng()+'&swlat='+sw.lat()+'&swlng='+sw.lng(), function(data) {
for (var i = 0; i < data.points.length; i++) {
var val = data.points[i];
newMarkerslistID.push(val.id);
newMarkerslistData[val.id] = new Array(val.lat, val.lng, val.icon);
}
// List of New Markers TO PLOT
var diffNewMarkers = $(newMarkerslistID).not(markerslistID).get();
// List of Old markers TO REMOVE
var diffOldMarkers = $(markerslistID).not(newMarkerslistID).get();
// Plotting the NEW MARKERS
for( var i = 0; i < diffNewMarkers.length; i++ ){
var marker = new google.maps.Marker({
position: new google.maps.LatLng(newMarkerslistData[diffNewMarkers[i]][0], newMarkerslistData[diffNewMarkers[i]][1]),
title : diffNewMarkers[i],
icon : './images/'+newMarkerslistData[diffNewMarkers[i]][2]+'.png'
});
mgr.addMarker(marker, 0);
}
/*****************************************
HERE WE HAVE TO REMOVE
THE MARKERS CONTAINED IN diffOldMarkers
*****************************************/
mgr.refresh();
// Switching the new list to the old, for the next event
markerslistID = newMarkerslistID;
markerslistData = newMarkerslistData;
});
}
Thank you for your help.
A one-liner to hide all markers that ar not in the current viewport.
!map.getBounds().contains(marker.getPosition()) && marker.setVisible(false);
Or,
if (map.getBounds().contains(marker.getPosition()) && !marker.getVisible()) {
marker.setVisible(true);
}
else if (!map.getBounds().contains(marker.getPosition()) && marker.getVisible()) {
marker.setVisible(false);
}

OL3: GetFeature from Layers by Coordinate

I want to get the Feature of a Layer by coordinate.
Furthermore I want to open this feature in a popup, which I have solved so far by an onclick event. But I want to realize by giving the coordinates of a feature and opening the popup of the featue.
I have a layer with the map and a layer with the features:
if (trackMap != null) {
for (var i = 0; i < trackMap.length; i++) {
var trackInfo = trackMap[i];
lat = parseFloat(trackInfo.lat);
lon = parseFloat(trackInfo.lon);
var layergpx = new ol.layer.Vector({
source: new ol.source.Vector({
parser: new ol.parser.GPX(),
url: '${contextRoot}/gps/gpx2' + trackInfo.url
})
});
layers.push(layergpx);
}
}
I want to get the feature of this layer in another Javascript function.
How I open a pop up by clicking on the map:
/**
* The Click Event to show the data
*/
var element = document.getElementById('popup');
var popup = new ol.Overlay({
element: element,
positioning: ol.OverlayPositioning.BOTTOM_CENTER,
stopEvent: false
});
map.addOverlay(popup);
map.on('singleclick', function(evt) {
map.getFeatures({
pixel: evt.getPixel(),
layers: vectorLayers,
success: function(layerFeatures) {
var feature = layerFeatures[0][0];
if (feature) {
var geometry = feature.getGeometry();
var coord = geometry.getCoordinates();
popup.setPosition(coord);
$(element).popover({
'placement': 'top',
'html': true,
'content': feature.get('desc')
});
$(element).popover('show');
} else {
$(element).popover('destroy');
}
}
});
});
But I want this feature not to be opened by clicking on it on the map, but by entering a coordinate in a textfield and the map opens this pop up, like in the onclick event.
Take a look at this example to see if it helps you:
http://openlayers.org/en/latest/examples/kml.html
var displayFeatureInfo = function(pixel) {
map.getFeatures({
pixel: pixel,
layers: [vector],
success: function(featuresByLayer) {
var features = featuresByLayer[0];
var info = [];
for (var i = 0, ii = features.length; i < ii; ++i) {
info.push(features[i].get('name'));
}
document.getElementById('info').innerHTML = info.join(', ') || '&nbsp';
}
});
map.getFeatures() has this success callback where it delivers the features of the layers specified in layers: [vector]. Customize it at will to get what you need.
=== Update ===
In the OpenLayers 3's Map object you have a function: getPixelFromCoordinate
/**
* #param {ol.Coordinate} coordinate Coordinate.
* #return {ol.Pixel} Pixel.
*/
ol.Map.prototype.getPixelFromCoordinate = function(coordinate) {
var frameState = this.frameState_;
if (goog.isNull(frameState)) {
return null;
} else {
var vec2 = coordinate.slice(0, 2);
return ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, vec2, vec2);
}
};

Show a moving marker on the map

I am trying to make a marker move(not disappear and appear again) on the map as a vehicle moves on the road.
I have two values of latLng and I want to move the marker between the two till the next point is sent by the vehicle. And then repeat the process again.
What I tried:[This is not a very efficient way, I know]
My thought was to implement the above using the technique in points below:
1) Draw a line between the two.
2) Get the latLng of each point on 1/10th fraction of the polyline.
3) Mark the 10 points on the map along with the polyline.
Here is my Code:
var isOpen = false;
var deviceID;
var accountID;
var displayNameOfVehicle;
var maps = {};
var lt_markers = {};
var lt_polyLine = {};
function drawMap(jsonData, mapObj, device, deleteMarker) {
var oldposition = null;
var oldimage = null;
var arrayOflatLng = [];
var lat = jsonData[0].latitude;
var lng = jsonData[0].longitude;
//alert(jsonData[0].imagePath);
var myLatLng = new google.maps.LatLng(lat, lng);
if (deleteMarker == true) {
if (lt_markers["marker" + device] != null) {
oldimage = lt_markers["marker" + device].getIcon().url;
oldposition = lt_markers["marker" + device].getPosition();
lt_markers["marker" + device].setMap(null);
lt_markers["marker" + device] = null;
}
else {
console.log('marker is null');
oldimage = new google.maps.MarkerImage(jsonData[0].imagePath,
null,
null,
new google.maps.Point(5, 17), //(15,27),
new google.maps.Size(30, 30));
oldposition = myLatLng;
}
}
var image = new google.maps.MarkerImage(jsonData[0].imagePath,
null,
null,
new google.maps.Point(5, 17), //(15,27),
new google.maps.Size(30, 30));
lt_markers["marker" + device] = new google.maps.Marker({
position: myLatLng,
icon: image,
title: jsonData[0].address
});
if (oldposition == myLatLng) {
alert('it is same');
lt_markers["marker" + device].setMap(mapObj);
mapObj.panTo(myLatLng);
}
else {
alert('it is not same');
var markMarker = null;
var i = 10;
for (i = 10; i <= 100; i + 10) {
//-------
// setTimeout(function() {
if (markMarker != null) {
markMarker.setMap(null);
markMarker = null;
}
alert('inside the loop');
var intermediatelatlng = mercatorInterpolate(mapObj, oldposition, myLatLng, i / 100);
alert('Intermediate Latlng is :' + intermediatelatlng);
arrayOflatLng.push(intermediatelatlng);
var flightPath = new google.maps.Polyline({
path: arrayOflatLng,
strokeColor: "#FFFFFF",
strokeOpacity: 1.0,
strokeWeight: 1
});
flightPath.setMap(mapObj);
if (i != 100) {
markMarker = new google.maps.Marker({
position: intermediatelatlng,
icon: image,
title: jsonData[0].address,
map: mapObj
});
}
else {
markMarker = new google.maps.Marker({
position: intermediatelatlng,
icon: oldimage,
title: jsonData[0].address,
map: mapObj
});
}
mapObj.panTo(intermediatelatlng);
//--------
// }, 1000);
}
}
}
function mercatorInterpolate(map, latLngFrom, latLngTo, fraction) {
// Get projected points
var projection = map.getProjection();
var pointFrom = projection.fromLatLngToPoint(latLngFrom);
var pointTo = projection.fromLatLngToPoint(latLngTo);
// Adjust for lines that cross the 180 meridian
if (Math.abs(pointTo.x - pointFrom.x) > 128) {
if (pointTo.x > pointFrom.x)
pointTo.x -= 256;
else
pointTo.x += 256;
}
// Calculate point between
var x = pointFrom.x + (pointTo.x - pointFrom.x) * fraction;
var y = pointFrom.y + (pointTo.y - pointFrom.y) * fraction;
var pointBetween = new google.maps.Point(x, y);
// Project back to lat/lng
var latLngBetween = projection.fromPointToLatLng(pointBetween);
return latLngBetween;
}
Problems Faced:
1) The marker is not showing up on the map because the process of plotting and removal of marker is so fast that the marker is not visisble on screen. I've tried setTimeOut, and It does not help at all.
2) if I alow the browser to run this code for more than 5 minutes, the browser crashes.
Note: The Above function is called every 10 seconds using setInterval.
What Can be a better solution? Please Help..
For the marker to move relatively smoothly, you need to
Update more than every 1/10 fraction of the polyline (at least every few pixels)
Call the update method more frequently
Don't delete and re-add the marker
For example, something like:
var counter = 0;
interval = window.setInterval(function() {
counter++;
// just pretend you were doing a real calculation of
// new position along the complex path
var pos = new google.maps.LatLng(35, -110 + counter / 100);
marker.setPosition(pos);
if (counter >= 1000) {
window.clearInterval(interval);
}
}, 10);
I made a simple example at http://jsfiddle.net/bmSbU/2/ which shows a marker moving along a straight path. If this is what you want, most of your code above regarding where along the line you are can be reused (or check out http://broady.github.io/maps-examples/points-along-line/along-directions.html )
You can use marker-animate-unobtrusive library to make markers
smoothly transition from one location to another (instead of reappearing).
You could initialize your marker like that:
var marker = new SlidingMarker({
//your original marker options
});
Just call marker.setPosition() each time new vehicle's coordinate arrive.
P.S. I'm the author of the library.
Why not keep the existing Marker/ MarkerImage and call setPosition() to move it, either on a timer or as the position changes?
Deleting it & recreating it is what causes it to flash/ flicker and eventually crash. If you keep the same instance but just move it, you should do much better.
See: Marker.setPosition()
https://developers.google.com/maps/documentation/javascript/reference#Marker

Extend Google Maps marker to animate smoothly on update?

Using the Google Maps API v3 I've been able to update multiple positions of markers via an AJAX call. However, it lacks any transition. Code below:
if ( !latlong.equals( point.latlong ) ) {
point.latlong = latlong;
point.marker.setPosition(latlong);
}
The drawback is that setPosition has no native animation method. Does anyone know any methods for extending setPosition so the marker can fluently "move" from it's old to new position? Or any methods available? I have not been able to find any documentation. Thanks!
I did not find any native way to create this animation. You can create your own animation by stepping the position from the current point to the final point using the setPosition. Here is a code snippet to give you an idea:
var map = undefined;
var marker = undefined;
var position = [43, -89];
function initialize() {
var latlng = new google.maps.LatLng(position[0], position[1]);
var myOptions = {
zoom: 8,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
marker = new google.maps.Marker({
position: latlng,
map: map,
title: "Your current location!"
});
google.maps.event.addListener(map, 'click', function(me) {
var result = [me.latLng.lat(), me.latLng.lng()];
transition(result);
});
}
var numDeltas = 100;
var delay = 10; //milliseconds
var i = 0;
var deltaLat;
var deltaLng;
function transition(result){
i = 0;
deltaLat = (result[0] - position[0])/numDeltas;
deltaLng = (result[1] - position[1])/numDeltas;
moveMarker();
}
function moveMarker(){
position[0] += deltaLat;
position[1] += deltaLng;
var latlng = new google.maps.LatLng(position[0], position[1]);
marker.setPosition(latlng);
if(i!=numDeltas){
i++;
setTimeout(moveMarker, delay);
}
}
This can probably be cleaned up a bit, but will give you a good start. I am using JavaScript's setTimeout method to create the animation. The initial call to 'transition' gets the animation started. The parameter to 'transition' is a two element array [lat, lng]. The 'transition' function calculates the step sizes for lat and lng based upon a couple of animation parametes (numDeltas, delay). It then calls 'moveMarker'. The function 'moveMarker' keeps a simple counter to indicate when the marker has reached the final destination. If not there, it calls itself again.
Here is a jsFiddle of the code working: https://jsfiddle.net/rcravens/RFHKd/2363/
Hope this helps.
Bob
In case you want smooth animations (with easing), these libraries should help:
https://github.com/terikon/marker-animate-unobtrusive
http://terikon.github.io/marker-animate-unobtrusive/demo/unobtrusive/markermove-sliding.html
I know its late but it might help the future SO wanderers.
Problem Statement: write a function(and not a library due to specific use-case) to animate a google maps marker to a new location.
Solution is based on this awesome library marker-animate-unobtrusive
function animateMarkerTo(marker, newPosition) {
var options = {
duration: 1000,
easing: function (x, t, b, c, d) { // jquery animation: swing (easeOutQuad)
return -c *(t/=d)*(t-2) + b;
}
};
window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
// save current position. prefixed to avoid name collisions. separate for lat/lng to avoid calling lat()/lng() in every frame
marker.AT_startPosition_lat = marker.getPosition().lat();
marker.AT_startPosition_lng = marker.getPosition().lng();
var newPosition_lat = newPosition.lat();
var newPosition_lng = newPosition.lng();
// crossing the 180° meridian and going the long way around the earth?
if (Math.abs(newPosition_lng - marker.AT_startPosition_lng) > 180) {
if (newPosition_lng > marker.AT_startPosition_lng) {
newPosition_lng -= 360;
} else {
newPosition_lng += 360;
}
}
var animateStep = function(marker, startTime) {
var ellapsedTime = (new Date()).getTime() - startTime;
var durationRatio = ellapsedTime / options.duration; // 0 - 1
var easingDurationRatio = options.easing(durationRatio, ellapsedTime, 0, 1, options.duration);
if (durationRatio < 1) {
marker.setPosition({
lat: (
marker.AT_startPosition_lat +
(newPosition_lat - marker.AT_startPosition_lat)*easingDurationRatio
),
lng: (
marker.AT_startPosition_lng +
(newPosition_lng - marker.AT_startPosition_lng)*easingDurationRatio
)
});
// use requestAnimationFrame if it exists on this browser. If not, use setTimeout with ~60 fps
if (window.requestAnimationFrame) {
marker.AT_animationHandler = window.requestAnimationFrame(function() {animateStep(marker, startTime)});
} else {
marker.AT_animationHandler = setTimeout(function() {animateStep(marker, startTime)}, 17);
}
} else {
marker.setPosition(newPosition);
}
}
// stop possibly running animation
if (window.cancelAnimationFrame) {
window.cancelAnimationFrame(marker.AT_animationHandler);
} else {
clearTimeout(marker.AT_animationHandler);
}
animateStep(marker, (new Date()).getTime());
}

Categories

Resources