получение геолокации пользователей через html5 и javascript

Я пытаюсь получить геолокацию пользователей через api геолокации html5, и я использую для этого следующий фрагмент:

if (navigator.geolocation) {
    var timeoutVal = 10 * 1000 * 1000;
    navigator.geolocation.getCurrentPosition(
      displayPosition, 
      displayError,
      { enableHighAccuracy: true, timeout: timeoutVal, maximumAge: 0 }
    );
  }
  else {
     // DO SOME STUFF HERE
  }


  function displayPosition(position) {

    // configuration
    var myZoom = 12;
    var myMarkerIsDraggable = true;
    var myCoordsLenght = 6;
    var defaultLat = position.coords.latitude;
    var defaultLng = position.coords.longitude;
    document.getElementById('latitude').value = defaultLat;
    document.getElementById('longitude').value = defaultLng;
    /*
      1. creates the map
      2. zooms
      3. centers the map
      4. sets the map’s type
    */
    var map = new google.maps.Map(document.getElementById('canvas'), {
      zoom: myZoom,
      center: new google.maps.LatLng(defaultLat, defaultLng),
      mapTypeId: google.maps.MapTypeId.ROADMAP
    });


    });
    // centers the map on markers coords
    map.setCenter(myMarker.position);
    // adds the marker on the map
    myMarker.setMap(map);
  }

  function displayError(error) {
    var errors = { 
      1: 'Permission denied',
      2: 'Position unavailable',
      3: 'Request timeout'
    };
    alert("Error: " + errors[error.code]);
  }
});

проблема с вышеуказанным подходом заключается в том, что мало кто из пользователей нашел его трудным в использовании. Несколько раз они нажали запретить вместо разрешить и продолжайте смотреть на экран. Поэтому с точки зрения удобства использования я думаю, что хорошим подходом было бы:

  1. спросить у них разрешения.

  2. подождите 3 секунды, если они нажмут "запретить" или "не отвечать", используйте IP для отображения геолокации на карте.

Как я могу выполнить второй шаг в моих приведенных выше фрагментах. Пожалуйста, дайте мне знать, Спасибо! Однако, что было бы лучшим способом справиться

8 ответов


вот скрипт (геолокатор.js) Я написал некоторое время назад и недавно обновлены.

обновление: выпущен Geolocator v2.

характеристики:

  • HTML5 геолокация (с разрешения пользователя)
  • местоположение по IP
  • геокодирования (координаты, Адрес)
  • обратное геокодирование (поиск адреса по координатам)
  • полная информация об адресе (улица, город, район, регион, страна, код страны, почтовый индекс и т. д...)
  • резервный механизм (от HTML5-геолокации до поиска IP-geo)
  • посмотреть географическое положение
  • получить матрицу расстояния и продолжительность
  • вычислить расстояние между двумя географическими точками
  • сделать пояс информация
  • получить IP-адрес клиента
  • поддержка Google Loader (загружает Google Maps динамически)
  • динамически создает Google Maps (с маркером, информационным окном, автоматически настраиваемым зумом)
  • неблокирующая загрузка скрипта (внешние источники загружаются на лету без прерывания загрузки страницы)

посмотреть live demo.
См.документация по API.

Geolocator Example Screenshot

использование:

var options = {
    enableHighAccuracy: true,
    timeout: 6000,
    maximumAge: 0,
    desiredAccuracy: 30, // meters
    fallbackToIP: true, // get location by IP if geolocation fails or rejected
    addressLookup: true, // requires Google API key
    timezone: true, // requires Google API key
    map: "my-map" // creates a Google map. requires Google API key
};
geolocator.locate(options, function (err, location) {
    console.log(err || location);
});

Пример:

{
    coords: {
        latitude: 37.4224764,
        longitude: -122.0842499,
        accuracy: 30,
        altitude: null,
        altitudeAccuracy: null,
        heading: null,
        speed: null
    },
    address: {
        commonName: "",
        street: "Amphitheatre Pkwy",
        route: "Amphitheatre Pkwy",
        streetNumber: "1600",
        neighborhood: "",
        town: "",
        city: "Mountain View",
        region: "Santa Clara County",
        state: "California",
        stateCode: "CA",
        postalCode: "94043",
        country: "United States",
        countryCode: "US"
    },
    formattedAddress: "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA",
    type: "ROOFTOP",
    placeId: "ChIJ2eUgeAK6j4ARbn5u_wAGqWA",
    timezone: {
        id: "America/Los_Angeles",
        name: "Pacific Standard Time",
        abbr: "PST",
        dstOffset: 0,
        rawOffset: -28800
    },
    flag: "//cdnjs.cloudflare.com/ajax/libs/flag-icon-css/2.3.1/flags/4x3/us.svg",
    map: {
        element: HTMLElement,
        instance: Object, // google.maps.Map
        marker: Object, // google.maps.Marker
        infoWindow: Object, // google.maps.InfoWindow
        options: Object // map options
    },
    timestamp: 1456795956380
}

