ラベル workshop の投稿を表示しています。 すべての投稿を表示
ラベル workshop の投稿を表示しています。 すべての投稿を表示

2018年10月31日水曜日

OpenLayers5 Workshop - 4.3 Render sea level

4 Raster Operations
4.3 Render sea level
平均海面を描画

In the previous step, we rendered the Terrain-RGB tiles directly on the map. What we want to do is render sea level on the map instead. And we want users to be able to adjust the height above sea level and see the adjusted height rendered on the map. We'll use a raster source to work with the elevation data directly and get the user input from an input slider on the page.

前回のステップで、Terrain-RGB タイルを直接マップ上に描画しました。(今回)したいことは、かわりに、平均海面をマップ上に描画します。そして、ユーザが海抜の高さを調整し、マップ上に描画された調節された高さを見ることができるようにします。elevation(標高)データで直接操作するためにラスタソースを使い、ページ上のインプットスライダからユーザインプット(input)を取得します。

Let's add the controls to the page first. In your index.html, add the following label and input slider:

最初にコントロ0るをページに追加しましょう。index.html に次のラベルとインプットスライダを追加します:
<label id="slider">
 Sea level
 <input id="level" type="range" min="0" max="100" value="1"/>
 +<span id="output"></span> m
</label>
Now add some style to those controls (in the <style> of your index.html):

では、(index.html の <style> に)いくつかのスタイルをそれらのコントロールに追加します:
#slider {
 position: absolute;
 bottom: 1rem;
 width: 100%;
 text-align: center;
 text-shadow: 0px 0px 4px rgba(255, 255, 255, 1);
}
Instead of directly rendering the R, G, B, A values from the Terrain-RGB tiles, we want to manipulate the pixel values before rendering. The raster source allows you to do this by accepting any number of input sources and an operation. This operation is a function that gets called for every pixel in the input sources. We only have one input source (elevation), so it will get called with an array of one pixel, where a pixel is a [red, green, blue, alpha] array. The operation also gets called with a data object. We'll use the data object to pass along the value of the input slider.

Terrain-RGB タイルから R、G、B、A 値を直接描画するかわりに、描画する前にピクセル値を操作するようにします。ラスタソース(raster source)は、任意の数のインプットソース(input source)と operation(オペレーション)を受け取ることによってこれを行うことを許可します。この operation はインプットソースのすべてのピクセルの呼び出し(call)を取得するファンクションです。1つのインプットソース(elevation)だけ持ち、そのため、1つのピクセルの配列を伴う呼び出しを取得し、ピクセルは、[red, green, blue, alpha] 配列になっています。operation は data(データ)オブジェクトを伴う呼び出しも取得します。インプットスライダの値に沿って渡すために data オブジェクトを使います。

First, import the RasterSource and ImageLayer (in main.js):

最初に、(main.js に)RasterSource と ImageLayer をインポートします:
import ImageLayer from 'ol/layer/Image';
import RasterSource from 'ol/source/Raster';
Add the function below to your main.js. This function decodes the input elevation data — transforming red, green, and blue values into a single elevation measure. For elevation values at or below the user selected value, the function returns a partially transparent blue pixel. For values above the user selected value, the function returns a transparent pixel.

下の function を main.js に追加します。このファンクションは、インプット elevation データを、赤(red)、緑(green)、青(blue)の値を単一の elevation 量に変換するために、デコード(復号化)します。ユーザが選択した、または、それより低い elevation 値の場合には、ファンクションは部分的に透明な青ピクセルを返します。ユーザが選択した値より高い場合には、ファンクションは透明なピクセルを返します。
function flood(pixels, data) {
 const pixel = pixels[0];
 if (pixel[3]) {
  // decode R, G, B values as elevation
  const height = -10000 + ((pixel[0] * 256 * 256 + pixel[1] * 256 + pixel[2]) * 0.1);
  if (height <= data.level) {
   // sea blue
   pixel[0] = 145; // red
   pixel[1] = 175; // green
   pixel[2] = 186; // blue
   pixel[3] = 255; // alpha
  } else {
   // transparent
   pixel[3] = 0;
  }
 }
 return pixel;
}
Create a raster source with a single input source (the elevation data), and configure it with the flood operation.

単一の入力ソース(elevation データ)でラスターソースを作成し、 flood operation でそれを設定します。
const raster = new RasterSource({
 sources: [elevation],
 operation: flood
});
Listen for changes on the slider input and re-run the raster operations when the user adjusts the value.

ユーザが値を調節するとき、スライダインプット(input)と raster operation の再実行の変更に対してリッスンします。
const control = document.getElementById('level');
const output = document.getElementById('output');
control.addEventListener('input', function() {
 output.innerText = control.value;
 raster.changed();
});
output.innerText = control.value;
The beforeoperations event is fired before the pixel operations are run on the raster source. This is our opportunity to provide additional data to the operations. In this case, we want to make the range input value (meters above sea level) available.

beforeoperations イベントは、pixel operations がラスタソースに対して実行される前に、始動します。これは、追加 data を operations に提供するための契機です。この場合、入力された値の範囲(標高メートル)を利用可能にします。
raster.on('beforeoperations', function(event) {
 event.data.level = control.value;
});
Finally, render the output from the raster operation by adding the source to an image layer. Replace the tile layer with an image layer that uses our raster source (modify the layers array in main.js):

最後に、ソースをイメージレイヤに追加することによって raster operation から出力を描画します。ラスタソースを使用するイメージレイヤで タイルレイヤを置き換えます(main.js で layers 配列を修正します):
new ImageLayer({
 opacity: 0.8,
 source: raster
})
With all this in place, the map should now have a slider that let's users control changes in sea level.

すべてこれを正しい場所に用いると、マップはユーザが海面の変化を調節できるスライダを保持できます。

Sea level rise in Boston

■□ Debian9 で試します■□
「Render sea level」の例を表示します。「Map setup」で使用した index.html のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp index.html index.html_mapsetup
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;
    }
   #slider {
    position: absolute;
    bottom: 1rem;
    width: 100%;
    text-align: center;
    text-shadow: 0px 0px 4px rgba(255, 255, 255, 1);
   }
  </style>
 </head>
 <body>
  <div id="map-container"></div>
  <label id="slider">
   Sea level
   <input id="level" type="range" min="0" max="100" value="1"/>
   +<span id="output"></span> m
  </label>
 </body>
</html>
「Render elevation data」で使用した main.js のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp main.js main.js_elevation
user@deb9-vmw:~/openlayers-workshop-en$ vim main.js
import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import XYZSource from 'ol/source/XYZ';
import {fromLonLat} from 'ol/proj';
import ImageLayer from 'ol/layer/Image';
import RasterSource from 'ol/source/Raster';
const key = '<your-default-public-token>';
const elevation = new XYZSource({
 url: 'https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token=' + key,
 crossOrigin: 'anonymous'
});
function flood(pixels, data) {
 const pixel = pixels[0];
 if (pixel[3]) {
  // decode R, G, B values as elevation
  const height = -10000 + ((pixel[0] * 256 * 256 + pixel[1] * 256 + pixel[2]) * 0.1);
  if (height <= data.level) {
   // sea blue
   pixel[0] = 145; // red
   pixel[1] = 175; // green
   pixel[2] = 186; // blue
   pixel[3] = 255; // alpha
  } else {
   // transparent
   pixel[3] = 0;
  }
 }
 return pixel;
}
const raster = new RasterSource({
 sources: [elevation],
 operation: flood
});
const control = document.getElementById('level');
const output = document.getElementById('output');
control.addEventListener('input', function() {
 output.innerText = control.value;
 raster.changed();
});
output.innerText = control.value;
raster.on('beforeoperations', function(event) {
 event.data.level = control.value;
});
new Map({
 target: 'map-container',
 layers: [
  new TileLayer({
   source: new XYZSource({
    url: 'http://tile.stamen.com/terrain/{z}/{x}/{y}.jpg'
   })
  }),
  new ImageLayer({
   opacity: 0.8,
   source: raster
  })
 ],
 view: new View({
  center: fromLonLat([-71.06, 42.37]),
  zoom: 12
 })
});
http://localhost:3000/ とブラウザでマップを開きます。(もし開かなければ、'npm start' を実行してください。



