高崎市にあるヤマダ電機から、車で5分以内、10分以内、20分以内に到達可能なエリア(到達圏)を算出し、統計局の「小地域(町丁・字等別)男女別人口総数及び世帯総数」と組み合わせて、到達圏ごとの男女年代別人口を計算。
このあたりの計算はすべてQGISを計算し、計算結果をGeoJSONとして出力してleaflet.jsを用いて表示している。
<!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>