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?

市区町村カバー率99%以上の小学校区・中学校データを地図に表示してみる

Posted at

はじめに

TerraMap APIから「小学校区・中学校区データ」を取得できるようになりましたので、その使用例をサンプルコードと一緒にご紹介したいと思います。

TerraMap APIが提供する「小学校区・中学校区データ」は国土数値情報で公開されている学校区データと異なり、99%以上の市区町村をカバーし、各市区町村で異なる利用条件への対応は必要ありません。

完成イメージ

Google Mapの地図上をクリックし、その地点の小学校区ポリゴンをGeoJSON形式で取得、ポリゴンと学校位置を表示させるアプリケーションを作成しました。

gmap_gakku_polygons.gif
国土数値情報では提供されていない東京都品川区の小学校区を表示した例

小学校区・中学校区データについて

TerraMap APIの「小学校区・中学校区データ」は、学区ポリゴンと各属性値で構成されています。主な用途や特徴は、以下が考えられます。

学校区データの主な用途

  • 教育関連施設の位置計画
  • 物件データに対する学区判定
  • 販促・広告計画

学校区データの特徴(国土数値情報との比較)

国土数値情報の学校区データより多くの市区町村、小学校、中学校に対応しています。また、市区町村ごとに分かれる利用条件への対応も必要ありません。

項目 TerraMap API 国土数値情報
ライセンス 商用利用可 一部商用利用不可
市区町村カバー率 99%以上
(約1,700 市区町村)
約87%
(約1,500 市区町村)
更新頻度 毎年 数年に1度

TerraMap API とは、多数のエリアマーケティングデータ(統計データ、ポリゴン、住所)を提供する地図システム開発支援APIです。詳しくは以下のリンク先をご参照下さい。

TerraMap API | マップマーケティング株式会社

フロントエンド

フロントエンドでは、以下のようなフローを実現させました。

地図上のクリック → サーバーへのリクエスト(緯度・経度を渡す) 
 → 小学校区ポリゴンの取得と表示 → 学校位置のマーカー表示

HTML

Google Mapを表示するには、YOUR_GOOGLE_MAP_KEY 部分にGoogle Maps Platform用のAPIキーが必要となります。この記事では「APIキーを使用する」等の手順は割愛させていただきます。

index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>小学校区ポリゴンを取得し、Google Mapに表示する</title>
    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="map" style="width: 97vw; height: 97vh"></div>

    <!-- prettier-ignore -->
    <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "YOUR_GOOGLE_MAP_KEY", v: "weekly"});</script>
  </body>
</html>

小学校区ポリゴン表示

地図のクリックイベントで、小学校区ポリゴンを取得し表示する処理は以下のようになります。

ポリゴン表示部分
// 地図クリックイベント
map.addListener("click", (event) => {
  const { latLng } = event;
  const lat = latLng.lat();
  const lng = latLng.lng();

  // クリックした位置の小学校区ポリゴンを取得
  fetch(`http://127.0.0.1:3000/get-gakku-polygon`, {    // サーバーURLは適宜変更してください
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ lat, lng }),
  })
    .then((response) => response.json())
    .then((data) => {
      // GeoJSONデータを地図に追加
      map.data.addGeoJson(data);
    })
    .catch((error) => {
      console.log(error);
    });
});

// ポリゴンのスタイル設定
const polygonStyleOptions = {
  strokeColor: "#810FCB",
  strokeOpacity: 1.0,
  strokeWeight: 2.0,
  fillColor: "#810FCB",
  fillOpacity: 0.5,
};

// 地図上のマルチポリゴンにスタイルを適用
map.data.setStyle((feature) => {
  if (feature.getGeometry().getType() === "MultiPolygon") {
    return polygonStyleOptions;
  }
  return null;
});

学校位置のマーカー表示

マーカー表示については現在推奨されている 高度なマーカー を用いて実現しています。AdvancedMarkerElementPinElement を読み込み、地図には マップID が必要になります。