затем вы будете использовать api geo ip, как этот:

http://freegeoip.net/static/index.html


Ok, так что это не кодовый ответ, а ответ на пользовательский интерфейс.

с точки зрения UX первое, что выделяется, - это отсутствие информации, которую вы предлагаете, прежде чем запускать браузер, чтобы попросить у них разрешения.

Я предлагаю вам какое-то окно наложения, показывающее снимок экрана (с большой стрелкой на нем), демонстрирующий "где" на экране, что они собираются получить разрешение. Также вы можете воспользоваться этой возможностью, чтобы сказать им что произойдет, если они откажут в разрешении или не примут его в течение, скажем, 10 секунд (т. е. где они игнорируют строку подсказки).

Я предлагаю вам не по умолчанию показывать Местоположение IP, потому что они по существу "могут сказать" я не согласен, чтобы вы знали, где я. Затем вы показываете большую карту, где они находятся, что может напугать несколько человек, которые нажали deny! Кроме того, это может быть очень неточно.

идея "не просите разрешения попросить прощения", может работа в Biz dev, но не в UI, поскольку они просто не возвращаются.

Я бы спросил себя, действительно ли вам нужна высокая точность, потому что это приведет к разрядке батареи пользователя, займет больше времени и не может дать вам гораздо больше взрыва для вашего доллара, особенно если вам нужно только узнать, где они находятся. Вы всегда можете позвонить ему позже для более точного чтения, если вам нужно.

концепция тайм-аута, если они не нажимают deny или allow, может быть достигнута с помощью setTimeout. Поэтому, как только они нажмут "Ок, я готов нажать "Разрешить" на вашем поле наложения, начните тайм-аут, и если он в конечном итоге тайм-аут, то сделайте то, что вы сказали им, что вы сделаете на вышеуказанном шаге.

используя этот метод, вы заставляете пользователя разрешать или запрещать(игнорировать), в любом случае он возвращает контроль в ваш суд и полностью информирует пользователя.

хотя это не конкретный ответ кода, из вашего JS ясно, что "справка по реализации кода" на самом деле не является проблемой здесь. Я надеюсь, что если ничего другого это не заставит вас думать немного больше о вашем пользовательском опыте.


посмотрите на этот пример tutsplus http://mobile.tutsplus.com/tutorials/mobile-web-apps/html5-geolocation/


Это может помочь: http://jsfiddle.net/sandesh2302/FghFZ/ Я использовал это для своих вещей, это сработало отлично.

Ex:

    <!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />    
    <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=true"></script>    

    <script type="text/javascript">
      function getLocation(){
        navigator.geolocation.getCurrentPosition(handleSuccess,handleError);
      }

      function initiate_watchlocation() {  
        if(watchProcess == null){
          watchProcess = navigator.geolocation.watchPosition(handleSuccess,handleError);
        }
      } 

      function stop_watchlocation() {  
        if(watchProcess != null){
          navigator.geolocation.clearWatch(watchProcess);
        }
      } 

      function handleSuccess(position){
        drawMap(position);
      }

      function handleError(error){
        switch(error.code)
        {
          case error.PERMISSION_DENIED: alert("User did not share geolocation data");break;  
          case error.POSITION_UNAVAILABLE: alert("Could not detect current position");break;  
          case error.TIMEOUT: alert("Retrieving position timed out");break;  
          default: alert("Unknown Error");break;  
        }
      }


      function drawMap(position) {
        var container = $('#map_canvas');
        var myLatLong = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
        var mapOptions = {
          center: myLatLong,
          zoom: 12,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        };
        var map = new google.maps.Map(container[0],mapOptions);
        container.css('display','block');
        var marker = new google.maps.Marker({ 
          position: myLatLong,
          map:map,
          title:"My Position (Accuracy of Position: " + position.coords.accuracy + " Meters), Altitude: " 
            + position.coords.altitude + ' Altitude Accuracy: ' + position.coords.altitudeAccuracy
        });
      }

      function drawStaticMap(position){
        var container = $('#map_canvas');
        var imageUrl = "http://maps.google.com/maps/api/staticmap?sensor=false&center=" + position.coords.latitude + "," +  
                    position.coords.longitude + "&zoom=18&size=640x500&markers=color:blue|label:S|" +  
                    position.coords.latitude + ',' + position.coords.longitude;  

        container.css({
          'display':'block',
          'width' : 640
        });
        $('<img/>',{
          src : imageUrl
        }).appendTo(container);
      } 
    </script>
  </head>
  <body >
    <button id="getLocation">Find My Location</button>
    <div style="text-align:center">
      <button id="initWatch">Put Watch on Your Position</button>
      <button id="stopWatch">Stop Position Watching</button>
    </div>
    <div id="map_canvas" ></div>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
    tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
    quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
    consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
    cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
    proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>



  </body>
