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
https://letswrite.tw/wp-content/uploads/2020/08/logo_512.jpg

隨選筆記文

API Front-End

WebSocket 基本介紹及使用筆記

WordPress

如何用 MAMP 在本機安裝 WordPress

Google Others

用 reCAPTCHA v2 來做非機器人驗證

Google Others

用 reCAPTCHA v3 來做非機器人驗證

Analytics Google

Google Analytics 加上 AI

Google Maps

Google Maps API 學習筆記 – 2:在地圖上畫個日本結界

API Front-End

用 Google Apps Script 寫一個 LINE 登入功能:下篇 – 三大步驟

Front-End

GitLab Pages:3 + 2 個步驟讓 GitLab 專案產生靜態頁

API Front-End

用 Google Apps Script 寫一個 LINE 登入功能:上篇 – 前置作業

Google Maps

Google Maps API 學習筆記 – 4:Place API 自動完成地址、地點評論摘要

本站準備替換留言功能,投票調查中,歡迎 參與投票

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

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

Jason
Jason
回覆給  startgo
1 月 之前

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

Jason
Jason
1 月 之前

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

jason
jason
1 月 之前

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

jason
jason
1 月 之前

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

jason
jason
回覆給  Augustus
1 月 之前

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

jason
jason
回覆給  Augustus
1 月 之前

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

charles
charles
19 天 之前

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

James
James
17 天 之前

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

Let's Write

前端工程師 Augustus 的學習筆記 — solving problems, in simple ways.