iT邦幫忙

2

D3.js - 地圖繪製

Ares 2019-10-24 16:56:114720 瀏覽
  • 分享至 

  • xImage
  •  

D3 除了繪製圖表外還可以拿來繪製地圖,而這篇的目標是繪製一個世界地圖,那就開始吧!

地圖格式

繪製地圖前我們要先了解一下會使用到的資料格式,比較常看見的會有 SHP、GeoJSON 與 TopoJSON,而其中 D3 可用的格式為 GeoJSONTopoJSON,詳細的就讓我們往下看

Shapefile

ESRI Shapefile(shp),或簡稱 shapefile,是美國環境系統研究所公司(ESRI)開發的空間資料開放格式,目前該檔案格式已經成為了地理資訊軟體界的開放標準
shapefile 檔案用於描述幾何體物件:點、折線與多邊形。例如其可以儲存井、河流、湖泊等空間物件的幾何位置。除了幾何位置,shp檔案也可以儲存這些空間物件的屬性,例如河流的名字、城市的溫度等等。

而 Shapefile 又有分為好幾種格式,我們會用到的是副檔名為 .shp 的格式,可以將其轉換成 D3 可用的格式,也就是 GeoJSON 與 TopoJSON

GeoJSON

GeoJSON 是一種基於 JSON 的地理空間數據交換格式,它定義了幾種類型 JSON 對象以及它們組合在一起的方法,以表示有關地理要素、屬性和它們的空間範圍的數據。

GeoJSON 同樣是屬於 JSON 的一種,只不過是對它的名稱進行規範後,專門用於表示地理信息的格式,此格式為 D3 主要使用的格式

TopoJSON

TopoJSON 是 GeoJSON 的擴展,由 D3 的作者所發明,透過將共享邊(arcs)整合的方法組成,消除了一些 GeoJSON 冗餘的部分,使檔案大小大幅縮小,縮小幅度約可達 80% 左右

格式轉換

首先我們先找到提供 shp 的網站將檔案下載下來,裡面會有 Shapefile 的各種格式,我們需要的是副檔名為 shp 的檔案,再來就是將它轉換成 GeoJSON 或是 TopoJSON 了

線上服務(shp 轉 GeoJSON、TopoJSON)

線上轉換可使用 mapshaper 的服務,它除了轉換還可以預覽,可以說是非常好用

  1. 將下載下來的檔案 import 進去
    mapshaper操作步驟一
  2. 預覽確認檔案正確後,將檔案 Export 並下載下來就完成囉
    mapshaper操作步驟二

shapefile 套件(shp 轉 GeoJSON)

首先安裝 shapefile 這個套件,它可以幫我們將 .shp 轉換成 GeoJSON,可以使用它的 API 或是直接使用終端機轉換,我們這邊使用終端機的方式

安裝

$ npm install -g shapefile

轉換

$ shp2json ne_110m_land.shp -o map.json
<!-- 將 ne_110m_land.shp 轉換成 map.json -->

$ shp2json ne_110m_land.shp -o map.json --encoding big5
<!-- 將 ne_110m_land.shp 轉換成 map.json,使用 big5 編碼 -->

topojson 套件(TopoJSON、GeoJSON 互相轉換)

TopoJSON 無法直接於 D3 使用,所以作者也另外提供了套件,讓我們將 TopoJSON 轉換為 GeoJSON 的格式,安裝一樣可以使用 npm 或是 CDN 方式載入,有興趣可以看看,這邊就不做示範了

繪製地圖

用上述方法得到 GeoJSON 資料後就可以開始繪製地圖了,這邊先介紹幾個會使用到的方法~

  • d3.geoMercator:將地圖以麥卡托投影法繪製
  • center:設定地圖中心點座標
  • scale:設定地圖縮放倍率
  • d3.geoPath:將投影資料轉換為 path 的路徑
// 設定 svg 的寬高
const map = d3
  .select('.map')
  .attr('width', 500)
  .attr('height', 500);

// 獲取 ne_110m_land.json 的檔案資訊 ( GeoJSON ),完成後執行 draw 函式
fetch('./ne_110m_land.json')
  .then(res => res.json())
  .then(data => draw(data));

function draw(mapData) {
  // 設定投影中心點與縮放倍率
  const projection = d3
    .geoMercator()
    .center([200, 10])
    .scale(70);

  // 將投影資料轉換為路徑
  const path = d3.geoPath(projection);

  // 繪製地圖
  map
    .selectAll('path')
    .data(mapData.geometries)
    .enter()
    .append('path')
    .attr('d', path)
    .attr('stroke', 'black')
    .attr('stroke-width', '0.7')
    .attr('fill', 'steelblue')
    .on('mouseover', function() {
      d3.select(this).attr('fill', '#007bff')
    })
    // 滑鼠碰到後改變顏色
    .on('mouseleave',  function() {
      d3.select(this).attr('fill', 'steelblue')
    })
    // 滑鼠離開將顏色變回
}

世界地圖成品

結語

繪製地圖並不難,只要有地圖的資料,並且把握好資料格式的轉換,相信對大家來說是輕而易舉的事情~


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言