1. 程式人生 > >HTML5地理定位

HTML5地理定位

在學習HeadFirstHtml5中,學到了地理定位,之前用過百度的地圖SDK,

是畢業設計Android APP的其中的一個小功能,這次我們用Google開放的API,

使用JS來實現瀏覽器的地理定位。

定位原理:

一般是GPS定位(4顆衛星,利用電磁波來定位), 或者基站三角定位(利用訊號強度定位), 以及WIFI定位(你開了WIFI就能掃描到附近的WIFI,如果此時你開啟了定位,就會收集到位置伺服器,你附近的WIFI也會收集起來,包括他們的MAC地址,根據訊號衰減公式就能推算出它們的距離)。wifi可以進行室內定位,一般情況下室外精度是GPS>WIFI>基站.另外有政策不允許那麼準。

參考手冊: 

第三方API,從某種角度講,是植根於第三方伺服器上的。要通過 JavaScript獲取它們,您首先需要連結到其功能介面上並使其在您的頁面上生效。通常來說,這首先需要您通過一個 <script> 元素連線到第三方伺服器所開放的JavaScript庫,

 <script src="https://maps.googleapis.com/maps
/api/js?key=AIzaSyDJW4jsPlNKgv6jFm3B5Edp5ywgdqL
Wdmc&sensor=true"></script>

其中第三方API一般來說都需要申請開發者的APIKEY,不過上述的apikey可以直接使用。這樣你就可以使用人家庫中的物件和方法了。

javascript主要提供的方法有三種:

navigator.geolocation.getCurrentPosition(displayLocation, displayError, options)

navigator.geolocation.watchPosition(displayLocation, displayError, options)

navigator.geolocation.clearWatch(watchId)

我們要做的是利用getCurrentPosition獲得我們的位置,第一次會彈出請求框,點選允許就可以。

獲取位置之後建立地圖,同時建立Marker標記我們的位置,然後控制精度、地圖型別等等,獲取我們

關心的資料。

下面是程式碼,可以對照文件閱讀:

myLoc.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Wherever you go, there you are</title>
    <script src="myLoc.js"></script>
    <!-- 這裡的sensor=true的引數表示使用地圖同時使用我的位置-->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDJW4jsPlNKgv6jFm3B5Edp5ywgdqLWdmc&sensor=true"></script>
    <link rel="stylesheet" href="myLoc.css">
</head>
<body>
    <form>
        <input type="button" id="watch" value="Watch me">
        <input type="button" id="clearWatch" value="Clear watch">
    </form>
    <div id="location">
        Your location will go here.
    </div>
    <div id="distance">
        Distance from WickedlySmart HQ will go here.
    </div>
    <div id="map">
        
    </div>
</body>
</html>

myLoc.css

/*
 * myLoc.css
 *
*/

body {
	font-family: Arial, Helvetica, sans-serif;
	margin: 10px;
}
form, div#location, div#distance {
	padding: 5px;
}

div#map {
	margin: 5px;
	width: 400px;
	height: 400px;
	border: 1px solid black;
}


/*
 * Use this CSS to make the map full screen
 *

html, body, div#map {
    width: 100%;
    height: 100%;
    margin: 0px;
}

form {
	position: absolute;
	top: 40px;
	right: 10px;
	z-index: 2;
}

div#location, div#distance {
	display: none;
}
 */

myLoc.js

var watchId = null; //可以使用這個id來clearWatch
var prevCoords = null; //我們將前一次定位和最近一次定位的經緯度之間距離計算,大於20米才加入Marker標記
var map; //全域性變數map,包含建立的Google地圖物件
//這是一個字面量物件
var ourCoords = {
    latitude: 47.624851,
    longitude: -122.52099
};

window.onload = getMyLocation;

function displayLocation(position) {
    //從position.coords物件中獲取緯度和經度
    var latitude = position.coords.latitude;
    var longitude = position.coords.longitude;

    //獲取經緯度
    var div = window.document.getElementById("location");
    div.innerHTML = "You are at Latitude: " + latitude + ", Longitude: " + longitude;
    div.innerHTML += " (with " + position.coords.accuracy + " meters accuracy)";

    //計算距離
    var km = computeDistance(position.coords, ourCoords);
    var distance = document.getElementById("distance");
    distance.innerHTML = "You are " + km  + " km from the WickedlySmart HQ";

    //建立地圖 coords物件有latitude、longitude、accuracy、altitude、altitudeAccuracy、heading、
    //speed等屬性,分別表示緯度、經度、準確度、海拔、海拔經度、你的方向、你的速度
    if(map == null){
        showMap(position.coords);
        prevCoords = position.coords; //記錄第一次的座標物件
    } else {
        var meters = computeDistance(position.coords, prevCoords) * 1000; //單位轉換
        if(meters > 20) {
            scrollMapToPosition(position.coords);
            prevCoords = position.coords;
        }
    }
}

//計算地理經緯度

