LoginSignup
0
0

More than 1 year has passed since last update.

1kmメッシュ滞在人口(全国人流オープンデータ)をMapbox GL JSで表示してみました

Posted at

はじめに

アウトプットイメージ


※出典:「全国の人流オープンデータ」(国土交通省)

※上記出典とは別に、編集・加工等を行った

前提条件

  • 1kmメッシュ滞在人口(全国人流オープンデータ)は、csv形式のデータで提供されていますが、Mapbox GL JSで表示するために、予めQGIS等でgeojson形式のデータ(メッシュポリゴンデータ)に変換しています。
  • 1kmメッシュ滞在人口(全国人流オープンデータ)のcsv形式のデータは以下のとおりです。
  • オープンデータ(人流データ)の定義書はこちらを参照してください。 image.png
  • 変換後のgeojson形式のデータは以下のとおりです。 image.png

html、css

mesh1km_pop.html
<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8' />
    <title>1kmメッシュ滞在人口</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js'></script>
    <script src='https://npmcdn.com/@turf/turf/turf.min.js'></script>

    <script src="https://d3js.org/d3.v5.min.js"></script>
    <script src="https://d3js.org/d3-queue.v3.min.js"></script>
    <script src="https://d3js.org/d3-request.v1.min.js"></script>

    <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css' rel='stylesheet' />

    <style>
        body {
            margin: 0;
            padding: 0;
        }

        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }

        .legend {
            background-color: #fff;
            border-radius: 3px;
            bottom: 30px;
            box-shadow: 0 1px 2px rgba(0, 0, 0, 0.10);
            font: 15px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
            padding: 10px;
            position: absolute;
            right: 10px;
            z-index: 1;
            line-height: 25px;
            height: 280px;
        }

        .legend h4 {
            margin: 0 0 10px;
        }

        .legend div span {
            border-radius: 50%;
            display: inline-block;
            height: 15px;
            margin-right: 10px;
            width: 15px;
            color: orangered
        }
    </style>
</head>

<body>
    <!-- Load the `mapbox-gl-geocoder` plugin. -->
    <script
        src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v4.7.2/mapbox-gl-geocoder.min.js"></script>
    <link rel="stylesheet"
        href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v4.7.2/mapbox-gl-geocoder.css"
        type="text/css">
    <div id="tooltip"></div>
    <div id='map'></div>
    <div id='county-legend' class='legend'>
        <h4>1kmメッシュ滞在人口</h4>
        <div><span style='background-color: rgb(44, 123, 182)'></span>0 - 4,000</div>
        <div><span style='background-color: rgb(100, 165, 205)'></span>4,000 - 8,000</div>
        <div><span style='background-color: rgb(157, 207, 228)'></span>8,000 - 12,000</div>
        <div><span style='background-color: rgb(199, 230, 219)'></span>12,000 - 16,000</div>
        <div><span style='background-color: rgb(237, 247, 201)'></span>16,000 - 20,000</div>
        <div><span style='background-color: rgb(255, 237, 170)'></span>20,000 - 24,000</div>
        <div><span style='background-color: rgb(254, 201, 128)'></span>24,000 - 28,000</div>
        <div><span style='background-color: rgb(249, 158, 89)'></span>28,000 - 32,000</div>
        <div><span style='background-color: rgb(232, 91, 58)'></span>32,000 - 36,000</div>
        <div><span style='background-color: rgb(215, 25, 28)'></span>36,000 - 40,000</div>
    </div>

</body>

<script type="text/javascript" src=script.js></script>

</html>

JavaScript

script.js
mapboxgl.accessToken = "Mapboxのアクセストークンを入力してください";

// Mapbox Streets読み込み
const map = new mapboxgl.Map({
  container: "map",
  style: 'mapbox://styles/mapbox/streets-v9',
  center: [139.7527995, 35.685175],
  zoom: 12
});

// Create a popup, but don't add it to the map yet.
let popup = new mapboxgl.Popup({
  closeButton: false,
  closeOnClick: false
});

let hoveredStateId = null;