OpenLayers5 Workshop - 4.2 Render elevation data

4 Raster Operations
4.2 Render elevation data
標高データを描画

We're going to work with elevation data that is encoded in PNG tiles (see the Mapbox post on Terrain-RGB for more detail). For this exercise, you'll need to sign up for a Mapbox account and use your access token for tiles.

PNG(ピングフォーマット画像)タイルでエンコードされる elevation(標高)データを使って作業します(さらに詳細は Mapbox に搭載の Terrain-RGB を参照)。この演習のために、Mapbox アカウントのサインアップとタイルのためのアクセストークンを使うことが必要です。

Add your default public token to main.js:

デフォルトのパブリックトークンを main.js を追加します:

const key = '<your-default-public-token>';

We want to manipulate the elevation data before rendering, but initially we'll add the Terrain-RGB tiles to the map just to see what they look like. To do this, create an XYZ source with the Terrain-RGB URL and your access token.

描画の前に elevation データを操作したいのですが、最初に、どのように見えるか単に見るため、Terrain-RGB タイルをマップに追加します。これを実行するため、Terrain-RGB URL とアクセストークンで XYZ ソースを作成します。
const elevation = new XYZSource({
 url: 'https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token=' + key,
 crossOrigin: 'anonymous'
});
Next, create a tile layer that uses the elevation source. Add this layer your map's layers array in main.js:

次に、elevation ソースを使うタイルレイヤを作成します。 main.js でこのレイヤをマップレイヤ配列に追加します:
new TileLayer({
 opacity: 0.8,
 source: elevation
})
You should now see some oddly colored tiles shown over your base layer. The elevation data in the Terrain-RGB tiles is encoded in the red, green, and blue channels. So while this data isn't meant to be rendered directly, it is interesting to look at.

ベースレイヤを覆って表示される奇妙なカラータイルが見られます。Terrain-RGB タイルの標高データは、赤、緑、青チャンネルにエンコードされます。このデータは、直接描画されるものではありませんが、見るのは興味深いです。

Terrain-RGB tiles rendered over Boston

■□ Debian9 で試します■□
「Render elevation data」の例を表示します。「Map setup」で使用した main.js のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp main.js main.js_mapsetup
user@deb9-vmw:~/openlayers-workshop-en$ vim main.js
import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import XYZSource from 'ol/source/XYZ';
import {fromLonLat} from 'ol/proj';
const key = '<your-default-public-token>';
const elevation = new XYZSource({
 url: 'https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token=' + key,
 crossOrigin: 'anonymous'
});
new Map({
 target: 'map-container',
 layers: [
  new TileLayer({
   source: new XYZSource({
    url: 'http://tile.stamen.com/terrain/{z}/{x}/{y}.jpg'
   })
  }),
  new TileLayer({
   opacity: 0.8,
   source: elevation
  })
 ],
 view: new View({
  center: fromLonLat([-71.06, 42.37]),
  zoom: 12
 })
});
http://localhost:3000/ とブラウザでマップを開きます。(もし開かなければ、'npm start' を実行してください。



OpenLayers5 Workshop - 4.1 Map setup

4 Raster Operations
ラスタ操作

Up to this point, when we have used raster data (with an XYZ tile source for example), we have used it for presentation purposes only — rendering the data directly to the map. It is also possible to work with the pixel values in the data we fetch, run operations on these values, and manipulate things before rendering. The Raster source provides a way to run pixel-wise operations on data from any number of input sources. When the source is used in an Image layer, the result of the raster operation can be rendered on the map.

ここまでで、(example の XYZ タイルソースを使用した)ラスタデータ使うとき、プレゼンテーション目的だけで使い、データを直接マップに描画します。描画前にものを取得して、これらの値に関する操作を実行し、操作するデータにピクセル値で動作することも可能です。ラスタソースは、任意の数の入力ソースからデータに関するピクセル関連の操作を実行する方法を提供します。ソースはイメージ(Image)レイヤで使用されるとき、ラスタ操作の結果は、マップ上に描画されます。

In these exercises, we'll work with elevation data served as XYZ tiles. Instead of rendering the encoded elevation data directly, we'll run a pixel-wise operation on the data before rendering.

この演習で、 XYZ アイルとして供給される標高データを使って作業します。エンコードされた標高データを直接描画するかわりに、描画の前にデータに関するピクセル関連の操作を実行します。

● Map setup
● Render elevation data
● Render sea level

● マップ装備
● 標高データを描画
● 海抜を描画

4.1 Map setup
マップ装備

Edit your index.html so we're ready to render a full page map:

全画面マップを描画する準備のために 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;
    }
  </style>
 </head>
 <body>
  <div id="map-container"></div>
 </body>
</html>
We'll start out with a map centered on Boston showing a single XYZ source. Update your main.js so it looks like this:

単一の XYZ ソースを表示するボストンを中心としたマップで始めます。このように見えるように main.js を更新します:
import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import XYZSource from 'ol/source/XYZ';
import {fromLonLat} from 'ol/proj';
new Map({
 target: 'map-container',
 layers: [
  new TileLayer({
   source: new XYZSource({
    url: 'http://tile.stamen.com/terrain/{z}/{x}/{y}.jpg'
   })
  })
 ],
 view: new View({
  center: fromLonLat([-71.06, 42.37]),
  zoom: 12
 })
});
A map of Boston

■□ Debian9 で試します■□
「Map setup」の例を表示します。「Making things look bright」で使用した index.html のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp index.html index.html_bright
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;
    }
  </style>
 </head>
 <body>
  <div id="map-container"></div>
 </body>
</html>
「Making things look bright」で使用した main.js のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp main.js main.js_bright
user@deb9-vmw:~/openlayers-workshop-en$ vim main.js
import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import XYZSource from 'ol/source/XYZ';
import {fromLonLat} from 'ol/proj';
new Map({
 target: 'map-container',
 layers: [
  new TileLayer({
   source: new XYZSource({
    url: 'http://tile.stamen.com/terrain/{z}/{x}/{y}.jpg'
   })
  })
 ],
 view: new View({
  center: fromLonLat([-71.06, 42.37]),
  zoom: 12
 })
});
http://localhost:3000/ とブラウザでマップを開きます。(もし開かなければ、'npm start' を実行してください。



OpenLayers5 Workshop - 3.4 Making things look bright

3 Vector Tile
3.4 Making things look bright
ものを明るく見せる

