D3.js、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.js 畫出的台灣地圖

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

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 } 是之後用 Vue.js 的 data

很多教學文是寫用 D3.js 去 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
這篇在 Stack Overflow 上的解答,讓 Augustus 理解到是可以用 translate 來偏移地圖的。


原始碼、Demo

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

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

Demo 在這邊:

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

Summary
D3.js、Vue 畫一個台灣地圖
Article Name
D3.js、Vue 畫一個台灣地圖
Description
本篇大綱:畫一個台灣地圖需要很多資源的幫忙、畫台灣地圖步驟、下載縣市界線經緯度、SHP 轉檔 GeoJSON、製作頁面、HTML、引用 D3.js、D3.js append SVG path、參考資源、原始碼、Demo。
Augustus
Let's Write
Let's Write
https://letswrite.tw/wp-content/uploads/2020/08/logo_512.jpg

隨選筆記文

Bot LINE

LIFF v2 基本使用筆記及範例

Bot Telegram

Telegram Bot 學習筆記 – 5:取得使用者大頭照

Vue

用 VuePress 製作說明文件頁面 – 1:安裝

Analytics Google

Google Analytics 加上 AI

Firebase Google

Firebase Dynamic Links API 做一個自己的縮網址生成器

WordPress

如何用 MAMP 在本機安裝 WordPress

Forms Google

完全客製 Google 表單,美化表單樣式

Vue

Vue CLI 安裝 Tailwind CSS

WordPress

WordPress SEO 有幫助的 3 + 4 個外掛

Bot Telegram

Telegram Bot 學習筆記 – 3:鍵盤 Keyboard

以下是留言,但關於留言的部份必需先讓你們知道:

本站的文章都是 Augustus 因為覺得有趣,才會實作並整理成筆記文而後進行發表。

如果留言是希望把 Demo 改成「你想要」的樣子,或是把功能改成「符合你需求」的樣子,

Sorry~ 除非那修改是 Augustus 也有興趣的,不然不會幫你們寫程式去面對工作或是交作業。

未來這類的留言不會再主動回覆。😎

另外,公開信箱是為了讓金流驗證用,

因為之前遇過幾次回信協助解決問題後,對方卻一聲謝謝也沒有,就這樣拿去幫工作交差。

因此決定不再回覆信件,有疑問就利用留言功能囉。

訂閱
通知
guest
11 Comments
最舊
最新
Inline Feedbacks
看所有留言
startgo
startgo
10 月 之前

有離島(金門、連江縣)含台灣本島的嗎?

Jason
Jason
回覆給  startgo
7 月 之前

嗯~ 金門、澎湖、連江…….,我也覺得需要!
畢竟這個台灣圖是我目前看過 d3.js 畫出來最精緻的,
真的該給些掌聲。

Jason
Jason
7 月 之前

1.請問Taiwan Map 放置中央的問題,costs u take 3 hrs to solve it !
 可否詳述該問題成因。(我想這是交換學習經驗心得的關鍵)
2.augurio-taiwan.min.js 等 .js 檔,可否提供非壓縮版(反去空白文字),
 以方便閱讀及debug。
3.另有關元宵節的放天燈程式,據您所述需具物理、數學的一些基礎科學
 的知識根基,可否略舉一二。
 (曾看到大陸學生用vb語言寫MD5加密演算法,將部落格密碼存入資料庫
 ,當時覺得DBMS有現存好用的函數做好此事,所以不覺得有啥好奇之處)  

jason
jason
6 月 之前

請問您的javascript (d3、Vue) 程式是在MS VisualStudio 的 IDE 整合介面上開發的嗎?

jason
jason
6 月 之前

prove coding ability with age 60 …..
(1) on click 改 on mouseover 
(2) countyeng 改 population (geojson檔 另加一個欄位)
(3) augurio-taiwan.min.js 反向工程改成易讀版,加空白及換行 (做苦工)
(4) 背景顏色黑色 改 淺灰 (研究中)

jason
jason
回覆給  Augustus
6 月 之前

感謝,上述問題皆已解決(只修改 HTML、CSS 屬性)。
進階問題較瑣碎…for ur reference on Github.

jason
jason
回覆給  Augustus
6 月 之前

我已將無法解決的程式上傳到 github ,thanx !

charles
charles
5 月 之前

下載『鄉鎮市區界線經緯度』,用您提供的程式 mouse 就無法移動。
可否 Demo 一下此部分。

James
James
5 月 之前

鄉鎮市區界線圖可畫出來(很慢),但滑鼠無法定位
某區域。