通过 html5 和 javascript 获取用户地理位置

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14642796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 22:12:45  来源:igfitidea点击:

getting users geolocation via html5 and javascript

javascripthtmlgoogle-mapsgeolocationip-geolocation

提问by whatf

I am trying to get the users geolocation via the html5 geolcation api, and i use the following snippet for it:

我正在尝试通过 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]);
  }
});

The trouble with the above approach is that, few of the users have found it difficult to use. Few of the times, they have clicked Denyinstead of Allowand keep staring on the screen. So from usability point of view, I think a good approach would be:

上述方法的问题在于,很少有用户发现它难以使用。他们很少点击拒绝而不是允许并一直盯着屏幕。所以从可用性的角度来看,我认为一个好的方法是:

  1. Ask them for permission.

  2. Wait for 3 seconds, if they click deny or don't respond, use IP to show the geolcation on the map.

  1. 征求他们的许可。

  2. 等待 3 秒,如果他们点击拒绝或不响应,则使用 IP 在地图上显示地理定位。

How can I accomplish the second step in my above snippets. Please let me know, thanks! However, what would be a better way to handle

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

回答by Onur Y?ld?r?m

Here is a script (geolocator.js) I wrote some time ago and updated recently.

这是我前段时间写的一个脚本(geolocator.js),最近更新了。

Update: Geolocator v2 is released.

更新:发布了 Geolocator v2。

Features:

特征:

  • HTML5 geolocation (by user permission)
  • Location by IP
  • Geocoding (coordinates from address)
  • Reverse Geocoding (address lookup from coordinates)
  • Full address information (street, town, neighborhood, region, country, country code, postal code, etc...)
  • Fallback mechanism (from HTML5-geolocation to IP-geo lookup)
  • Watch geographic position
  • Get distance matrix and duration
  • Calculate distance between two geographic points
  • Get timezone information
  • Get client IP
  • Supports Google Loader (loads Google Maps dynamically)
  • Dynamically creates Google Maps (with marker, info window, auto-adjusted zoom)
  • Non-blocking script loading (external sources are loaded on the fly without interrupting page load)
  • HTML5 地理定位(经用户许可)
  • 通过 IP 定位
  • 地理编码(来自地址的坐标)
  • 反向地理编码(从坐标查找地址)
  • 完整的地址信息(街道、城镇、街区、地区、国家、国家代码、邮政编码等...)
  • 回退机制(从 HTML5 地理定位到 IP 地理查找)
  • 观看地理位置
  • 获取距离矩阵和持续时间
  • 计算两个地理点之间的距离
  • 获取时区信息
  • 获取客户端IP
  • 支持谷歌加载器(动态加载谷歌地图)
  • 动态创建谷歌地图(带标记、信息窗口、自动调整缩放)
  • 非阻塞脚本加载(外部源在不中断页面加载的情况下即时加载)

See a live demo.
See API documentation.

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

Geolocator Example Screenshot

地理定位器示例截图

Usage:

用法:

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);
});

Example Output:

示例输出:

{
    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
}

回答by cliffbarnes

You would then use a geo ip api like this one:

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

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

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

回答by Rick Hurst

Ok so this is not a code answer, more of an User Experience answer.

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

From a UX standpoint, the first thing that stands out is the lack of information you are offering before you trigger the browser to ask them for permission.

从用户体验的角度来看,首先突出的是在您触发浏览器请求他们的许可之前您提供的信息缺乏。

I suggest you have some sort of overlay box showing a screen shot (with a large arrow on it) demonstrating "where" on the screen that they are going to get asked for permission. Also you can take that opportunity to tell them what will happen if they deny permission or fail to accept it within say 10 seconds (ie. where they ignore the prompt bar).

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

I suggest you don't default to showing the IP location, because they essentially 'could be saying' I don't agree to letting you know where I am. Then you show a big map of where they are, that may freak a few people out that clicked deny! Besides it may be very inaccurate.

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

The idea of "don't ask for permission ask for forgiveness", may work in Biz dev, but not in UI as they just don't come back.

