Help us understand the problem. What is going on with this article?

「東京ドーム1個分の大きさ」を可視化してみた

はじめに

誰もがテレビで「東京ドーム〇〇個分の大きさ」という表現を耳にしたことがあると思います。
しかしこれは、東京ドームを見たことがない人にはあまりピンと来ない表現です。

そこで、東京ドームの大きさを身近に感じられる地図コンテンツを作りました。

何を作ったか

現在地を東京ドームと(大体)同じ大きさのポリゴンで覆う地図コンテンツを作りました。

デモページ
差分(航空写真 var.)

このコンテンツでは、ボタンを押すだけで、現在地を中心としたポリゴンが載ったWeb地図を生成することができます。
(※閲覧はスマホ推奨、PCでも可)

東京ドーム型のポリゴンについて

東京ドーム型のポリゴンの大きさは、東京ドームを円形と仮定して、公式HPの情報をもとに計算しました。
大きさの設定に用いたパラメータは、以下のとおりです。

  • 半径: 122m(※建築面積から算出)
  • 最高部の高さ: 56.190m

どう作ったか

地図描画ライブラリMapbox GL JSと、地理空間データ分析ライブラリTurf.jsを用いて実装しました。
ただし、現在地の取得にはMapbox GL JSのメソッドを使わず、Geolocation APIを利用しています。

ソースコード

この記事では要点を絞って、下記の2つの機能のスクリプトを紹介します。

  1. 現在地の緯度経度を受け渡す機能
  2. 渡された緯度経度を中心とした東京ドームポリゴン付きの地図を生成する機能

ちなみに、コンテンツ全体のソースコードは次のページに掲載しています。
https://bl.ocks.org/Hirosaji/ed4443946608237eaddcf1207b3776cb
https://gist.github.com/Hirosaji/ed4443946608237eaddcf1207b3776cb

1. 現在地の緯度経度を受け渡す機能

ボタンのクリックイベントを受け取ってGeolocation APIの呼び出し、呼び出し成功時に緯度経度を 2. の関数に渡すスクリプトです。

var successCallBackFunction, errorCallBackFunction;

// API option
var option = {
    enableHighAccuracy: true, // Whether to use GPS to improve accuracy
    maximumAge: 0, // To hold cache ms
    timeout: 30000 // Timeout ms
};

/**
* Processing at the end of HTML loading
*/
window.addEventListener('load', function () {

    // Check whether API is enabled/disabled
    if (!navigator.geolocation) {
        alert('Geolocation API is disabled');
        return;
    }

    // Set button to get position info from API
    document.getElementById('button_id').addEventListener('click', function () {
    // API call
        navigator.geolocation.getCurrentPosition(successCallBackFunction, errorCallBackFunction, option);
    }, false);
}, false);

/**
* Callback func at successful getting position info
*/
successCallBackFunction = function (position) {
    var lng = position.coords.longitude;
    var lat = position.coords.latitude;
    // Pass lng & lat to creating polygon function (for 2.)
    latlng2polygon(lng, lat);
};

/**
* Callback func at faild getting position info
*/
errorCallBackFunction = function (positionError) {
    alert(positionError.code + ': ' + positionError.message);
};

参考リンク

2. 取得した緯度経度を中心とした東京ドームポリゴン付きの地図を生成する機能

取得した緯度経度を中心とした東京ドーム型のポリゴンをTruf.jsで生成し、Mapboxの地図上に載せるスクリプトです。

function latlng2polygon(lng, lat) {

    mapboxgl.accessToken = 'Your token';
    var center = [lng, lat];
    var radius = 0.122;
    var precision = 0.001525;
    var epsilon = 0.0001;

    // Create new Mapbox object
    var map = new mapboxgl.Map({
        container: 'map',
        style: 'mapbox://styles/mapbox/light-v9',
        center: center,
        zoom: 16,
        pitch: 60
    });

    /**
    * Create Tokyo Dome Polygon using Turf.js
    */
    var grid = turf.hexGrid(turf.bbox(turf.circle(center, radius)), precision);

    // Calculate parameters of each element in turf circular bbox
    var dome = turf.featureCollection(grid.features.map(function (feature) {
        var point = turf.centroid(feature);
        var distance = turf.distance(center, point);
        if (distance > radius) { return; }

        // sphere r^2 = x^2 + y^2 + z^2
        // therefore z = Math.sqrt(r^2 - x^2 - y^2)
        //             = Math.sqrt(r^2 - (x^2 + y^2))
        // but distance^2 = x^2 + y^2
        // so z = Math.sqrt(r^2 - distance^2)
        var z = Math.sqrt(Math.pow(radius, 2) - Math.pow(distance, 2));
        var normHeight = 56.190 / 122; // to normalize height
        z = isNaN(z) ? 0 : z * normHeight;

        // Adapt parameters to Tokyo dome polygon data
        return turf.feature(feature.geometry, {
            base_height: z * 1000, // adopt z / m from z / km
            height: (z * 1000) + (distance * 1000 + epsilon) * 0.1
        });
    }).filter(function (feature) { return feature; }));

    // add Tokyo Dome polygon Layer on Mapbox
    map.on('load', function () {
        map.addSource('dome', {
            type: 'geojson',
            data: dome
        });

        map.addLayer({
            id: 'dome',
            type: 'fill-extrusion',
            source: 'dome',
            paint: {
                'fill-extrusion-color': 'red',
                'fill-extrusion-base': {
                    type: 'identity',
                    property: 'base_height'
                },
                'fill-extrusion-height': {
                    type: 'identity',
                    property: 'height'
                },
                'fill-extrusion-opacity': 0.5
            }
        });
    });
};

参考リンク

おわりに

この記事では、東京ドームの大きさを可視化した地図コンテンツを紹介し、その要点となるスクリプトをコメントアウト付きで掲載しました。
地図系のライブラリは、組み合わせ次第で様々な表現ができるので、使っていてとても楽しいです。

特にMapbox GL JSは、3D表現が可能なWebGLを用いたライブラリの中でも、とにかく多様な表現ができることで有名です。
Mapbox GL JSをご存知ない方は、ぜひ公式のExamplesを覗いてみてください。
その表現の幅広さに、エンジニアなら誰もが気持ちを高ぶらせてしまうと思います。

またTurf.jsは、地理空間上で数値計算やデータ分析をする際には欠かせないライブラリです。
まだ参考サイトは少ないですが、今後リッチなWeb地図を作りたい方は、覚えておいて損はないと思います。

以上、ぜひ皆さんも自分だけの新たな地図を作ってみてください。

Hirosaji
ゲーム実況を観ながらプログラミングをするのが好きなWebエンジニアです。
https://bl.ocks.org/hirosaji
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away