block by shimizu 869f924ad3007a9f8ba1bfe9f93f3193

商圏分析

Full Screen

高崎市にあるヤマダ電機から、車で5分以内、10分以内、20分以内に到達可能なエリア(到達圏)を算出し、統計局の「小地域(町丁・字等別)男女別人口総数及び世帯総数」と組み合わせて、到達圏ごとの男女年代別人口を計算。

このあたりの計算はすべてQGISを計算し、計算結果をGeoJSONとして出力してleaflet.jsを用いて表示している。

index.html

<!DOCTYPE html>
<html lang='jp'>

<head>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.4.0/dist/leaflet.css"
    integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA=="
    crossorigin="" />
<script src="https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"
    integrity="sha512-QVftwZFqvtRNi0ZyCtsznlKSWOStnDORoefr1enyq5mVL4tmKB3S/EnC3rRJcxCPavG10IcrVGSmPh6Qw5lwrg=="
    crossorigin=""></script>
<script src='//unpkg.com/d3@5.0.0/dist/d3.min.js'></script>


<style>
html,
body {
    width: 100%;
    height: 100%;
    padding: 0px;
    margin: 0px;
}

#stage {
    width: 960px;
    height: 500px;
    overflow: auto;
   border:1px solid gray;
}


#flexbox {
   display: flex;
}

#mapid {
    width: 800px;
    height: 500px;
}
#info {
    padding:10px;
    font-size: 12px;
}
#table ,#table tbody {
    width: 100%;
}
#table tr:nth-child(even){
    background:#F2F2F2;
}
#table td:nth-child(even){
    width: 45px;
    text-align: right;
}
#table thead, #table tbody 
{ 
    display: block; 
}
#table tbody {
    overflow-y: auto;   
}

#stats {
    background-color: white;
    padding: 5px;
    border-radius: 4px;
    font-size:12px;
}

#stats, select {
    font-size:12px;
}
#stats td:nth-child(even){
    text-align: right;
}

</style>

</head>

<body>
<div id="stage">
    <div id="flexbox">
        <div id="mapid"></div>
        <div id="info"></div>
    </div>
</div>


<script>
var defaultType = "男20~24歳"; 
var info = document.getElementById("info");
var format = d3.format(",")

var label = {
    "T000849026": "男20~24歳",
    "T000849027": "男25~29歳",
    "T000849028": "男30~34歳",
    "T000849029": "男35~39歳",
    "T000849030": "男40~44歳",
    "T000849031": "男45~49歳",
    "T000849032": "男50~54歳",
    "T000849033": "男55~59歳",
    "T000849034": "男60~64歳",
    "T000849035": "男65~69歳",
    "T000849036": "男70~74歳",
    "T000849046": "女20~24歳",
    "T000849047": "女25~29歳",
    "T000849048": "女30~34歳",
    "T000849049": "女35~39歳",
    "T000849050": "女40~44歳",
    "T000849051": "女45~49歳",
    "T000849052": "女50~54歳",
    "T000849053": "女55~59歳",
    "T000849054": "女60~64歳",
    "T000849055": "女65~69歳",
    "T000849056": "女70~74歳",
}

var idLable = {
    1: "5分以内の到達圏(赤)",
    2: "10分以内の到達圏(緑)",
    3: "20分以内の到達圏(青)",
}

var mymap = L.map('mapid').setView([36.3229373, 139.0125926], 11);
L.tileLayer('https://api.maptiler.com/maps/hybrid/{z}/{x}/{y}.jpg?key=K7gU5zPWuSFKb6p1zwsh', {
    tileSize: 512,
    zoomOffset: -1,
    maxZoom: 14,
    attribution: '<a href="https://maptiler.jp/" target="_blank">© MIERUNE</a> <a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>',
    crossOrigin: true
}).addTo(mymap);


var p1 = d3.json('shouken.geojson');

Promise.all([p1]).then(function (data) {
    var poligon = data[0];


    var marker = L.marker([36.3229373, 139.0125926,]).addTo(mymap);
    var newpopup = L.popup({
        closeOnClick: false,
        autoClose: false
    }).setContent("ヤマダ電機");
    marker.bindPopup(newpopup).openPopup();


    var whenClicked = function(e){
        var p = e.target.feature.properties;

        var tr = Object.keys(p).map(function(key){
            if(key.indexOf("T0008")) return ;
            var keyname = label[key];
            if(!keyname) return ;
            return "<tr><td>"+ keyname+"</td><td>"+ p[key] + "人</td></tr>"
        });

        info.innerHTML = '<table id="table">'+ tr.join("\n") +"</table>";
    }


    var onEachFeature = function (feature, layer) {
        if (feature.properties) {
                var p = feature.properties;
            layer.bindPopup(p.CITY_NAME + p.S_NAME);
            layer.on({
                click: whenClicked
            });

        }
    }


    L.geoJSON(poligon, {
        style: function (feature) {
            fillColor = "#0000"
            switch (feature.properties.ID) {
                case "1": fillColor = "red"; break;
                case "2": fillColor = "lime"; break;
                case "3": fillColor = "skyblue"; break;
            }
            return  { 
                "weight": 0.5, 
                color:"black",
                fillColor: fillColor,
                fillOpacity: 0.5
                }
        },
        onEachFeature: onEachFeature
    }).addTo(mymap);


    var nested = d3.nest()
        .rollup(function (d) {
            var values = d.map(function (p) {
                var p = p.properties;
                var tmp = {};
                Object.keys(p).forEach(function (key) {
                    if (key.indexOf("T0008")) return;
                    tmp[key] = +p[key]
                });
                return tmp
            });
            var sums = {}

            Object.keys(label).forEach(function (key) {
                sums[label[key]] = d3.sum(values, function (d) { return d[key] })
            });

            return sums;
        })
        .key(function (d) { return d.properties.ID })
        .map(poligon.features)



    var renderStats = function (table, type) {
        var result = nested.entries().map(function (d) {
            return { id: idLable[d.key], value: d.value[type] }
        })
        table.selectAll("tr").remove();

        table
            .selectAll("tr")
            .data(result)
            .enter()
            .append("tr")
            .selectAll("td")
            .data(function (d) { return [d.id, format(d.value) + "人"] })
            .enter()
            .append("td")
            .text(function (d) { return d })

    }


    L.Control.Watermark = L.Control.extend({
        onAdd: function (map) {
            var div = L.DomUtil.create('div');
            var d3div = d3.select(div).attr("id", "stats");

            d3div.append("p")
                .text("到達圏(車)で集計")

            d3div.append("select") 

            var table = d3div.append("table")
            
            var typeSelector = d3div.select("select")

            typeSelector.selectAll("option")
                .data(Object.keys(label))
                .enter()
                .append("option")
                .attr("value", function (key) { return label[key] })
                .text(function (key) { return label[key] })

            typeSelector.on("change", function () {
                renderStats(table, this.value)
            });

            renderStats(table, defaultType);

            return div;
        }
    });

    L.control.watermark = function (opts) {
        return new L.Control.Watermark(opts);
    }

    L.control.watermark({ position: 'bottomleft' }).addTo(mymap);


});






</script>
</body>

</html>