Right now I have an array of locations and one of those locations will be a marker.
The second marker will be based on the location a user searches.
Right now the code is this:
function find_closest_marker( lat1, lon1 ) {
var pi = Math.PI;
var R = 6371; //equatorial radius
var distances = [];
var closest = -1;
var markers = allMyLocations;
for( i=0;i<markers.length; i++ ) {
var lat2 = markers[i][1];
var lon2 = markers[i][2];
var chLat = lat2-lat1;
var chLon = lon2-lon1;
var dLat = chLat*(pi/180);
var dLon = chLon*(pi/180);
var rLat1 = lat1*(pi/180);
var rLat2 = lat2*(pi/180);
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(rLat1) * Math.cos(rLat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
distances[i] = d;
if ( closest == -1 || d < distances[closest] ) {
closest = i;
}
var closestMarker = markers[closest];
var newLat = markers[closest][1]
var newLon = markers[closest][2]
var b = new google.maps.LatLng(newLat, newLon);
map.setCenter(b);
map.setZoom(10);
google.maps.event.addListenerOnce(map, 'tilesloaded', function(){
ShowHideMenu();
if($('#newPos').length==0){
$('div.gmnoprint').last().parent().wrap('<div id="newPos" />');
}
//showInfoWindow(map, closest);
});
}
}
Right now this code gets the closest location from where a user searches and centers that on the page. What I'm trying to do is make it zoom so that the the location searched is centered and the location in the array is within the area of the maps. The map isn't a normal size, it is 790px by 400px.
Can someone please help me with the logic of zoom and how I could make this possible?
Have you tried the LatLngBounds function This function will construct a viewable are based upon the soutwest and north east corners. As a result the pins will be centered in the map. You can use zoom if you want but you could omit it to see if it gives you the desired result.
A sample of the code would be:
make your declaration
var mybounds = new google.maps.LatLngBounds();
then within your event listener where you create the markers add
mybounds.extend(b);
then finally outside of the event listener
map.fitBounds(mybounds)
Related
How do I compute the distance in mile/meters of the displayed Map? Assuming I have the coordinates of the center of the map. I would like to know the distance/radius from the center to the left/right most displayed part of the map? I already got this using Google Map but I'm new in Openlayers. Is there a way to achieve this? Right now my computation in GoogleMap is like this
var bounds = this.instance.getBounds();
var center = bounds.getCenter();
var ne = bounds.getNorthEast();
// r = radius of the earth in statute miles
var r = 3963.0;
var to_radians_divide = 57.2958;
// Convert lat or lng from decimal degrees into radians (divide by 57.2958)
var lat1 = center.lat() / to_radians_divide;
var lon1 = center.lng() / to_radians_divide;
var lat2 = ne.lat() / to_radians_divide;
var lon2 = ne.lng() / to_radians_divide;
// distance = circle radius from center to Northeast corner of bounds
var dis = r * Math.acos(Math.sin(lat1) * Math.sin(lat2) +
Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1));
return dis;
Is there a way to achieve this in OpenLayers? I just want to find out the distance of the left most part of the displayed map from the center
You can achieve this in openlayers also. Here is the code for that and I am using openlayers 3.20.0 version for this example.
var size = map.getSize();
var center = map.getView().getCenter();
var sourceProj = map.getView().getProjection();
var extent = map.getView().calculateExtent(size);
extent = ol.proj.transformExtent(extent, sourceProj, 'EPSG:4326');
var posSW = [extent[0], extent[1]];
var posNE = [extent[2], extent[3]];
center = ol.proj.transform(center, sourceProj, 'EPSG:4326');
var wgs84Sphere = new ol.Sphere(6378137);
var centerToSW = wgs84Sphere.haversineDistance(center, posSW);
var centerToNE = wgs84Sphere.haversineDistance(center, posNE);
console.log("centerToSW - ",centerToSW);
console.log("centerToNE - ",centerToNE);
Note: The problem is not specific to Leaflet, but GIS in general.
I'm trying to draw an arc on a map. I have a function to generate the polygon points and it works on a canvas for example, but not on Lng,Lat map.
The problem is that I cannot figure out how to convert the inner/outer radius from Meters to degrees (as in lng/lat), what I tried so far looks more elliptic than circular.
How to accurately convert meters to longitude or latitude at any point on earth (except the poles)?
Here is what I tried (works) on canvas.
$(document).ready(function() {
var d_canvas = document.getElementById('canvas');
var c2 = d_canvas.getContext('2d');
c2.fillStyle = '#f00';
c2.beginPath();
var fromDeg = 0;
var toDeg = 90;
var fromRad = getAngle(fromDeg);
var toRad = getAngle(toDeg);
var segments = 100;
var step = getAngle(toDeg-fromDeg)/segments;
var x = 250;
var y = 250;
var outR = 250;
var inR = 230;
c2.moveTo(x+(Math.sin(fromRad)*inR),y-(Math.cos(fromRad)*inR));
//c2.moveTo(x,y);
for (var i = fromRad; i<=toRad; i=i+step){
c2.lineTo(x+(Math.sin(i)*inR),y-(Math.cos(i)*inR));
}
//c2.closePath();
for (var i = toRad; i>=fromRad; i=i-step){
c2.lineTo(x+(Math.sin(i)*outR),y-(Math.cos(i)*outR));
}
c2.lineTo(x+(Math.sin(fromRad)*inR),y-(Math.cos(fromRad)*inR));
//c2.closePath();
c2.stroke();
});
function getAngle(deg){
var val = 2*(deg/360);
return Math.PI*val;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width="500" height="500"></canvas>
And here is what I tried ( dosn't work well ) on Leaflet map.
var osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
osmAttrib = '© OpenStreetMap contributors',
osm = L.tileLayer(osmUrl, {
maxZoom: 18,
attribution: osmAttrib
});
// initialize the map on the "map" div with a given center and zoom
var map = L.map('map').setView([59.56667, 150.80000], 12).addLayer(osm);
// Script for adding marker on map click
L.polygon(getPolygon()).addTo(map);
function getPolygon() {
var fromDeg = 0;
var toDeg = 90;
var fromRad = getAngle(fromDeg);
var toRad = getAngle(toDeg);
var segments = 100;
var step = getAngle(toDeg - fromDeg) / segments;
var y = 150.84229;
var x = 59.55416;
var outR = 0.05; // <------ should be dynamic?
var inR = 0.025; // <------ this also?
var polygon = [];
polygon.push([x + (Math.sin(fromRad) * inR), y + (Math.cos(fromRad) * inR)]);
for (var i = fromRad; i <= toRad; i = i + step) {
polygon.push([x + (Math.sin(i) * inR), y + (Math.cos(i) * inR)]);
}
//c2.closePath();
for (var i = toRad; i >= fromRad; i = i - step) {
polygon.push([x + (Math.sin(i) * outR), y + (Math.cos(i) * outR)]);
}
polygon.push([x + (Math.sin(fromRad) * inR), y + (Math.cos(fromRad) * inR)]);
return polygon;
}
function getAngle(deg) {
var val = 2 * (deg / 360);
return Math.PI * val;
}
#map {
height: 500px;
width: 80%;
}
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
<link href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" rel="stylesheet" />
<script src="http://unpkg.com/leaflet-arc/bin/leaflet-arc.min.js"></script>
<div id="map"></div>
So your original question is
How to accurately convert meters to longitude or latitude at any point on earth (except the poles)?
But my brain reads that as
Given a [lat, lng] point and a distance d in meters, how to calculate a second [lat2, lng2] point which is d meters away from the first point?
Which, if you know some GIS jargon, is the same as asking
How do I solve the direct geodesic problem?
The answer involves mathematical concepts such as ellipsoids and great circles.
But given that you're working with Javascript and Leaflet, I'll just jump to practical implementations.
If you need a super-accurate answer, you want to have a look at the JS implementation of GeographicLib, and its methods to solve the direct geodesic problem.
If you don't really care about accuracy (and specially do not care about accuracy at the poles), you want to have a look at cheap-ruler, and specifically its destination(p, dist, bearing) method.
There are more solutions, like using a equidistant map projection centered on the point, or some other implementations of the geodesic problems, or some turf.js trickery, or creating the geometries outside of JS with similar methods, or whatever.
This problem has been solved already, so I advise to use any of the existing solutions.
This solved the problem
var osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
osmAttrib = '© OpenStreetMap contributors',
osm = L.tileLayer(osmUrl, {
maxZoom: 18,
attribution: osmAttrib
});
// initialize the map on the "map" div with a given center and zoom
var map = L.map('map').setView([59.56667, 150.80000], 12).addLayer(osm);
// Script for adding marker on map click
L.polygon(getPolygon()).addTo(map);
function getPolygon() {
var fromDeg = 0;
var toDeg = 120;
var lat = 59.56667;
var lon = 150.80000;
var outR = 200;
var inR = 180;
var polygon = [];
for (var i = fromDeg; i <= toDeg; i++) {
polygon.push(getPoint(lat, lon, inR, i));
}
for (var i = toDeg; i >= fromDeg; i--) {
polygon.push(getPoint(lat, lon, outR, i));
}
polygon.push(getPoint(lat, lon, inR, fromDeg));
return polygon;
}
/*************************
* The solution
*************************/
function getPoint(lat, lon, r, deg) {
lat2 = (r / 111230) * Math.cos(deg2rad(deg));
lat2 += lat;
lon2 = (r / 111230) * Math.sin(deg2rad(deg));
lon2 = lon2 * (1 / Math.cos(deg2rad(lat2)));
lon2 += lon;
return [lat2, lon2];
}
function deg2rad(deg) {
return deg * (Math.PI / 180);
}
#map {
height: 500px;
width: 80%;
}
<link href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" rel="stylesheet"/>
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
<div id="map"></div>
How can I get the current width of the visible area on Google map, i have read many docs but not success? I need to get real width of visible area in kilometers.
I think getBounds() is what you are looking for.
var map = new google.maps.Map(document.getElementById("map_canvas"),
myOptions);
google.maps.event.addListener(map, 'idle', function(event) {
var bounds = map.getBounds();
You will receive a LatLngBounds object (for reference https://developers.google.com/maps/documentation/javascript/reference#LatLngBounds).
This contains NortEase and SouthWest LatLng points. Using those it should be easy to get the width in kilometers using this formula. You can create 2 pairs out of LatLng points to create a NorthWest and NorthEast pair and calculate the distance between those.
var R = 6371000; // metres
var φ1 = lat1.toRadians();
var φ2 = lat2.toRadians();
var Δφ = (lat2-lat1).toRadians();
var Δλ = (lon2-lon1).toRadians();
var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
See this as an reference (http://www.movable-type.co.uk/scripts/latlong.html).
I have an array of users and their gps coordinates.
what formula can I use to get all the users that are within X KM range
from a user?
I need to avoid heavy calculations.
I was thinking about sorting the array, but I realized that it isn't a good idea, because I would have to set a sorted array for each user.
Use the Haversine formula to find the users that are within a specified distance from a specified point:
function getNearbyUsers(lat, lng, distanceInKm, users) {
var R = 6373;
var latRad = lat * Math.PI/180;
var lngRad = lng * Math.PI/180;
var returnUsers = [];
for (var i = 0; i < users.length; i++) {
var lat2Rad = users[i].lat * Math.PI/180;
var lng2Rad = users[i].lng * Math.PI/180;
var dlat = lat2Rad - latRad;
var dlng = lng2Rad - lngRad;
var a = Math.pow(Math.sin(dlat/2),2) + Math.cos(latRad) * Math.cos(lat2Rad) * Math.pow(Math.sin(dlng/2),2);
var c = 2 * Math.atan2(Math.sqrt(a),Math.sqrt(1-a)); // great circle distance in radians
var d = c * R; // Distance from user in km
if (d < distanceInKm) returnUsers.push(users[i]);
}
return returnUsers;
}
So i want to calculate distance between my start point and multiple points, than display the shortest route to this point,but it show me always the last point. this is my distanceCal function it works fine :
function getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1); // deg2rad below
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; // Distance in km
return d;
}
function deg2rad(deg) {
return deg * (Math.PI / 180)
}
and this is my points latt/long :
var dist = [
[35.733972, -5.881999],
[ 35.734077, -5.881033],
[ 35.736898, -5.877771],
[35.738396, -5.875154]
];
then my script to display directions :
function calcRoute() {
var start = new google.maps.LatLng(35.728329, -5.882750);
for (var i = 0; i < dist.length; i++)
{
var dis = dist[i];
//here i need something to choose the shortest route
var min = Math.min(getDistanceFromLatLonInKm(35.728329, -5.882750, dis[0], dis[1]));
var end = new google.maps.LatLng(dis[0], dis[1]);
}
var request = {
origin: start,
destination: end,
optimizeWaypoints: true,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
google.maps.event.addDomListener(window, 'load', getMap);
so please if someone have any idea or solution i will be very appreciate.
The following code uses Googles geometry library to calculate distances between points.The distances are stored in an array and then parsed to find minimum distance .
I have changed the array from dist[] to coords[] as we need an array to hold distances dist[].
<script type="text/javascript" src="//maps.googleapis.com/maps/api/js?libraries=geometry&sensor=false"></script>
<script type="text/javascript">
var coords = [
[35.733972, -5.881999],
[35.734077, -5.881033],
[35.736898, -5.877771],
[35.738396, -5.875154]
];
var dist = [];//Array to hold distances
function calcRoute() { {
var start = new google.maps.LatLng(35.728329, -5.882750);
for (var i = 0; i < coords.length; i++){
var point = new google.maps.LatLng(coords[i][0],coords[i][1]);
var distance = google.maps.geometry.spherical.computeDistanceBetween(start, point);
dist.push(distance);
}
var test = dist[0];
var index = 0;
for (var i = 1; i < dist.length; i++){
if(dist[i] < test){
test = dist[i];
index = i;
}
}
var end = new google.maps.LatLng(coords[index][0],coords[index][1]);
// Apply the rest of your code here
It sounds like you want to use optimizeWaypoints:true in your DirectionsServiceRequest:
optimizeWaypoints | boolean | If set to true, the DirectionService will attempt to re-order the supplied intermediate waypoints to minimize overall cost of the route. If waypoints are optimized, inspect DirectionsRoute.waypoint_order in the response to determine the new ordering.
The DirectionsResult
Each leg of each route returned includes distance and duration information.