There have been many attempts to create tools and formats for styling maps. The most popular formats were probably SLD and CartoCSS. A graphical tool that comes to mind is Atlas Styler. But none of these format or tools were really convenient to use.

マップをスタイルするためにツールとフォーマットを作成する試みがたくさんあります。最も一般的なフォーマットは、おそらく、SLD と CartoCSS です。頭に浮かぶグラフィカルツールは、Atlas Styler です。これらのフォーマット、または、ツールは、使うのに本当に便利ではありません。

Mapbox finally came up with Mapbox Studio, a very user friendly style editor, and the Mapbox Style format. The Mapbox Style format is supported by a growing number of applications, and a graphical Open Source editor, Maputnik, is available for creating and modifying Mapbox Style files.

Mapbox は、とても使いやすいスタイルエディタ、Mapbox Studio と Mapbox Style フォーマットをついに出しました。Mapbox Style フォーマットは、増え続けるアプリケーションによって支援され、グラフィカル Open Source エディタ Maputnik は、Mapbox Style ファイルを作成し編集することに利用できます。

The ol-mapbox-style package adds support for the Mapbox Style format to OpenLayers. Let's see if we can get a nicer looking map than the one from the previous exercise.

ol-mapbox-style パッケージは、OpenLayers に Mapbox Style フォーマットのためのサポートを追加します。前回の演習からより見栄えの良いマップを取得できるかみてみます。

Creating Mapbox Style files in Maputnik
Maputnik で Mapbox Style ファイルを作成

You can play with a live instance of Maputnik at https://maputnik.github.io/editor/, or download and install it locally. I have created a file with our ugly style. You can download that file, ugly.json, and open it in Maputnik to verify it looks just as ugly there as it does in our OpenLayers application:

https://maputnik.github.io/editor/ にあるか、または、ローカルでダウンロードしインストールして Maputnik のインスタンス化で楽しめます。私は ugly スタイルでファイルを作成しています。あなたはそのファイル、ugly.json をダウンロードし、OpenLayers アプリケーションで実行するのと同じようにそこで ugly かを確かめるために Maputnik で開きます。

Ugly style in Maputnik

Create a map from a Mapbox Style in OpenLayers
OpenLayers で Mapbox Style からマップを作成

We'll import the apply function from the ol-mapbox-style package, so we can simply have a map with all the contents from a style file rendered into our map-container. But first we need to install the package:

ol-mapbox-style から apply ファンクションをインポートすると、map-container に描画されたスタイルファイルからすべてのコンテンツと一緒にマップを簡単に持つことができます。しかし、最初にパッケージをインストールする必要があります:

npm install ol-mapbox-style@beta

(訳注:実施には npm install ol-mapbox-style)

Now we can import the function into our main.js:

main.js にファンクションをインポートします:

import {apply} from 'ol-mapbox-style';

We can also remove all other imports except for these two:

これら2つを除いて他のインポートすべても削除します:
import 'ol/ol.css';
import Overlay from 'ol/Overlay';
While we are at cleaning up, we can also delete the key, map, layer definitions. And we can – of course – remove all the style code. Finally, in index.html, we can remove the line that adds the Open Sans font, and the background-color for the map.

クリーンアップの間、key、map、layer 定義も削除できます。そして、もちろん、スタイルコードをすべて削除できます。最後に、index.html で Open Sans ファンとを追加するラインとマップの background-color を削除します。

Instead of the previous map code, we need a single line to create a map from our ugly Mapbox style, which we insert below our imports:

前述のマップコードのかわりに、ugly Mapbox スタイルからマップを作成するための1つのラインが必要で、import の下に挿入します:

const map = apply('map-container', './data/ugly.json');

This should give us the same ugly map as before, just with less application code. But hey, we wanted to make things look bright, and not look at an ugly map again. So let's open the 'OSM Bright' from Maputnik's Gallery Styles, and use that. I have prepared it already, and made the result available as http://localhost:3000/data/bright.json. So let's change the apply() line to

これは前回と同じ ugly map を、より少ないアプリケーションコードで、与えます。しかし、おい、明るく見せたいし、また、 ugly(見苦しい)マップを見たくありません。それでは、Maputnik's Gallery Styles から 'OSM Bright' を開き、それを使います。それはすでに準備されていて、http://localhost:3000/data/bright.json として結果を利用できます。それでは、 apply() ラインを変更します:

const map = apply('map-container', './data/bright.json');

What a relief. Finally we can enjoy a nice looking world map, and zoom to Boston!

ホッとしました。最後に、見栄えの良い世界地図を楽しみ、ボストンにズームインします。

A bright map of Boston

And note that our map is still interactive, meaning you get an info popup when you click on any geometry.

このマップは、まだ、インタラクティブな状態で、ジオメトリをクリックしたとき情報ポッパップを取得することに注意してください。


■□ Debian9 で試します■□
「Interact with VectorTile features」の例を表示します。 最初に、ol-mapbox-style パッケージをインストールします。

nob61@deb9-vmw:~/openlayers-workshop-en$ npm install ol-mapbox-style@beta
npm WARN extract-text-webpack-plugin@3.0.2 requires a peer of webpack@^3.1.0 but none is installed. You must install peer dependencies yourself.

+ ol-mapbox-style@3.0.0-beta.9
added 2 packages from 1 contributor, removed 16 packages, updated 3 packages and audited 7504 packages in 10.782s found 0 vulnerabilities

「Styling a VectorTile layer」で使用した index.html のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp index.html index.html_styling
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;
    background-color: rgb(248, 244, 240);
   }
   .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>
「Styling a VectorTile layer」」で使用した main.js のバックアップを保存して次のように修正します。削除するインポート(import)、key、layer、map の定義などは、ugly.json ファイルに記述されています。

user@deb9-vmw:~/openlayers-workshop-en$ cp main.js main.js_styling
user@deb9-vmw:~/openlayers-workshop-en$ vim main.js
import 'ol/ol.css';
import Overlay from 'ol/Overlay';
import {apply} from 'ol-mapbox-style'; 
const map = apply('map-container', './data/ugly.json'); 
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);
 }
});
'npm start' を実行すると次のようなメッセージが表示され、コンパイルできませんました。

nob61@deb9-vmw:~/openlayers-workshop-en$ npm start
$gt; ol-workshop@0.0.0 start /home/nob61/openlayers-workshop-en
$gt; webpack-dev-server --mode=development

ℹ 「wds」: Project is running at http://localhost:3000/
ℹ 「wds」: webpack output is served from /
✖ 「wdm」: 
ERROR in ./node_modules/@mapbox/mapbox-gl-style-spec/util/color.js
Module parse failed: Unexpected token (17:5)
You may need an appropriate loader to handle this file type.
|  */
| class Color {
|     r: number;
|     g: number;
|     b: number;
 @ ./node_modules/ol-mapbox-style/index.js 23:0-60 190:38-43
 @ ./main.js
 @ multi (webpack)-dev-server/client?http://localhost:3000 ./main.js
---
ℹ 「wdm」: Failed to compile.

OpenLayers5 Workshop - 3.3 Styling a VectorTile layer

3 Vector Tile
3.3 Styling a VectorTile layer
VectorTile レイヤをスタイルする

Styling a vector tile layer works exactly the same way as styling a vector layer. We will now try to style our world map so it actually looks like a world map is supposed to look.

ベクタタイルレイヤをスタイルすることは、ベクタレイヤをスタイルするのと全く同じ方法で動作します。実際に見るはずの世界地図のように見えるよう世界地図をスタイルしてみます。

Load fonts
フォントをロードする

Let's say we want to use a nicer font for labels in our map. I decided to use the Open Sans font family, which can easily be loaded with an additional stylesheet in the <head> of our index.html:

マップでラベルに見た目が良いフォントを使いたいとします。Open Sans フォントファミリを使うことを決めましたが、index.html の <head> に追加のスタイルシートを使って簡単にロードできます。

<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">

Set a map background
マップの背景を設定する

A common style element in vector tile maps is a background color, which the user sees in places that are not covered by any geometries. Like we already saw in the vector exercise, this can be done by simply setting a background color in a <style> for the #map-container:

ベクタタイルマップで一般的なスタイルエレメントは背景色(background color)ですが、どのジオメトリにも覆われていない場所に見られます。すでにベクタ演習で見られたように、これは #map-container の <style> に背景色を単純に設定することによって実行できます。

background-color: rgb(248, 244, 240);

Style the layer with a style function
style ファンクションを使ってレイヤをスタイルする

Now we are going to add some application code to main.js.

では、main.js にいくつかアプリケーションコードを追加します。

First, we'll need imports for the styles we are going to use:

最初に、使うスタイルのインポートが必要です:

import {Style, Fill, Stroke, Circle, Text} from 'ol/style';
// import {createDefaultStyle} from 'ol/style/Style';
The style function is a bit long:

style ファンクションは少し長いです:
layer.setStyle(function(feature, resolution) {
 const properties = feature.getProperties();
 // Water polygons
 if (properties.layer == 'water') {
  return new Style({
   fill: new Fill({
    color: 'rgba(0, 0, 255, 0.7)'
   })
  });
 }
 // Boundary lines
 if (properties.layer == 'boundary' && properties.admin_level == 2) {
  return new Style({
   stroke: new Stroke({
    color: 'gray'
   })
  });
 }
 // Continent labels
 if (properties.layer == 'place' && properties.class == 'continent') {
  return new Style({
   text: new Text({
    text: properties.name,
    font: 'bold 16px Open Sans',
    fill: new Fill({
     color: 'black'
    }),
    stroke: new Stroke({
     color: 'white'
    })
   })
  });
 }
 // Country labels
 if (properties.layer == 'place' && properties.class == 'country' &&
  resolution < map.getView().getResolutionForZoom(5)) {
   return new Style({
    text: new Text({
     text: properties.name,
     font: 'normal 13px Open Sans',
     fill: new Fill({
      color: 'black'
     }),
     stroke: new Stroke({
      color: 'white'
     })
    })
   });
 }
 // Capital icons and labels
 if (properties.layer == 'place' && properties.capital) {
  const point = new Style({
   image: new Circle({
    radius: 5,
    fill: new Fill({
     color: 'black'
    }),
    stroke: new Stroke({
     color: 'gray'
    })
   })
  });
  if (resolution < map.getView().getResolutionForZoom(6)) {
   point.setText(new Text({
    text: properties.name,
    font: 'italic 12px Open Sans',
    offsetY: -12,
     fill: new Fill({
      color: '#013'
     }),
     stroke: new Stroke({
      color: 'white'
     })
   }));
  }
  return point;
 }
 // return createDefaultStyle(feature, resolution);
});
I think you will agree that we have not reached our goal of creating a beautiful world map:

美しい世界地図を作成する最終目的に達していないと考えていると思います:

An ugly world map

There is much more effort involved in styling a world map appropriately, and writing a style function in JavaScript is probably not the right tool. In the next exercise, we will learn a different way of loading and styling vector tile layers.

適切に世界地図をスタイリングするものに含まれているもっとたくさんの効果があり、JavaScript に style ファンクションを書くことは、おそらく正しいツールではありません。この演習で、ベクタタイルレイヤをロードしスタイリングする難しい方法を学びます。

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

user@deb9-vmw:~/openlayers-workshop-en$ cp index.html index.html_interact
user@deb9-vmw:~/openlayers-workshop-en$ vim index.html
<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
  <title>OpenLayers</title>
  <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet"> 
  <style>
   html, body, #map-container {
    margin: 0;
    height: 100%;
    width: 100%;
    font-family: sans-serif;
    background-color: rgb(248, 244, 240);
   }
   .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_interact
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();
 }
});
layer.setStyle(function(feature, resolution) {
 const properties = feature.getProperties();
 // Water polygons
 if (properties.layer == 'water') {
  return new Style({
   fill: new Fill({
    color: 'rgba(0, 0, 255, 0.7)'
   })
  });
 }
 // Boundary lines
 if (properties.layer == 'boundary' && properties.admin_level == 2) {
  return new Style({
   stroke: new Stroke({
    color: 'gray'
   })
  });
 }
 // Continent labels 
 if (properties.layer == 'place' && properties.class == 'continent') {
  return new Style({
   text: new Text({
    text: properties.name,
    font: 'bold 16px Open Sans',
    fill: new Fill({
     color: 'black'
    }),
    stroke: new Stroke({
     color: 'white'
    })
   })
  });
 }
 // Country labels 
 if (properties.layer == 'place' && properties.class == 'country' &&
     resolution < map.getView().getResolutionForZoom(5)) {
  return new Style({
   text: new Text({
    text: properties.name,
    font: 'normal 13px Open Sans',
    fill: new Fill({
     color: 'black'
    }),
    stroke: new Stroke({
     color: 'white'
    })
   })
  });
 }
 // Capital icons and labels 
 if (properties.layer == 'place' && properties.capital) {
  const point = new Style({
   image: new Circle({
    radius: 5,
    fill: new Fill({
     color: 'black'
    }),
    stroke: new Stroke({
     color: 'gray'
    })
   })
  });
  if (resolution < map.getView().getResolutionForZoom(6)) {
   point.setText(new Text({
    text: properties.name,
    font: 'italic 12px Open Sans',
    offsetY: -12,
    fill: new Fill({
     color: '#013'
    }),
    stroke: new Stroke({
     color: 'white'
    })
   }));
  }
  return point;
 }
 // return createDefaultStyle(feature, resolution);
});
http://localhost:3000/ とブラウザでマップを開きます。(もし開かなければ、'npm start' を実行してください。



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' を実行してください。



OpenLayers5 Workshop - 3.1 The VectorTile layer

3 Vector Tile

Beautiful maps with vector tiles

In this module we will learn everything about the VectorTile layer in OpenLayers, and bring in the ol-mapbox-style utility to work with Mapbox Style files.

このモジュールでは、OpenLayers の VectorTile レイヤについてすべてを学習し、Mapbox Style ファイルで動作するために ol-mapbox-style ユーティリティを導入します。

● The VectorTile layer
● Interact with VectorTile features
● Styling a VectorTile layer
● Making things look bright

● VectorTile レイヤ
● VectorTile フィーチャを使ってインタラクション
● VectorTile レイヤをスタイルする
● ものを明るく見せる


3.1 The VectorTile layer
VectorTile レイヤ

We now know how to load tiled images, and we have seen different ways to load and render vector data. But what if we could have tiles that are fast to transfer to the browser, and can be styled on the fly? Well, this is what vector tiles were made for. OpenLayers supports vector tiles through the VectorTile layer.

