Skip to content

Instantly share code, notes, and snippets.

@shimizu

shimizu/README.md

Last active Sep 8, 2020
Embed
What would you like to do?
商圏分析

高崎市にあるヤマダ電機から、車で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>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment