Как запустить функцию для каждого элемента в массивах

#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, которые написал сам.