0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

gzipベクトルタイルを作成してホスティングする

Posted at

はじめに

gzipなし(圧縮なし)のベクトルタイルデータをGitHubでホスティングすることは出来ていました。gzipありのMbtilesデータについては、サーバを立ててホスティングしました。ここでは、gzipありのpbf形式のベクトルタイルをホスティングする方法を検討してみます。

gzipつきのベクトルタイルを作成する

こちらの記事では、 pbfベクトルタイルを圧縮形式にしない方式でデータを作成しました。ここでは、同様のデータを用いて、shpファイルからGeojsonを作成し、そこからベクトルタイルへ変換したいと思います。ソースデータ、ベクトルタイルの構成は同じです。

shpからGeojsonへの変換

ogr2ogr -f GeoJSON coastl.geojson ne_110m_coastline.shp
ogr2ogr -f GeoJSON landmass.geojson ne_110m_land.shp
ogr2ogr -f GeoJSON riverl.geojson ne_110m_rivers_lake_centerlines.shp

Geojsonからベクトルタイルへの変換

tippecanoe -e VTpractice --no-feature-limit --no-tile-size-limit --drop-rate=1 -Z0 -z4 -L coastl:coastl.geojson -L landmass:landmass.geojson -L riverl:riverl.geojson

--no-tile-compression
を含めないようにして、gzip圧縮として、ベクトルタイルを作成します。

レンタルサーバでホスティング

Linux9のレンタルサーバでホスティングをします。フォルダ名を20250506gzipHostingとしました。
こちらの記事のコードを使用します。

以下はmbtiles用のコードなので削除します。

appHttps.js
const VTRouter = require("./routes/VT");
app.use("/VT", VTRouter);

configファイルは以下のとおりです。

default.hjson
{
  htdocsPath: htdocs
  port: 8080
  logDirPath: log
  morganFormat: tiny
  mbtilesDir: mbtiles
  privkeyPath: ./key/privkey.pem
  fullchainPath: ./key/cert.pem
}

keyフォルダを作成して、cert.pemとprivkey.pemを保存しました。

以下のコマンドで必要な最新版のパッケージをインストールします。

npm install @mapbox/mbtiles config cors express hh-mm-ss hjson morgan winston sqlite3 winston-daily-rotate-file spdy

こちらの記事のindex.htmlを利用します。

index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Display a map</title>
    <meta
      property="og:description"
      content="Initialize a map in an HTML element with MapLibre GL JS."
    />
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link
      rel="stylesheet"
      href="https://unpkg.com/maplibre-gl@4.5.0/dist/maplibre-gl.css"
    />
    <script src="https://unpkg.com/maplibre-gl@4.5.0/dist/maplibre-gl.js"></script>
    <style>
      body {
        margin: 0;
        padding: 0;
      }
      html,
      body,
      #map {
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      const map = new maplibregl.Map({
        container: "map", // container id
        style:
          "./download_style.json", // style URL
        center: [0, 0], // starting position [lng, lat]
        zoom: 1, // starting zoom
        maplibreLogo: true,
        hash: true,
      });

      //UI
      map.addControl(new maplibregl.NavigationControl(), "bottom-right");
      map.addControl(new maplibregl.ScaleControl());

      //debug
      map.showTileBoundaries = true;
      map.showCollisionBoxes = false;
    </script>
  </body>
</html>

スタイルファイルは上記の記事に含まれているdownload_style.jsonを利用します。
tilesの部分のみURLを変更しました。

download_style.json
{
  "version": 8,
  "name": "Empty Style",
  "metadata": {"maputnik:renderer": "mlgljs"},
  "sources": {
    "v": {
      "type": "vector",
      "tiles": [
        "https://k96mz.xyz/normalVT/{z}/{x}/{y}.pbf"
      ],
      "minzoom": 0,
      "maxzoom": 4
    }
  },
  "sprite": "",
  "glyphs": "https://orangemug.github.io/font-glyphs/glyphs/{fontstack}/{range}.pbf",
  "layers": [
    {
      "id": "coastl",
      "type": "line",
      "source": "v",
      "source-layer": "coastl",
      "maxzoom": 5
    },
    {
      "id": "landmass",
      "type": "fill",
      "source": "v",
      "source-layer": "landmass",
      "maxzoom": 5,
      "paint": {"fill-color": "rgba(195, 176, 176, 1)"}
    },
    {
      "id": "riverl",
      "type": "line",
      "source": "v",
      "source-layer": "riverl",
      "maxzoom": 5,
      "paint": {"line-color": "blue", "line-width": 2}
    }
  ],
  "id": "dsyugj9"
}

