Animate a curved path/route between two geo-localized points markers using the Google map js v3 API. Here is the relevant part of the path animation. Modify based on your requirements. Hope it helps.

``````
// ... init the google maps as usual then:

maps.setTwinMarker(
{ id: "a", lat: 34.0380, lng: -118.3086, bubble: 'a div defining your marker' },
{ id: "b", lat: 34.0224, lng: -118.4871, bubble: 'a div defining your marker' }
);

// ...

setTwinMarker = function( ma, mb )
{
this.clear();
this.addMarker( ma.lat, ma.lng, ma.id, ma.bubble, true );
this.addMarker( mb.lat, mb.lng, mb.id, mb.bubble, true );
this.fit();

function larp( a, b, t )
{
return { lat: a.lat + ( b.lat - a.lat ) * t, lng: a.lng + ( b.lng - a.lng ) * t };
}

function getBezier( points, t )
{
var ab = larp( points[ 0 ], points[ 1 ], t );
var bc = larp( points[ 1 ], points[ 2 ], t );
var cd = larp( points[ 2 ], points[ 3 ], t );
var abbc = larp( ab, bc, t );
var bccd = larp( bc, cd, t );

return larp( abbc, bccd, t );
}

function getBezierHandles( p0, p1 )
{
// a, b points are perpendicular to q1, q3 which are on line connecting p0 and p1.
// slope between two points : ( y2 - y1 ) / (x2 - x1 ).
// to get perpendicular slope use, reciprocal slope function: -(x2 - x1 ) / ( y2 - y1 )
// curvature is distance between q1 and a; q3 and b;
//
//        a              b
//        |              |
//        |              |
// p0-----q1-----q2-----q3-----p1

var q2 = { lat: (p0.lat + p1.lat) / 2, lng: (p0.lng + p1.lng) / 2 };
var q1 = { lat: (p0.lat + q2.lat) / 2, lng: (p0.lng + q2.lng) / 2 };
var q3 = { lat: (q2.lat + p1.lat) / 2, lng: (q2.lng + p1.lng) / 2 };

var dLat = p1.lat - p0.lat;
var dLng = p1.lng - p0.lng;

var curvature = 0.15;

if( p0.lng > p1.lng )
{
return {
a: { lat: q1.lat + ( -dLng * curvature ), lng: q1.lng + ( dLat * curvature ) },
b: { lat: q3.lat + ( -dLng * curvature ), lng: q3.lng + ( dLat * curvature ) }
};
}
else
{
return {
a: { lat: q1.lat - ( -dLng * curvature ), lng: q1.lng + ( dLat * curvature ) },
b: { lat: q3.lat - ( -dLng * curvature ), lng: q3.lng + ( dLat * curvature ) }
};
}
}

function getLatLngPath( p0, p1 )
{
var handles = getBezierHandles( p0, p1 );

var points = [ p0, handles.a, handles.b, p1 ];

var path = [];

var sections = 40;

for( var t = 0; t <= sections; ++t )
{
var b = getBezier( points, t / sections );

path.push( new google.maps.LatLng( b.lat, b.lng ) );
}

return path;
}

var path = getLatLngPath( { lat: ma.lat, lng: ma.lng }, { lat: mb.lat, lng: mb.lng } );

var dotIcon = {
path: 'M -1,1 0,0 1,1',
scale: 5,
strokeWeight: 1.5,
strokeColor: '#232e40'
};

path: path,
map: _map,
geodesic: false,
strokeOpacity: 1,
strokeWeight: 0,
strokeColor: 'transparent',
icons: [ { icon: dotIcon, repeat: '80px' } ]
} );

this.animate();
};

// ...

animate = function()
{
var count = 0;

_polyDotAnimTimerId = window.setInterval( function()
{
count = ++count % 80;

if( _polyDot )
{
var icons = _polyDot.get( 'icons' );

icons[ 0 ].offset = count + 'px';

_polyDot.set( 'icons', icons );
}

}, 40 );
};

// ...
``````
``````
.bubble {
background:#232e40;