d3、vue 畫一個台灣地圖

d3、vue 畫一個台灣地圖

畫一個台灣地圖需要很多資源的幫忙

最近想做一個「台灣本島XXX地圖」的頁面,比如台灣本島素食地圖、台灣本島氣象地圖。

原本想說就簡單的找個台灣地圖的svg檔,後來發現台北、新北這二塊很多找得到的圖層沒處理好,按了新北會包含到台北那塊,然後Augustus對於illustrator又沒很會用,只好放棄。

接著又Google爬了一下網路的高手們是怎麼處理的,看了很多篇,結果發現很多篇都是從某一篇複製貼上的,內容大同小異,先從政府資料開放平台上下載,接著用d3.js轉topojson,再處理path就完成了。

教學文章都寫到這,秀出載入出的台灣地圖就停了,但Augustus想做的是可以讓台灣是置中的,而實際上照以上的步驟執行後,台灣本島不會在正中央,研究了3個多小時才找到解決辦法。

本篇筆記會紀錄在網頁上畫出一個台灣本島的步驟,包含拿資料、轉檔、用d3.js繪製地圖,以及把台灣本島放在區塊中央。

最後也會附上這次摸索過程中得到幫助的資源,希望也想畫一個台灣地圖的你可以避掉這些Augustus踩到的眾坑們。


畫台灣地圖步驟

步驟如下:

  1. 到政府資料開放平台下載縣市界線經緯度
  2. 到mapshaper將下載的資料做簡化、轉檔
  3. 製作頁面,引入d3.js
  4. 用d3.js append svg path

d3.js的部份不用擔心,因為Augustus也不太會(咦?),但找到的一些教學文有列出demo,看了一下覺得有點像jQuery,且實際append path的部份也沒說到很複雜,就是直接複製貼上code也行。


下載縣市界線經緯度

進到資料開放平台:

https://data.gov.tw/dataset/7442

點擊「SHP」的按鈕,下載SHP的檔案,解壓縮後會看到以下6個檔案:

市界線經緯度下載後的資料夾
市界線經緯度下載後的資料夾

會需要的是.dbf、.prj、.shp、.shx這4個副檔名的檔案。

這邊附上另外2個檔案下載的連結,如果想畫更細的區域地圖可以下載:

鄉鎮市區界線經緯度

村里界圖


SHP轉檔GeoJSON

.shp轉檔有一個好用的線上工具「mapshaper」:

https://mapshaper.org

它可以把shp檔轉成:shapefile、GeoJSON、TopoJSON、JSON records、CSV、SVG。

進到mapshaper的頁面後,選擇需要的4個檔案,再按下import,就會看見台灣地圖出現了:

選擇4個檔案後按import
選擇4個檔案後按import
出現台灣地圖
出現台灣地圖

mapshaper還有一個好用的功能,就是簡化,按下頁面右上角的「Simplify」,勾選要的項目後,按下Apply,就會出現一條拉霸來選擇簡化的幅度:

確認簡化功能的項目
確認簡化功能的項目
移動拉霸調整簡化幅度
移動拉霸調整簡化幅度

原本未簡化過的地圖,轉成GeoJSON下載時是12.8MB,簡化到0.06%後,下載的GeoJSON是18KB。

因為本篇筆記實作的注重在台灣本島的部份,也覺得原本的地圖很多鋸齒的邊線,就選用簡化過的版本。

確定要匯出就按下頁面右上角的Export,會看見匯出檔案格式的選擇,這邊選用GeoJSON。

匯出檔案格式的選單
匯出檔案格式的選單

特別說明,蠻多教學文都說改用TopoJSON,檔案會比GeoJSON更小。但這篇因為是用簡化過的地圖,大小用的是34KB,不大,再加上用了TopoJSON還要多引用一隻js進行轉成GeoJSON的步驟,如果檔案不大就不考慮多做這一步。最後GeoJSON的格式看比較懂,所以本筆記選擇的是GeoJSON。

轉成GeoJSON下載後,本篇僅畫台灣本島,就開啟下載的檔案刪掉離島的資料就行。