markerライブラリ、マップID
async function initMap() {
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary("marker");

  const centerLocation = { lat: 35.681095, lng: 139.686144 };
  const map = new Map(document.getElementById("map"), {
    zoom: 14,
    center: centerLocation,
    mapId: "DEMO_MAP_ID",     // デモ用マップID。本番環境では適切なマップIDに変更してください。
  });
  
  // 以降省略

小学校区ポリゴンに含まれる小学校位置と小学校名を読み取り、マーカーを地図に追加するには、 map.data.addGeoJson(data); の後に以下を記述します。

今回はマーカーラベルにdiv要素を用いているので、CSSによるスタイル設定も可能になります。

マーカーの追加部分
        // 小学校の位置
        const schoolPosition = {
          lat: data.features[0].properties.point_coordinates[1],
          lng: data.features[0].properties.point_coordinates[0],
        };
        // マーカーラベルの作成
        let markerLabel = document.createElement("div");
        markerLabel.classList.add("mark-label");
        markerLabel.innerText = data.features[0].properties.points[0][0];
        // ピン要素の作成
        let iconImage = new PinElement({
          glyph: markerLabel,
          background: "#6f98efff",
          borderColor: "#3718e6ff",
          scale: 0.8,
        });
        // マーカー要素の作成
        const marker = new AdvancedMarkerElement({
          map,
          position: schoolPosition,
          title: data.features[0].properties.points[0][0],
          content: iconImage.element,
        });

最終的な JavaScript、CSS

index.js
index.js
async function initMap() {
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary("marker");

  const centerLocation = { lat: 35.681095, lng: 139.686144 };
  const map = new Map(document.getElementById("map"), {
    zoom: 14,
    center: centerLocation,
    mapId: "DEMO_MAP_ID",     // デモ用マップID。本番環境では適切なマップIDに変更してください。
  });

  // 地図クリックイベント
  map.addListener("click", (event) => {
    const { latLng } = event;
    const lat = latLng.lat();
    const lng = latLng.lng();

    // クリックした位置の小学校区ポリゴンを取得
    fetch(`http://127.0.0.1:3000/get-gakku-polygon`, {   // サーバーURLは適宜変更してください
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ lat, lng }),
    })
      .then((response) => response.json())
      .then((data) => {
        // GeoJSONデータを地図に追加
        map.data.addGeoJson(data);
        // 小学校の位置
        const schoolPosition = {
          lat: data.features[0].properties.point_coordinates[1],
          lng: data.features[0].properties.point_coordinates[0],
        };
        // マーカーラベルの作成
        let markerLabel = document.createElement("div");
        markerLabel.classList.add("mark-label");
        markerLabel.innerText = data.features[0].properties.points[0][0];
        // ピン要素の作成
        let iconImage = new PinElement({
          glyph: markerLabel,
          background: "#6f98efff",
          borderColor: "#3718e6ff",
          scale: 0.8,
        });
        // マーカー要素の作成
        const marker = new AdvancedMarkerElement({
          map,
          position: schoolPosition,
          title: data.features[0].properties.points[0][0],
          content: iconImage.element,
        });
      })
      .catch((error) => {
        console.log(error);
      });
  });

  // ポリゴンのスタイル設定
  const polygonStyleOptions = {
    strokeColor: "#810FCB",
    strokeOpacity: 1.0,
    strokeWeight: 2.0,
    fillColor: "#810FCB",
    fillOpacity: 0.5,
  };

  // 地図上のマルチポリゴンにスタイルを適用
  map.data.setStyle((feature) => {
    if (feature.getGeometry().getType() === "MultiPolygon") {
      return polygonStyleOptions;
    }
    return null;
  });
}

initMap();
style.css
.mark-label {
  color: white;
  font-size: 10px;
  background-color: rgba(0, 0, 0, 0.5);
  padding: 2px 10px;
  border-radius: 8px;
  flex: none;
  transform: translateY(35px);  
}

ポリゴン、マーカー、マーカーラベルの例

サーバーサイド(Node.js)

TerraMap APIを利用するには専用のAPIキーが必要になり、サーバープログラムでの使用を推奨しています。下記コードでは YOUR_TERRAMAP_API_KEY 部分にAPIキーを入力します。

/get-gakku-polygon のエンドポイントは、Google Mapからの座標情報を受け取り小学校区ポリゴンを返すように作成しています。内部ではTerraMap APIのインターフェース仕様に従ったリクエストを実行しています。

server.js
const axios = require("axios");
const cors = require("cors");
const express = require("express");

const app = express();

// CORS設定  全てのオリジンを許可(開発用)
app.use(cors());

// JSONのパーサーを使用
app.use(express.json());

// TerraMap APIの小学校区ポリゴン取得エンドポイント
app.post("/get-gakku-polygon", async (req, res) => {
  // リクエストボディから緯度経度を取得
  const { lat, lng } = req.body;

  if (!lat || !lng) {
    return res.status(400).json({
      error: "lat and lng are required",
    });
  }

  try {
    const response = await axios.post(
      "https://tmapi.mapmarketing.jp/api/area",
      {
        layer_id: "10101",          // 小学校区のレイヤーID:10101    中学校区のレイヤーID:10102
        area_type: "coordinate",    // 座標指定を選択
        coordinates: [[lng, lat]],
        output: "polygon,point",    // ポリゴンとポイント情報(学校名)を取得
      },
      {
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": "YOUR_TERRAMAP_API_KEY",
        },
      }
    );

    res.json(response.data);
  } catch (error) {
    console.error("get-gakku-polygons error:", error.message);
    res.status(500).json({
      error: "Failed to get gakku polygons",
    });
  }
});

// サーバー起動
app.listen(3000, () => {
  console.log("TerraMap API中継サーバーがポート3000で起動中です");
});

ライブラリのインストール

npm install axios cors express

サーバー起動

node server.js

※ Node.js以外の言語でのTerraMap APIへのリクエスト例については、以下のスタートアップガイドをご参照下さい。

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?