14

我正在尝试通过 html5 geolcation api 获取用户地理位置,我使用以下代码段:

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 在地图上显示地理定位。

我如何才能完成上述代码段中的第二步。请让我知道,谢谢!但是,有什么更好的处理方式

4

8 回答 8

16

这是我前段时间编写并最近更新的脚本( geolocator.js )。

更新:Geolocator v2 已发布。

特征:

  • HTML5 地理位置(由用户许可)
  • 按 IP 定位
  • 地理编码(地址坐标)
  • 反向地理编码(从坐标中查找地址)
  • 完整的地址信息(街道、城镇、社区、地区、国家、国家代码、邮政编码等...)
  • 回退机制(从 HTML5-geolocation 到 IP-geo 查找)
  • 看地理位置
  • 获取距离矩阵和持续时间
  • 计算两个地理点之间的距离
  • 获取时区信息
  • 获取客户端 IP
  • 支持谷歌加载器(动态加载谷歌地图)
  • 动态创建谷歌地图(带有标记、信息窗口、自动调整缩放)
  • 非阻塞脚本加载(在不中断页面加载的情况下动态加载外部源)

观看现场演示
请参阅API 文档

地理定位器示例截图

用法:

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
}
于 2013-02-11T10:57:24.337 回答
3

然后,您将使用这样的地理 ip api:

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

于 2013-02-01T14:24:29.843 回答
2

好的,所以这不是代码答案,更多的是用户体验答案。

从用户体验的角度来看,最突出的第一件事是在您触发浏览器请求他们许可之前您提供的信息不足。

我建议您使用某种覆盖框来显示屏幕截图(上面有一个大箭头),在屏幕上展示他们将被要求获得许可的“位置”。您也可以借此机会告诉他们,如果他们在 10 秒内拒绝或未能接受许可(即他们忽略提示栏),将会发生什么。

我建议您不要默认显示 IP 位置,因为他们基本上“可能会说”我不同意让您知道我在哪里。然后你显示他们在哪里的大地图,这可能会吓坏一些点击拒绝的人!此外,它可能非常不准确。

“不请求许可请求原谅”的想法可能在 Biz dev 中有效,但在 UI 中无效,因为它们只是不会回来。

我会问自己是否真的需要高精度,因为它会耗尽用户电池,花费更长的时间,并且可能不会给你带来更多的收益,特别是如果你只需要它来松散地找出它们的位置。如果需要,您可以随时再次调用它以获得更准确的读数。

如果他们不点击拒绝或允许,则超时的概念可以通过 setTimeout 来实现。因此,一旦他们在您的叠加框上单击“好的,我已准备好单击允许”,请启动超时,如果它最终超时,然后按照您在上述步骤中告诉他们的操作。

通过使用这种方法,您可以强制用户允许或拒绝(忽略),无论哪种方式,它都会将控制权交还给您,并让用户完全了解情况。

尽管这不是特定于代码的答案,但从您的 JS 中可以清楚地看出,“代码实现帮助”并不是真正的问题。我希望如果没有别的,这能让你更多地思考你的用户体验。

于 2013-02-04T17:37:14.947 回答
0

您可以使用此在线服务轻松获取 lat lng:

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

关于超时,我认为没有办法干扰浏览器的权限机制(例如,在一定秒数后关闭该权限弹出窗口)——尽管我很乐意被证明是错误的。您可以做的是设置一个计时器,并在三秒后获取基于 IP 的地理位置并将地图设置为它(或者,在 3 秒后刷新页面,并设置一个触发基于 IP 的地理而不是 HTML5 的 cookie geo,但如果你问我,那有点过分了)。

然后,如果他们给予许可,它将使用 HTML5 地理位置刷新地图(应该更准确)。您还可以将 IP 地理回退封装到一个函数中,如果他们没有 HTML5 地理位置或者他们点击拒绝,则可以使用它。

这是一个小提琴: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
}

(我犹豫把整个代码块放在这里,因为它相当长,所以检查小提琴的其余部分和完整的实现)

于 2013-02-06T21:40:27.997 回答
0

如果超时或用户拒绝请求,我会设置一个默认位置,如纽约,纽约 (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}});
}

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. 尝试 navigator.geolocation。
  2. 尝试从 localStorage 中提取他们的最后一个位置
  3. 使用Google Loader通过 IP 查找位置
  4. 使用纽约州纽约市
于 2013-02-08T23:03:20.387 回答
0

看看这个 tutsplus 示例http://mobile.tutsplus.com/tutorials/mobile-web-apps/html5-geolocation/

于 2013-02-03T11:06:01.283 回答
0

这可能会有所帮助: http: //jsfiddle.net/sandesh2302/FghFZ/ 我用它来做我的东西,效果很好。

前任:

    <!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>
于 2013-02-04T17:46:55.857 回答
-1

从 UI 的角度来看,我将遵循以下步骤:

A)显示一个漂亮的文本框,解释接下来会发生什么(即“浏览器会要求您授予权限”、“单击允许”等)并要求按下按钮继续 B)像您一样显示地图现在

于 2013-02-07T07:58:48.817 回答