This bit of Javascript parses an xml file which contains latitude and longitude co-ordinates for a start and end point. I can get the markers out on a map fine, the issue I'm having is that the map doesn't center on the points (eventually it's going to make a call to the Google Directions Service and draw a route between the two points, so would be good to have the map fit nicely around both points rather than just centering on one of the points).
At the minute the map is created using hardcoded lat and long values so I know that needs changing, but I've tried putting in 'startpoint, and 'endpoint' to no avail, the map doesn't load, so I'm guessing the way I'm doing it below is incorrect.
jQuery(document).ready(function($) {
downloadUrl("xml.php", function(data) {
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++) {
var name = markers[i].getAttribute("title");
var startpoint = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("startlat")),
parseFloat(markers[i].getAttribute("startlng")));
var endpoint = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("endlat")),
parseFloat(markers[i].getAttribute("endlng")));
var html = "<b>" + name;
var icon = customIcons || {};
var startmarker = new google.maps.Marker({
map: map,
position: startpoint,
icon: icon.icon,
shadow: icon.shadow
});
bindInfoWindow(startmarker, map, infoWindow, html);
var endmarker = new google.maps.Marker({
map: map,
position: endpoint,
icon: icon.icon,
shadow: icon.shadow
});
bindInfoWindow(endmarker, map, infoWindow, html);
}
});
var map = new google.maps.Map(document.getElementById("map_canvas"), {
center: new google.maps.LatLng(startpoint, endpoint),
zoom: 13,
mapTypeId: 'roadmap'
});
var infoWindow = new google.maps.InfoWindow;
});
This is the output of the XML...
<markers>
<marker title="Journey" description="Lorem Ipsum..." startlat="53.403023" startlng="-2.130801" endlat="53.414257" endlng="-2.094128"/>
</markers>
If you generate a bounds using your startpoint and endpoint, you can fit the map to display that bounds.
var map = new google.maps.Map(document.getElementById("map_canvas"), {
zoom: 13,
mapTypeId: 'roadmap'
});
var bounds = new google.maps.LatLngBounds();
bounds.extend(startpoint);
bounds.extend(endpoint);
map.fitBounds(bounds);
LatLng expect's latitude and longtude of the point where you want to center your map.
And that is why below code doesn't work.
center: new google.maps.LatLng(startpoint, endpoint),
To show the route between two point's on centre of the map. you can try finding the middle point between your start and end point.
Here is an implementation in java that calculate's middle point, more info - Haversine_formula
public static void midPoint(double lat1,double lon1,double lat2,double lon2){
double dLon = Math.toRadians(lon2 - lon1);
//convert to radians
lat1 = Math.toRadians(lat1);
lat2 = Math.toRadians(lat2);
lon1 = Math.toRadians(lon1);
double Bx = Math.cos(lat2) * Math.cos(dLon);
double By = Math.cos(lat2) * Math.sin(dLon);
double lat3 = Math.atan2(Math.sin(lat1) + Math.sin(lat2), Math.sqrt((Math.cos(lat1) + Bx) * (Math.cos(lat1) + Bx) + By * By));
double lon3 = lon1 + Math.atan2(By, Math.cos(lat1) + Bx);
//print out in degrees
System.out.println(Math.toDegrees(lat3) + " " + Math.toDegrees(lon3));
}
Edit:
Javascript implementation
function middlePoint(lat1,lon1,lat2,lon2){
var dLon = toRad(lon2 - lon1);
lat1 = toRad(lat1);
lat2 = toRad(lat2);
lon1 = toRad(lon1);
var Bx = Math.cos(lat2) * Math.cos(dLon);
var By = Math.cos(lat2) * Math.sin(dLon);
var lat3 = Math.atan2(Math.sin(lat1) + Math.sin(lat2), Math.sqrt((Math.cos(lat1) + Bx) * (Math.cos(lat1) + Bx) + By * By));
var lon3 = lon1 + Math.atan2(By, Math.cos(lat1) + Bx);
var middlePoint = new Object();
middlePoint.latitude=lat3;
middlePoint.longitude=lon3;
return middlePoint;
}
function toRad(Value) {
return Value * Math.PI / 180;
}
Related
I can't manage with drawing rectangle between two cities. I've searched everywhere on the Internet and can't find out why my polygon is drawn on Google Maps as parallelogram even so on 2d plane (not earth plane) this rectangle is drawn properly.
What I noticed is that the curvature sides of parallelogram depends on where cities are placed on map. If two cities are placed vis-a-vis then my function draw rectangle successfully. But If they are placed diagonally then my function draw parallelogram. The result should be rotated rectangle with height as distance between two cities and width as kilometers that user chooses.
Here is my function that should draw rectangle between two cities. As args we need to give position of first city ($x1 is lat, $y1 is lng), position of second city and as third arg a radius in kilometers ($l1) from center point of rectangle.
function getPolygon($x1,$y1,$x2,$y2,$l1){
var $l1 = $l1*0.010526; //approx kilometers
var $distanceV = [($x2 - $x1), ($y2 - $y1)];
var $vlen = Math.sqrt(Math.pow($distanceV[0], 2) +
Math.pow($distanceV[1],2));
if($vlen == 0)
return [[0,0],[0,0],[0,0],[0,0]];
var $l2 = $vlen;
var $normalized = [($distanceV[0] / $vlen), ($distanceV[1] / $vlen)];
var $rotated = [(-1 * $normalized[1]), ($normalized[0])];
var $p1 = [($x1 - $rotated[0] * $l1 / 2), ($y1 - $rotated[1] * $l1 / 2)];
var $p2 = [($p1[0] + $rotated[0] * $l1), ($p1[1] + $rotated[1] * $l1)];
var $p3 = [($p1[0] + $normalized[0] * $l2), ($p1[1] + $normalized[1] * $l2)];
var $p4 = [($p3[0] + $rotated[0] * $l1), ($p3[1] + $rotated[1] * $l1)];
var $points = [
{lat: $p1[0], lng: $p1[1]},
{lat: $p3[0], lng: $p3[1]},
{lat: $p4[0], lng: $p4[1]},
{lat: $p2[0], lng: $p2[1]},
{lat: $p1[0], lng: $p1[1]}
];
return $points;
}
Then I draw it on Google Maps like this:
new google.maps.Polygon({
paths: getPolygon(first_city_lat, first_city_lng, second_city_lat, second_city_lng, 30),
strokeColor: '#FF0000',
strokeOpacity: 0.5,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.05
});
Here is an example should be rectangle between Birmingham and Oxford: JSFiddle
Additionally I'm sure that kilometers converter is not exact and it again depends how cities are placed.
The earth is curved. To get a polygon that appears rectangular on the curved sphere, you need to use calculations that take the projection of the map into account.
The Google Maps Javascript API v3 has a spherical geometry library that can be used to compute the desired points.
function getPolygon($x1,$y1,$x2,$y2,$l1){
var points = [];
var city1 = new google.maps.LatLng($x1, $y1);
var city2 = new google.maps.LatLng($x2, $y2);
var heading = google.maps.geometry.spherical.computeHeading(city1, city2);
points.push(google.maps.geometry.spherical.computeOffset(city1, $l1/2*1000, heading+90));
points.push(google.maps.geometry.spherical.computeOffset(city1, $l1/2*1000, heading-90));
points.push(google.maps.geometry.spherical.computeOffset(city2, $l1/2*1000, heading-90));
points.push(google.maps.geometry.spherical.computeOffset(city2, $l1/2*1000, heading+90));
points.push(points[0]);
return points;
}
proof of concept fiddle
code snippet:
var map;
google.maps.event.addDomListener(window, "load", function() {
var map = new google.maps.Map(document.getElementById("map_div"), {
center: new google.maps.LatLng(52.489471, -1.898575),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var trace = new google.maps.Polygon({
paths: getPolygon(52.489471, -1.898575, 51.752022, -1.257677, 30),
strokeColor: '#FF0000',
strokeOpacity: 0.5,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.05,
map: map
});
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < trace.getPath().getLength(); i++) {
bounds.extend(trace.getPath().getAt(i));
}
map.fitBounds(bounds);
function getPolygon($x1, $y1, $x2, $y2, $l1) {
var points = [];
var city1 = new google.maps.LatLng($x1, $y1);
var city2 = new google.maps.LatLng($x2, $y2);
var heading = google.maps.geometry.spherical.computeHeading(city1, city2);
points.push(google.maps.geometry.spherical.computeOffset(city1, $l1 / 2 * 1000, heading + 90));
points.push(google.maps.geometry.spherical.computeOffset(city1, $l1 / 2 * 1000, heading - 90));
points.push(google.maps.geometry.spherical.computeOffset(city2, $l1 / 2 * 1000, heading - 90));
points.push(google.maps.geometry.spherical.computeOffset(city2, $l1 / 2 * 1000, heading + 90));
points.push(points[0]);
return points;
}
});
html,
body {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
}
#map_div {
height: 95%;
}
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
<div id="map_div"></div>
Trying to make the similar effect on my Googlemaps map.
This is using Ionic Native Google Maps plugin.
I currently have the following code.
Points are used to create an overlaying polygon across the whole map, and then I am using the drawCircle function to draw a circle by adding lat / lng points to the array extp.push({lat: ey,lng: ex});
points = [
{lat: 85,lng: 90},
{lat: 85,lng: 0.1},
{lat: 85,lng: -90},
{lat: 85,lng: -179.9},
{lat: 0,lng: -179.9},
{lat: -85,lng: -179.9},
{lat: -85,lng: -90},
{lat: -85,lng: 0.1},
{lat: -85,lng: 90},
{lat: -85,lng: 179.9},
{lat: 0,lng: 179.9},
{lat: 85,lng: 179.9} ];
drawCircle(point, radius, dir) {
let lat;
let lng;
var d2r = Math.PI / 180; // degrees to radians
var r2d = 180 / Math.PI; // radians to degrees
var earthsradius = 3963; // 3963 is the radius of the earth in miles or 6371 in km
var points = 32;
// find the raidus in lat/lon
var rlat = (radius / earthsradius) * r2d;
var rlng = rlat / Math.cos(point.lat() * d2r);
var extp = new Array();
if (dir==1) {var start=0;var end=points+1} // one extra here makes sure we connect the ends
else {var start=points+1;var end=0}
for (var i=start; (dir==1 ? i < end : i > end); i=i+dir) {
var theta = Math.PI * (i / (points/2));
let ey = point.lng() + (rlng * Math.cos(theta)); // center a + radius x * cos(theta)
let ex = point.lat() + (rlat * Math.sin(theta)); // center b + radius y * sin(theta)
extp.push({lat: ey,lng: ex});
}
return extp;
}
Loading the map here
this.map.on(GoogleMapsEvent.MAP_READY).subscribe(() => {
console.log('Map is ready!');
this.geolocation.getCurrentPosition({enableHighAccuracy: true}).then((resp) => {
console.log(resp.coords.latitude);
console.log(resp.coords.longitude);
this.myLat = resp.coords.latitude;
this.myLong = resp.coords.longitude;
let loc: LatLng;
loc = new LatLng (resp.coords.latitude, resp.coords.longitude);
this.map.addPolygon({
'points': this.points,
'strokeColor': "blue",
'holes': this.drawCircle(loc,10,-1), //when adding this I lose the overlay and the hole is not drawn. When I remove it, it starts to work again but without a hole.
'strokeWidth': 4,
'fillColor': "#222222"
});
this.map.moveCamera({
'target': loc,
'zoom': 14
});
this.map.addMarker({
'position': loc,
'title': "Hello GoogleMap for Cordova!",
'icon' : 'https://image.flaticon.com/icons/svg/147/147144.svg'
});
}).catch((error) => {
console.log('Error getting location', error);
});
});
you can make hole by using ctx.clip() function.
1.make a canvas with full width,height.
2.fill canvas with "argb(100,255,0,0)".
3.use arc() and clip() to make a hole.
4.set strokeStyle to "argb(255,255,0,0)".
5.use arc() and stroke() to make red outline.
this is how to make a hole.
I'm currently building a webpage that shows customer reviews on a Google Maps. There is one issue and that is that there are already over 1200 reviews that needs to be shown on the map but those reviews only have a city attached to them so when I load all of those reviews in the map than a lot of them will share the exact same coordinates.
I am looking for a way to scatter identical markers within a certain radius. So lets say pick every single marker on the map and move them al 1% in a random direction to create distance between them.
I don't really mind how this will be done, be it by javascript or PHP, duriong the placement of the markers or beforehand with an algorithm that sets new coordinates one.
May be something like this
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 5,
center: { lat: -25.363, lng: 131.044 }
});
var originalMarker = new google.maps.Marker({
position: { lat: -25.363, lng: 131.044 },
map: map,
title: ''
});
google.maps.event.addListenerOnce(map, 'idle', function () {
var circle = new google.maps.Circle({
map: map,
radius: 1000 * 1000, //in metres
fillColor: '#AA0000'
});
circle.bindTo('center', originalMarker, 'position');
drawMarkersInCircle(circle, 200);
});
}
function drawMarkersInCircle(circle, count) {
var map = circle.getMap();
var proj = map.getProjection();
var centerPoint = proj.fromLatLngToPoint(circle.getCenter());
var radius = Math.abs(proj.fromLatLngToPoint(circle.getBounds().getNorthEast()).x - centerPoint.x);
for (var i = 0; i < count; i++) {
var point = createRandomPointInCircle(centerPoint, radius);
var pos = proj.fromPointToLatLng(point);
//console.log(point);
var marker = new google.maps.Marker({
position: pos,
map: map,
title: ''
});
}
}
function createRandomPointInCircle(centerPoint, radius) {
var angle = Math.random() * Math.PI * 2;
var x = (Math.cos(angle) * getRandomArbitrary(0, radius)) + centerPoint.x;
var y = (Math.sin(angle) * getRandomArbitrary(0, radius)) + centerPoint.y;
return new google.maps.Point(x, y);
}
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
google.maps.event.addDomListener(window, 'load', initMap);
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
<script src="http://maps.googleapis.com/maps/api/js?key=&sensor=false"></script>
<div id="map"></div>
The example demonstrates how to draw a markers randomly inside a circle.
I have a array of point with latitude and longitude. Next, I add all points to my map.
I need solution/algorithm to move user to the nearest point from my array using geoloation on page load.
(if geolocation success of course)
This should do the trick. I combined both HTML5 geolocation to find the user's current location and Haversine function to calculate distances from a set of locations and the user's current location. The set of locations is defined in the JS array 'locations'.
<!DOCTYPE html>
<html>
<head>
<title>Google Map Template with Marker at User's Position</title>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script> <!-- Google Maps API -->
<script>
// set of locations represented by lat/lon pairs
var locations = [{lat:45, lon:-120}, {lat:44, lon:-121}, {lat:45.6, lon:-120.5}];
var map; // Google map object
// Initialize and display a google map
function Init()
{
// HTML5/W3C Geolocation
if ( navigator.geolocation )
{
navigator.geolocation.getCurrentPosition( UserLocation, errorCallback,{maximumAge:60000,timeout:10000});
}
// Default to Washington, DC
else
ClosestLocation( 38.8951, -77.0367, "Washington, DC" );
}
function errorCallback( error )
{
}
// Callback function for asynchronous call to HTML5 geolocation
function UserLocation( position )
{
ClosestLocation( position.coords.latitude, position.coords.longitude, "This is my Location" );
}
// Display a map centered at the specified coordinate with a marker and InfoWindow.
function ClosestLocation( lat, lon, title )
{
// Create a Google coordinate object for where to center the map
var latlng = new google.maps.LatLng( lat, lon );
// Map options for how to display the Google map
var mapOptions = { zoom: 12, center: latlng };
// Show the Google map in the div with the attribute id 'map-canvas'.
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
// Place a Google Marker at the same location as the map center
// When you hover over the marker, it will display the title
var marker = new google.maps.Marker( {
position: latlng,
map: map,
title: title
});
// Create an InfoWindow for the marker
var contentString = "<b>" + title + "</b>"; // HTML text to display in the InfoWindow
var infowindow = new google.maps.InfoWindow( { content: contentString } );
// Set event to display the InfoWindow anchored to the marker when the marker is clicked.
google.maps.event.addListener( marker, 'click', function() { infowindow.open( map, marker ); });
// find the closest location to the user's location
var closest = 0;
var mindist = 99999;
for(var i = 0; i < locations.length; i++)
{
// get the distance between user's location and this point
var dist = Haversine( locations[ i ].lat, locations[ i ].lon, lat, lon );
// check if this is the shortest distance so far
if ( dist < mindist )
{
closest = i;
mindist = dist;
}
}
// Create a Google coordinate object for the closest location
var latlng = new google.maps.LatLng( locations[ closest].lat, locations[ closest].lon );
// Place a Google Marker at the closest location as the map center
// When you hover over the marker, it will display the title
var marker2 = new google.maps.Marker( {
position: latlng,
map: map,
title: "Closest Location to User: Distance is " + mindist + " km"
});
// Create an InfoWindow for the marker
var contentString = "<b>" + "Closest Location to User: Distance is " + mindist + " km" + "</b>"; // HTML text to display in the InfoWindow
var infowindow = new google.maps.InfoWindow( { content: contentString } );
// Set event to display the InfoWindow anchored to the marker when the marker is clicked.
google.maps.event.addListener( marker2, 'click', function() { infowindow.open( map, marker2 ); });
map.setCenter( latlng );
}
// Call the method 'Init()' to display the google map when the web page is displayed ( load event )
google.maps.event.addDomListener( window, 'load', Init );
</script>
<script>
// Convert Degress to Radians
function Deg2Rad( deg ) {
return deg * Math.PI / 180;
}
// Get Distance between two lat/lng points using the Haversine function
// First published by Roger Sinnott in Sky & Telescope magazine in 1984 (“Virtues of the Haversine”)
//
function Haversine( lat1, lon1, lat2, lon2 )
{
var R = 6372.8; // Earth Radius in Kilometers
var dLat = Deg2Rad(lat2-lat1);
var dLon = Deg2Rad(lon2-lon1);
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(Deg2Rad(lat1)) * Math.cos(Deg2Rad(lat2)) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
// Return Distance in Kilometers
return d;
}
// Get Distance between two lat/lng points using the Pythagoras Theorem on a Equirectangular projection to account
// for curvature of the longitude lines.
function PythagorasEquirectangular( lat1, lon1, lat2, lon2 )
{
lat1 = Deg2Rad(lat1);
lat2 = Deg2Rad(lat2);
lon1 = Deg2Rad(lon1);
lon2 = Deg2Rad(lon2);
var R = 6371; // km
var x = (lon2-lon1) * Math.cos((lat1+lat2)/2);
var y = (lat2-lat1);
var d = Math.sqrt(x*x + y*y) * R;
return d;
}
</script>
<style>
/* style settings for Google map */
#map-canvas
{
width : 500px; /* map width */
height: 500px; /* map height */
}
</style>
</head>
<body>
<!-- Dislay Google map here -->
<div id='map-canvas' ></div>
</body>
</html>
I have in my code this
var map;
function initialize() {
var mapDiv = document.getElementById('map-canvas');
map = new google.maps.Map(mapDiv, {
center: new google.maps.LatLng(37.4419, -122.1419),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
google.maps.event.addListenerOnce(map, 'tilesloaded', addMarkers);
}
function addMarkers() {
var iconoMarca = "/assets/giftRayo.gif");
var bounds = map.getBounds();
var southWest = bounds.getSouthWest();
var northEast = bounds.getNorthEast();
var lngSpan = northEast.lng() - southWest.lng();
var latSpan = northEast.lat() - southWest.lat();
for (var i = 0; i < 10; i++) {
var latLng = new google.maps.LatLng(southWest.lat() + latSpan * Math.random(),
southWest.lng() + lngSpan * Math.random());
var marker = new google.maps.Marker({
position: latLng,
map: map,
icon: iconoMarca
});
}
}
but the marker doesn't appear and if I use a png or jpeg it works. What am I doing wrong?? Do the gif animations have another treatment?
As a standard, the markers use something called optimized rendering that always renders the markers as static. To see animated gifs you need to set optimized = false on your marker. The code for generating your marker would then be:
var marker = new google.maps.Marker({
position: latLng,
map: map,
icon: iconoMarca,
optimized: false
});
This should solve your problem.
Ps.:
You seem to have a small bug in your code:
var iconoMarca = "/assets/giftRayo.gif");
You should remove the ).