Related
I created a custom teams application using Microsoft Teams Toolkit for VS Code. I am trying to read the location from the app. I am able to load the coordinates in the Browser and Android version of teams but it fails in the Desktop version of teams with the below error.
Network location provider at 'https://www.googleapis.com/' : No response received.
The function to load the Location-
const getLocation = () => {
let that = this;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
alert('got position');
var positionInfo = "Your current position is (Latitude: " + position.coords.latitude + ", Longitude: " + position.coords.longitude + ")";
alert(positionInfo);
}, (error) => {
alert("Error: " + error.message);
}, { timeout: 30000, enableHighAccuracy: true, maximumAge: 75000 });
} else {
alert("Geolocation is not supported by this browser.");
}
}
It might be a problem with the navigator.geolocation().getCurrentPosition API. Any leads on this will be useful.
I will let this question be here for anyone looking for an answer or if anyone finds an update to this.
I found this official documentation from MSFT that states geolocation API is not fully supported in the teams desktop client currently and they suggest using the getLocation API of TeamsSDK.
https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/device-capabilities/native-device-permissions?tabs=desktop
Using the Google Geocoder v3, if I try to geocode 20 addresses, I get an OVER_QUERY_LIMIT unless I time them to be ~1 second apart, but then it takes 20 seconds before my markers are all placed.
Is there any other way to do it, other than storing the coordinates in advance?
No, there is not really any other way : if you have many locations and want to display them on a map, the best solution is to :
fetch the latitude+longitude, using the geocoder, when a location is created
store those in your database, alongside the address
and use those stored latitude+longitude when you want to display the map.
This is, of course, considering that you have a lot less creation/modification of locations than you have consultations of locations.
Yes, it means you'll have to do a bit more work when saving the locations -- but it also means :
You'll be able to search by geographical coordinates
i.e. "I want a list of points that are near where I'm now"
Displaying the map will be a lot faster
Even with more than 20 locations on it
Oh, and, also (last but not least) : this will work ;-)
You will less likely hit the limit of X geocoder calls in N seconds.
And you will less likely hit the limit of Y geocoder calls per day.
You actually do not have to wait a full second for each request. I found that if I wait 200 miliseconds between each request I am able to avoid the OVER_QUERY_LIMIT response and the user experience is passable. With this solution you can load 20 items in 4 seconds.
$(items).each(function(i, item){
setTimeout(function(){
geoLocate("my address", function(myLatlng){
...
});
}, 200 * i);
}
Unfortunately this is a restriction of the Google maps service.
I am currently working on an application using the geocoding feature, and I'm saving each unique address on a per-user basis. I generate the address information (city, street, state, etc) based on the information returned by Google maps, and then save the lat/long information in the database as well. This prevents you from having to re-code things, and gives you nicely formatted addresses.
Another reason you want to do this is because there is a daily limit on the number of addresses that can be geocoded from a particular IP address. You don't want your application to fail for a person for that reason.
I'm facing the same problem trying to geocode 140 addresses.
My workaround was adding usleep(100000) for each loop of next geocoding request. If status of the request is OVER_QUERY_LIMIT, the usleep is increased by 50000 and request is repeated, and so on.
And of cause all received data (lat/long) are stored in XML file not to run request every time the page is loading.
EDIT:
Forgot to say that this solution is in pure js, the only thing you need is a browser that supports promises https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise
For those who still needs to accomplish such, I've written my own solution that combines promises with timeouts.
Code:
/*
class: Geolocalizer
- Handles location triangulation and calculations.
-- Returns various prototypes to fetch position from strings or coords or dragons or whatever.
*/
var Geolocalizer = function () {
this.queue = []; // queue handler..
this.resolved = [];
this.geolocalizer = new google.maps.Geocoder();
};
Geolocalizer.prototype = {
/*
#fn: Localize
#scope: resolve single or multiple queued requests.
#params: <array> needles
#returns: <deferred> object
*/
Localize: function ( needles ) {
var that = this;
// Enqueue the needles.
for ( var i = 0; i < needles.length; i++ ) {
this.queue.push(needles[i]);
}
// return a promise and resolve it after every element have been fetched (either with success or failure), then reset the queue.
return new Promise (
function (resolve, reject) {
that.resolveQueueElements().then(function(resolved){
resolve(resolved);
that.queue = [];
that.resolved = [];
});
}
);
},
/*
#fn: resolveQueueElements
#scope: resolve queue elements.
#returns: <deferred> object (promise)
*/
resolveQueueElements: function (callback) {
var that = this;
return new Promise(
function(resolve, reject) {
// Loop the queue and resolve each element.
// Prevent QUERY_LIMIT by delaying actions by one second.
(function loopWithDelay(such, queue, i){
console.log("Attempting the resolution of " +queue[i-1]);
setTimeout(function(){
such.find(queue[i-1], function(res){
such.resolved.push(res);
});
if (--i) {
loopWithDelay(such,queue,i);
}
}, 1000);
})(that, that.queue, that.queue.length);
// Check every second if the queue has been cleared.
var it = setInterval(function(){
if (that.queue.length == that.resolved.length) {
resolve(that.resolved);
clearInterval(it);
}
}, 1000);
}
);
},
/*
#fn: find
#scope: resolve an address from string
#params: <string> s, <fn> Callback
*/
find: function (s, callback) {
this.geolocalizer.geocode({
"address": s
}, function(res, status){
if (status == google.maps.GeocoderStatus.OK) {
var r = {
originalString: s,
lat: res[0].geometry.location.lat(),
lng: res[0].geometry.location.lng()
};
callback(r);
}
else {
callback(undefined);
console.log(status);
console.log("could not locate " + s);
}
});
}
};
Please note that it's just a part of a bigger library I wrote to handle google maps stuff, hence comments may be confusing.
Usage is quite simple, the approach, however, is slightly different: instead of looping and resolving one address at a time, you will need to pass an array of addresses to the class and it will handle the search by itself, returning a promise which, when resolved, returns an array containing all the resolved (and unresolved) address.
Example:
var myAmazingGeo = new Geolocalizer();
var locations = ["Italy","California","Dragons are thugs...","China","Georgia"];
myAmazingGeo.Localize(locations).then(function(res){
console.log(res);
});
Console output:
Attempting the resolution of Georgia
Attempting the resolution of China
Attempting the resolution of Dragons are thugs...
Attempting the resolution of California
ZERO_RESULTS
could not locate Dragons are thugs...
Attempting the resolution of Italy
Object returned:
The whole magic happens here:
(function loopWithDelay(such, queue, i){
console.log("Attempting the resolution of " +queue[i-1]);
setTimeout(function(){
such.find(queue[i-1], function(res){
such.resolved.push(res);
});
if (--i) {
loopWithDelay(such,queue,i);
}
}, 750);
})(that, that.queue, that.queue.length);
Basically, it loops every item with a delay of 750 milliseconds between each of them, hence every 750 milliseconds an address is controlled.
I've made some further testings and I've found out that even at 700 milliseconds I was sometimes getting the QUERY_LIMIT error, while with 750 I haven't had any issue at all.
In any case, feel free to edit the 750 above if you feel you are safe by handling a lower delay.
Hope this helps someone in the near future ;)
I have just tested Google Geocoder and got the same problem as you have.
I noticed I only get the OVER_QUERY_LIMIT status once every 12 requests
So I wait for 1 second (that's the minimum delay to wait)
It slows down the application but less than waiting 1 second every request
info = getInfos(getLatLng(code)); //In here I call Google API
record(code, info);
generated++;
if(generated%interval == 0) {
holdOn(delay); // Every x requests, I sleep for 1 second
}
With the basic holdOn method :
private void holdOn(long delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException ex) {
// ignore
}
}
Hope it helps
This worked well for me, after intermittent trial and error over the past couple days. I am using react instant-search-hooks via Algolia with Nextjs and Sanity for a new jobs site for a large company.
Postal Code is a facet for filtering/sorting/query matching that is defined in the algolia index. In another script file, I map out all of these facets (postal code, city, etc); Now that I have 100 returned files they can be mapped out by iterating through a mapped asynchronous import and the lat/lng coords matched to the corresponding zip codes defining a job posting (there are ~2500 postings but only ~100 zip codes to narrow down the coordinates of)
import * as dotenv from "dotenv";
dotenv.config();
import {
googleNetwork,
axiosConfig as googleAxiosConfig
} from "../utils/google-axios";
import JSONData from "../../public/data/postalCode/2022/05/26.json";
import fs from "fs";
import { join } from "path";
import type { GeneratedGeolocData } from "../types/algolia";
import { timezoneHelper } from "../utils/timezone-helper";
import { Unenumerate } from "../types/helpers";
let i = 0;
i < JSONData.postalCodes.facetHits.length;
i++;
const getGeoCode = (
record: Unenumerate<typeof JSONData.postalCodes.facetHits>
) =>
function () {
return JSONData.postalCodes.facetHits.map(async (data = record, u) => {
const googleBase = process.env.NEXT_PUBLIC_GOOGLE_MAPS_BASE_PATH ?? "";
const googleApiKey =
process.env.NEXT_PUBLIC_TAKEDA_JOBS_GOOGLE_SERVICES ?? "";
const params: (string | undefined)[][] = [
["address", data.value],
["key", googleApiKey]
];
const query = params
.reduce<string[]>((arr, [k, v]) => {
if (v) arr.push(`${k}=${encodeURIComponent(v)}`);
return arr;
}, [])
.join("&");
return await googleNetwork("GET")
.get(`${googleBase}geocode/json?${query}`, googleAxiosConfig)
.then(dat => {
const geoloc = dat.data as GeneratedGeolocData;
const {
[0]: Year,
[2]: Month,
[4]: Day
} = new Date(Date.now())
.toISOString()
.split(/(T)/)[0]
.split(/([-])/g);
const localizedTimestamp = timezoneHelper({
dateField: new Date(Date.now()),
timezone: "America/Chicago"
});
return setTimeout(
() =>
fs.appendFileSync(
join(
process.cwd(),
`public/data/geoloc/${Year}/${Month}/${Day}-${[i]}.json`
),
JSON.stringify(
{
generated: localizedTimestamp,
_geoloc: {
postalCode: data.value,
geolocation: geoloc
}
},
null,
2
)
),
1000
);
});
});
};
getGeoCode(JSONData.postalCodes.facetHits[i]);
It took a lot less time than anticipated -- under 4 seconds for 100 unique results to generate
Context on the Unenumerate type -- Unenumerate strips the internal repeating unit within an array:
type Unenumerate<T> = T extends Array<infer U> ? U : T;
so i'm currently working on an exercise application for a mobile device that tracks the location of the user while constantly updating the distance they have traveled. I can get the starting location of the user easy enough but its actually tracking them that I have no idea how to even start. I have a button for the user to get the current location called 'location' and i have a button called 'record' that will actually start the tracking process.
I know it has something to do with watchPosition() but im not quite sure how to use it and how to make it work with what i currently have. This is the first time ive done anything that required geoLocation.
Any helped would be much apreciated.
<script>
var c = function(position){
var latitude = position.coords.latitude,
longitude = position.coords.longitude,
acc = accuracy.coords.accuracy,
coords = position+ ', ' + long;
timeStamp = position.timestamp;
document.getElementById('google_map').setAttribute('src', 'https://maps.google.co.uk/?q=' + coords + '&z=50&output=embed');
}
var e = function(error){
switch(error.code){
case 0:
updateStatus("There was an error while retrieving your location: " +
error.message);
break;
case 1:
alert("The user prevented this page from retrieving a location.");
break;
case 2:
updateStatus("The browser was unable to determine your location: " +
error.message);
break;
case 3:
updateStatus("The browser timed out before retrieving the location.");
break;
}
}
document.getElementById('location').onclick = function() {
var watchId = navigator.geolocation.getCurrentPosition(c, e, {
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 1000
});
return false;
}
document.getElementById("stop").onclick = function(){
navigator.geolocation.clearWatch(watchId);
}
</script>
I'm writing an Cordova/Phonegap app and I use a Geolocation plugin...this is my code...
var onSuccess = function(position) {
longitude = position.coords.longitude;
latitude = position.coords.latitude;
console.log("Latitude: "+position.coords.latitude);
console.log("Longitude: "+position.coords.longitude);
};
function onError(error) {
logService.debug("Code: "+error.code);
logService.debug("Message: "+error.message);
};
navigator.geolocation.getCurrentPosition(onSuccess, onError, { maximumAge: 3000, timeout: 15000, enableHighAccuracy: true });
Now, I test it on browser and when I don't the permission I receive Error code 1 (PositionError.PERMISSION_DENIED), when I do the permission it works very well on browser...Now born che question...When I test this on device and the GPS is off I don't receive the Error code 1 (PositionError.PERMISSION_DENIED) but receive always timeout...in this way I don't discern the difference...I set the timeout to 150000 but I receive always code 3 (PositionError.TIMEOUT)...Why? How can use it in the rigth way?
I've found the handling of the geolcation errors to be platform-specific. Since setting enableHighAccuracy: true causes your app to ask the OS retreive a position using the GPS hardware, the effect of turning off GPS on an Android device varies depending on the Android version: either the OS is never able to retreive a high-accuracy position, so the TIMEOUT error occurs (PERMISSION_DENIED will not be received on Android) or a low accuracy position will be retrieved and passed instead using Wifi/cell triangulation.
I'd suggest using watchPosition() instead of getCurrentPosition() to retrieve the location; getCurrentPosition() makes a single request for the device position at that current point in time, so the position timeout may occur before the GPS hardware on the device has had a chance to get a position fix, whereas using watchPosition() you can setup a watcher which will call the success function each time the OS receives a location update from the GPS hardware. If you only want a single location, clear the watcher after receiving a position of sufficient accuracy. If GPS is turned off on the Android device when the watcher is added, it will continue to return a TIMEOUT error; my workaround for this is to clear and re-add the watcher after a number of consequetive errors.
So try something along these lines:
var MAX_POSITION_ERRORS_BEFORE_RESET = 3,
MIN_ACCURACY_IN_METRES = 20,
positionWatchId = null,
watchpositionErrorCount = 0,
options = {
maximumAge: 60000,
timeout: 15000,
enableHighAccuracy: true
};
function addWatch(){
positionWatchId = navigator.geolocation.watchPosition(onWatchPositionSuccess, onWatchPositionError, options);
}
function clearWatch(){
navigator.geolocation.clearWatch(positionWatchId);
}
function onWatchPositionSuccess(position) {
watchpositionErrorCount = 0;
// Reject if accuracy is not sufficient
if(position.coords.accuracy > MIN_ACCURACY_IN_METRES){
return;
}
// If only single position is required, clear watcher
clearWatch();
// Do something with position
var lat = position.coords.latitude,
lon = position.coords.longitude;
}
function onWatchPositionError(err) {
watchpositionErrorCount++;
if (watchpositionErrorCount >= MAX_POSITION_ERRORS_BEFORE_RESET) {
clearWatch();
addWatch();
watchpositionErrorCount = 0;
}
}
addWatch();
Closed. This question is not about programming or software development. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 4 months ago.
Improve this question
I'm trying to extend the native geolocation function
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
});
}
so that I can use the visitor's country name (perhaps return an informative array).
So far all I've been able to find are functions that display a google maps interface but none actually gave what I want, except for this library which worked well in this example but for some reason didn't work on my computer. I'm not sure why that went wrong there.
Anyways, do you know how I can simply return an array containing information like country, city, etc. from latitude and longitude values?
You can use my service, http://ipinfo.io, for this. It will give you the client IP, hostname, geolocation information (city, region, country, area code, zip code etc) and network owner. Here's a simple example that logs the city and country:
$.get("https://ipinfo.io", function(response) {
console.log(response.city, response.country);
}, "jsonp");
Here's a more detailed JSFiddle example that also prints out the full response information, so you can see all of the available details: http://jsfiddle.net/zK5FN/2/
The location will generally be less accurate than the native geolocation details, but it doesn't require any user permission.
You don't need to locate the user if you only need their country. You can look their IP address up in any IP-to-location service (like maxmind, ipregistry or ip2location). This will be accurate most of the time.
Here is a client-side example with Ipregistry (disclaimer, I am working for):
fetch('https://api.ipregistry.co/?key=tryout')
.then(function (response) {
return response.json();
})
.then(function (payload) {
console.log(payload.location.country.name + ', ' + payload.location.city);
});
If you really need to get their location, you can get their lat/lng with that method, then query Google's or Yahoo's reverse geocoding service.
You can do this natively wihtout relying on IP services. You can get the user's timezone like this:
Intl.DateTimeFormat().resolvedOptions().timeZone
and then extract the country from that value. Here is a working example on CodePen.
You can use your IP address to get your 'country', 'city', 'isp' etc...
Just use one of the web-services that provide you with a simple api like http://ip-api.com which provide you a JSON service at http://ip-api.com/json. Simple send a Ajax (or Xhr) request and then parse the JSON to get whatever data you need.
var requestUrl = "http://ip-api.com/json";
$.ajax({
url: requestUrl,
type: 'GET',
success: function(json)
{
console.log("My country is: " + json.country);
},
error: function(err)
{
console.log("Request failed, error= " + err);
}
});
See ipdata.co a service I built that is fast and has reliable performance thanks to having 10 global endpoints each able to handle >10,000 requests per second!
This answer uses a 'test' API Key that is very limited and only meant for testing a few calls. Signup for your own Free API Key and get up to 1500 requests daily for development.
This snippet will return the details of your current ip. To lookup other ip addresses, simply append the ip to the https://api.ipdata.co?api-key=test url eg.
https://api.ipdata.co/1.1.1.1?api-key=test
The API also provides an is_eu field indicating whether the user is in an EU country.
$.get("https://api.ipdata.co?api-key=test", function (response) {
$("#response").html(JSON.stringify(response, null, 4));
}, "jsonp");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre id="response"></pre>
Here's the fiddle; https://jsfiddle.net/ipdata/6wtf0q4g/922/
I also wrote this detailed analysis of 8 of the best IP Geolocation APIs.
A very easy to use service is provided by ws.geonames.org. Here's an example URL:
http://ws.geonames.org/countryCode?lat=43.7534932&lng=28.5743187&type=JSON
And here's some (jQuery) code which I've added to your code:
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
$.getJSON('http://ws.geonames.org/countryCode', {
lat: position.coords.latitude,
lng: position.coords.longitude,
type: 'JSON'
}, function(result) {
alert('Country: ' + result.countryName + '\n' + 'Code: ' + result.countryCode);
});
});
}
Try it on jsfiddle.net ...
A free and easy to use service is provided at Webtechriser (click here to read the article) (called wipmania). This one is a JSONP service and requires plain javascript coding with HTML. It can also be used in JQuery. I modified the code a bit to change the output format and this is what I've used and found to be working: (it's the code of my HTML page)
<html>
<body>
<p id="loc"></p>
<script type="text/javascript">
var a = document.getElementById("loc");
function jsonpCallback(data) {
a.innerHTML = "Latitude: " + data.latitude +
"<br/>Longitude: " + data.longitude +
"<br/>Country: " + data.address.country;
}
</script>
<script src="http://api.wipmania.com/jsonp?callback=jsonpCallback"
type="text/javascript"></script>
</body>
</html>
PLEASE NOTE: This service gets the location of the visitor without prompting the visitor to choose whether to share their location, unlike the HTML 5 geolocation API (the code that you've written). Therefore, privacy is compromised. So, you should make judicial use of this service.
I wanted to localize client side pricing for few countries without using any external api, so I used local Date object to fetch the country using
new Date()).toString().split('(')[1].split(" ")[0]
document.write((new Date()).toString().split('(')[1].split(" ")[0])
Basically this small code snippet extracts the first word from Date object. To check for various time zone, you can change the time of your local machine.
In my case, our service only included three countries, so I was able to get the location using the following code.
const countries = ["India", "Australia", "Singapore"]
const countryTimeZoneCodes = {
"IND": 0,
"IST": 0,
"AUS": 1,
"AES": 1,
"ACS": 1,
"AWS": 1,
"SGT": 2,
"SIN": 2,
"SST": 2
} // Probable three characters from timezone part of Date object
let index = 0
try {
const codeToCheck = (new Date()).toString().split('(')[1].split(" ")[0].toUpperCase().substring(0, 3)
index = countryTimeZoneCodes[codeToCheck]
} catch (e) {
document.write(e)
index = 0
}
document.write(countries[index])
This was just to improve user experience. It's not a full proof solution to detect location. As a fallback for not detecting correctly, I added a dropdown in the menubar for selecting the country.
For developers looking for a full-featured geolocation utility, you can have a look at geolocator.js (I'm the author).
Example below will first try HTML5 Geolocation API to obtain the exact coordinates. If fails or rejected, it will fallback to Geo-IP look-up. Once it gets the coordinates, it will reverse-geocode the coordinates into an address.
var options = {
enableHighAccuracy: true,
timeout: 6000,
maximumAge: 0,
desiredAccuracy: 30,
fallbackToIP: true, // if HTML5 geolocation fails or rejected
addressLookup: true, // get detailed address information
timezone: true,
map: "my-map" // this will even create a map for you
};
geolocator.locate(options, function (err, location) {
console.log(err || location);
});
It supports geo-location (via HTML5 or IP lookups), geocoding, address look-ups (reverse geocoding), distance & durations, timezone information and more...
You can simply import in your app.component.ts or whichever component you want to use
import { HttpClient } from '#angular/common/http';
Then make a simple GET request to http://ip-api.com/json
getIPAddress() {
this.http.get("http://ip-api.com/json").subscribe((res: any) => {
console.log('res ', res);
})
}
You will get the following response by using it:
{
"status": "success",
"country": "country fullname here",
"countryCode": "country shortname here",
"region": "region shortname here",
"regionName": "region fullname here",
"city": "city fullname here",
"zip": "zipcode will be in string",
"lat": "latitude here will be in integer",
"lon": "logitude here will be in integer",
"timezone": "timezone here",
"isp": "internet service provider name here",
"org": "internet service provider organization name here",
"as": "internet service provider name with some code here",
"query": "ip address here"
}
You can use ip-api.io to get visitor's location. It supports IPv6.
As a bonus it allows to check whether ip address is a tor node, public proxy or spammer.
JavaScript Code:
function getIPDetails() {
var ipAddress = document.getElementById("txtIP").value;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
console.log(JSON.parse(xhttp.responseText));
}
};
xhttp.open("GET", "http://ip-api.io/json/" + ipAddress, true);
xhttp.send();
}
<input type="text" id="txtIP" placeholder="Enter the ip address" />
<button onclick="getIPDetails()">Get IP Details</button>
jQuery Code:
$(document).ready(function () {
$('#btnGetIpDetail').click(function () {
if ($('#txtIP').val() == '') {
alert('IP address is reqired');
return false;
}
$.getJSON("http://ip-api.io/json/" + $('#txtIP').val(),
function (result) {
alert('Country Name: ' + result.country_name)
console.log(result);
});
});
});
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<div>
<input type="text" id="txtIP" />
<button id="btnGetIpDetail">Get Location of IP</button>
</div>
If you don't want to use an api and only the country is enough for you, you can use topojson and worldatlas.
import { feature } from "https://cdn.skypack.dev/topojson#3.0.2";
import { geoContains, geoCentroid, geoDistance } from "https://cdn.skypack.dev/d3#7.0.0";
async function success(position) {
const topology = await fetch("https://cdn.jsdelivr.net/npm/world-atlas#2/countries-50m.json").then(response => response.json());
const geojson = feature(topology, topology.objects.countries);
const {
longitude,
latitude,
} = position.coords;
const location = geojson.features
.filter(d => geoContains(d, [longitude, latitude]))
.shift();
if (location) {
document.querySelector('#location').innerHTML = `You are in <u>${location.properties.name}</u>`;
}
if (!location) {
const closestCountry = geojson.features
// You could improve the distance calculation so that you get a more accurate result
.map(d => ({ ...d, distance: geoDistance(geoCentroid(d), [longitude, latitude]) }))
.sort((a, b) => a.distance - b.distance)
.splice(0, 5);
if (closestCountry.length > 0) {
const possibleLocations = closestCountry.map(d => d.properties.name);
const suggestLoctions = `${possibleLocations.slice(0, -1).join(', ')} or ${possibleLocations.slice(-1)}`;
document.querySelector('#location').innerHTML = `It's not clear where you are!<section>Looks like you are in ${suggestLoctions}</section>`;
}
if (closestCountry.length === 0) {
error();
}
}
}
function error() {
document.querySelector('#location').innerHTML = 'Sorry, I could not locate you';
};
navigator.geolocation.getCurrentPosition(success, error);
This code takes longitude and latitude and checks if this point is included in one of the geojson's feature (a spatially bounded entity). I created also a working example.