2018年10月31日水曜日

OpenLayers5 Workshop - 3.2 Interact with VectorTile features

3 Vector Tile
3.2 Interact with VectorTile features
VectorTile フィーチャを使ってインタラクション

If we want to style the layer we just created, it would be nice to get some information about each geometry we see on the map. The nice thing about vector tile layers is that we can interact with them just like with vector layers. So it is easy to add a listener for clicks to the map, query the features at the clicked position, and display a popup with the attributes of each feature.

今、作成されたレイヤをスタイル(装飾)したいなら、マップ上に見える個々のジオメトリについて情報を取得することは良いことです。ベクタタイルレイヤについて良いことは、ベクタレイヤと同じくそれらを情報交換できるということです。マップにクリックリスナを追加することは簡単なので、クリックされた場所のフィーチャに問い合わせ、個々のフィーチャの属性と一緒にポップアップを表示します。

Adding a popup
ポップアップを追加

We create a popup style by going to http://www.cssarrowplease.com/. I decided to choose a darker popup. The css is added to the <style> section of our index.html:

http://www.cssarrowplease.com/ に行ってポップアップを作成します。ここでは、暗いポップアップを選ぶことにしました。css は、index.html の <style> セクションに追加します:
.arrow_box {
 position: relative;
 background: #000;
 border: 1px solid #003c88;
}
.arrow_box:after, .arrow_box:before {
 top: 100%;
 left: 50%;
 border: solid transparent;
 content: " ";
 height: 0;
 width: 0;
 position: absolute;
 pointer-events: none;
}
.arrow_box:after {
 border-color: rgba(0, 0, 0, 0);
 border-top-color: #000;
 border-width: 10px;
 margin-left: -10px;
}
.arrow_box:before {
 border-color: rgba(0, 60, 136, 0);
 border-top-color: #003c88;
 border-width: 11px;
 margin-left: -11px;
}
.arrow_box {
 border-radius: 5px;
 padding: 10px;
 opacity: 0.8;
 background-color: black;
 color: white;
}
We are going to render scrollable HTML tables into our popup, so our markup for the popup also needs a <div> for the popup content:

ポップアップにスクロールできる HTML テーブル(表)を描画するので、ポップアップのためのマークアップにもポップアップコンテンツに <div> が必要です:
<div class="arrow_box" id="popup-container">
 <div id="popup-content"></div>
</div>
To style the tables, we add some more style to the <style> section of index.html:

テーブルをスタイルするために、index.html の <style> セクションにいくつかさらにスタイルを追加します。
#popup-content {
  max-height: 200px;
  overflow: auto;
}
#popup-content th {
  text-align: left;
  width: 125px;
}
In the application's main.js import the Overlay class:

アプリケーションの main.js に Overlay クラスをインポートします:

import Overlay from 'ol/Overlay';

Again in the application's main.js, we can now append the code for the popup's Overlay:

もう一度、アプリケーションの main.js に、ポップアップの Overlay に対するコードを、直ちに、追加できます:

const overlay = new Overlay({
 element: document.getElementById('popup-container'),
 positioning: 'bottom-center',
 offset: [0, -10],
 autoPan: true
});
map.addOverlay(overlay);
To make it easy to close the popup so it does not cover other features we might want to click, we add a click listener to the overlay, so it closes when we click on it:

クリックしたい他のフィーチャを覆わないようにポップアップを閉じるのを簡単にするために、クリックリスナをオーバレイに追加し、それにより、クリックしたときそれが閉じます。
overlay.getElement().addEventListener('click', function() {
 overlay.setPosition();
});
Calling setPosition() on an overlay sets an undefined position, which causes the overlay to disappear.

オーバレイ上の setPosition() を呼び出すことは、定義されていない場所を設定し、オーバレイを消します。

Fill the popup with feature attributes
ポップアップをフィーチャ属性で満たす

Now it is time to connect the popup to a click listener on the map. We append more code at the bottom of main.js:

今、マップ上のポップアップをクリックリスナに接続するときです。main.js の下部にさらに多くのコードを追加します:
map.on('click', function(e) {
 let markup = '';
 map.forEachFeatureAtPixel(e.pixel, function(feature) {
  markup += `${markup && '<hr>'}<table>`;
  const properties = feature.getProperties();
  for (const property in properties) {
   markup += `<tr><th>${property}</th><td>${properties[property]}</td></tr>`;
  }
  markup += '</table>';
 }, {hitTolerance: 1});
 if (markup) {
  document.getElementById('popup-content').innerHTML = markup;
  overlay.setPosition(e.coordinate);
 } else {
  overlay.setPosition();
 }
});
By iterating through all the features we get at the clicked position (map.forEachFeatureAtPixel), we build a separate table for each feature. With each feature, we iterate through its properties (feature.getProperties()), and add a table row (<tr>) for each property. We also set a hitTolerance of 1 pixel to make it easier to click on lines.

すべてのフィーチャに渡って繰り返すことによって、クリックされた位置を取得し(map.forEachFeatureAtPixel)、個々のフィーチャに対する分かれたテーブルを構築します。個々のフィーチャで、そのプロパティに渡って繰り返し(feature.getProperties())、個々のプロパティに対してテーブルロー(列)を追加します。線上をクリックするのを簡単にするために1ピクセルの hitTolerance の設定もします。

Using the interactivity to build a style for our map
インタラクティビティをマップのスタイルを構築するために使う

Now we can click on any geometry in the map, and use the information we get in the popup to create styles in the next exercise. Note that vector tile features have a special layer property, which indicates the source layer (i.e. the layer the feature belongs to in the vector tile's structure, which is a layer -> feature hierarchy).

現在、マップのすべてのジオメトリ上をクリックでき、次の演習でスタイルを作成するためにポップアップで取得する情報を使います。ベクタタイルフィーチャは特別なレイヤプロパティを持ち、それは、ソースレイヤを示します(例えば、フィーチャが所属しているベクタタイル構造のレイヤで、それは レイヤ -> フィーチャヒエラルキです)。

Getting feature information

■□ Debian9 で試します■□
「Interact with VectorTile features」の例を表示します。「The VectorTile layer」で使用した index.html のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp index.html index.html_vectortile
user@deb9-vmw:~/openlayers-workshop-en$ vim index.html
<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
  <title>OpenLayers</title>
  <style>
   html, body, #map-container {
    margin: 0;
    height: 100%;
    width: 100%;
    font-family: sans-serif;
   }
   .arrow_box {
    position: relative;
    background: #000;
    border: 1px solid #003c88;
   }
   .arrow_box:after, .arrow_box:before {
    top: 100%;
    left: 50%;
    border: solid transparent;
    content: " ";
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
   }
   .arrow_box:after {
    border-color: rgba(0, 0, 0, 0);
    border-top-color: #000;
    border-width: 10px;
    margin-left: -10px;
   }
   .arrow_box:before {
    border-color: rgba(0, 60, 136, 0);
    border-top-color: #003c88;
    border-width: 11px; 
    margin-left: -11px; 
   } 
   .arrow_box { 
    border-radius: 5px; 
    padding: 10px; 
    opacity: 0.8; 
    background-color: black; 
    color: white; 
   }
   #popup-content { 
    max-height: 200px; 
    overflow: auto; 
   } 
   #popup-content th { 
    text-align: left; 
    width: 125px; 
   }
  </style>
 </head>
 <body>
  <div id="map-container"></div>
  <div class="arrow_box" id="popup-container"> 
   <div id="popup-content"></div>
  </div>
 </body>
</html>
「The VectorTile layer」」で使用した main.js のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp main.js main.js_vectortile
user@deb9-vmw:~/openlayers-workshop-en$ vim main.js
import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import MVT from 'ol/format/MVT';
import VectorTileLayer from 'ol/layer/VectorTile';
import VectorTileSource from 'ol/source/VectorTile';
import Overlay from 'ol/Overlay';
// See https://openmaptiles.com/hosting/ for terms and access key
const key = '<your-access-key-here>';
const map = new Map({
 target: 'map-container',
 view: new  View({
  center: [0, 0],
  zoom: 2
 })
});
const layer = new VectorTileLayer({
 source: new VectorTileSource({
  attributions: [
   '<a href="http://www.openmaptiles.org/" target="_blank">&copy; OpenMapTiles</a>',
   '<a href="http://www.openstreetmap.org/about/" target="_blank">&copy; OpenStreetMap contributors</a>'
  ],
  format: new MVT(),
  url: `https://free-{1-3}.tilehosting.com/data/v3/{z}/{x}/{y}.pbf.pict?key=${key}`,
  maxZoom: 14
 })
});
map.addLayer(layer); 
const overlay = new Overlay({
 element: document.getElementById('popup-container'),
 positioning: 'bottom-center',
 offset: [0, -10],
 autoPan: true
});
map.addOverlay(overlay);
overlay.getElement().addEventListener('click', function() {
 overlay.setPosition();
});
map.on('click', function(e) {
 let markup = '';
 map.forEachFeatureAtPixel(e.pixel, function(feature) {
  markup += `${markup && '<hr>'}<table>`;
  const properties = feature.getProperties();
  for (const property in properties) {
   markup += `<tr><th>${property}</th><td>${properties[property]}</td></tr>`;
  }
  markup += '</table>';
 }, {hitTolerance: 1});
 if (markup) {
  document.getElementById('popup-content').innerHTML = markup;
  overlay.setPosition(e.coordinate);
 } else {
  overlay.setPosition();
 }
});
http://localhost:3000/ とブラウザでマップを開きます。(もし開かなければ、'npm start' を実行してください。



0 件のコメント: