iT邦幫忙

2023 iThome 鐵人賽

DAY 12
0
SideProject30

製作適用於網頁的台灣登山地圖系列 第 12

[Day12] 開始動手做圖磚

  • 分享至 

  • xImage
  •  

前天提到了專門用於將 OSM 資料集轉換為向量圖磚的 tilemaker。今天我們就先來實作看看,把有關登山的向量圖磚展示在前端!

首先從簡單的點資料開始,先試著把「山頂」做成圖磚!

取得 OSM 資料集

這邊使用 Day7 提到過的 Geofabrik 來下載近24小時更新的台灣資料集,格式為 pbf:

# 在撰寫這篇文章的當下,pbf 檔案大小約為223MB
curl -O http://download.geofabrik.de/asia/taiwan-latest.osm.pbf

使用 tilemaker 製作圖磚

除了 Arch-based 的 Linux 發行版,tilemaker 似乎沒有被涵蓋在其它常用的套件管理工具中,因此可以參考 INSTALL 頁面 進行安裝和編譯步驟。

git clone https://github.com/systemed/tilemaker/ && cd tilemaker

[依步驟安裝]
...

接著,我們可以參照示範檔案 resources/config-example.json 的寫法,先把有關「山頂」的 Layer 定義出來:

// config.json

{
  "layers": {
    "peak":    { "minzoom": 10, "maxzoom": 14 }
  },
  "settings": {
    "minzoom": 10,
    "maxzoom": 14,
    "basezoom": 14,
    "include_ids": false,
    "name": "test",
    "version": "0.1",
    "description": "Tile schema for hiking",
    "compress": "none"
  }
}

可以看到,我們只定義了一個被稱作 peakLayer

接著在 Lua 檔案中,撰寫資料處理的邏輯:

// process.lua

-- 只有當 OSM 物件具有以下的 key,才會被處理
node_keys = { "natural", "survey_point" }

-- 開始邏輯,tilemaker 需要,留白即可
function init_function()
end

-- 結束邏輯,tilemaker 需要,留白即可
function exit_function()
end

-- 如何處理每個 node 物件
function node_function(node)
    -- natural 標籤的值
    local natural = node:Find("natural")
    
    -- survey_point 標籤的值
    local survey_point = node:Find("survey_point")
    
    -- 若 natural 為 peak(山頂)或 volcano(火山),或者 survey_point 不為空白值
    -- 則將該 node 寫入 Layer
    if natural == "peak" or natural == "volcano" or survey_point ~= "" then
        node:Layer("peak", false)
        
        -- 為 Feature 加入 欄位 "natural"
        if node:Holds("natural") then node:Attribute("natural", natural) end
        
        -- 為 Feature 加入 欄位 "survey_point"
        if survey_piont ~= "" then node:Attribute("survey_point", survey_point) end
        return
    end
end

-- 如何處理每個 way 物件,先留白即可
function way_function(way)
end

接著就直接產生圖磚吧,先存在 output/ 目錄中:

tilemaker --input taiwan-latest.osm.pbf \
          --output output/ \
          --config config.json \
          --process process.lua

接著,我們就可以在目錄中看到以下的結構:

output
├── 10
├── 11
├── 12
├── 13
├── 14
└── metadata.json

共有 10-14 縮放層級的向量圖磚。

使用 Maplibre 和樣式檔案來渲染圖磚

這邊先依照 Maplibre 的範例撰寫最簡單地圖頁面,並使用名為 style.json 的樣式檔案。

有關 Maplibre 樣式檔案的撰寫是個大哉問,下面我不多作解釋先直接寫下簡單的規則,有關各種細節會在往後的系列文中提到。

// index.html

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
  <script src='https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.js'></script>
  <link href='https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css' rel='stylesheet' />
  <style>
    #map {position: absolute; top: 0; right: 0; bottom: 0; left: 0;}
  </style>
</head>
<body>
  <div id="map"></div>
  <script>
    var map = new maplibregl.Map({
      container: 'map',
      style: 'style.json',
      center: [121, 24],
      zoom: 10
    });
  </script>
</body>
</html>

使用 python 的 http 模組,將 html 頁面和圖磚目錄跑在 localhost 上:

> ls
index.html output/

> python -m http.server output
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

接著為了在地圖中有國家邊界當參考,這邊我們先使用 Demo Tiles 的渲染樣式:

curl -LO https://demotiles.maplibre.org/style.json

接著,在樣式檔案 style.json 中,在 sources 加入剛剛上線的圖磚服務

"peak": {
    "tiles": [
        "http://localhost:8000/output/{z}/{x}/{y}.pbf"
    ],
    "type": "vector"
}

在 layers 中寫入要渲染出來的圖層:

{
    "id": "peak",
    "type": "circle",
    "source": "peak",
    "source-layer": "peak",
    "minzoom": 10,
    "paint": {
        "circle-color": "red",
        "circle-stroke-width": 2,
        "circle-stroke-color": "white"
    }
}

再打開網頁: http:localhost:8000#10.6/22.8226/120.3198 ,就可以看到山頂以紅色圓圈的形式顯示在地圖上啦:
showcase

結語

今天我們製作了簡單的向量圖磚,僅僅只包含了有關山頂的資料。往後的文章中會再加入更多的物件來充實登山地圖。相關的程式碼可以在 Github 上查閱。


上一篇
[Day11] 檢視向量圖磚
下一篇
[Day13] 開始動手做圖磚 - 以縮放層級篩選資料
系列文
製作適用於網頁的台灣登山地圖25
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言