現在、タイル化した画像をロードする方法を知っていて、ベクタデータをロードし描画する違う方法を確認します。しかし、ブラウザに転送するのが速い、そしてスタイルできるタイルがここにあるならどうしますか。ところで、これはベクタタイル向きです。OpenLayers は、VectorTile レイヤを通してベクタタイルをサポートします。

A world map rendered from vector data
ベクタデータから描画された世界地図

We'll start with the same markup in index.html as in the Basics exercise.

Basics 演習と同じ 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;
   }
  </style>
 </head>
 <body>
  <div id="map-container"></div>
 </body>
</html>
As usual, we save index.html in the root of our workshop folder.

いつもの通り、ワークショップフォルダのルートに index.html を保存します。

For the application, we'll start with a fresh main.js in the root of the workshop folder, and add the required imports:

アプリケーションのために、ワークショップフォルダのルートに新しい main.js で始め、必要とされる import を追加します:
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';
The data source we are going to use requires an access key. Please read the terms at https://openmaptiles.com/hosting/, where you can also get your own key. The code below assigns the key to a constant we're going to use later:

使おうとしているデータソースは、アクセスキーが必要です。自身のキーも取得できる https://openmaptiles.com/hosting/ で項目を読みます。コードの下部にキーをあとで使う定数(const)に割り当てます:
// See https://openmaptiles.com/hosting/ for terms and access key
const key = '<your-access-key-here>';
The map we're going to create here is the same that we have used in previous exercises:

ここに作成するマップは、前回の演習で使われたのと同じです:
const map = new Map({
 target: 'map-container',
 view: new  View({
  center: [0, 0],
  zoom: 2
 })
});
The layer type we are going to use now is VectorTileLayer, with a VectorTileSource:

今、使うレイヤタイプは VectorTileLayer で、VectorTileSource と一緒に使います:
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);
Our data source provides only zoom levels 0 to 14, so we need to configure custom tile grid. Vector tile layers are usually optimized for a tile size of 512 pixels, which we also configured with the tile grid. The data provider also requires us to display some attributions.

データソースは、ズームレベル 0 から 14 までだけ提供するので、カスタムタイルグリッドを設定する必要があります。ベクタタイルレイヤは、通常、512 ピクセルのタイルサイズに最適化され、タイルグリッドで設定もされます。データプロバイダ(提供者)も出典(attribution)を表示するために必要です。

As you can see, a VectorTileSource is configured with a format and a url, just like a VectorLayer. The MVT format parses Mapbox Vector Tiles.

見た通り、VectorTileSource は、VectorLayer のように、format と url で設定します。

The working example at http://localhost:3000/ shows an unstyled vector map like this:

http://localhost:3000/ で演習例は、このようなスタイルされていないベクタマップを表示します:

A world map without style

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

user@deb9-vmw:~/openlayers-workshop-en$ cp index.html index.html_vectordata
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;
   }
  </style>
 </head>
 <body>
  <div id="map-container"></div>
 </body>
