世界の測量

Sibling of "Relevant, Timely, and Accurate, " but much lighter and shorter ※自らの所属する組織の見解を示すものでない

ベクトルタイル・いちさと(小学校区)Pt. 4 アンクリップト・タイル

面データでは、タイル境界の問題が顕著である。TileLayer.Vector.Unclipped.jsを利用して、タイルにかかるポリゴンをタイル境界で切り取らないように用意したタイルから、タイル境界なしにポリゴンデータを描画する方法を試してみた。

結果

f:id:hfu:20140106232404p:plain
http://handygeospatial.github.io/mapsites/2014/01/06/unclipped.html
new L.TileLayer.Vector.Unclipped(...) というコンストラクタでレイヤを作ることがポイントである。また、unique プロパティにセットした関数を通じて、データのアイデンティティを表現する。同じ返り値のデータは二度とレイヤに加えない、ということを行っている。

なお、オリジナルのL.TileLayer.GeoJSONでは、unique プロパティにセットした関数の返り値が同じジオメトリを、マルチジオメトリとしてまとめる。この方法では、タイル境界の線は消えないが、例えば hover したときにタイル境界をまたいでポリゴン全体のスタイルを変えたりすることはできるし、データの肥大化も防げるであろう。

アンクリップト・タイルの作成

アンクリップト・タイルを作成するには、tilestache.cfgのlayers..provider.clippedの値をfalseにする(デフォルトはtrueだったので、先ほどはクリップされたタイルができた。)。
tilestache.cfg の内容はつぎのとおり。

{"cache": {
  "name": "Disk",
  "path": "/vagrant/es",
  "dirs": "portable",
  "gzip": []
  },
 "layers": {
  "school_district_unclipped": {
    "provider": {"name": "vector", "driver": "ESRI Shapefile", "verbose": true,
      "clipped": false,
      "parameters": { 
        "file": "school_district.shp"},
        "properties": ["id", "A27_005", "A27_006", "A27_007", "A27_008"]
      }
    }
  }
}

なお、ズームレベル13において、clippedなタイルは全体で60MB程度であり、unclippedなタイルは全体で160MB程度であった。

コード

コードはつぎのとおり。

<!doctype html>
<html>
<head>
  <!-- thx https://github.com/ebrelsford/leaflet-tilelayer-vector -->
  <meta charset='UTF-8'>
  <meta name="viewport" 
   content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <meta name="apple-mobile-web-app-capable" content="yes"/>
  <meta name="apple-mobile-web-app-status-bar-style" 
   content="black-translucent" />
  <link rel="apple-touch-icon" 
   href="https://si0.twimg.com/profile_images/666603054/r.png"/>
  <title>ベクトルタイル・いちさと(小学校区)Unclipped</title>
  <link rel='stylesheet' href='http://cdn.leafletjs.com/leaflet-0.7/leaflet.css'>
  <link rel="stylesheet" href="http://leaflet.github.io/Leaflet.label/leaflet.label.css">
  <script src='http://cdn.leafletjs.com/leaflet-0.7/leaflet.js'></script>

  <script src="http://leaflet.github.io/Leaflet.label/leaflet.label.js"></script>
  <script src="http://handygeospatial.github.io/mapsites/2014/01/01/communist.min.js"></script>
  <script src="http://handygeospatial.github.io/mapsites/2014/01/01/TileCache.js"></script>
  <script src="http://handygeospatial.github.io/mapsites/2014/01/01/TileQueue.js"></script>
  <script src="http://handygeospatial.github.io/mapsites/2014/01/01/AbstractWorker.js"></script>
  <script src="http://handygeospatial.github.io/mapsites/2014/01/01/CommunistWorker.js"></script>
  <script src="http://handygeospatial.github.io/mapsites/2014/01/01/TileLayer.GeoJSON.js"></script>
  <script src="http://handygeospatial.github.io/mapsites/2014/01/01/TileLayer.Overzoom.js"></script>
  <script src="http://handygeospatial.github.io/mapsites/2014/01/01/Leaflet.label-patch.js"></script>
<!-- important -->
  <script src="http://handygeospatial.github.io/mapsites/2013/12/31/TileLayer.Vector.Unclipped.js"></script>
  <script src="http://handygeospatial.github.io/mapsites/2013/12/31/TileLayer.Vector.Debug.js"></script>
  <script src="http://handygeospatial.github.io/mapsites/2013/12/31/TileLayer.Div.js"></script>
  <script src="http://handygeospatial.github.io/mapsites/2013/12/31/TileLayer.Progress.js"></script>
<!-- end of important part -->
  <script src="http://handygeospatial.github.io/mapsites/2014/01/01/leaflet-hash.js"></script>
  <style>
  html, body, #mapdiv {margin: 0; padding: 0; width: 100%; height: 100%;}
  </style>
</head>
<body>
  <div id='mapdiv'/>
  <script>
map = new L.Map('mapdiv', {zoom: 13, center: 
  [(35.66811 + 36.153059) / 2 , (139.233398 + 140.914307) / 2]});
hash = new L.Hash(map);
var normal_style = {
  "clickable": true,
  "color": "#00F",
  "fillColor": "#00F",
  "weight": 1,
  "opacity": 0.3,
  "fillOpacity": 0.2
};
var hover_style = {
  "fillColor": "#f00"
};
map.addLayer(new L.TileLayer(
  'http://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png',
  {attribution: '地理院タイル', minZoom: 13, maxZoom: 13}));
map.addLayer(new L.TileLayer.Vector.Unclipped(
  'http://www.handygeospatial.info/2014/01/06/unclipped/{z}/{x}/{y}.geojson',
  {attribution: '国土数値情報(小学校区データ) 国土交通省', 
   unloadInvisibleTiles: true, minZoom: 13, maxZoom: 13,
   serverZooms: [13],
   filter: function(feature) {return true;},
   unique: function(feature) {return feature.properties.id;}
  }, 
  {style: normal_style,
   onEachFeature: function(feature, layer) {
     layer.on('mouseover', function() {
       layer.setStyle(hover_style);
     });
     layer.on('mouseout', function() {
       layer.setStyle(normal_style);
     });
     layer.bindPopup(
       "市区町村コード: " + feature.properties.A27_005 +
       "<br/>設置主体: " + feature.properties.A27_006 +
       "<br/>名称: " + feature.properties.A27_007+ 
       "<br/>所在地: " + feature.properties.A27_008
     );
   }
  }));
  </script>
</body>
</html>