</html>

вы можете использовать этот онлайн-сервис, чтобы легко получить LAT lng:

http://dev.maxmind.com/geoip/javascript

Что касается тайм - аута, я не думаю, что есть способ помешать механизму разрешения браузеров (например, закрыть это всплывающее окно разрешения через определенное количество секунд), хотя я с удовольствием был бы неправ. Что вы могли бы сделать, это установить таймер и через три секунды получить геолокацию на основе IP и установить на нее карту (или обновите страницу через 3 секунды и установите cookie, который запускает гео на основе IP, а не гео HTML5, но это немного выше, если вы спросите меня).

затем, если они дадут разрешение, он обновит карту с геолокацией HTML5 (которая должна быть намного более точной). Вы также можете инкапсулировать резервный IP geo в функцию и использовать ее, если у них нет геолокации HTML5 или они нажмут deny.

вот огурчик: http://jsfiddle.net/mfNCn/1/

вот грубый срез со скрипки:

<script src="http://j.maxmind.com/app/geoip.js" charset="ISO-8859-1" type="text/javascript"></script>
...
var time_perm = window.setTimeout(get_by_ip, 3000);
...
function get_by_ip() {
    var lat = geoip_latitude();
    var lng = geoip_longitude();
    map_it(lat, lng);
}
...
function map_it(lat,lng) {
    // build your map here
}

(Я не решаюсь поместить здесь весь фрагмент кода, так как он довольно длинный, поэтому проверьте скрипку для остальной и полной реализации)


Если есть тайм-аут или пользователь отрицает запрос, я бы установил местоположение по умолчанию, как Нью-Йорк, Нью-Йорк (40.7142, -74.0064). Если пользователь отклоняет запрос, он также должен ожидать, что вы не будете знать их местоположение, поэтому выбор понятного значения по умолчанию-следующая лучшая вещь.

использование по умолчанию без изменения кода многое может быть достигнуто путем вызова displayPosition({coords: {latitude: 40.7142, longitude: -74.0064}}) в двух местах:

if (navigator.geolocation) {
    var timeoutVal = 10 * 1000 * 1000;
    navigator.geolocation.getCurrentPosition(
        displayPosition, 
        displayError,
        { enableHighAccuracy: true, timeout: timeoutVal, maximumAge: 0 }
    );
}
else {
    displayPosition({coords: {latitude: 40.7142, longitude: -74.0064}})
}
....
function handleError(error){
    switch(error.code)
    {
        case error.PERMISSION_DENIED: alert("User did not share geolocation data");break;  
        case error.POSITION_UNAVAILABLE: alert("Could not detect current position");break;  
        case error.TIMEOUT: alert("Retrieving position timed out");break;  
        default: alert("Unknown Error");break;  
    }
    displayPosition({coords: {latitude: 40.7142, longitude: -74.0064}});
}

On http://nearbytweets.com я использую" очередь" функции для поиска местоположения пользователя, цикл через очередь, пока один из них не найдет допустимое местоположение. Последняя функция возвращает Нью-Йорк, Нью-Йорк, Что означает, что все остальные попытки не удалось. Вот пример кода, слегка измененного:

var position_finders = [                                                                                                                                                                                                              
    function () {
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(check_position, check_position);
            return;
        }   
        check_position();
    },  
    function () {
        check_position(JSON.parse(localStorage.getItem('last_location')));
    },  
    function () {
        $.ajax({
            url: 'http://www.google.com/jsapi?key=' + google_api_key,
            dataType: 'script',
            success: check_position
        }); 
    },  
    function () {
        check_position({latitude: 40.7142, longitude: -74.0064}, true);
    }   
],

check_position = function (pos, failed) {
    pos = pos || {}; 
    pos = pos.coords ? 
        pos.coords :
        pos.loader ?
        pos.loader.clientLocation :
        pos;

    if (typeof pos.latitude === 'undefined' || typeof pos.longitude === 'undefined') {
        position_finders.shift()();
        return;
    }   

    localStorage.setItem('last_location', JSON.stringify(pos));

    // using your code, I would call this:
    displayPosition(pos);
};

check_position();

вот что делает каждый position_finder:

  1. пытается навигатор.геолокация.
  2. пытается вытащить свое последнее местоположение из localStorage
  3. использует Google Loader найти расположение по И. П.
  4. использует Нью-Йорк, Нью-Йорк

с точки зрения пользовательского интерфейса я бы выполнил следующие шаги:

A) показать хорошее текстовое поле, объясняющее, что произойдет дальше (т. е. "браузер попросит вас предоставить разрешение", "нажмите Разрешить" и т. д.) и попросит нажать кнопку, чтобы продолжить B) отображение карты, как вы делаете сейчас