#googleAPI
#XHR
#navigator.geolocation
作品連結可點擊首頁右上方查看。
*功能說明:一進入網站詢問是否開啟定位功能。使用定位功能測得最近測站並顯示其AQI、PM2.5、發佈時間以及狀態。下方的地圖將資料視覺化,一覽全臺空汙狀況,點擊可顯示測站名。
1.使用到的變數們
var data;
var nowLongitude,nowLatitude,increaseNum=1000000;
var everyDistance = [],minDistance=10000000,minKey;
var nearSite = document.getElementById("nearSite"),
aqi=document.getElementById("aqi"),
pm=document.getElementById("pm"),
time=document.getElementById("time"),
airstatus=document.getElementById("airstatus");
var searchSite = document.getElementById("searchSite"),
confirm = document.getElementById("confirm");
searchResult = document.getElementById("searchResult");
var url="https://opendata.epa.gov.tw/api/v1/AQI?%24skip=0&%24top=1000&%24format=json";
var map, markerLatLng = [],marker=[],infowindow=[],markercolor=[];
2..ajax
首先要取得空汙資料。使用的是政府開放平台的資料(https://opendata.epa.gov.tw/Data/Contents/AQI/),每一小時會更新一次。這份api裡面包含很多資料,有測站名字、縣市、發佈時間、AQI、測站經緯度等。十分詳盡且方便使用。
var xhr = new XMLHttpRequest();
xhr.open('GET',url,true);
xhr.send();
if(xhr.readyState!=4){
nearSite.innerHTML="目前無法連上API";
}
xhr.onload = function(){
data = JSON.parse(xhr.response);
getLocation();
}
首先建立一個XMLHttpRequest物件,接著open()方法設定('傳送資料的方法'、'資料來源'、'是否為非同步'),而sned()方法送出Http Request,因為沒有要傳送資料過去,所以裡面是null。
xhr.readyState=4時代表連接完成,因此若不等於4時,告訴使用者目前API的連接出現了狀況。xhr.onload代表一連接上的時候執行function。xhr.response為回傳過來的資料,將它轉為JSON格式並定義為data(先看一下data裡面有哪些可以用的資料)。接著執行getLocation()函式。
3.navigator.geolocation
function getLocation()
{
if (navigator.geolocation)
{
navigator.geolocation.getCurrentPosition(showPosition);
}
else
{
alert("瀏覽器不支援");
}
}
先判斷navigator.geolocation物件是否可用。如果可以,使用getCurrentPosition(),這個函式會請求使用者的的位置,在()裡加入取得後執行的函式。
function showPosition(position)
{
nowLatitude = position.coords.latitude;
nowLongitude = position.coords.longitude;
let a=[],b=[];
for(let i =0;i<data.length;i++){
a[i]=(nowLongitude-data[i].Longitude)*(nowLongitude-data[i].Longitude);
b[i]=(nowLatitude-data[i].Latitude)*(nowLatitude-data[i].Latitude);
everyDistance[i]=(a[i]+b[i])*increaseNum;
if(everyDistance[i]<minDistance){
minDistance=everyDistance[i];
minKey=i;
}
}
nearSite.innerHTML= data[minKey].SiteName;
searchSite.innerHTML= data[minKey].SiteName;
aqi.innerHTML= data[minKey]['AQI'];
pm.innerHTML= data[minKey]['PM2.5'];
time.innerHTML= data[minKey].PublishTime;
airstatus.innerHTML= data[minKey].Status;
addmarker();
search();
}
showPosition裡面做的事情是利用取得的使用者位置跟xhr要來的資料,判斷最近的測站,以及在網頁上顯示該測站測得的資料。
position.coords.latitude、position.coords.longitude 這兩個即為使用者同意後,得到的位置經緯度。定義在nowLatitude跟nowLongitude裡面。接著開始計算每個測站跟這個經緯度之間的距離,用距離公式:((x1-x2)平方+(y1-y2)平方)開根號。這邊因為只是比較距離,就不開根號了。
先將每筆算出來的距離存進everyDistance[]陣列裡面,這邊乘上了increasenum變數是因為相減之後會得到小數點後很多位,為避免得到一堆零無法比較結果的情況,調整位數。
在計算距離、距離塞入陣列的時候,開始取得最小值。minDistance一開始先定為一個很大的數字,接著去跟每一個距離做比較,如果資料裡的某一筆值小於minDistance,則minDistance賦值為此筆資料。以此下去找到最小值。再將篩選出的資料丟到html上。
4.搜尋測站資料
function search(){
var optionGroup="";
for(let i =0;i<data.length;i++){
optionGroup += '<option value="'+i+'">'+data[i].SiteName+'</option>';
}
searchResult.innerHTML = optionGroup;
}
confirm.addEventListener('click',function(){
searchSite.innerHTML= data[searchResult.value].SiteName;
aqi.innerHTML= data[searchResult.value]['AQI'];
pm.innerHTML= data[searchResult.value]['PM2.5'];
time.innerHTML= data[searchResult.value].PublishTime;
airstatus.innerHTML= data[searchResult.value].Status;
});
在html上已經有了<select>,接著要將選項丟入標籤裡面。當確認按鈕(這邊命名為confirm)點下去後,serchResult是select標籤上的id。運用上面有將測站於data中的key設為value,取得要顯示那些資料。
5.google api
google api的部分添加marker跟infowindow。marker的部分,會添加在各個測站的位置上,並以圓形顯示,AQI數值越大、透明度越大、scale越大,並且以該狀態代表的顏色顯示;infowindow則單純顯示測站名字。
(顏色參考:https://airtw.epa.gov.tw/CHT/Information/Standard/AirQualityIndicator.aspx)
使用google api 需先在script引入。之後在html添加放地圖的區塊,一開始的時候先渲染出地圖。
function initialize(position) {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 8,
center: new google.maps.LatLng(23.5,121),
mapTypeId: 'terrain'
});
}
創造出google.maps.Map物件,第二個參數定義了map的各項設定,讓中心在臺灣島中間。
function addmarker(){
for(let i =0;i<data.length;i++){
if( 0<=data[i].AQI&&data[i].AQI<=50)markercolor[i]="green";
else if(51<=data[i].AQI&&data[i].AQI<=100)markercolor[i]="yellow";
else if(101<=data[i].AQI&&data[i].AQI<=150)markercolor[i]="orange";
else if(151<=data[i].AQI&&data[i].AQI<=200)markercolor[i]="red";
else if(201<=data[i].AQI&&data[i].AQI<=300)markercolor[i]="purple";
else if(301<=data[i].AQI&&data[i].AQI<=500)markercolor[i]="brown";
markerLatLng.push({});
markerLatLng[i].lat = parseFloat(data[i].Latitude,10);
markerLatLng[i].lng = parseFloat(data[i].Longitude,10);
marker[i]= new google.maps.Marker({
position:markerLatLng[i],
map:map,
icon: {
path: google.maps.SymbolPath.CIRCLE,
fillColor: markercolor[i],
fillOpacity: data[i]['AQI']/200,
scale: data[i]['AQI']/5,
strokeWeight: .5,
strokeColor: 'white'
},
label:{text:data[i]['AQI'],color:"blue"}
});
}
添加marker要創建google.maps.Marker物件,這邊特別處理的是marker的位置、icon、label。
上面的markerLatLng陣列紀錄的是每一個測站的經緯度。在迴圈裡面,每一次執行時先將物件塞入陣列裡面,然後物件裡面寫入每一筆資料的lat、lng值。這邊會這麼做是因為,position的格式要呈現"{lat=.. , lng=...}"。
icon的部分,fillColor填入用markercolor[]記錄下來的每一筆資料的顏色。上面一連串的判斷中,決定了什麼數值配對什麼顏色 ; fillOpacity、scale也用AQI的數值去決定了scale跟透明度。
而infowindow的部分,也寫在一個function裡面
for(let i =0 ;i<data.length;i++){
infowindow[i] = new google.maps.InfoWindow({
content: ""+data[i].SiteName
});
marker[i].addListener('click', function() {
infowindow[i].open(map, marker[i]);
});
創建google.maps.InfoWindow物件,內容定為測站名字。加上監聽事件,點擊後,open(map,哪一個marker)
這樣就完成了
以下為demo影片
留言
張貼留言