├── README.md
├── leaflet-hash.js
├── index.html
└── TileLayer.GeoJSON.js
/README.md:
--------------------------------------------------------------------------------
1 | experimental_pni
2 | ================
3 | 国土地理院ベクトルタイル提供実験(地名情報)
4 |
5 | ## 地名情報の GeoJSON タイル
6 | 国土地理院が整備している地名情報のうち、居住地名、自然地名、公共施設、住居表示住所について、GeoJSONタイルに変換したものを提供実験いたします。
7 |
8 | ## 地名情報
9 | ### テンプレートURL:
10 | - 地名情報(居住地名)
11 | https://cyberjapandata.gsi.go.jp/xyz/experimental_nrpt/{z}/{x}/{y}.geojson
12 | - 地名情報(自然地名)
13 | https://cyberjapandata.gsi.go.jp/xyz/experimental_nnfpt/{z}/{x}/{y}.geojson
14 | - 地名情報(公共施設)
15 | https://cyberjapandata.gsi.go.jp/xyz/experimental_pfpt/{z}/{x}/{y}.geojson
16 | - 地名情報(住居表示住所)
17 | https://cyberjapandata.gsi.go.jp/xyz/experimental_jhj/{z}/{x}/{y}.geojson
18 | - サンプル:
19 | https://cyberjapandata.gsi.go.jp/xyz/experimental_nrpt/15/27574/14087.geojson
20 |
21 | ### ベクトルタイルスタイル定義:
22 | - 地名情報(居住地名)
23 | https://cyberjapandata.gsi.go.jp/xyz/experimental_nrpt/style.js
24 | - 地名情報(自然地名)
25 | https://cyberjapandata.gsi.go.jp/xyz/experimental_nnfpt/style.js
26 | - 地名情報(公共施設)
27 | https://cyberjapandata.gsi.go.jp/xyz/experimental_pfpt/style.js
28 | - 地名情報(住居表示住所)
29 | https://cyberjapandata.gsi.go.jp/xyz/experimental_jhj/style.js
30 |
31 | ## データについて
32 | 電子国土基本図(地名情報)のうち、居住地名、自然地名、公共施設をズームレベル15の、住居表示住所をズームレベル18のGeoJSONタイルに変換したものを提供実験いたします。
33 | 提供範囲は日本全国になります。
34 | データの内容の詳細は、電子国土基本図(地名情報)ファイル仕様書(PDFファイル)(http://www.gsi.go.jp/common/000187334.pdf )
35 | 及び電子国土基本図(地名情報)「住居表示住所」ファイル仕様書(http://www.gsi.go.jp/common/000187306.pdf )等をご覧ください。
36 |
37 | なお、以下の属性については本提供実験には含まれません。
38 | - 居住地名:都道府県名のよみ、市区町村名のよみ
39 | - 自然地名:行政コード、都道府県名、市区町村名
40 | - 住居表示住所:住所コード(可読)、住所コード(数値)、経度、緯度
41 |
42 |
43 | ## デモサイトについて
44 | デモサイトを次の場所に用意しております。
45 | - 本レポジトリ
46 | https://gsi-cyberjapan.github.io/experimental_pni/
47 | - 地理院地図
48 | https://maps.gsi.go.jp/#18/35.682597/139.856129/&base=ort&ls=ort|experimental_nrpt|experimental_nnfpt|experimental_pfpt|experimental_jhj&disp=11111&lcd=experimental_jhj&vs=c1j0l0u0t0z0r0f0&d=vl
49 |
50 | ## 提供の位置づけ
51 | 国土地理院ベクトルタイル提供実験におけるデータの提供の位置づけは次のとおりです。
52 | - 本提供実験は、ベクトルタイル提供における技術的・施策的課題を国土地理院が把握するとともに、外部からの技術的な提案を受け取り、外部との技術的な議論を通じてベクトルタイルの適切な提供方法を研究開発することを目的とするものです。
53 | - 本提供実験の期間は、2014年8月1日から本提供実験終了までとなります。
54 | - 本提供実験のデータは、国土地理院コンテンツ利用規約( http://www.gsi.go.jp/kikakuchousei/kikakuchousei40182.html )に従って利用できます。
55 | - 本提供実験のベクトルタイルは基本測量成果と位置付けているものではありませんが、基本測量成果としての提供を検討するにあたって、提供を行うものです。
56 | - 本提供実験の利用により生じた損失及び損害等について、国土地理院はいかなる責任も負わないものとします。
57 |
58 | ## 履歴
59 | 2017-08-04「地名情報(居住地名)」、「地名情報(自然地名)」、「地名情報(公共施設)」及び「地名情報(住居表示住所)」の提供実験を開始。
60 |
--------------------------------------------------------------------------------
/leaflet-hash.js:
--------------------------------------------------------------------------------
1 | // original: https://github.com/mlevans/leaflet-hash/blob/master/leaflet-hash.js
2 | // license: https://github.com/mlevans/leaflet-hash/blob/master/LICENSE.md
3 | (function(window) {
4 | var HAS_HASHCHANGE = (function() {
5 | var doc_mode = window.documentMode;
6 | return ('onhashchange' in window) &&
7 | (doc_mode === undefined || doc_mode > 7);
8 | })();
9 |
10 | L.Hash = function(map) {
11 | this.onHashChange = L.Util.bind(this.onHashChange, this);
12 |
13 | if (map) {
14 | this.init(map);
15 | }
16 | };
17 |
18 | L.Hash.parseHash = function(hash) {
19 | if(hash.indexOf('#') === 0) {
20 | hash = hash.substr(1);
21 | }
22 | var args = hash.split("/");
23 | if (args.length == 3) {
24 | var zoom = parseInt(args[0], 10),
25 | lat = parseFloat(args[1]),
26 | lon = parseFloat(args[2]);
27 | if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) {
28 | return false;
29 | } else {
30 | return {
31 | center: new L.LatLng(lat, lon),
32 | zoom: zoom
33 | };
34 | }
35 | } else {
36 | return false;
37 | }
38 | };
39 |
40 | L.Hash.formatHash = function(map) {
41 | var center = map.getCenter(),
42 | zoom = map.getZoom(),
43 | precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
44 |
45 | return "#" + [zoom,
46 | center.lat.toFixed(precision),
47 | center.lng.toFixed(precision)
48 | ].join("/");
49 | },
50 |
51 | L.Hash.prototype = {
52 | map: null,
53 | lastHash: null,
54 |
55 | parseHash: L.Hash.parseHash,
56 | formatHash: L.Hash.formatHash,
57 |
58 | init: function(map) {
59 | this.map = map;
60 |
61 | // reset the hash
62 | this.lastHash = null;
63 | this.onHashChange();
64 |
65 | if (!this.isListening) {
66 | this.startListening();
67 | }
68 | },
69 |
70 | removeFrom: function(map) {
71 | if (this.changeTimeout) {
72 | clearTimeout(this.changeTimeout);
73 | }
74 |
75 | if (this.isListening) {
76 | this.stopListening();
77 | }
78 |
79 | this.map = null;
80 | },
81 |
82 | onMapMove: function() {
83 | // bail if we're moving the map (updating from a hash),
84 | // or if the map is not yet loaded
85 |
86 | if (this.movingMap || !this.map._loaded) {
87 | return false;
88 | }
89 |
90 | var hash = this.formatHash(this.map);
91 | if (this.lastHash != hash) {
92 | location.replace(hash);
93 | this.lastHash = hash;
94 | }
95 | },
96 |
97 | movingMap: false,
98 | update: function() {
99 | var hash = location.hash;
100 | if (hash === this.lastHash) {
101 | return;
102 | }
103 | var parsed = this.parseHash(hash);
104 | if (parsed) {
105 | this.movingMap = true;
106 |
107 | this.map.setView(parsed.center, parsed.zoom);
108 |
109 | this.movingMap = false;
110 | } else {
111 | this.onMapMove(this.map);
112 | }
113 | },
114 |
115 | // defer hash change updates every 100ms
116 | changeDefer: 100,
117 | changeTimeout: null,
118 | onHashChange: function() {
119 | // throttle calls to update() so that they only happen every
120 | // `changeDefer` ms
121 | if (!this.changeTimeout) {
122 | var that = this;
123 | this.changeTimeout = setTimeout(function() {
124 | that.update();
125 | that.changeTimeout = null;
126 | }, this.changeDefer);
127 | }
128 | },
129 |
130 | isListening: false,
131 | hashChangeInterval: null,
132 | startListening: function() {
133 | this.map.on("moveend", this.onMapMove, this);
134 |
135 | if (HAS_HASHCHANGE) {
136 | L.DomEvent.addListener(window, "hashchange", this.onHashChange);
137 | } else {
138 | clearInterval(this.hashChangeInterval);
139 | this.hashChangeInterval = setInterval(this.onHashChange, 50);
140 | }
141 | this.isListening = true;
142 | },
143 |
144 | stopListening: function() {
145 | this.map.off("moveend", this.onMapMove, this);
146 |
147 | if (HAS_HASHCHANGE) {
148 | L.DomEvent.removeListener(window, "hashchange", this.onHashChange);
149 | } else {
150 | clearInterval(this.hashChangeInterval);
151 | }
152 | this.isListening = false;
153 | }
154 | };
155 | L.hash = function(map) {
156 | return new L.Hash(map);
157 | };
158 | L.Map.prototype.addHash = function() {
159 | this._hash = L.hash(this);
160 | };
161 | L.Map.prototype.removeHash = function() {
162 | this._hash.removeFrom();
163 | };
164 | })(window);
165 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 地理院ベクトルタイル提供実験
7 |
8 |
9 |
10 |
11 |
22 |
23 |
24 |
25 |
200 |
201 |
202 |
--------------------------------------------------------------------------------
/TileLayer.GeoJSON.js:
--------------------------------------------------------------------------------
1 | // copy of http://raw.github.com/glenrobertson/leaflet-tilelayer-geojson/master/TileLayer.GeoJSON.js
2 | // LICENCE: https://github.com/glenrobertson/leaflet-tilelayer-geojson/blob/master/LICENCE
3 | // Load data tiles from an AJAX data source
4 | L.TileLayer.Ajax = L.TileLayer.extend({
5 | _requests: [],
6 | _addTile: function (tilePoint) {
7 | var tile = { datum: null, processed: false };
8 | this._tiles[tilePoint.x + ':' + tilePoint.y] = tile;
9 | this._loadTile(tile, tilePoint);
10 | },
11 | // XMLHttpRequest handler; closure over the XHR object, the layer, and the tile
12 | _xhrHandler: function (req, layer, tile, tilePoint) {
13 | return function () {
14 | if (req.readyState !== 4) {
15 | return;
16 | }
17 | var s = req.status;
18 | if ((s >= 200 && s < 300) || s === 304) {
19 | tile.datum = JSON.parse(req.responseText);
20 | layer._tileLoaded(tile, tilePoint);
21 | } else {
22 | layer._tileLoaded(tile, tilePoint);
23 | }
24 | };
25 | },
26 | // Load the requested tile via AJAX
27 | _loadTile: function (tile, tilePoint) {
28 | this._adjustTilePoint(tilePoint);
29 | var layer = this;
30 | var req = new XMLHttpRequest();
31 | this._requests.push(req);
32 | req.onreadystatechange = this._xhrHandler(req, layer, tile, tilePoint);
33 | req.open('GET', this.getTileUrl(tilePoint), true);
34 | req.send();
35 | },
36 | _reset: function () {
37 | L.TileLayer.prototype._reset.apply(this, arguments);
38 | for (var i in this._requests) {
39 | this._requests[i].abort();
40 | }
41 | this._requests = [];
42 | },
43 | _update: function () {
44 | if (this._map._panTransition && this._map._panTransition._inProgress) { return; }
45 | if (this._tilesToLoad < 0) { this._tilesToLoad = 0; }
46 | L.TileLayer.prototype._update.apply(this, arguments);
47 | }
48 | });
49 |
50 |
51 | L.TileLayer.GeoJSON = L.TileLayer.Ajax.extend({
52 | // Store each GeometryCollection's layer by key, if options.unique function is present
53 | _keyLayers: {},
54 |
55 | // Used to calculate svg path string for clip path elements
56 | _clipPathRectangles: {},
57 |
58 | initialize: function (url, options, geojsonOptions) {
59 | L.TileLayer.Ajax.prototype.initialize.call(this, url, options);
60 | this.geojsonLayer = new L.GeoJSON(null, geojsonOptions);
61 | },
62 | onAdd: function (map) {
63 | this._map = map;
64 | L.TileLayer.Ajax.prototype.onAdd.call(this, map);
65 | map.addLayer(this.geojsonLayer);
66 | },
67 | onRemove: function (map) {
68 | map.removeLayer(this.geojsonLayer);
69 | L.TileLayer.Ajax.prototype.onRemove.call(this, map);
70 | },
71 | _reset: function () {
72 | this.geojsonLayer.clearLayers();
73 | this._keyLayers = {};
74 | this._removeOldClipPaths();
75 | L.TileLayer.Ajax.prototype._reset.apply(this, arguments);
76 | },
77 |
78 | // Remove clip path elements from other earlier zoom levels
79 | _removeOldClipPaths: function () {
80 | for (var clipPathId in this._clipPathRectangles) {
81 | var clipPathZXY = clipPathId.split('_').slice(1);
82 | var zoom = parseInt(clipPathZXY[0], 10);
83 | if (zoom !== this._map.getZoom()) {
84 | var rectangle = this._clipPathRectangles[clipPathId];
85 | this._map.removeLayer(rectangle);
86 | var clipPath = document.getElementById(clipPathId);
87 | if (clipPath !== null) {
88 | clipPath.parentNode.removeChild(clipPath);
89 | }
90 | delete this._clipPathRectangles[clipPathId];
91 | }
92 | }
93 | },
94 |
95 | // Recurse LayerGroups and call func() on L.Path layer instances
96 | _recurseLayerUntilPath: function (func, layer) {
97 | if (layer instanceof L.Path) {
98 | func(layer);
99 | }
100 | else if (layer instanceof L.LayerGroup) {
101 | // Recurse each child layer
102 | layer.getLayers().forEach(this._recurseLayerUntilPath.bind(this, func), this);
103 | }
104 | },
105 |
106 | _clipLayerToTileBoundary: function (layer, tilePoint) {
107 | // Only perform SVG clipping if the browser is using SVG
108 | if (!L.Path.SVG) { return; }
109 |
110 | var svg = this._map._pathRoot;
111 |
112 | // create the defs container if it doesn't exist
113 | var defs = null;
114 | if (svg.getElementsByTagName('defs').length === 0) {
115 | defs = document.createElementNS(L.Path.SVG_NS, 'defs');
116 | svg.insertBefore(defs, svg.firstChild);
117 | }
118 | else {
119 | defs = svg.getElementsByTagName('defs')[0];
120 | }
121 |
122 | // Create the clipPath for the tile if it doesn't exist
123 | var clipPathId = 'tileClipPath_' + tilePoint.z + '_' + tilePoint.x + '_' + tilePoint.y;
124 | var clipPath = document.getElementById(clipPathId);
125 | if (clipPath === null) {
126 | clipPath = document.createElementNS(L.Path.SVG_NS, 'clipPath');
127 | clipPath.id = clipPathId;
128 |
129 | // Create a hidden L.Rectangle to represent the tile's area
130 | var tileSize = this.options.tileSize,
131 | nwPoint = tilePoint.multiplyBy(tileSize),
132 | sePoint = nwPoint.add([tileSize, tileSize]),
133 | nw = this._map.unproject(nwPoint),
134 | se = this._map.unproject(sePoint);
135 | this._clipPathRectangles[clipPathId] = new L.Rectangle(new L.LatLngBounds([nw, se]), {
136 | opacity: 0,
137 | fillOpacity: 0,
138 | clickable: false,
139 | noClip: true
140 | });
141 | this._map.addLayer(this._clipPathRectangles[clipPathId]);
142 |
143 | // Add a clip path element to the SVG defs element
144 | // With a path element that has the hidden rectangle's SVG path string
145 | var path = document.createElementNS(L.Path.SVG_NS, 'path');
146 | var pathString = this._clipPathRectangles[clipPathId].getPathString();
147 | path.setAttribute('d', pathString);
148 | clipPath.appendChild(path);
149 | defs.appendChild(clipPath);
150 | }
151 |
152 | // Add the clip-path attribute to reference the id of the tile clipPath
153 | this._recurseLayerUntilPath(function (pathLayer) {
154 | pathLayer._container.setAttribute('clip-path', 'url(#' + clipPathId + ')');
155 | }, layer);
156 | },
157 |
158 | // Add a geojson object from a tile to the GeoJSON layer
159 | // * If the options.unique function is specified, merge geometries into GeometryCollections
160 | // grouped by the key returned by options.unique(feature) for each GeoJSON feature
161 | // * If options.clipTiles is set, and the browser is using SVG, perform SVG clipping on each
162 | // tile's GeometryCollection
163 | addTileData: function (geojson, tilePoint) {
164 | var features = L.Util.isArray(geojson) ? geojson : geojson.features,
165 | i, len, feature;
166 |
167 | if (features) {
168 | for (i = 0, len = features.length; i < len; i++) {
169 | // Only add this if geometry or geometries are set and not null
170 | feature = features[i];
171 | if (feature.geometries || feature.geometry || feature.features || feature.coordinates) {
172 | this.addTileData(features[i], tilePoint);
173 | }
174 | }
175 | return this;
176 | }
177 |
178 | var options = this.geojsonLayer.options;
179 |
180 | if (options.filter && !options.filter(geojson)) { return; }
181 |
182 | var parentLayer = this.geojsonLayer;
183 | var incomingLayer = null;
184 | if (this.options.unique && typeof(this.options.unique) === 'function') {
185 | var key = this.options.unique(geojson);
186 |
187 | // When creating the layer for a unique key,
188 | // Force the geojson to be a geometry collection
189 | if (!(key in this._keyLayers && geojson.geometry.type !== 'GeometryCollection')) {
190 | geojson.geometry = {
191 | type: 'GeometryCollection',
192 | geometries: [geojson.geometry]
193 | };
194 | }
195 |
196 | // Transform the geojson into a new Layer
197 | try {
198 | incomingLayer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng);
199 | }
200 | // Ignore GeoJSON objects that could not be parsed
201 | catch (e) {
202 | return this;
203 | }
204 |
205 | // Add the incoming Layer to existing key's GeometryCollection
206 | if (key in this._keyLayers) {
207 | parentLayer = this._keyLayers[key];
208 | parentLayer.feature.geometry.geometries.push(geojson.geometry);
209 | }
210 | // Convert the incoming GeoJSON feature into a new GeometryCollection layer
211 | else {
212 | incomingLayer.feature = L.GeoJSON.asFeature(geojson);
213 | this._keyLayers[key] = incomingLayer;
214 | }
215 | }
216 | // Add the incoming geojson feature to the L.GeoJSON Layer
217 | else {
218 | // Transform the geojson into a new layer
219 | try {
220 | incomingLayer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng);
221 | }
222 | // Ignore GeoJSON objects that could not be parsed
223 | catch (e) {
224 | return this;
225 | }
226 | incomingLayer.feature = L.GeoJSON.asFeature(geojson);
227 | }
228 | incomingLayer.defaultOptions = incomingLayer.options;
229 |
230 | this.geojsonLayer.resetStyle(incomingLayer);
231 |
232 | if (options.onEachFeature) {
233 | options.onEachFeature(geojson, incomingLayer);
234 | }
235 | parentLayer.addLayer(incomingLayer);
236 |
237 | // If options.clipTiles is set and the browser is using SVG
238 | // then clip the layer using SVG clipping
239 | if (this.options.clipTiles) {
240 | this._clipLayerToTileBoundary(incomingLayer, tilePoint);
241 | }
242 | return this;
243 | },
244 |
245 | _tileLoaded: function (tile, tilePoint) {
246 | L.TileLayer.Ajax.prototype._tileLoaded.apply(this, arguments);
247 | if (tile.datum === null) { return null; }
248 | this.addTileData(tile.datum, tilePoint);
249 | }
250 | });
251 |
--------------------------------------------------------------------------------