地図を表示する

gzip圧縮なし

まずは、gzip圧縮なしで表示できるか試します。(現在はサーバを立てていないので、アクセスできません。)
https://k96mz.xyz/index.html

無事に表示出来ました。

スクリーンショット 2025-05-06 11.02.11.jpg

gzip圧縮あり

次にgzip圧縮ありの地図を表示します。
https://k96mz.xyz/index_gzip.html

スクリーンショット 2025-05-06 11.13.55.jpg

Status Codeが200 OKとなっているにも関わらず、地図が表示されません。

以下のメッセージがでています。
"Unable to parse the tile at https://k96mz.xyz/gzipVT/0/0/0.pbf, please make sure the data is not gzipped and that you have configured the relevant header in the server"

ベクトルタイル (.pbf) が gzip 圧縮されているのに、HTTP レスポンスに Content-Encoding: gzip ヘッダーが設定されていないことが原因のエラーです。
そのため、以下のとおり設定します。

appHttps
app.use(express.static(htdocsPath, {
  setHeaders: (res, path) => {
    if (path.endsWith('.pbf')) {
      res.setHeader('Content-Encoding', 'gzip'); // 重要
      res.setHeader('Content-Type', 'application/vnd.mapbox-vector-tile');
    }
  }
}));

最終的なコードは以下のとおりです。

appHttps.js
// Set Module
const config = require("config");
const express = require("express");
const cors = require("cors");
const morgan = require("morgan");
const winston = require("winston");
const DailyRotateFile = require("winston-daily-rotate-file");
const fs = require("fs");
const spdy = require("spdy"); //for https

// Configure constant
const port = config.get("port");
const htdocsPath = config.get("htdocsPath");
const morganFormat = config.get("morganFormat");
const logDirPath = config.get("logDirPath");
const privkeyPath = config.get("privkeyPath");
const fullchainPath = config.get("fullchainPath");

// Logger configuration
const logger = winston.createLogger({
  transports: [
    new winston.transports.Console(),
    new DailyRotateFile({
      filename: `${logDirPath}/server-%DATE%.log`,
      datePattern: "YYYY-MM-DD",
    }),
  ],
});

logger.stream = {
  write: (message) => {
    logger.info(message.trim());
  },
};

// Middleware
const app = express();
app.use(cors());
// const VTRouter = require("./routes/VT");
app.use(
  morgan(morganFormat, {
    stream: logger.stream,
  })
);
// app.use(express.static(`${__dirname}/${htdocsPath}`));
app.use(express.static(htdocsPath, {
  setHeaders: (res, path) => {
    if (path.endsWith('.pbf')) {
      res.setHeader('Content-Encoding', 'gzip'); // 重要
      res.setHeader('Content-Type', 'application/vnd.mapbox-vector-tile');
      // res.setHeader('Access-Control-Allow-Origin', '*'); // CORS対策
    }
  }
}));

// app.use("/VT", VTRouter);

// for http
// app.listen(port, () => {
//   console.log(`Starting server at port ${port}`);
// });

// for https
spdy
  .createServer(
    {
      key: fs.readFileSync(privkeyPath),
      cert: fs.readFileSync(fullchainPath),
    },
    app
  )
  .listen(port);

無事に表示されました。

スクリーンショット 2025-05-06 11.25.59.jpg

以下も正常に反映されています。
content-encoding:gzip
content-type:application/vnd.mapbox-vector-tile

まとめ

gzipありのpbf形式のベクトルタイルをホスティングする方法をまとめました。HTTP レスポンスに Content-Encoding: gzip ヘッダーを設定することが重要です。

Reference

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?