#javascript #jquery #loops
#javascript #jquery #циклы
Вопрос:
Я хочу, чтобы div отображался на основе расстояния. Для этого я получаю местоположение пользователя и координаты места, где должен появиться div, и я успешно добиваюсь этого. Моя проблема сейчас в том, что будут разные места, где я хочу, чтобы это было доступно, поэтому мне нужно найти способ зацикливаться и постоянно проверять, где находится человек, и посмотреть, близко ли оно к расстоянию от моих координат.
— Получение местоположения человека
if (navigator.geolocation){
navigator.geolocation.watchPosition(showPosition)
}
— Функция для отображения рабочего div
function showPosition(position){
let locationLatitude = []
let locationsLongitude = []
//AJAX CALL TO GET THE POSITION OF THE PLACES AND PUSHING THEM TO THE ARRAYS
let success = function(res){
let locations = res.locations
for (var i=0; i<locations.length; i ){
locationLatitude.push(locations[i]['place_latitude'])
locationsLongitude.push(locations[i]['place_longitude'])
}
}
$.ajax({
type: 'GET',
url: '/api/locations',
crossDomain: true,
dataType: 'json',
async: false,
success : success,
});
// LOOP TO GET ALL COORDIANTES FROM PLACES (LAT,LONG)
var locationLatitudeLength = locationLatitude.length
var locationsLongitudeLength = locationsLongitude.length
let startPosLat
let startPosLong
for(var i=0; i<locationLatitudeLength; i ){
for(var j=0; j<locationsLongitudeLength; j ){
startPosLat = locationLatitude[i]
startPosLong = locationsLongitude[j]
userlocationLatitude = position.coords.latitude
userlocationLongitude = position.coords.longitude
//PASS VALUES OF COORDINATES TO THE FUNCTION
let distance = calculateDistance(startPosLat, startPosLong, userlocationLatitude, userlocationLongitude)
}
}
if(distance < .05){
$('.div-image').attr('src', 'pic2.jpg')
}else if(distance > .05){
$('.div-image').attr('src', 'pic.jpg')
}
//function to calculate the distance between two points of coordinates
function calculateDistance(lat1, lon1, lat2, lon2) {
var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2)
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
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 d;
}
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
}
проблема в том, что он не распознает координаты, поступающие из цикла.
У кого-нибудь есть рекомендации о том, как заставить функцию запускаться для каждой координаты в цикле, чтобы проверить, есть ли я там или нет.
Ответ №1:
Похоже, что двойной цикл, проходящий через координаты, не ожидает ответа от ajax (я предполагаю, что все координаты требуются перед обработкой). Поскольку вызов ajax является асинхронным, местоположения не будут заполнены до тех пор, пока сервер не ответит; однако цикл, проходящий через массив местоположений, начнет выполняться сразу после отправки первоначального запроса на сервер и, что наиболее важно, до заполнения местоположений.
Попробуйте переместить большую часть вашей функции в функцию успеха.
function showPosition(position){
let locationLatitude = []
let locationsLongitude = []
//AJAX CALL TO GET THE POSITION OF THE PLACES AND PUSHING THEM TO THE ARRAYS
let success = function(res){
let locations = res.locations
for (var i=0; i<locations.length; i ){
locationLatitude.push(locations[i]['place_latitude'])
locationsLongitude.push(locations[i]['place_longitude'])
}
// LOOP TO GET ALL COORDIANTES FROM PLACES (LAT,LONG)
var locationLatitudeLength = locationLatitude.length
var locationsLongitudeLength = locationsLongitude.length
let startPosLat
let startPosLong
for(var i=0; i<locationLatitudeLength; i ){
for(var j=0; j<locationsLongitudeLength; j ){
startPosLat = locationLatitude[i]
startPosLong = locationsLongitude[j]
userlocationLatitude = position.coords.latitude
userlocationLongitude = position.coords.longitude
//PASS VALUES OF COORDINATES TO THE FUNCTION
let distance = calculateDistance(startPosLat, startPosLong, userlocationLatitude, userlocationLongitude)
}
}
if(distance < .05){
$('.div-image').attr('src', 'pic2.jpg')
}else if(distance > .05){
$('.div-image').attr('src', 'pic.jpg')
}
}
$.ajax({
type: 'GET',
url: '/api/locations',
crossDomain: true,
dataType: 'json',
async: false,
success : success,
});
//function to calculate the distance between two points of coordinates
function calculateDistance(lat1, lon1, lat2, lon2) {
var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2)
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
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 d;
}
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
}```
Ответ №2:
Я думаю, что ваш алгоритм можно было бы немного упростить. В частности, разбиение широт и долгот на отдельные массивы, а затем последующее использование вложенных for
циклов для их объединения кажется ненужным. Вот предложение, которое пропускает эти шаги.
Обратите внимание, что это совершенно непроверенное, но это может привести вас на правильный путь.
Другие вещи, на которые следует обратить внимание, — это возможность использования for...of
вместо традиционных for
циклов, использование distance
в той же области, в которой оно объявлено, и готовность к ситуации, когда distance == .05
.
function showPosition(position){
const userlocationLatitude = position.coords.latitude;
const userlocationLongitude = position.coords.longitude;
let success = function(res){
for(let location of res.locations){
let startPosLat = location['place_latitude'],
startPosLng = location['place_longitude'],
distance = calculateDistance(startPosLat, startPosLong, userlocationLatitude, userlocationLongitude);
if(distance < .05){ $('.div-image').attr('src', 'pic2.jpg'); }
else{ $('.div-image').attr('src', 'pic.jpg'); }
}
}
$.ajax({ type: 'GET', url: '/api/locations', crossDomain: true, dataType: 'json', async: false, success : success });
//function to calculate the distance between two points of coordinates
function calculateDistance(lat1, lon1, lat2, lon2) {
var R = 6371, dLat = (lat2-lat1).toRad(), dLon = (lon2-lon1).toRad(),
a = Math.sin(dLat/2) * Math.sin(dLat/2) Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * Math.sin(dLon/2) * Math.sin(dLon/2),
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
}
Number.prototype.toRad = function() { return this * Math.PI / 180; }
}
Комментарии:
1. Большое вам спасибо, это помогло, и теперь моя функция выполняется со всеми координатами !!
![]()
Ответ №3:
Сначала я бы предложил использовать массив массивов для хранения координат, чтобы ваши широта и долгота указывались рядом друг с другом. Я привел несколько основных примеров зацикливания, предполагая, что checkFunction — это то, что вы определяете для обработки проверок координат.
Вы можете использовать vanilla JS для выполнения цикла следующим образом:
for (var i in myArray) {
checkFunction(myArray[i]);
}
Или вы можете использовать jQuery для выполнения цикла следующим образом:
$(myArray).each(function(index, value) {
checkFunction(value);
});
Комментарии:
1. Мы должны использовать
for...of
для обработки итерации по массивам, в то времяfor...in
как обрабатывает свойства объекта.2. Нет? Я не говорю, что for …of не будет работать, но я скажу, что for…in действительно работает. Я использую его ежедневно. jsfiddle.net/9hL42cuk
3. Вы правы, я не должен говорить, что мы «должны» делать что-либо подобное. В большинстве случаев перебор перечислимых свойств массива аналогичен перебору его повторяющихся свойств. Это просто требует нескольких разумных предположений (например, что в вашем массиве не будет никаких неопределенных ключей, никто не будет пытаться использовать деструктурирование в цикле, а Array.prototype не имеет никаких пользовательских свойств в текущей области). Рекомендуется использовать
for...of
для защиты от запаха.4. Теперь, когда я никогда не знал, но я также довольно строг в отношении того, как я структурирую данные (т. Е. Не вкладываю странные вещи). В основном я работаю с API, которые написал сам.