Google Maps API - 顯示 GeoJSON 資料
透過 Google Maps API 在地圖上繪製圖形不困難,但「取得地圖上的資料」卻令人頭痛,幸好隨著科技的進步,我們可以透過 GeoJSON 這種專門處理地理資訊結構的格式,更方便的在地圖上顯示各種資訊,這篇就來簡單介紹一下 GeoJSON,並在 Google 地圖上顯示對應的樣貌。
GeoJSON 簡介
GeoJSON 是一種對地理資訊結構進行編碼的格式,基於 JavaScript 物件標記的地理空間資訊資料交換格式 ( 所以才會是 Geo + json ),GeoJSON 支援像是點、線、多邊形、多點、多線、多個多邊形的幾何形狀,當中也包含了特徵或特徵的集合資訊。
舉例來說,一個 GeoJSON 最外層包含一個 type 為 FeatureCollection 的屬性,接著 features 的屬性包含了許多 type 為 Feature 的物件,這些 Feature 物件裡包含 properties 的屬性,可以設定區域的顏色、邊框...等樣式,也包含了 geometry 的屬性,定義地圖上形狀的面貌,以下面這段 GeoJSON 來說,就是在台北 101 旁的松壽路上,畫「一段粗細 10px,透明度 0.5 的紅色直線」。
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"stroke": "#ff0000",
"stroke-width": 10,
"stroke-opacity": 0.5
},
"geometry": {
"type": "LineString",
"coordinates": [
[
121.56351685523987,
25.03585799721269
],
[
121.56548023223877,
25.0358093932627
]
]
}
}
]
}
![]()
上面的例子中,type 設定為 LineString 呈現的是直線,如果要呈現多邊形,就要將 type 設為 Polygon,下面的 GeoJSON 呈現的是台北 101 被一個「黑色實線、紅色半透明填滿的正方形」圍住。
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"stroke": "#000000",
"stroke-width": 2,
"stroke-opacity": 1,
"fill": "#ff2600",
"fill-opacity": 0.5
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
121.56345248222352,
25.03295144714567
],
[
121.5654158592224,
25.03295144714567
],
[
121.5654158592224,
25.03476926411677
],
[
121.56345248222352,
25.03476926411677
],
[
121.56345248222352,
25.03295144714567
]
]
]
}
}
]
}
![]()
產生 GeoJSON
雖然說已經知道了 GeoJSON 的格式,但要產生 GeoJSON 最麻煩的仍然是那些小數點好多位數的「座標」,這時候就要透過 geojson.io 這個線上服務,來幫我們產生標準又漂亮的 GeoJSON。
參考連結:http://geojson.io/
打開網頁後,映入眼簾的是左右兩個視窗,左邊的視窗是地圖,右上角有繪圖的工具,右邊的視窗會根據所繪製的圖案,自動產生 GroJSON。
![]()
用「多邊形」工具把台北 101 旁邊的台北世界貿易中心框起來,就會看到對應的 GeoJSON 自動產生出來。
![]()
用滑鼠點擊畫好的多邊形,就可以修改多邊形的屬性,修改後在 GeoJSON 裡的 properties 也會自動產生,下圖就是把繪製的多邊形,改成黑色外框紅色填滿的屬性。
![]()
透過 geojson.io 這個方便好用的網站,要產生 GeoJSON 已經不再那麼困難,接著就來實作如何用 Google 地圖顯示 GeoJSON 資料。
Google 地圖顯示 GeoJSON 資料
匯入 GeoJSON 資料其實很簡單,每個 Google 地圖都有一個 map.data 物件,做為任意地理空間資料(包括 GeoJSON)的資料圖層,只要呼叫 data 物件的loadGeoJSON()方法就可以,用法如下:
map.data.loadGeoJson('GeoJSON.json');
舉例來說,下面這段程式碼,就會在地圖上載入上面我們所畫好的台北世貿中心。
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 17,
center: {lat: 25.034010, lng:121.562428}
});
map.data.loadGeoJson('geojson.demo.json');
}
![]()
不過很神奇的,載入之後我們原本設定的樣式反而不見了,這時候就得使用Data.setStyle()方法來指定資料外觀,以剛剛的例子來說,只要改寫成下面這樣,就能讓原本的形狀多了些色彩。
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 17,
center: {lat: 25.034010, lng:121.562428}
});
map.data.loadGeoJson('geojson.demo.json');
map.data.setStyle({
strokeWeight: 20,
strokeOpacity: .5,
strokeColor: '#f00',
fillColor: '#0c0',
fillOpacity: .35
});
}
![]()
如果還是想使用我們自定義的 GeoJSON 樣式該怎麼做呢?這時就得用到map.data.setStyle(function(feature)){}來取的每筆資料的屬性,下面的例子將會把我們自定義的 properties 的樣式取出,套用到 Google 地圖上。
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 17,
center: {lat: 25.034010, lng:121.562428}
});
map.data.loadGeoJson('geojson.demo.json');
map.data.setStyle(function(feature){
return {
strokeWeight: feature.getProperty('stroke-width'),
strokeOpacity: feature.getProperty('stroke-opacity'),
strokeColor: feature.getProperty('stroke'),
fillColor: feature.getProperty('fill'),
fillOpacity: feature.getProperty('fill-opacity')
}
});
}
![]()
同樣道理,如果我們手動在 properties 內定義一個名為 name 的屬性,就可以在「多個形狀」的資料下,指定每筆資料產生的形狀樣式,以下面的例子來說,透過 name 的屬性,就能指定紅色和綠色的區塊按照 GeoJSON 的配置顯示色彩,而另外一個區塊就用預設的 Google 形狀來顯示。
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 17,
center: {lat: 25.034010, lng:121.562428}
});
map.data.loadGeoJson('geojson.demo2.json');
map.data.setStyle(function(feature){
if(feature.getProperty('name')=='red' || feature.getProperty('name')=='green'){
return {
strokeWeight: feature.getProperty('stroke-width'),
strokeOpacity: feature.getProperty('stroke-opacity'),
strokeColor: feature.getProperty('stroke'),
fillColor: feature.getProperty('fill'),
fillOpacity: feature.getProperty('fill-opacity')
}
}
});
}
![]()
小結
基本上透過 Google 地圖來顯示 GeoJSON 資料沒有太大的難度,比較難的是讀取資料後要怎麼用視覺化呈現,讓使用者可以一目瞭然,接下來會再嘗試讀取資料後再做一些變化,敬請期待囉~ ^_^