I'd like to draw an animated (geodesic) polyline in google maps, a bit like this: http://planefinder.net/route/SFO/
I found many tutorials on how to animate a symbol along a polyline, but nothing about animating the polyline itself from the source to the destination.
Any hints ? Where should I start ?
Any help is really appreciated.
I've had some success with the following:
var departure = new google.maps.LatLng(dept_lat, dept_lng); //Set to whatever lat/lng you need for your departure location
var arrival = new google.maps.LatLng(arr_lat, arr_lng); //Set to whatever lat/lng you need for your arrival location
var line = new google.maps.Polyline({
path: [departure, departure],
strokeColor: "#FF0000",
strokeOpacity: 1,
strokeWeight: 1,
geodesic: true, //set to false if you want straight line instead of arc
map: map,
});
var step = 0;
var numSteps = 250; //Change this to set animation resolution
var timePerStep = 5; //Change this to alter animation speed
var interval = setInterval(function() {
step += 1;
if (step > numSteps) {
clearInterval(interval);
} else {
var are_we_there_yet = google.maps.geometry.spherical.interpolate(departure,arrival,step/numSteps);
line.setPath([departure, are_we_there_yet]);
}
}, timePerStep);
This is basically using an interval to redraw the path. At each step, the visible, animated path makes up a larger percentage of the total path from departure to arrival until finally the arrival location is reached.
Related
So I am using JavaScript to plot a position of a flight and its flight path on a visualisation map. I am getting the data from a node server that I have created. I have looked at similar question on stack over flow but I haven't been able to get them working.
I am currently struggling with the positioning of the flight icon, as I want it to point in the same direction as the flight path or even put a marker at the top of the image so it can point to a certain latitude and longitude. At the minute the flight icon only faces north.
Here is a screenshot of my code. I tried using the anchor in the Google maps API but I couldn't get it working so I commented it out.
var flightCord = [];
for (var i = 0; i < data.flight.length; i++) {
var lat = data.flight[0].lat1;
var lng = data.flight[0].lng1;
// Co-ordinates for Dublin Airport 53.421379, -6.27
var image = new google.maps.MarkerImage("plane3.png"
//new google.maps.Size(25,25),
//null, null,
//new google.maps.Point(53.4213879,-6.27)
//new google.maps.Point(0, 50)
);
var latLng = new google.maps.LatLng(lat,lng);
var marker = new google.maps.Marker({
position: latLng,
map: map,
icon: image
});
var flightCord = [
{lat:data.flight[0].lat1, lng: data.flight[0].lng1},
{lat:data.flight[i].lat1, lng:data.flight[i].lng1}];
}
var flightPath = new google.maps.Polyline({
path: flightCord,
geodesic: true,
strokeColor: '#FF0000',
strokeOpacity: 1.0,
strokeWeight: 1
});
I have an array of 3 different levels of color with speed ranging between values of
less than 60
between 60 and 80
more than 120.
I can put each lat long in an array where speed is one of the 3 options and use a different color for each however I have noticed that, if I have speed less than 60 as a starting point, for example, and then only have that at the end as well, the less than 60 at the beginning will connect with the less than 60 at the end therefore drawing a straight line, is there a way I can connect polyline based on minimum distance perhaps, even if I use different zoom levels point Y in an array of say less than 60 will connect to point Z (the next point) because it does not know of the other two arrays in between.
var myTripGoing60 = [];
for (i = 0; i < latlngdataGoing60.length; i = i + 2) {
var point = new google.maps.LatLng(latlngdataGoing60[i], latlngdataGoing60[i + 1]);
myTripGoing60.push(point);
}
var myTripGoing6080 = [];
for (i = 0; i < latlngdataGoing6080.length; i = i + 2) {
var point = new google.maps.LatLng(latlngdataGoing6080[i], latlngdataGoing6080[i + 1]);
myTripGoing6080.push(point);
}
var myTripGoing120 = [];
for (i = 0; i < latlngdataGoing120.length; i = i + 2) {
var point = new google.maps.LatLng(latlngdataGoing120[i], latlngdataGoing120[i + 1]);
myTripGoing120.push(point);
}
var flightPath = new google.maps.Polyline({
path: myTripGoing60,
strokeColor: "#000000",
strokeOpacity: 0.8,
strokeWeight: 7
});
flightPath.setMap(map);
var flightPath = new google.maps.Polyline({
path: myTripGoing6080,
strokeColor: "#99FF00",
strokeOpacity: 0.8,
strokeWeight: 7
});
flightPath.setMap(map);
var flightPath = new google.maps.Polyline({
path: myTripGoing120,
strokeColor: "#003300",
strokeOpacity: 0.8,
strokeWeight: 7
});
flightPath.setMap(map);
I used Markers (dots) instead of Polyline - It will do for now.
What I did to achieve this was:
Go through every coordinate in your array, and grab the current iteration as the starting point of the polyline and the current iteration + 1 for the end point of that polyline, you can put the colour you want for that line.
Then you move to the next one, and so on, repeat this process for every coordinate you have in your array.
I´m trying to animate the growth/shrink of the radius of a circle on the Google Maps API. Right now what I have is a method in JS that takes the time given, the final radius and calculates a delta of the radius, with that it calculates the time rate (or the number of milliseconds to wait until the next iteration of the cycle). The thing is that it's working for larger times (like 3 seconds or more) and for smaller times it's taking it more than it should (almost for everything lower or equal to 1 sec, it's taking it like 2 secs).
Here's the method>
var animateRadius = function(change){
var radiusDelta = Math.abs(change.FinalRadius-Circle.getRadius());
var radiusChangeRate = 1;
var timeRate = (radiusChangeRate*change.FinalTime)/radiusDelta;
if(timeRate <= 1){
/*since the setInterval method only works with miliseconds
if the timespan is less than one milisecond, the radius change
rate has to be bigger in order to make it on time, and since this
only happens in smaller times, I think the error is around here..*/
timeRate = 1;
radiusChangeRate = (timeRate*radiusDelta)/change.FinalTime;
}
if(change.FinalRadius > Circle.getRadius()){
//This just tells if the circle is growing or shrinking
radiusChangeRate = radiusChangeRate*-1;
}
var interval = window.setInterval(function(){
if(visionRadiusCircle.getRadius() == change.FinalRadius){
window.clearInterval(interval);
interval = 0;
}
Circle.setRadius(Circle.getRadius() - radiusChangeRate);
}, timeRate);
}
I can't figure out why this is not working. Any thoughts? Any idea is welcome, even if it's a different algorithm (I'm not even sure if there's a better way to do this).
Thanks!
Here is what I have done. You can adjust the animation by adjusting the time interval given in setTimeout function. http://jsbin.com/oritec/2/edit
function getCircle() {
var circle = {
path: google.maps.SymbolPath.CIRCLE,
fillColor: 'red',
fillOpacity: 0.6,
scale: 2,
strokeColor: 'red',
strokeWeight: 1,
strokeOpacity: 0.6
};
return circle;
}
function init() {
var mapCenter = new google.maps.LatLng(41.7833, 5.2167);
var map = new google.maps.Map(document.getElementById('map'), {
'zoom': 2,
'center': mapCenter,
draggable: false,
disableDefaultUI: true,
'mapTypeId': google.maps.MapTypeId.ROADMAP
});
var rad = 0;
var sop = 1;
var sw = 1;
var fillop = 1;
var marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(18.7000, 79.1833),
icon: getCircle(),
draggable: false
});
for(var i=0;i<10;i++)
{
setTimeout(function(){
animate();
rad += 50000;
sop -= 0.1;
fillop -= 0.1;
sw -= 0.1;
},i* 50);
}
function animate(){
var circle2 = new google.maps.Circle({
map: map,
radius: rad,
center: new google.maps.LatLng(18.7000, 79.1833),
strokeColor: "#FF0000",
fillColor: "#FF0000",
fillOpacity: fillop,
strokeWeight: sw,
strokeOpacity: sop
});
setTimeout(function(){
circle2.setMap(null); },100);
}
}
google.maps.event.addDomListener(window, 'load', init);
I have a set of latitude and longitude coordinates in an array. When plotted as points on a Polygon in Google Maps, they form roughly an irregular oval pointing from west to east.
I would like to rotate the polygon to arbitrary degrees with a point near the far left (western) axis as the origin point.
What's important to me is that the overall distances are preserved — the total length and width of the polygon in miles should be preserved even though size of the polygon in pixels will obviously vary because of the map projection.
I've spent many hours Googling and searching on this site for an answer to this question but haven't been able to find one. Strictly speaking this is not a Google Maps issue — it's just a geometry issue related to rotating polygons on a map projection.
Here is more or less (some things dropped/renamed for simplicity) what I've been playing with so far:
function transpose_poly() {
//the polygon I'm transposing; these are actually in lng,lat not lat,lng
var poly = [
[165.2467094000077,11.90511591102683],[165.1960646350092,11.8776472999036],[165.163749733589,11.84385698549516],[165.1260503052001,11.79105209544025],[165.1174590975139,11.73721064669002],[165.1239723221977,11.68443896599666],[165.1455712453083,11.62322111902237],[165.1628352566873,11.60212814234246],[165.2801792409835,11.57112282455308],[165.3469838984795,11.55321856612457],[165.4267372080734,11.49929306693537],[165.565122175408,11.43334434041074],[165.7036021721537,11.37198352732909],[165.7982543390455,11.32757670668951],[165.942446703552,11.2660302522167],[166.0435044916007,11.23207374453692],[166.1628753311194,11.19161490039798],[166.3468035041342,11.13537294275959],[166.432786256031,11.11077339082378],[166.6460225244011,11.09603091173615],[166.9054486129032,11.10353634871533],[167.0953310801652,11.11920326808891],[167.2738338244123,11.14546202299651],[167.5299835821322,11.20017441185735],[167.7587090824888,11.25007287877568],[168.0532186132958,11.32987818697488],[168.3030699093596,11.40339603540862],[168.592055474493,11.49329084618948],[168.8894586866613,11.59767488596071],[169.1097084341002,11.70426500697907],[169.3388671138959,11.8464629880637],[169.47335151263,11.96284699062962],[169.4987805640997,12.00051052731504],[169.5113979458664,12.04997756596092],[169.496674063518,12.07975001861134],[169.4439862794831,12.10473302818016],[169.3792705121883,12.11718325976015],[169.2053586392944,12.12366910168141],[169.0210976722354,12.12171866909852],[168.7390558752391,12.08703266811138],[168.4733370821476,12.04764814638675],[168.1055698159765,12.00021651042535],[167.8745488025422,11.97152786285725],[167.5955303201492,11.94724207538445],[167.1571321566584,11.94152529858467],[166.8673995936747,11.95771709621411],[166.6698153277294,11.98911065050636],[166.4432968316392,12.03361885637251],[166.2604579582592,12.0693923391982],[166.0834945953367,12.09610600014998],[165.9206278637858,12.10688793842689],[165.7421018997999,12.1070118835482],[165.6244752224984,12.09489163127243],[165.4939687494391,12.0642833194958],[165.4055155587918,12.02521842289156],[165.3386147079753,11.97769336095395],[165.278157772496,11.92168821285675],[165.2467094000077,11.90511591102683],
];
var pos = marker.getPosition(); //where it transposes it to
var marker_lat = pos.lat();
var marker_lng = pos.lng();
var angle = document.getElementById("poly_angle").value; //rotational angle
var original_lat = 11.697222; //the original lat/lng of the polygon coordinates above
var original_lng = 165.27194399999996; //used to move the general polygon to a new set of coords as an offset
var new_poly = []; //the transformed polygon
//iterate over polygon array, create new array of Google Maps LatLng objects that are transposed and rotated
for(var i=0; i<poly.length; i++) {
new_poly.push( rotateLatLng( (poly[i][1]-original_lat)+marker_lat,(poly[i][0].lng()-original_lng)+marker_lng,angle));
}
// plot the polygon on the map
poly_obj = new google.maps.Polygon({
paths: poly_new,
strokeColor: "#ff763b",
strokeOpacity: 1,
strokeWeight: 1,
fillColor: "#ff763b",
fillOpacity: 0.25,
map: map,
visible: true
});
}
//this rotating function is cobbled together from code I found... it doesn't really work. It somewhat rotates it but distorts it terribly and gives really bizarre results
function rotateLatLng (pointLat,pointLng,angle) {
var pos = marker.getPosition();
var theX = pointLat;
var theY = pointLng;
var rotationTheta = angle;
var rotationThetaRad = rotationTheta*(Math.PI/180);
var rotationOriginX = pos.lat();
var rotationOriginY = pos.lng();
var newX;
var newY;
if (rotationOriginX == 0 && rotationOriginY == 0) {
newX = theX * Math.cos(rotationThetaRad) - Math.sin(rotationThetaRad) * theY;
newY = theX * Math.sin(rotationThetaRad) + Math.cos(rotationThetaRad) * theY;
} else {
newX = (theX - rotationOriginX) * Math.cos(rotationThetaRad) - (theY - rotationOriginY) * Math.sin(rotationTheta) + rotationOriginX;
newY = (theX - rotationOriginX) * Math.sin(rotationThetaRad) + (theY - rotationOriginY) * Math.cos(rotationTheta) + rotationOriginY;
}
return new google.maps.LatLng(newX,newY);
}
I don't think the above is necessarily the right way to do it at all. Any pointers would be helpful.
A much more simplified version of this problem would be to say that if I had an origin point of lat1,lng1, and another target point of lat2,lng2, how do I calculate lat3,lng3 which is defined as being the same distance between lat1,lng1 and lat2,lng2 but at an arbitrary angle? Because if I knew how to do that, applying that to the entire polygon should be a snap.
I have two coordinates for which I would like to draw a perpendicular line of equal length. Is there either a simple google maps offset for this or a clean javascript approach by which I might accomplish this? What would that be?
Here is what I have thus far. As you can see, I plot the two points as markers and then attempt to draw a line between them, except I need to get that line perpendicular to the line between the two coordinates.
var locations = [
['', position.coords.latitude, position.coords.longitude, 1],
['', llat, llng, 2]
];
var marker, i;
for ( var i = 0; i < locations.length; i++ )
{
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map
});
}
var borderPlanCoordinates = [
new google.maps.LatLng(llat, position.coords.longitude),
new google.maps.LatLng(position.coords.latitude,llng)
];
var borderPath = new google.maps.Polyline({
path: borderPlanCoordinates,
strokeColor: "#FF0000",
strokeOpacity: 1.0,
strokeWeight: 10,
map: map
});
borderPath.setMap(map);
So you have two points with coordinates (x1,y1) and (x2, y2) and you want to draw a line segment whose length is the distance between them, which is the perpendicular bisector of the segment connecting them, and which is bisected by said segment?
Probably the simplest way is to set cx = (x1 + x2)/2, cy = (y1+y2)/2), dx = (x2-x1)/2, dy = (y2-y1)/2 and then draw a line from (cx-dy, cy+dx) to (cx+dy, cy-dx).
This works because (cx, cy) is the midpoint of the segment you want, and then you're just taking the vector from that midpoint to (x2,y2) and rotating it by plus and minus 90 degrees to find the endpoints of the segment you want to draw.
I tried this solution, the middle of the segment is ok BUT it doesn't look perpendicular on google maps, I suspect because of spherical projection (not orthonormal).
Here is a solution that works :
spherical = google.maps.geometry.spherical;
var F = new google.maps.LatLng(latF, longF);
var T = new google.maps.LatLng(latT, longT);
// M is the middle of [FT]
var latM = (latF + latT)/2;
var longM = (longF + longT)/2;
var M = new google.maps.LatLng(latM, longM);
// Get direction of the segment
var heading = spherical.computeHeading(F, T);
var dist = 200; // distance in meters
// Place point A that is oriented at 90° in a distance of dist from M
var A = spherical.computeOffset(M, dist, heading+90);
var perpendicularCoordinates = [M, A ];
var perpendicular = new google.maps.Polyline({
path: perpendicularCoordinates,
geodesic: true,
strokeColor: '#FF0000',
strokeOpacity: 1.0,
strokeWeight: 2,
map: map
});
Here is the related fiddle : http://jsfiddle.net/8m7vm650/15/
Please note that you need to use an optional google maps library called geometry which is done by adding libraries=geometry to query string when loading maps : http://maps.googleapis.com/maps/api/js?libraries=geometry&sensor=false