</html>
「Vector Data」で使用した main.js のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp main.js main.js_style
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';
// 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); 
「MapTiler CLOUD」のアクセスキーを取得するためにホームページ(https://cloud.maptiler.com/)右上の「Sign in」をクリックします。
「Sign in or create account」ページのアカウント作成方法のうち、Google アカウントがあったので、「Sign in with Google」をクリックします。
Google のログインページが表示されるので、ログインします。
「Get started」ページが表示されるので、左側の「Account」をクリックします。
「Account」の「Settings」ページが表示されるので、左側の「key」をクリックして、「Key」を確認します。
const key = '<your-access-key-here>'; に key を入力します。

http://localhost:3000/ とブラウザでマップを開きます。(もし開かなければ、'npm start' を実行してください。



2018年9月26日水曜日

OpenLayers5 Workshop - 2.7 Making it look nice

2 Vector Data
2.7 Making it look nice
見栄えを良くする

At this point we have a feature editor with basic import, editing, and export functionality. But we haven't spent any time trying to make the features look nice. When you create a vector layer in OpenLayers, you get a set of default styles. The editing interactions (draw and modify) also come with their own default styles. You may have noticed how geometries had a thicker stroke during editing. This behavior can be controlled by providing a style option to your vector layer and editing interactions.

このポイントは、基本的なインポートと編集、エクスポート機能があるフィーチャエディタがあります。しかし、フィーチャの見栄えを良くさせる試みに全く時間を使っていません。OpenLayers でベクタレイヤを作成するとき、一連のデフォルトスタイルを取得します。editing インストラクション(draw と modify)も、それら自身のデフォルトスタイルを備えています。ジオメトリは編集中により太いストロークをどのように持っていたか気がついているでしょう。この動作は、ベクタレイヤにスタイルオプションと editing インストラクションを提供することによって制御されます。

Static style
静的スタイル

If we wanted to give all features the same style, we could configure our vector layer like this:

もしすべてのフィーチャに同じスタイルを与えるなら、ベクタレイヤをこのように設定します:
const layer = new VectorLayer({
 source: source,
 style: new Style({
  fill: new Fill({
   color: 'red'
  }),
  stroke: new Stroke({
   color: 'white'
  })
 })
});
It is also possible to set the style property to an array of styles. This allows rendering of a cased line (a wide stroke below and a narrower one on top), for example.

スタイルプロパティをスタイルの配列に設定することも可能です。例えば、台形ライン(下が広く上が狭いストローク)の描画を許可します。

While there isn't really a good justification of it here, for the sake of this exercise we'll take advantage of dynamic styling.

その良い根拠はここには本当にないですが、この演習のために、動的スタイリングの有利な点を使用します。

Dynamic style
動的スタイル

When you want to make decisions about how each feature should get rendered based on something about the feature or the current view resolution, you can configure a vector layer with a style function. This function gets called with each feature at each render frame, so it is important to write an efficient function if you have many features and want to maintain good rendering performance.

各々のフィーチャがフィーチャと現在のビューの投影法を元に描画される方法について決定するとき、ベクタレイヤをスタイル(style)ファンクションで設定できます。このファンクションは各々の描画フレームの各々のフィーチャで呼び出されるので、多くのフィーチャがあり良好な描画パフォーマンスを維持したいなら効率的なファンクションを書くことが重要です。

Here is an example that renders features using one of two styles depending on whether the "name" attribute starts with "A-M" or "N-Z" (a completely contrived example).

ここに "name" 属性が "A-M" または "N-Z" で開始するかによる2つのスタイルの1つを使用してフィーチャを描画する(全く不自然な)例があります。
const layer = new VectorLayer({
 source: source,
 style: function(feature, resolution) {
  const name = feature.get('name').toUpperCase();
  return name < "N" ? style1 : style2; // assuming these are created elsewhere
 }
});
Styling based on geometry area
ジオメトリエリアを元とするスタイリング

To see how dynamic styling works, we'll create a style function that renders features based on the geometry area. To do this, we're going to make use of a colormap package on npm. We can add this to our dependencies like this:

動的スタイリングがどのように動作するかを確認するために、ジオメトリエリアを元とするフィーチャを描画するスタイルファンクションを作成します。これを実行するために、npm の colormap パッケージを使用します。これを依存関係にこのように追加します:

npm install colormap

Now, we need to import the style constructors, the colormap package, and ol/sphere for spherical area calculations.

では、スタイルコンストラクタと colormap パッケージ、球面の計算のための ol/sphere をインポートします。
import {Fill, Stroke, Style} from 'ol/style';
import {getArea} from 'ol/sphere';
import colormap from 'colormap';
Next we'll write a couple functions to determine a color based on the area of a geometry:

次に、ジオメトリの面積をもととする色を決定する対のファンクションを書きます:
const min = 1e8; // the smallest area
const max = 2e13; // the biggest area
const steps = 50;
const ramp = colormap({
 colormap: 'blackbody',
 nshades: steps
});
function clamp(value, low, high) {
 return Math.max(low, Math.min(value, high));
}
function getColor(feature) {
 const area = getArea(feature.getGeometry());
 const f = Math.pow(clamp((area - min) / (max - min), 0, 1), 1 / 2);
 const index = Math.round(f * (steps - 1));
 return ramp[index];
}
And now we can add a function that creates a style with a fill color based on the geometry area. Set this function as the style property of your vector layer:

それでは、ジオメトリの面積をもとに塗りつぶし色(fill color)でスタイルを作成するのファンクションを追加できます。このファンクションをベクタレイヤのスタイルプロパティとして設定します:
const layer = new VectorLayer({
 source: source,
 style: function(feature) {
  return new Style({
   fill: new Fill({
    color: getColor(feature)
   }),
   stroke: new Stroke({
    color: 'rgba(255,255,255,0.8)'
   })
  });
 }
});
Features colored by area

■□ Debian9 で試します■□
「Static style」の例を表示します。前回使用した main.js のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp main.js main.js_dawnload user@deb9-vmw:~/openlayers-workshop-en$ vim main.js
import 'ol/ol.css';
import GeoJSON from 'ol/format/GeoJSON':
import Map from 'ol/Map';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import DragAndDrop from 'ol/interaction/DragAndDrop';
import Modify from 'ol/interaction/Modify';
import Draw from 'ol/interaction/Draw';
import Snap from 'ol/interaction/Snap';
import sync from 'ol-hashed';
import Style from 'ol/style/Style';
import Fill from 'ol/style/Fill';
import Stroke from 'ol/style/Stroke';
const map = new Map({
 target: 'map-container',
 view: new View({
  center: [0, 0],
  zoom: 2
 })
}); 
sync(map);
const source = new VectorSource();

const layer = new VectorLayer({
 source: source,
 style: new Style({
  fill: new Fill({
   color: 'red'
  }),
  stroke: new Stroke({
   color: 'white'
  })
 })
});
map.addLayer(layer);
map.addInteraction(new DragAndDrop({
 source: source,
 formatConstructors: [GeoJSON]
}));

map.addInteraction(new Modify({
 source: source
}));

map.addInteraction(new Draw({
 type: 'Polygon',
 source: source
}));

map.addInteraction(new Snap({
 source: source
}));
const clear = document.getElementById('clear');
clear.addEventListener('click', function() {
 source.clear();
});
const format = new GeoJSON({featureProjection: 'EPSG:3857'});
const download = document.getElementById('download');
source.on('change', function() {
 const features = source.getFeatures();
 const json = format.writeFeatures(features);
 download.href = 'data:text/json;charset=utf-8,' + json;
});
http://localhost:3000/ とブラウザでマップを開きます。(もし開かなければ、'npm start' を実行してください。


「Dynamic style」の例を表示します。main.js を次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ vim main.js
import 'ol/ol.css';
import GeoJSON from 'ol/format/GeoJSON':
import Map from 'ol/Map';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import DragAndDrop from 'ol/interaction/DragAndDrop';
import Modify from 'ol/interaction/Modify';
import Draw from 'ol/interaction/Draw';
import Snap from 'ol/interaction/Snap';
import sync from 'ol-hashed';
import Style from 'ol/style/Style';
import Fill from 'ol/style/Fill';
import Stroke from 'ol/style/Stroke';
const map = new Map({
 target: 'map-container',
 view: new View({
  center: [0, 0],
  zoom: 2
 })
}); 
sync(map);

const source = new VectorSource();
/**
 * const layer = new VectorLayer({
 *  source: source,
 *  style: new Style({
 *   fill: new Fill({
 *    color: 'red'
 *    }),
 *   stroke: new Stroke({
 *    color: 'white'
 *   })
 *  })
 * });
 */
const layer = new VectorLayer({
 source: source,
 style: function(feature, resolution) {
  const name = feature.get('name').toUpperCase();
   return name < "N" ? style1 : style2;
 }
});
const style1 = new Style({
 fill: new Fill({
  color: 'red'
  }),
 stroke: new Stroke({
  color: 'white'
 })
});
const style2 = new Style({
 fill: new Fill({
  color: 'blue'
  }),
 stroke: new Stroke({
  color: 'yellow'
 })
});
map.addLayer(layer);
map.addInteraction(new DragAndDrop({
 source: source,
 formatConstructors: [GeoJSON]
}));

map.addInteraction(new Modify({
 source: source
}));

map.addInteraction(new Draw({
 type: 'Polygon',
 source: source
}));

map.addInteraction(new Snap({
 source: source
}));
const clear = document.getElementById('clear');
clear.addEventListener('click', function() {
 source.clear();
});
const format = new GeoJSON({featureProjection: 'EPSG:3857'});
const download = document.getElementById('download');
source.on('change', function() {
 const features = source.getFeatures();
 const json = format.writeFeatures(features);
 download.href = 'data:text/json;charset=utf-8,' + json;
});
http://localhost:3000/ とブラウザでマップを開きます。


「Styling based on geometry area」の例を表示します。 colormap パッケージをインストールします。

npm install colormap

main.js を次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ vim main.js
import 'ol/ol.css';
import GeoJSON from 'ol/format/GeoJSON':
import Map from 'ol/Map';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import DragAndDrop from 'ol/interaction/DragAndDrop';
import Modify from 'ol/interaction/Modify';
import Draw from 'ol/interaction/Draw';
import Snap from 'ol/interaction/Snap';
import sync from 'ol-hashed';
import {Fill, Stroke, Style} from 'ol/style';
import {getArea} from 'ol/sphere';
import colormap from 'colormap'; 
const min = 1e8; // the smallest area
const max = 2e13; // the biggest area
const steps = 50;
const ramp = colormap({
 colormap: 'blackbody',
 nshades: steps
});
function clamp(value, low, high) {
 return Math.max(low, Math.min(value, high));
}
function getColor(feature) {
 const area = getArea(feature.getGeometry());
 const f = Math.pow(clamp((area - min) / (max - min), 0, 1), 1 / 2);
 const index = Math.round(f * (steps - 1));
 return ramp[index];
}
const map = new Map({
 target: 'map-container',
 view: new View({
  center: [0, 0],
  zoom: 2
 })
}); 
sync(map);

const source = new VectorSource();
/**
 * const layer = new VectorLayer({
 *  source: source,
 *  style: new Style({
 *   fill: new Fill({
 *    color: 'red'
 *    }),
 *   stroke: new Stroke({
 *    color: 'white'
 *   })
 *  })
 * });
 */
/**
 * const layer = new VectorLayer({
 *  source: source,
 *  style: function(feature, resolution) {
 *   const name = feature.get('name').toUpperCase();
 *    return name < "N" ? style1 : style2;
 *  }
 * });
 * const style1 = new Style({
 *  fill: new Fill({
 *   color: 'red'
 *   }),
 *  stroke: new Stroke({
 *   color: 'white'
 *  })
 * });
 * const style2 = new Style({
 *  fill: new Fill({
 *   color: 'blue'
 *   }),
 *  stroke: new Stroke({
 *   color: 'yellow'
 *  })
 * });
 */
const layer = new VectorLayer({
 source: source,
 style: function(feature) {
  return new Style({
   fill: new Fill({
    color: getColor(feature)
   }),
   stroke: new Stroke({
    color: 'rgba(255,255,255,0.8)'
   })
  });
 }
});
map.addLayer(layer);
map.addInteraction(new DragAndDrop({
 source: source,
 formatConstructors: [GeoJSON]
}));

map.addInteraction(new Modify({
 source: source
}));

map.addInteraction(new Draw({
 type: 'Polygon',
 source: source
}));

map.addInteraction(new Snap({
 source: source
}));
const clear = document.getElementById('clear');
clear.addEventListener('click', function() {
 source.clear();
});
const format = new GeoJSON({featureProjection: 'EPSG:3857'});
const download = document.getElementById('download');
source.on('change', function() {
 const features = source.getFeatures();
 const json = format.writeFeatures(features);
 download.href = 'data:text/json;charset=utf-8,' + json;
});
http://localhost:3000/ とブラウザでマップを開きます。


OpenLayers5 Workshop - 2.6 Downloading features

2 Vector Data
2.6 Downloading features
フィーチャをダウンロード

After uploading data and editing it, we want to let our users download the result. To do this, we'll serialize our feature data as GeoJSON and create an <a> element with a download attribute that triggers the browser's file save dialog. At the same time, we'll add a button to the map that let's users clear existing features and start over.

データをアップロードして編集した後、ユーザが結果をダウンロードできるようにします。これをするために、フィーチャデータを GeoJSON としてシリアル化し、ブラウザのファイル保存ダイアログをトリガ(動作開始)する download 属性と共う <a> エレメントを作成します。同時に、ユーザが既存のフィーチャを削除し、やり直すボタンをマップに追加します。

First, we need a bit of markup to represent the buttons. Add the following elements below the map-container in your index.html:

最初に、ボタンを表示する少しのマークアップが必要です。index.html の map-container の下に次のエレメントを追加します:
<div id="tools">
 <a id="clear">Clear</a>
 <a id="download" download="features.json">Download</a>
</div>
Now we need some CSS to make the buttons look right. Add something like this to the <style> element in index.html:

次に、右の方に見えるボタンを作るためのいくつかの CSS が必要です。 index.html にこのようなものを <style> エレメントに追加します:
#tools {
 position: absolute;
 top: 1rem;
 right: 1rem;
}
#tools a {
 display: inline-block;
 padding: 0.5rem;
 background: white;
 cursor: pointer;
}
Clearing features is the easier part, so we'll do that first. The vector source has a source.clear() method. We want clicks on the "Clear" button to call that method, so we'll add a listener for click in our main.js:

フィーチャの削除は簡単な部分なので、最初に行います。ベクタソース(vector source)は source.clear() メソッドがあります。メッソドを呼び出すために "Clear" ボタンをクリックしたいので、main.js に click のリスナを追加します:
const clear = document.getElementById('clear');
clear.addEventListener('click', function() {
 source.clear();
});
To serialize our feature data for download, we'll use a GeoJSON format. Since we want the "Download" button to work at any time during editing, we'll serialize features on every change event from the source and construct a data URI for the anchor element's href attribute:

ダウンロード用のフィーチャデータをシリアル化するために、GeoJSON フォーマットを使います。編集中いつでも動作する "Download" ボタンがほしいので、いつの change イベントでもソースからフィーチャをシリアル化し、アンカーエレメントの href 属性用のデータ URI を構築します:
const format = new GeoJSON({featureProjection: 'EPSG:3857'});
const download = document.getElementById('download');
source.on('change', function() {
 const features = source.getFeatures();
 const json = format.writeFeatures(features);
 download.href = 'data:text/json;charset=utf-8,' + json;
});
Buttons to clear and download data

■□ Debian9 で試します■□
前回使用した index.html のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp index.html index.html_snap
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;
    background-color: #04041b;
   }
   #tools {
    position: absolute;
    top: 1rem;
    right: 1rem;
   }
   #tools a {
    display: inline-block;
    padding: 0.5rem;
    background: white;
    cursor: pointer;
   }
  </style>
 </head>
 <body>
  <div id="map-container"></div>
  <div id="tools">
   <a id="clear">Clear</a>
   <a id="download" download="features.json">Download</a>
  </div>
 </body>
</html>
前回使用した main.js のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp main.js main.js_snap user@deb9-vmw:~/openlayers-workshop-en$ vim main.js
import 'ol/ol.css';
import GeoJSON from 'ol/format/GeoJSON':
import Map from 'ol/Map';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import DragAndDrop from 'ol/interaction/DragAndDrop';
import Modify from 'ol/interaction/Modify';
import Draw from 'ol/interaction/Draw';
import Snap from 'ol/interaction/Snap';
import sync from 'ol-hashed';
const map = new Map({
 target: 'map-container',
 view: new View({
  center: [0, 0],
  zoom: 2
 })
}); 
sync(map);

const source = new VectorSource();

const layer = new VectorLayer({
 source: source
});
map.addLayer(layer);

map.addInteraction(new DragAndDrop({
 source: source,
 formatConstructors: [GeoJSON]
}));

map.addInteraction(new Modify({
 source: source
}));

map.addInteraction(new Draw({
 type: 'Polygon',
 source: source
}));

map.addInteraction(new Snap({
 source: source
}));

const clear = document.getElementById('clear');
clear.addEventListener('click', function() {
 source.clear();
});

const format = new GeoJSON({featureProjection: 'EPSG:3857'});
const download = document.getElementById('download');
source.on('change', function() {
 const features = source.getFeatures();
 const json = format.writeFeatures(features);
 download.href = 'data:text/json;charset=utf-8,' + json;
});
http://localhost:3000/ とブラウザでマップを開きます。(もし開かなければ、'npm start' を実行してください。

三角形を描画します。(地図は表示しません。そのデータもダウンロードされてしまいます。)


「Download」ボタンをクリックします。


ダイアログで「OK」ボタンをクリックします。


ファイルがダウンロードディレクトリに保存されます。


内容は次のようになていました。
{"type":"FeatureCollection","features":
 [{"type":"Feature","geometry":
  {"type":"Polygon","coordinates":
   [[
    [76.76796875,59.17592824927138],
    [56.02578125,40.97989806962016],
    [93.99453125,40.17887331434699],
    [76.76796875,59.17592824927138]
   ]]
  },
  "properties":null
}]}

OpenLayers5 Workshop - 2.5 Snapping

2 Vector Data
2.5 Snapping
スナップ

You may have noticed that it is easy to draw features that don't line up nicely with existing features. In addition, when modifying features, we can break topology — adding a void between polygons that were previously adjacent. The Snap interaction can be used to help preserve topology while drawing and editing features.

既存のフィーチャと一緒にきちんと並ばないフィーチャを描画することは簡単であることに注意します。加えて、フィーチャを変形するとき、トポロジを壊すことができ - 元は隣りにあったポリゴンの間の空所を追加します。Snap インタラクションは、フィーチャを描画および編集する間、トポロジを維持するのに役立てるために使われます。