製作頁面

最後會做出來的頁面長這樣:

 d3+vue 畫出的台灣地圖
d3+vue 畫出的台灣地圖

左邊是地圖,右邊是內容,本篇就做一個簡單的點了地圖後,右邊的文字會換成該縣市的中、英文名稱。

HTML

附上Pug:

#app.container
  // 地圖
  .taiwan-map(ref="map")
  #map
    svg#svg(xmlns="http://www.w3.org/2000/svg", preserveAspectRatio="xMidYMid meet")
  
  // 內容
  .shop-list
    h1 {{ h1 }}
    h2 {{ h2 }}

ref="map"是為了讓svg能抓到寬高。{ h1 }{ h2 }是之後用vu.js的data。

很多教學文是寫用d3去append地圖的svg出來,Augustus這邊改成直接把svg寫在html裡,讓d3選擇器可以直接抓。

引用d3.js

目前d3.js的版本到了v5,但因為對d3還不熟,而且說明文件堪比辭海,所以這部份就是修改教學文中的demo,跟著引用v3版的。

頁面引用d3 v3的cdn:

https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js

d3.js append svg path

為了把GeoJSON裡的路徑變成可以投影成地圖的路徑,必須要先轉換過,轉換的方式如下:

// 座標變換函式
var path = d3.geo.path().projection(
  d3.geo
    .mercator()
    .center([121, 24])
    .scale(mercatorScale)
    .translate([width/2, height/2.5])
);

mercatorScale的部份是指要把台灣放大多少倍,Augustus實驗發現,螢幕寬1366px以上用11000倍,以下用9000,手機時用6000,這三個倍數看比較適合。整理成判斷如下:

let mercatorScale, w = window.screen.width;
if(w > 1366) { mercatorScale = 11000; }
else if(w <= 1366 && w > 480) { mercatorScale = 9000; }
else { mercatorScale = 6000; }

translate這個是研究了3個小時後領悟到的重點,d3畫出地圖後,想讓台灣置中就要靠這個讓地圖偏移回來。

width/2, height/2.5這個是實驗結果,這樣的偏移量可以在桌機、手機時都讓台灣維持在正中央。

有了轉換path的function後,就可以開始用d3抓GeoJSON進來,然後把路徑寫進svg path裡。

以上,就可以畫出一個美美的台灣地圖了。


參考資源

感謝網路上的特級高手們無私的分享出經驗,這邊列出在研究的過程中覺得很有幫助的資源。

老闆 來點寇汀吧 讓我們來操控地圖顯示對應天氣吧!!
看完這個教學影片後,會對怎麼控制地圖上的每個縣市有了概念。也可以直接參考影片裡的方式製作一個可互動的台灣地圖。

視覺化實戰 - D3.js 地理區塊視覺化
這篇的教學文很豐富,搜尋的排名也很高,之後再google其它篇教學,會看見很多內容都跟這篇一樣。

Data Man 的資料視覺化筆記
這篇PO文介紹了mapshaper這個線上轉檔功能,是個好物。

trouble with D3js world map and svg group element width
這篇在stackoverflow上的解答,讓Augustus理解到是可以用translate來偏移地圖的。


原始碼、Demo

本篇筆記整理過的原始碼放上Github了,大家可以一起來畫個台灣:

https://github.com/letswritetw/letswrite-taiwan-map-basic

Demo在這邊:

https://letswritetw.github.io/letswrite-taiwan-map-basic/


Summary
d3、vue 畫一個台灣地圖
Article Name
d3、vue 畫一個台灣地圖
Description
本篇大綱:畫一個台灣地圖需要很多資源的幫忙、畫台灣地圖步驟、下載縣市界線經緯度、SHP轉檔GeoJSON、製作頁面、HTML、引用d3.js、d3.js append svg path、參考資源、原始碼、Demo。本篇紀錄在畫一個台灣的步驟,包含拿資料、轉檔、用d3.js繪製地圖,以及把台灣本島放在區塊中央。
Augustus
Let's Write
Let's Write
Publisher Logo

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *