地図の上で用途地域を確認できる用途地域地図サイトの構築について

用途地域地図

用途地域とは

用途地域は、住居、商業、工業など市街地の大枠としての土地利用を定めるもので、

  • 第1種低層住居専用地域
  • 第2種低層住居専用地域
  • 第1種中高層住居専用地域
  • 第2種中高層住居専用地域
  • 第1種住居地域
  • 第2種住居地域
  • 準住居地域
  • 近隣商業地域
  • 商業地域
  • 準工業地域
  • 工業地域
  • 工業専用地域

13種類あります。用途地域が指定されると、それぞれの目的に応じて、建てられる建物の種類が決められます。
国都交通省ではそのデータが無料で提供されております。
http://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-A29.html

建築などプランを作成する上でも大変重要な情報の一つになります。

今回は用途地域を地図上からに簡単に確認できるサイトを構築したいと思います。

まず、成果物はこちらです。

用途地域地図

leafletをベースにした、用途地域サイトの実装

ベースとなる地図は恒例のleafletです。

用途地域データの準備

国都交通省のデータはshapeファイルであるため、qgisなど特定のソフトでしか表示できない。
webで表示させるためにgeojsonフォーマットに変換する。shapeからgeojsonの変換は一昔は面倒だったが、
今はqgisを使えば今は簡単にできます。

単純にgeojsonデータをwebで表示することもできるが、用途地域データの場合、データ量が大きいため
エリア分けて表示することになる。今回日本全国シームレスで表示したいため、geojsonをmapboxの
ベクトルタイルフォーマットに変換します。

ベクトルタイル仕様書

変換ツールはtippecanoeです。

用途地域描画の実装

用途地域のラベリング

用途地域デーはポリゴンデータであるため
まず、ポリゴンの中心を計算しラベリングのポイントにする。

地図のズームや移動を対応しながら、重ならないラベリングを実装するため、こちらの内容を参考に実装しました。

ベクトルタイルの描画

mapboxなら、ディフォルトでベクトルタイルの描画が内装されているが、leafletでは独自の実装が必要です。実装方法についてはベクトルタイルの使用をわかっているかたなら難しくはないと思います。後日コードを整理して公開したいと思います。

感想

GISデータをすぐ巨大になりがちです。ここ数年IT業界でビッグデータという言葉が流行っていますが、地図データは昔ながらのビッグデータです。
一方、サービスとしてweb提供するには、ネットワーク、端末メモリやcpuの制限があります。そこで、いかにデータを捌き、いかにUIデザインを工夫するのが醍醐味ですね。

まだまだ勉強不足ではありますが、日々精神していきたいと思います。

国土地理院標高APIを利用したleafletマウスポイント標高プラグインの実装

標高表示プラグイン

背景

国土地理院標高APIが公開され、任意地点の
高精度な標高値が簡単に取得できるようになっています。
一方leafletでまだそれを利用した標高表示プラグインが見当たらい為作ってみました。

まず、デモサイトはこちらです。

実装

leaflet は軽量でありながら、大変強力なライブラリです。実際地理院地図2Dはleafletがベースになっています。
今回jQueryとunderscore.jsを依存します。

データ取得時の$.ajaxと、eventを抑えるための.debounce、と描画じに.templateを使っています。

コード抜粋を貼ります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
var ElevitionJP = L.Control.extend({
options: {
position: 'bottomright'
},
demApiURL: '//cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php',
onAdd: function(map){
this._container = L.DomUtil.create('div', 'l_elevitionjp');
L.DomEvent.disableClickPropagation(this._container);
map.on('mousemove', this._onMouseMove, this);

var me = this;
me._lazyDem = _.debounce(function(){
var requestData = {
lat: me.currentLatLng.lat,
lon: me.currentLatLng.lng,
outtype: 'JSON'
};
$.ajax({
url: me.demApiURL,
dataType: 'json',
data: requestData,
beforeSend: function(jqXHR, settings){
jqXHR.requestData = requestData;
}
}).done(function(data, textStatus, jqXHR) {
if(jqXHR.requestData.lat == me.currentLatLng.lat && jqXHR.requestData.lon == me.currentLatLng.lng) {
me.currentDem = data;
me.resetHtml();
}
});
}, 300);

me.currentLatLng = {lon: null, lng: null};

return me._container;
},

onRemove: function(map){
var me = this;
map.off('mousemove', me._onMouseMove, me);
},

_onMouseMove: function(e){
var me = this;
me.currentLatLng = e.latlng.clone();
me.currentDem = {elevation: '-----', hsrc: '-----'};
me._lazyDem();
me.resetHtml();
},

resetHtml: function(){
var me = this;
var zoom = me.currentZoom;
var lat = me.currentLatLng.lat;
var lng = me.currentLatLng.lng;
var html = _.template([
'<table>',
' <tr><td colspan="2" style="text-align: left;"><%=elevation=="-----" ? "標高: -----" : "標高: " + Math.round(elevation*3.28084) + " ft " + elevation + " m" %></td></tr>',
' <tr><td><%=lat10%></td><td><%=lng10%></td></tr>',
' <tr><td><%=lat60%></td><td><%=lng60%></td></tr>',
'</table>'
].join('\n'))(_.extend({
lat10: lat ? me.convertLat2NS(lat, 5) : '',
lng10: lng ? me.convertLng2EW(lng, 5) : '',
lat60: lat ? me.convertLat2DMS(lat) : '',
lng60: lng ? me.convertLng2DMS(lng) : '',
zoom: zoom,
elevation: '-----',
hsrc: '-----'
}, me.currentDem));
me._container.innerHTML = html;
},
//...
});
  • onAdd onRemove
    L.Control にて初期化や削除時の必須実装。

  • _lazyDem
    ajax を抑えながらデータを取得する実装。

  • resetHtml
    htmlレンダリングの部分です。

CSS

見栄えは .l_elevitionjp で制御できます。
デモサイトでは下記通りです。

1
2
3
4
5
.l_elevitionjp {
border-radius: 5px;
background-color: rgba(256,256,256,0.9);
padding: 5px;
}

ソースコード

コースコードはgithub https://github.com/sengine-xyz/leaflet.elevationJP
にUPしました。

ElevitionJP.jsの内容そのまま使ってもよいが、必要な内容を切り取って使って頂いてもよいです。
参考になって頂ければ幸いです。

地図上距離測定できるページ作成について

地図上距離測定ページ

目的

GIS勉強の一環として、簡易な距離測定WEBページを作成して見たいと思います。

ツール選択

web系GISライブラリとして、Google Map, Mapbox, OpenLayersが有名ですが、ライセンスがうるさいため、ここは軽量且つパワフルなleafletを使います。

ベース地図

地理院タイル及びGoogleの地図タイルを利用します。
無料で利用できる地図タイルはありがたいですね。地理院の方はいい仕事してくれました。
初めて税金が正しいところに使われたと実感します。
地理院の地図タイルはたくさんあります。ここで使うものをリストします。

  • 地理院標準地図
    https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png

  • 地理院淡色地図
    https://cyberjapandata.gsi.go.jp/xyz/pale/{z}/{x}/{y}.png

  • 地理院航空写真
    https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg

  • Google地図のみ
    https://mt1.google.com/vt/lyrs=r&x={x}&y={y}&z={z}

  • Google写真+地図
    https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}

  • Google写真のみ
    https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}

CSS

全部手書きでもよいがbootstrapを利用します。

JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var map = L.map('map', {
zoomAnimation: false,
zoomControl: false,
inertia: false,
maxZoom: 18,
minZoom: 6,
maxBounds: [[80, 0], [-80, 360]],
maxBoundsViscosity: 1,
worldCopyJump: false,
preferCanvas: false,
zoomSnap: 1,
zoomDelta: 1,
wheelPxPerZoomLevel: 240,
padding: 0,
doubleClickZoom: false,
renderer: L.canvas()
}).setView(new L.LatLng(35.681236, 139.767125), 12);


L.control.polylineMeasure({
showMeasurementsClearControl: false,
showUnitControl: true,
showBearings: false
}).addTo(map);

new MousePositionControl().addTo(map);

var tile = L.tileLayer('https://mt1.google.com/vt/lyrs=r&x={x}&y={y}&z={z}', {
attribution: "<a href='https://developers.google.com/maps/documentation' target='_blank'>Google Map</a> | <a href='https://maps.gsi.go.jp/development/ichiran.html' target='_blank'>地理院タイル</a>"
});
map.addLayer(tile);



$('.ctl-tile-url').on('click', function(e){
e.preventDefault();
var tile_url = $(e.target).data('url');
tile.setUrl(tile_url);
});

成果物

地図上距離測定

地図上距離測定して見たい方はぜひ使ってみてください。

ソースコードもコンパイルしてないので、興味のある方はぜひ見てください。

感想

leafletは他のライブラリを依存しないし、ソースコードも少ないため、読んでみるとjavascriptの勉強にもなります。
大変素晴らしいライブラリです。今後もっと深堀して行きたいと思います。