First, import the Snap interaction into your main.js:

最初に、Snap インタラクションを main.js にインポートします:

import Snap from 'ol/interaction/Snap';

As with the other editing interactions, we'll configure the snap interaction to work with our vector source and add it to the map:

他の編集インタラクションと同様に、ベクタソースで動作し、マップに追加するために snap インタラクションを設定します:

map.addInteraction(new Snap({
 source: source
}));

With the draw, modify, and snap interactions all active, we can edit data while maintaining topology.

draw と modify、snap インタラクションがすべて有効で、トポロジを維持してる間、データを編集できます。

Uniting nations with the snap interaction

■□ Debian9 で試します■□
前回使用した main.js のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp main.js main.js_draw user@deb9-vmw:~/openlayers-workshop-en$ vim main.js
import 'ol/ol.css';
import GeoJSON from 'ol/format/GeoJSON':
import Map from 'ol/Map';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import DragAndDrop from 'ol/interaction/DragAndDrop';
import Modify from 'ol/interaction/Modify';
import Draw from 'ol/interaction/Draw';
import Snap from 'ol/interaction/Snap';
import sync from 'ol-hashed';
const map = new Map({
 target: 'map-container',
 view: new View({
  center: [0, 0],
  zoom: 2
 })
}); 
sync(map);

const source = new VectorSource();

const layer = new VectorLayer({
 source: source
});
map.addLayer(layer);

map.addInteraction(new DragAndDrop({
 source: source,
 formatConstructors: [GeoJSON]
}));

map.addInteraction(new Modify({
 source: source
}));

map.addInteraction(new Draw({
 type: 'Polygon',
 source: source
}));

map.addInteraction(new Snap({
 source: source
}));
http://localhost:3000/ とブラウザでマップを開きます。(もし開かなければ、'npm start' を実行してください。

1辺が接している三角形を作成します。2個めの三角形を作成するとき、頂点にポインタを合わせるのが簡単にできます。

三角形を描画していきます。
頂点を合わせてダブルクリックします。

Snap インタラクションを設定していないと、接する辺を変形させたときに一方の三角形の辺(境界線)しか変形しません。(両方の境界線をつかむのが難しくなります。)


■□ここまで■□

OpenLayers5 Workshop - 2.4 Drawing new features

2 Vector Data
2.4 Drawing new features
新しいフィーチャを描画

Our feature editor can now be used for loading data and modifying features. Next up, we'll add a Draw interaction to allow people to draw new features and add them to our source.

フィーチャエディタは、現在、データをロードしフィーチャを変形することに使用されます。次は、新しいフィーチャを描画しソースに追加すること許可する Draw インタラクションを追加します。

First, import the Draw interaction (in main.js):

最初に、(main.js に)Draw インタラクションをインポートします:

import Draw from 'ol/interaction/Draw';

Now, create a draw interaction configured to draw polygons and add them to our vector source:

次に、ポリゴンを描画するために設定される draw インタラクションを作成しベクタソースに追加します:

map.addInteraction(new Draw({
 type: 'Polygon',
 source: source
}));

The type property of the draw interaction controls what type of geometries are drawn. The value can be any of the GeoJSON geometry types. Note that we could have also imported the GeometryType enum (import GeometryType from 'ol/geom/GeometryType';) and used GeometryType.POLYGON instead of the 'Polygon' string above.

draw インタラクションの type プロパティは、ジオメトリのタイプ(type)が描画されることを制御します。value は、どんな GeoJSON ジオメトリタイプにもできます。GeometryType enum (import GeometryType from 'ol/geom/GeometryType';) をインポートし、そして、上記の 'Polygon' 文字列のかわりに GeometryType.POLYGON を使用していることにも注意してください。

With our draw interaction in place, we can now add new features to our vector source.

適切な draw インタラクションで、ベクタソースに新しいフィーチャを直ちに追加できます。

A new island nation in the Caribbean

■□ Debian9 で試します■□
前回使用した main.js のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp main.js main.js_modify
user@deb9-vmw:~/openlayers-workshop-en$ vim main.js
import 'ol/ol.css';
import GeoJSON from 'ol/format/GeoJSON':
import Map from 'ol/Map';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import DragAndDrop from 'ol/interaction/DragAndDrop';
import Modify from 'ol/interaction/Modify';
import Draw from 'ol/interaction/Draw';
import sync from 'ol-hashed';
const map = new Map({
 target: 'map-container',
 view: new View({
  center: [0, 0],
  zoom: 2
 })
}); 
sync(map);

const source = new VectorSource();

const layer = new VectorLayer({
 source: source
});
map.addLayer(layer);

map.addInteraction(new DragAndDrop({
 source: source,
 formatConstructors: [GeoJSON]
}));

map.addInteraction(new Modify({
 source: source
}));

map.addInteraction(new Draw({
 type: 'Polygon',
 source: source
}));
http://localhost:3000/ とブラウザでマップを開きます。(もし開かなければ、'npm start' を実行してください。

開始点をクリックします。


経過点をクリックします。


終点をダブルクリックします。



■□ここまで■□

OpenLayers5 Workshop - 2.3 Modifying features

2 Vector Data
2.3 Modifying features
フィーチャを変形

Now that we have a way for users to load data into the editor, we want to let them edit features. We'll use the Modify interaction for this, configuring it to modify features on our vector source.

ユーザがデータをエディタにロードする方法があるので、それらにフィーチャを編集させます。このために Modify インストラクションを使い、ベクタソースのフィーチャを変形するためにそれを設定します。

First, import the Modify interaction in your main.js:

最初に、Modify インストラクションを main.js にインポートします:

import Modify from 'ol/interaction/Modify';

Next, create a new interaction connected to the vector source and add it to the map (at the bottom of main.js):

次に、ベクタソースに接続させる新しいインストラクションを作成し map(main.js の下部)に追加します:

map.addInteraction(new Modify({
 source: source
}));

After adding data to the map confirm that you can modify features by dragging their vertices. You can also delete vertices with Alt+Click.

データを map に追加した後に、頂点をドラッグすることによってフィーチャを変形できることを確認します。Alt + Click で頂点を削除することもできます。


■□ Debian9 で試します■□
前回使用した main.js のバックアップを保存して次のように修正します。

user@deb9-vmw:~/openlayers-workshop-en$ cp main.js main.js_drag-drop user@deb9-vmw:~/openlayers-workshop-en$ vim main.js
import 'ol/ol.css';
import GeoJSON from 'ol/format/GeoJSON':
import Map from 'ol/Map';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import DragAndDrop from 'ol/interaction/DragAndDrop';
import Modify from 'ol/interaction/Modify';
import sync from 'ol-hashed';
const map = new Map({
 target: 'map-container',
 view: new View({
  center: [0, 0],
  zoom: 2
 })
}); 
sync(map);

const source = new VectorSource();

const layer = new VectorLayer({
 source: source
});
map.addLayer(layer);

map.addInteraction(new DragAndDrop({
 source: source,
 formatConstructors: [GeoJSON]
}));

map.addInteraction(new Modify({
 source: source
}));
http://localhost:3000/ とブラウザでマップを開きます。(もし開かなければ、'npm start' を実行してください。

国境の頂点に沿ってポイントのマークが表示されます。


ドラッグすると国境の頂点が変形されます。ダブルクリックして確定します。


■□ここまで■□