“不请求许可请求宽恕”的想法可能适用于 Biz 开发,但不适用于 UI,因为它们不会回来。

I would ask yourself if you really need high accuracy too, because it will drain user battery, take longer, and may not give you much more bang for your buck, especially if you only need it to find out loosely where they are. You can always call it again later for a more accurate reading if you need to.

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

The concept of timing out if they don't click deny or allow could be achieved with a setTimeout. So once they click "Ok I'm ready to click allow" on your overlay box, kick off a timeout and if it does eventually timeout then do what you told them you would do in the above step.

如果他们不单击拒绝或允许则超时的概念可以通过 setTimeout 实现。因此,一旦他们在您的覆盖框上单击“好的,我准备单击允许”,请启动超时,如果最终超时,则执行您在上述步骤中告诉他们的操作。

By using this method, you force the user to either allow or deny(ignore), either-way it puts control back in your court, and keep the user totally informed.

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

Although this is not a code specific answer, it is clear from your JS that "code implementation help" is not really the issue here. I hope if nothing else this gets you thinking a little more about your User Experience.

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

回答by StackedFlow

This, might be of help: http://jsfiddle.net/sandesh2302/FghFZ/I used this for my stuff, it worked fine.

这可能会有所帮助: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>

回答by hejhi

You can use this online service to get the lat lng easily:

您可以使用此在线服务轻松获取经纬度:

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

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

Regarding the timeout, I don't think there's a way to interfere with the browsers permission mechanism (as in, to close that permission popup after a certain amount of seconds) - though I would gladly be proven wrong. What you could do would be to set a timer and after three seconds, get the IP based geolocation and set the map to it (or, refresh the page after 3 seconds, and set a cookie that triggers the IP based geo and not the HTML5 geo, but that's a bit over the top if you ask me).

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

Then, if they give permission, it would refresh the map with the HTML5 geolocation (which should be much more accurate). You can also encapsulate the IP geo fallback into a function and use it if they don't have HTML5 geolocation or they hit deny.

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

Here's a fiddle: http://jsfiddle.net/mfNCn/1/

这是一个小提琴:http: //jsfiddle.net/mfNCn/1/

Here's the rough cut from the fiddle:

这是小提琴的粗剪:

<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
}

(I hesitate to put the whole code chunk onto here, as it's rather lengthy, so check the fiddle for the rest and full implementation)

(我犹豫是否将整个代码块放在此处,因为它相当冗长,因此请查看小提琴以了解其余部分和完整实现)

回答by Brian Cray

If there is a timeout or the user denies the request, I would set a default location like New York, NY (40.7142, -74.0064). If a user denies a request, they have to also expect that you won't know their location so choosing an intelligible default is the next best thing.

如果出现超时或用户拒绝请求,我会设置一个默认位置,如纽约州纽约 (40.7142, -74.0064)。如果用户拒绝请求,他们还必须期望您不会知道他们的位置,因此选择一个可理解的默认值是下一个最好的选择。

Using a default without changing your code much can be accomplished by calling displayPosition({coords: {latitude: 40.7142, longitude: -74.0064}})in two places:

使用默认值而不更改代码可以通过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.comI use a "queue" of functions for finding a user's location, looping through the queue until one of them finds a valid location. The last function returns New York, NY, which means all other attempts have failed. Here's a sample of the code modified slightly:

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();

Here's what each position_finder does:

以下是每个 position_finder 的作用:

  1. Tries navigator.geolocation.
  2. Tries pulling their last location from localStorage
  3. Uses Google Loaderto find location via I.P.
  4. Uses New York, NY
  1. 尝试 navigator.geolocation。
  2. 尝试从 localStorage 中提取他们的最后位置
  3. 使用Google Loader通过 IP 查找位置
  4. 使用纽约,纽约

回答by aquauser

From UI point of view, I would follow these steps:

从用户界面的角度来看,我将遵循以下步骤:

A) show a nice text box explaining what's going to happen next (I.e. 'the browser will ask you to grant a permission', 'click allow', etc) and asking to push a button to proceed B) display the map as you do now

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