map.on("mousemove", "2DmeshLayer", function (e) {

  map.getCanvas().style.cursor = 'pointer';

  if (e.features.length > 0) {
    if (hoveredStateId) {
      map.setFeatureState({ source: 'meshdata', id: hoveredStateId }, { hover: false });
    }
    hoveredStateId = e.features[0].layer.id;
    map.setFeatureState({ source: 'meshdata', id: hoveredStateId }, { hover: true });
  }

  popup.setLngLat(e.lngLat)
    .setHTML(
      "<div><b>3次メッシュコード &nbsp;</b>" + e.features[0].properties.meshid + "</div>" +
       "<div><b>1kmメッシュ滞在人口</b></div>" +
      "<div>" + Math.round(e.features[0].properties.population) + " 人</div>")
    .addTo(map);

});

// When the mouse leaves the state-fill layer, update the feature state of the
// previously hovered feature.
map.on("mouseleave", "2DmeshLayer", function () {
  map.getCanvas().style.cursor = '';
  popup.remove();
  if (hoveredStateId) {
    map.setFeatureState({ source: 'meshdata', id: hoveredStateId }, { hover: false });
  }
  hoveredStateId = null;
});

let POP_1 = ["<", ["get", "population"], 4000];
let POP_2 = ["all", [">=", ["get", "population"], 4000], ["<", ["get", "population"], 8000]];
let POP_3 = ["all", [">=", ["get", "population"], 8000], ["<", ["get", "population"], 12000]];
let POP_4 = ["all", [">=", ["get", "population"], 12000], ["<", ["get", "population"], 16000]];
let POP_5 = ["all", [">=", ["get", "population"], 16000], ["<", ["get", "population"], 20000]];
let POP_6 = ["all", [">=", ["get", "population"], 20000], ["<", ["get", "population"], 24000]];
let POP_7 = ["all", [">=", ["get", "population"], 24000], ["<", ["get", "population"], 28000]];
let POP_8 = ["all", [">=", ["get", "population"], 28000], ["<", ["get", "population"], 32000]];
let POP_9 = ["all", [">=", ["get", "population"], 32000], ["<", ["get", "population"], 36000]];
let POP_10 = ["all", [">=", ["get", "population"], 36000], ["<", ["get", "population"], 40000]];

let colors = [
  'rgb(44, 123, 182)',
  'rgb(100, 165, 205)',
  'rgb(157, 207, 228)',
  'rgb(199, 230, 219)',
  'rgb(237, 247, 201)',
  'rgb(255, 237, 170)',
  'rgb(254, 201, 128)',
  'rgb(249, 158, 89)',
  'rgb(232, 91, 58)',
  'rgb(215, 25, 28)'
]

const meshToMap = (meshdata) => {

  map.addSource('meshdata', {
    type: 'geojson',
    data: meshdata,
  });

  map.addLayer({
    'id': '2DmeshLayer',
    'type': 'fill',
    'source': 'meshdata',
    'layout': {},
    'paint': {
      "fill-color":
        ["case",
          POP_1, colors[0],
          POP_2, colors[1],
          POP_3, colors[2],
          POP_4, colors[3],
          POP_5, colors[4],
          POP_6, colors[5],
          POP_7, colors[6],
          POP_8, colors[7],
          POP_9, colors[8],
          POP_10, colors[9],
          colors[9]
        ],
      "fill-outline-color": "white",
      "fill-opacity": ["case",
        ["boolean", ["feature-state", "hover"], false],
        1,
        0.5
      ]
    }
  });

};

let meshGeoJsonURL = 'data/monthly_mdp_mesh1km_202008_1_0.geojson';

const handleGetData = (err, meshdata) => {
  meshToMap(meshdata);
}

d3.queue()
  .defer(d3.json, meshGeoJsonURL)
  .await(handleGetData);

// コントロール関係表示
var nav = new mapboxgl.NavigationControl();
map.addControl(nav, 'top-left');

// スケール表示
map.addControl(new mapboxgl.ScaleControl({
  maxWidth: 200,
  unit: 'metric'
}));

// Add the control to the map.
map.addControl(
  new MapboxGeocoder({
    accessToken: mapboxgl.accessToken,
    mapboxgl: mapboxgl
  })
);

参考文献

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