I'm developing a job board type website for a client that has filters for the jobs posted. This website is built off of Wordpress and using the Ajax Load More plugin to dynamically populate the jobs. I want to have a filter that a user can enter their address and the closest jobs to that entered address would populate.
I currently have it set up to grab the latitude and longitude of each job posted, as well as, the latitude and longitude of the address when the user enters it, using the Google Maps API. What I can't figure out his how to correlate the two and have Ajax Load More populate the jobs with the closest lat/long to the entered address?
First, create an array that contains the lat/lng's of the job posted. Here's an example:
var job_locs = [ //job locations array
{lat:59.611975, lng:16.547017},//within radius
{lat:59.612186, lng:16.544901},//within radius
{lat:59.614412, lng:16.538992},//within radius
{lat:59.615677, lng:16.546703},//within radius
{lat:59.618794, lng:16.545480},//within radius
{lat:59.622650, lng:16.558984},//outside radius
{lat:59.615612, lng:16.555962},//outside radius
{lat:59.610812, lng:16.549959},//outside radius
{lat:59.608804, lng:16.541045},//outside radius
{lat:59.608084, lng:16.537515},//outside radius
];
As you can see there, I have provided 5 within the 500 meter radius of the user and another 5 outside the radius. Here's the user's location:
var user = { lat: 59.615911, lng: 16.544232 };
Now you just have to loop through the array of job locations and check if they are within the radius. To do this, there is a post about this here in SO: Check if a latitude and longitude is within a circle google maps
if you check the accepted answer (credits to Guffa), he used this function to check if the point is within the radius:
function arePointsNear(checkPoint, centerPoint, km) { // credits to user:69083
var ky = 40000 / 360;
var kx = Math.cos(Math.PI * centerPoint.lat / 180.0) * ky;
var dx = Math.abs(centerPoint.lng - checkPoint.lng) * kx;
var dy = Math.abs(centerPoint.lat - checkPoint.lat) * ky;
return Math.sqrt(dx * dx + dy * dy) <= km;
}
Now we use this function in a loop:
job_locs.forEach(function(locs){
var n = arePointsNear(user, locs, 0.5); //0.5km = 500meters
if(n){
marker = new google.maps.Marker({
map: map,
position: locs,
label: {
text:"I", //marking all jobs inside radius with I
color:"white"
}
});
}else{ //remove this to see only the locations within radius
marker = new google.maps.Marker({
map: map,
position: locs,
label: {
text:"O", //marking all jobs outside radius with O
color:"white"
}
});
}
});
Note: This displays all the nearby locations from the list within the
provided radius. If there are no location found within the radius,
there will be no result. Also, please read the source of
arePointsNear function,
for the limitation of this function.
Here is a working sample in JS Bin: click me!
What You Have
Latitude/Longitude of each job
Latitude/Longitude of user's address
What You Want
List of job post displaying by nearest location
Approach
Calculate the distance using formula in this page
Load list of jobs by the order of distance calculated
Related
I want to calculate distance from a collection of geo coordinates. I have converted this to a GPX file and I am able to use in HERE Maps to calculate distance.
Now, I want to use this in Google Maps as per my customer requirement. Is there any option in Google Maps which accepts GPX file and return distance ? I have seen distancematrix option and believe this is in different format.
There are some parts here. The calculation based on Google Maps docs.
Notice that if you need only to calculate the distances, you don't need even google maps api. The calculation is based on the coordinates only.
Parse GPX file
GPX is basically an xml as well as html. So After you parse the content of the file using window.DOMParser().parseFromString(str, "text/xml")); you can use the DOM API (such as querySelector, querySelectorAll etc.) to retrieve all the trkpt element and extract their lat and lon values.
const coords = Array.from(xml.querySelectorAll("trkpt")).map(
element =>
new google.maps.LatLng(
Number(element.getAttribute("lat")),
Number(element.getAttribute("lon"))
)
);
I used google.maps.LatLng but you can store it in a plain object if you don't need it to interact with your map.
Calculate the distances
Iterate over the coordinates array and measure from one point to another.
function haversine_distance(coord1, coord2) {
const R = 3958.8; // Radius of the Earth in miles
const rlat1 = coord1.lat() * (Math.PI/180); // Convert degrees to radians
const rlat2 = coord2.lat() * (Math.PI/180); // Convert degrees to radians
const difflat = rlat2-rlat1; // Radian difference (latitudes)
const difflon = (coord2.lng()-coord1.lng()) * (Math.PI/180); // Radian difference (longitudes)
const d = 2 * R * Math.asin(Math.sqrt(Math.sin(difflat/2)*Math.sin(difflat/2)+Math.cos(rlat1)*Math.cos(rlat2)*Math.sin(difflon/2)*Math.sin(difflon/2)));
return d;
}
Then you can the function to build the distances array
const distances = coords.reduce((old, ne, index, original) => {
if (index > 0) {
old.push(haversine_distance(ne, original[index - 1]));
}
return old;
}, []);
https://codesandbox.io/s/elegant-turing-tvhu1?file=/index.html
Using trimble maps, i'm creating a route with origin and destination points given by latitude and longitude. The user can put new stops at the interactive map. The problem is that when the library returns me the stops locations, it is giving me those like X and Y and not like longitude and latitude.
For example, if the origin is
Latitude: 37.66427
Longitude: -97.72388
The application is returning me the point like
x: -10878572.558428662
y: 4532106.384744367
I'm doing this to get the stops:
var routeElements = routingLayer.getRouteElements("MyRoute");
var numberOfStops = routeElements.stops.length;
for (var i = 0; i < numberOfStops; i++) {
console.log("Stop " + i);
console.log("Lon: " + routeElements.stops[i].geometry.x);
console.log("Lat: " + routeElements.stops[i].geometry.y);
}
As says at the following documentation:
https://developer.trimblemaps.com/trimble-maps/1.2/docs/routing/
I need to know the way to convert X and Y to Longitude and Latitude or get directly the LonLat with any specific command.
You'd have to use the transform function to change the point back to a geographic projection.
In this case you would need to call
routeElements.stops[i].transform(map.getProjectionObject(),new ALKMaps.Projection("EPSG:4326"))
to get a Point object where the x and y are longitude and latitude values.
It's basically the reverse of what's described here: https://developer.trimblemaps.com/trimble-maps/1.2/docs/getting-started/spherical-mercator/
I have a list with 50 items:
var mylocations = [{'id':'A', 'loc':[-21,2]},...,];
How can I in leaflet or JavaScript most efficiently make it such that if I accept an input of a specific location [<longitude>,<latitude>], a radius (e.g. 50 miles)... I can get all of the "mylocations" that fall within that circle?
Using external libraries is fine.
Leaflet's L.LatLng objects include a distanceTo method:
Returns the distance (in meters) to the given LatLng calculated using the Haversine formula.
http://leafletjs.com/reference.html#latlng-distanceto
var inRange = [], latlng_a = new L.LatLng(0, 0), latlng_b;
locations.forEach(function (location) {
latlng_b_ = new L.LatLng(location.pos[0], location.pos[1]);
if (latlng_a.distanceTo(latlng_b) < 80.4672) {
inRange.push(location);
}
});
I have locations stored in mongodb that look like this in mongoose schema:
location: {
type: [Number],
index: '2d'
}
And on web client I'm using google maps api with custom radius resizer:
On each drag I'm making request with radius value that is calculated on client. Radius is the distance between pink arrow marker and center coordinates:
function metersToMiles (meters) {
return meters * 0.000621371192;
}
google.maps.event.addListener(this.sizer, 'dragend', () => {
const radius = this.circle.getRadius();
const radiusValue = Math.round(metersToMiles(radius) * 10) / 10; // convert to tenths (this is shown on UI as well)
this.props.onRadiusChange(radiusValue); // it's a react component
});
In mongodb request I'm using $nearSphere with radius in $maxDistance:
function milesToRadian(miles){
const earthRadiusInMiles = 3963.2;
return parseFloat(miles) / earthRadiusInMiles;
}
const { radius, lat, lon } = req.query;
const coords = (lat && lon) ? [lat, lon] : ukCoordinates;
const radians = milesToRadian(radius);
console.log('%s, %s, %s', radius, coords, radians);
// what I receive: 1.6, 0.00040371417036737993, [ 51.507351, -0.127758 ]
// ...
{
$nearSphere: coords,
$maxDistance: radians
}
However if you take a look on the gif image you'll see that there's some inaccuracy in results. For now I'm stucked with it, could you suggest what is the problem?
So the problem was really funny but still tricky. I've found out that in MongoDB you need to store coordinate pairs as [longitude, latitude] and not vice versa:
location: {
type: [Number], // longitude, latitude
index: '2d'
}
But in Google Maps SDK the order is different:
new google.maps.LatLng(lat, lng);
So to fix my problem I've needed to store coordinates in right order in MongoDB.
I am traking user movement according to their latitude and longitude.so for last 1hr i got more than 20 coordinates.Using that co-ordinates i am drawing the map using google map api.I got one curly line(user's movement graph) and i want the get the distance from the staring point to ending point.
these are my co-ordinates:-
[[12.938419, 77.62224],
[12.938494, 77.622377],
[12.938369, 77.622449],
[12.938345, 77.622521],
[12.938322, 77.622575],
[12.938346, 77.622631],
[12.938306, 77.622648],
[12.938299, 77.622695],
[12.938254, 77.622715],
[12.938242, 77.622761],
[12.938227, 77.622805],
[12.93819, 77.622792],
[12.938138, 77.622837],
[12.938129, 77.622887],
[12.938103, 77.622949],
[12.938066, 77.622989],
[12.938006, 77.622966],
[12.937933, 77.623001],
[12.937976, 77.623073],
[12.937954, 77.623128],
[12.937912, 77.623111],
[12.937882, 77.623034],
[12.937933, 77.623001],
[12.938006, 77.622966],
[12.937921, 77.62293]]
Get the distance between each set of points using google.maps.geometry.spherical.computeDistanceBetween (convert each point to a google.maps.LatLng first). Sum those distances for the total.
Or use the google.maps.geometry.spherical.computeLength method on an array of google.maps.LatLng objects created from your coordinates.
fiddle
for (var i=0; i < coordinates.length; i++) {
path.push(new google.maps.LatLng(coordinates[i][0],
coordinates[i][1]));
}
var polyline = new google.maps.Polyline({
path: path,
map: map,
strokeWeight: 2,
strokeColor: "blue"
});
var length = google.maps.geometry.spherical.computeLength(polyline.getPath());
document.getElementById('length').innerHTML = "length="+(length/1000).toFixed(2)+ " km";