//編寫 錯誤處理程式,geolocation物件會向你的處理程式傳入一個error物件,
//其中包含一個數值碼,描述它未能確定瀏覽器位置的原因。
function displayError(error) {
    alert(typeof(error.code));
    var errorTypes = {
        0: "Unknown error",
        1: "Permission denied by user",
        2: "Position is not available",
        3: "Request timed out"
    };
    
    var errorMessage = errorTypes[error.code];
    //這裡error.code是一個number值,errorTypes會把數字屬性自動轉換為字串,可以直接
    //errorTypes[error.code]來索引,也可以用errorTypes["1"]類似形式來索引
    if(error.code == 0 || error.code == 2){
        //對於0和2錯誤,error.message可能還有額外的資訊
        errorMessage = errorMessage + " " + error.message; 
    }
    var div = document.getElementById("location");
    div.innerHTML = errorMessage;
}

function getMyLocation() {
    if(navigator.geolocation) {
        // navigator.geolocation.getCurrentPosition(displayLocation, 
        //     displayError);
        var watchButton = document.getElementById("watch");
        watchButton.onclick = watchLocation;
        var clearWatchButton = document.getElementById("clearWatch");
        clearWatchButton.onclick = clearWatch;
    } else {
        alert("Oops, no geolocation support");
    }
}

//利用Haversine公式計算經緯度點之間的距離

function degreesToRadians(degrees) {
    var radians = (degrees * Math.PI) / 180;
    return radians;
}

function computeDistance(startCoords, destCoords) {
    var startLatRads = degreesToRadians(startCoords.latitude);
    var startLongRads = degreesToRadians(startCoords.longitude);
    var destLatRads = degreesToRadians(destCoords.latitude);
    var destLongRads = degreesToRadians(destCoords.longitude);

    var Radius = 6371; //radius of the Earth in km
    var distance = Math.acos(Math.sin(startLatRads) * Math.sin(destLatRads) + 
        Math.cos(startLatRads) * Math.cos(destLatRads) * 
        Math.cos(startLongRads - destLongRads)) * Radius;

    return distance;
}

//建立地圖 參考開發文件https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs#Adding_a_custom_marker
//google map platform: https://developers.google.cn/maps/documentation/javascript/tutorial
function showMap(coords) {
    //使用Google提供的建構函式來建立一個包含經緯度的物件
    var googleLatAndLong = new google.maps.LatLng(coords.latitude, coords.longitude);
    
        /**
         * Google提供了一些選項來控制如何建立地圖。
         * zoom: 範圍是0~21的一個值,是地圖的比例尺
         * center: 地圖中我們的位置是居中 
         * mapTypedId: 地圖的型別(道路地圖、衛星地圖、或者二者兼有)
         * SATELLITE、HYBRID
         */
    var mapOptions = {
        zoom: 20,
        center: googleLatAndLong,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    var mapDiv = document.getElementById("map");
    map = new google.maps.Map(mapDiv, mapOptions); //引數是一個元素物件、和我們的選項物件

    var title = "Your Location:";
    var content = "You are here: " + coords.latitude + ", " + coords.longitude;
    addMarker(map, googleLatAndLong, title, content);
} 

//建立marker
function addMarker(map, latLong, title, content) {
    //makerOptions物件包含了經緯度,地圖,標題,以及是否可以點選
    var markerOptions = {
        position: latLong,
        map: map,
        title: title,
        clickable: true
    };

    var marker = new google.maps.Marker(markerOptions);
    var infoWindowOptions = {
        content: content,
        position: latLong
    };

    var infoWindow = new google.maps.InfoWindow(infoWindowOptions);

    google.maps.event.addListener(marker, "click", function(){
        infoWindow.open(map);
    });
    // marker.addListener("click", function() {
    //     infoWindow.open(map, marker);
    // })
}

/**
 * 持續跟蹤位置 geolocation.watchPosition方法有三個引數,
 * 成功處理函式,錯誤處理函式,以及選項控制地理定位的超時時間,最大生存時間,是否最高精度等。
 */
function watchLocation() {
    //每次位置更新會呼叫displayLocation函式
    watchId = navigator.geolocation.watchPosition(displayLocation, displayError);
}

function clearWatchButton() {
    if(watchId) {
        navigator.geolocation.clearWatch(watchId);
        watchId = null; 
    }
}

//移動的時候我們可以在地圖上新增多個marker標誌,下面定義一個函式
function scrollMapToPosition(coords) {
    var latitude = coords.latitude;
    var longitude = coords.longtitude;
    var latLong = new google.maps.LatLng(latitude, longitude);

    map.panTo(latlong); //地圖的panTo方法取得座標物件,移動到地圖中心

    addMarker(map, latlong, "Your new location", "You moved to: " + 
        latitude + ", " + longitude);
}

下圖是結果:

我們在form表單中建立了兩個按鈕,分別可以監控我們的實時位置,或者清除我們的位置。

結果如圖: 我電腦不容易移動,移動之後只要距離超過20m跨度,就會出現一個紅色預設的Marker來標記

當前位置