7

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..

writeToBhuwan
  • 3,233
  • 11
  • 39
  • 67
  • 1
    [Animated marker along arbitrary polyline (from XML)](http://www.geocodezip.com/v3_animate_marker_xml.html); [animated marker along polyline from DirectionsService](http://www.geocodezip.com/v3_animate_marker_directions.html) – geocodezip May 02 '13 at 13:14
  • what's wrong with using a callback function too draw a marker on every point you've interpolated? So you draw a marker; in the next cycle you remove it; and put a marker on the next calculated latlng... – Thomas May 02 '13 at 13:16
  • Thanks GeocodeZip..! Let me try it once.! – writeToBhuwan May 02 '13 at 13:18
  • Thomas Can you explain the callabck mechanism in a code? – writeToBhuwan May 02 '13 at 13:18
  • You make a callback function (look for requestAnimationFrame and setTimeout function). That function is than going to be called every x ms. That's the frame rate of your animation. Inside the callback function you add a new marker and remove the old one. – Thomas May 02 '13 at 13:21
  • If you read carefully I've clearly written in my question that " I've tried setTimeOut, and It does not help at all." – writeToBhuwan May 02 '13 at 13:23
  • https://developers.google.com/maps/documentation/javascript/examples/overlay-symbol-animate – Thomas May 02 '13 at 13:37
  • Also Can you please tell me how to snap the polyline to road? – writeToBhuwan May 02 '13 at 14:37

3 Answers3

19

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 )

jlivni
  • 4,759
  • 1
  • 19
  • 30
6

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.

viskin
  • 493
  • 4
  • 15
  • Thank you.! This is an amazing answer. ! And good work on the library. – writeToBhuwan Mar 19 '15 at 17:59
  • Any idea how we can play/pause the animation? – writeToBhuwan Mar 19 '15 at 18:00
  • You can set duration of animation to 0. This technically will disable animation. – viskin Mar 20 '15 at 19:44
  • If you want your vehicle just to stop in the middle of animation, you can call marker.setPosition(marker.getAnimationPosition()). This will set animation destination to current visible position, stopping it. – viskin Mar 20 '15 at 19:47
  • @viskin its a good library. What did you use to animate the marker? Did you set the position of the marker using the setPosition() method or remove/create new markers for the animation? – Rahatur Mar 29 '15 at 13:28
  • Actually, I rely on [marker-animate](https://github.com/combatwombat/marker-animate) library to perform animation. Alternatively, any other animation library can be used. What my library does is hides animation from Google Maps API user, so animation is transparent to those who call setPosition() or getPosition() on marker. – viskin Mar 30 '15 at 17:25
  • Inside, there 2 markers created. One is invisible for user, but has all the properties like there is no animation in place, and use work with it. Second marker is visible for user and setPosition is being called on it to make it animate, but you never work with it directly and you never receive its movement events. – viskin Mar 30 '15 at 17:30
2

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

Thomas W
  • 13,940
  • 4
  • 58
  • 76