JavaScriptですぐに使える、市区町村のポリゴンデータを公開した話


サマリ🗾

日本の全ての市区町村の境界線データを、JavaScriptからすぐに使うことができるデータセットjpCityPolygonを公開しました。
面倒な緯度経度の計算だとか、メルカトルが云々とか考えずに、ただそこに市区町村ポリゴンを描きたいあなたにお勧めです。

成果物

jpCityPolygon: a dataset consisting of polygon data of all cities in Japan.
2021/10/21 現在のversionは0.8.0のbeta releaseです。
2021/10/23 現在のversionは0.9.0のbeta releaseです。
2021/10/26 現在のversionは1.0.0です。

これを使うと、この様なGenerative Artも秒で描けます。


- Generative Hometown

きっかけ

Saitama.jsという名前のイベントでanozonさんが発表されていた、『埼玉県の描き方』の内容が面白かったので、自分でも、思い入れのある土地、なんなら都道府県よりも、もっと愛着のある市区町村レベルで絵を描けないかな?と調べ始めました。
実際に使えそうなデータがないかと調べ始めると、ライセンス的に使用が難しいものだったり、データが不正確だったり・・・そして、なによりJSでパッとURLにアクセスしたらすぐ描けるようなデータというものは見当たりませんでした。(検索力ないだけかも・・・)

それなら自分で作ろうと思い立ったのが、本取り組みのきっかけです。

簡単な使い方

環境

今回のデータはWebから扱えるようにJavaScirptObjectデータとして公開しています。

データのインポート

https://tetunori.github.io/jpCityPolygon/dist/v1.0.0/の下にすべての市区町村に対応したスクリプトファイルがあるので、お好きな都市を選んでください。
ファイルは<都道府県名>/<市区町村名>.min.jsおよび<都道府県名>/<市区町村名>.jsの両方の形式で提供しています。もちろんmin.jsのほうがファイルサイズが小さいので、使用される際はこちらがお勧めです。なお、v0.9.0より、都道府県全域のポリゴンデータも追加しました。ファイルは<都道府県名>/<都道府県名>.min.jsおよび<都道府県名>/<都道府県名>.jsの両方の形式で提供しています。
GitHubのリポジトリへアクセスし確認してみてください。

例えば、北海道北広島市というデータを取得する場合は、このようなscriptタグを読み込んでください。

<script src="https://tetunori.github.io/jpCityPolygon/dist/v1.0.0/北海道/北広島市.min.js"></script>
<script src="https://tetunori.github.io/jpCityPolygon/dist/v1.0.0/北海道/北海道.min.js"></script>

データを使う

オブジェクトの構成

全ての<都道府県名>/<市区町村名>.js同.min.jsは1つのメインオブジェクト<都道府県名><市区町村名>を持っています。また、全ての<都道府県名>/<都道府県名>.js同.min.jsは1つのメインオブジェクト<都道府県名>を持っています。

先程の例ですと、北海道北広島市オブジェクトや北海道オブジェクトが含まれています。
このオブジェクトには、下記の5つのプロパティが含まれています:

  • prefecture: String
    • 都道府県名
  • name: String
    • 市区町村名
  • latlons: ポリゴンデータのArray
    • 緯度経度情報の生値{'lat':..., 'lon':...}の形式で複数のポリゴンを形成。
  • polygons: ポリゴンデータのArray
    • 緯度経度情報からメルカトル投影で平面にマッピングした(x, y)情報の生値{'x':..., 'y':...}の形式で複数のポリゴンを形成。
  • normalizedPolygons: ポリゴンデータのArray
    • 上記polygonsのデータをサイズ360*360にちょうど収まるように正規化したポリゴンデータ。{'x':..., 'y':...}の形式で複数のポリゴンを形成。
    • 特にこのデータを使うことをお勧めします!

実際にp5.jsで使ってみる

なんてシンプルなんだ!

function setup() {
  createCanvas(360, 360);
}

function draw() {
  background(220);

  // 今回はnormalizedPolygonsを使います。
  const polygons = 北海道北広島市.normalizedPolygons;
  // const polygons = 北海道.normalizedPolygons;

  // メインのオブジェクトは複数のポリゴンデータで構成されています。
  polygons.forEach((polygon) => {
    beginShape();
    for (let i = 0; i < polygon.length; i++) {
      // vertexに放り込むだけ!
      vertex(polygon[i].x, polygon[i].y);
    }
    endShape();
  });
}

実装サンプル

Basic Sample: シンプルに境界線を描く



- Sample On GitHub
- Sample On OpenProcessing

Generative Hometown: ジェネラティブアートにする



- Sample On GitHub
- Sample On OpenProcessing

技術的なポイント

元データの素性

正確性とライセンスの都合から、国土交通省のデータを使いました。比較的緩い制約で使えるので大変助かります。
「国土数値情報(行政区域データ)」(国土交通省)
※ なお、データの基準年月日は平成31(2019)年 1月 1日時点となります。

メルカトル投影のロジック

いろいろ調べたりしたのですが、緯度経度が与えられたときに、XY平面に変換するロジックは下記で実装してみました。たぶんあっていると思うけどあまり自信がないです。

// (中略) 
// k: each (lat, lon) coordinates
// calucurate as Mercator projection
const radians = (deg) => deg * (Math.PI / 180);
const polygon = l.map((k) => ({
  x: radians(k[0]),
  y: Math.log(Math.tan(Math.PI / 4 + radians(k[1]) / 2)),
}));

サンプルの実装

スクリプトの動的ロード

ポリゴンデータを含んでいるため結構なサイズのファイルになってしまい、事前に全部読み込むことは現実的ではありません。そこでサンプルでは、市区町村が選択された際に動的にスクリプトを読みこむようにしてみました。ロードのパフォーマンスも個人的には満足しています。

generativeHometownのパターン生成について

SYM380さんが作られているスーパークールなツール、p5.patternを使っています。下記のサンプルのようにめちゃめちゃ簡単にパターン生成できるので、大変たすかりました!みんな積極的に使おうな。
How to use p5.pattern by SYM380