為了因應Flash的停用,需要重新尋找作為繪製地圖的套件,最後考慮到D3.js的可控性並且使用BSD授權,因此使用D3.js來作為繪製地圖的工具。
D3.js 是以一個使用動態圖形進行資料視覺化的JavaScript程式庫,並且相容於W3C標準,其中主要使用SVG作為圖形格式。
由於我們的地圖來源是使用shp格式,但是d3是使用geojson的資料格式進行地圖繪製,因此我們使用免費開源的QGIS作為編輯以及轉換軟體進行處理。
以下使用d3.v4作為編寫
首先需要先準備一個svg元素來作為容器來繪製地圖
<svg width="1600" height="900"></svg>
之後要重新定位地圖的中心點與縮放比率,好讓地圖能在畫面中心顯示出來
抓取出頁面的長和寬
var svg = d3.select("svg");
var width = +svg.attr("width");
var height = +svg.attr("height");
d3.select: 回傳與選擇器相符的第一個元素,如果沒有匹配的元素則返回空選擇
selection.attr: 回傳選擇元素指定的屬性
利用頁面的長和寬去轉換地圖的位置
var projection = d3.geoMercator().scale(10000)
.center([121,24])
.translate([width / 2, height / 2]);
d3.geoMercator: 使用矩形投影縮放地圖
projection.scale: 設定縮放倍率
projection.center: 設定投影中心點
projection.translate: 設定投影偏移量(總是先translate再進行scale)
之後需要將地圖檔Load進來,json/COUNTY_MOI.geojson為地圖檔,ready為自訂繪製地圖的function
d3.queue().defer(d3.json, "json/COUNTY_MOI.geojson").await(draw);
d3.queue:使用異步執行一個或多個defer任務,並在任務都完成或發生錯誤後將結果傳給await
再來定義自己繪圖的function
function draw(error, map) {
svg.append("g")
.selectAll("path")
.data(map.features)
.enter()
.append("path")
.attr("d", d3.geoPath(projection))
.attr("fill", "#69b3a2")
.style("stroke", "#fff");
}
error: 如果發生錯誤會記錄在這裡
map: 剛才defer(d3.json, "json/COUNTY_MOI.geojson")回傳的地圖檔
selection.append: 附加元素在指定選擇器之內,並回傳新的選擇器
selection.selectAll: 回傳與選擇器相符的所有元素,如果沒有匹配的元素則返回空選擇
selection.data: 將數據組綁定到選定的元素組,並返回更新的選擇器(update selection)
selection.enter: 返回新增的選擇器(enter selection)
enter.append: 如果選擇器為新增選擇器(enter selection),則附加新增的元素到指定選擇器內
selection.attr("d", d3.geoPath(projection)): 設定地圖繪製出來的投影縮放
最後來解釋一下什麼是update selection、enter selection與exit selection
當d3在處理數據綁定時會把每個更新的元素都分成以上三個分類,
當在執行selection.data資料綁定時主要會發生以下三種狀況:
1. selection元素組數量小於更新的數據數量:
2. selection元素組數量大於更新的數據數量:
3. selection元素組數量等於更新的數據數量:
當元素組小於數據組時,會先創立空的元素以對應新增的數據,這部分被稱為enter selection,
而有元素對應的部分被稱為update selection,而當元素組大於數據組時,多餘的則被稱為exit selection。
所以當我們使用selectAll先選擇空選擇器在data綁定數據時,所有新增的數據都會先綁定到空的選擇器並且被分類成enter selection,
使得在selection.enter取回新增的enter selection時,在append能直接新增到svg上。