Web 地圖底圖是什麼?vector vs raster、tile pyramid、style spec 一次搞懂
本篇是「打造 TaxMap-TW:用 Astro 做台灣所得地圖」系列的第 3 / 10 篇。你可以從系列總覽開始閱讀,也可以直接接著看本文。
剛開始碰 Web 地圖時,我看技術文章常常卡在一些術語:vector tile、raster tile、tile pyramid、style spec、z/x/y、PMTiles、MBTiles… 每一個拆開都不難,但混在一起就會頭很大。
寫完 TaxMap-TW 後回頭整理,發現 Web 地圖底圖其實就是三個核心概念:tile、format、style。把這三個搞懂,其他術語都是周邊。
這篇給沒碰過 GIS 的讀者鋪底,把這三件事說清楚。
第一個觀念:Web 地圖底圖為什麼要切成 tile?
打開 Google Maps,你拖、你縮、它都很順。但全球地圖資料動輒幾百 GB,瀏覽器不可能一次下載完。
解法:把地圖切成方格,需要哪一塊才下載哪一塊。這個方格就叫 tile。
每個 tile 通常是 256×256 或 512×512 像素的小圖。瀏覽器看你縮放到哪個 zoom level、視窗範圍涵蓋哪些 tile,就只下載那幾張。
縮小看全世界 → 1 張 tile 就夠 放大到台北街道 → 視窗內有 4-8 張 tile
這個機制讓 Web 地圖能用「漸進式載入」處理 PB 等級的資料。
Tile pyramid(瓦片金字塔):z/x/y 是什麼?
你常常會看到地圖圖磚的 URL 長這樣:
https://tiles.example.com/{z}/{x}/{y}.pbf
z 是 zoom level(縮放等級),x、y 是該 zoom 下的座標。
整個地圖被組織成「金字塔」結構:
- z = 0:整個地球切成 1 張 tile(1×1 = 1 張)
- z = 1:切成 4 張(2×2)
- z = 2:切成 16 張(4×4)
- …
- z = 18:切成 687 億張(262144×262144)
每多一個 zoom level,tile 數量乘 4。z=18 大概是看清楚門牌號碼的等級。
對地圖服務商來說,這個金字塔是固定的世界座標,所有人共享同一套切法。你開發地圖時,瀏覽器自動算出「現在這個視窗在 z=10 需要 (532, 411) 這張 tile」,然後請求那個 URL。
第二個觀念:vector tile vs raster tile
Tile 有兩種主要格式,差別決定了你的地圖能做什麼。
Raster tile(點陣圖磚)
每張 tile 是一張預先渲染好的 PNG / JPG 圖片。瀏覽器拿到就直接貼上去,沒有運算成本,連最老的瀏覽器都吃得下。代價是樣式被烤進圖裡了:顏色改不了、標籤關不掉,文字放大會糊(因為早就被點陣化),而且每換一種風格就得整套重切,存儲很快就爆。
不過我要先澄清一件事,因為我自己一開始也搞錯:raster 不是「過時」,它是「不同需求」。有些東西本來就只能用 raster——衛星影像、空拍圖、地形暈渲這類本身就是像素的資料,沒有 geometry 可以拿來向量化;要列印或匯出成圖檔時,也是點陣圖最直接。基礎建設上 raster 也最簡單,一個資料夾擺一堆 PNG、丟到任何靜態 host 就能跑,不需要 WebGL、不需要 style JSON。Leaflet 這種老牌、輕量的函式庫原生就吃 raster。
所以老牌地圖服務(Google Maps 早期版本、傳統 OSM tile server)用 raster,不代表它們「劣等」,只是當年那個需求 raster 就夠了。
Vector tile(向量圖磚)
每張 tile 是 geometry + properties 的二進位資料(通常 .pbf Protocol Buffer 格式),不是圖片。瀏覽器拿到資料後即時渲染,所以可以動態改顏色、隱藏特定圖層,文字永遠清晰(在客戶端用向量字型正確繪製),而且同一套 tile 可以套用無限多種風格。這幾個優點是我選 vector 的主因。
但 vector 不是免費午餐,這點當初的我也低估了。它要用 WebGL,老瀏覽器不支援,渲染還要吃客戶端的 CPU/GPU——這兩點是課本都會講的。實務上真正咬人的是另外幾件:你得載一包 MapLibre GL JS(壓縮後也有兩三百 KB),外加 glyphs(字型切片)和 sprites(圖示集),這些都算進首屏成本,比直接貼 PNG 重得多;行動裝置上持續的 GPU 渲染也比較耗電。如果你想自己切 vector tile(不是用現成服務),tippecanoe 那套工具鏈和 schema 設計的門檻也比烤一堆 PNG 高一截。最後是中文專案逃不掉的坑:CJK 字型切成 glyphs 後檔案動輒幾十 MB,字型 fallback 沒設好就會看到一堆豆腐方塊。
所以我的結論是:如果你只是要在頁面上放一張不會動的底圖,用 vector 其實是殺雞用牛刀,raster 反而省事;vector 的價值要在「需要動態換樣式、疊資料層」時才真的兌現。
近 5 年的主流地圖服務(Mapbox、MapTiler、OpenFreeMap)多半預設 vector tile,但這是「主流方向」不是「raster 被淘汰」——兩者是分工,各自守著不同的場景。
簡單記憶法:raster 是「拍照」,vector 是「設計稿」。設計稿可以改顏色,照片不行;但要的就是一張照片時,硬套設計稿流程反而麻煩。
第三個觀念:style spec — 同一份 tile,無限種風格
既然 vector tile 是 geometry + properties,那要怎麼決定「這條路畫多粗」、「這個 polygon 上什麼色」?
答案是 style spec — 一份 JSON 規格,描述每個圖層怎麼畫。
MapLibre Style Spec(從 Mapbox GL JS 衍生)是業界標準。一個典型的 style 長這樣:
{
"version": 8,
"sources": {
"openmaptiles": {
"type": "vector",
"url": "https://tiles.openfreemap.org/planet"
}
},
"layers": [
{
"id": "water",
"type": "fill",
"source": "openmaptiles",
"source-layer": "water",
"paint": {
"fill-color": "#a1d6f2"
}
},
{
"id": "road",
"type": "line",
"source": "openmaptiles",
"source-layer": "transportation",
"paint": {
"line-color": "#ffffff",
"line-width": 1
}
}
]
}
每個 layer 對應 vector tile 裡的一種圖層(water、road、building…),定義怎麼畫。
換 style URL = 換樣式。底圖資料完全一樣,但灰白底色、深色模式、夜景樣式都是換 style 達成的。
不過「無限種風格」有個前提常被忽略:你只能畫 tile 裡有的東西。style 是在既有的 geometry + properties 上塗色,tile 沒切進去的圖層(例如某個 POI 類別、某條行政界線),style 再怎麼寫也變不出來——那種時候只能回頭重切一份 tile。所以 style 給你的是「呈現自由」,不是「資料自由」。
OpenFreeMap 最常用的是 positron(灰白)、bright(彩色)、liberty(OSM 經典)三種預設 style,另外還有 dark、fiord 等選擇;當然你也完全可以自己寫一份 style JSON 丟給 MapLibre 用。
一個典型的 Web 地圖管線
理解了 tile、format、style 之後,現代 Web 地圖的完整管線就清楚了:
OSM 原始資料 (PB 等級)
↓ 切 tile
Vector tiles ({z}/{x}/{y}.pbf)
↓ 由 tile server / CDN serve
你的瀏覽器
↓ MapLibre 讀取 tile + 套用 style
畫在 canvas 上的地圖
↓ 你加上自己的資料層(標記、polygon...)
完整的應用
對開發者來說,要做決定的點是:
- Tile 從哪來:用第三方服務(OpenFreeMap / MapTiler / Mapbox)?自架?
- Style 用什麼:服務商預設?自己寫?
- 怎麼顯示:MapLibre / Leaflet(原生只支援 raster,要吃 vector 需外掛)/ deck.gl?
大致上,「Web 地圖底圖」這個題目的自由度就落在這三件事上——當然細節還有很多,但抓住這三條主軸就不太會迷路。
三個延伸場景
場景 A:你只是要在網站上放一張可拖拉的地圖
最簡單:用 Leaflet + OSM raster tiles。10 行 code 搞定。
場景 B:你要做資料視覺化(choropleth、heatmap)
進階:MapLibre + vector tile 服務(OpenFreeMap 或 MapTiler)+ 自己加資料層。
場景 C:你要做完全離線、或客製化到底的地圖
最進階:自架 tile server,或者用 PMTiles 把 tile 打包成單檔。
TaxMap-TW 我走的是場景 B:要在底圖上疊 7,747 個村里的所得 choropleth,又想要灰白底圖不搶戲、之後還能換深色模式,所以選了 MapLibre + OpenFreeMap 的 vector tile,自己加一層 GeoJSON 資料層。每個場景對 tile、style、顯示函式庫的選擇都不一樣,先想清楚自己在哪一格,後面的決定才不會亂套。
收尾
寫到這裡,前面的術語應該都能 mapping 回三個核心概念:
- z/x/y URL = tile 在金字塔的座標
- PBF / MBTiles / PMTiles = vector tile 不同的封裝格式
- Style URL = 怎麼把 vector tile 變成你看到的地圖
- WebGL = vector tile 需要的渲染技術
老實說這三個概念我當初前後摸了快兩個晚上才串起來,但串起來之後再看任何一篇地圖技術文章,那些術語就各自歸位、不再嚇人了。如果要我給個偏好:大多數人其實不需要急著鑽 vector 的細節,先用場景 A 的 raster 把地圖跑起來、確定真的需要動態樣式了,再升級到 vector 也不遲。