2018年10月31日水曜日

OpenLayers5 Workshop - 5 Deploying

5 Deploying
5 デプロイ
(訳注:デプロイとは、主にネットワークを通じて提供されるWebアプリケーションなどのシステム開発工程において、システムを利用可能な状態にすることである。[Webilo 辞書、IT用語辞典「デプロイ:https://www.weblio.jp/content/%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4」より]

Throughout the workshop, we've been using a development server to view the examples. This is similar to the setup you would use when developing an application with the ol package. When you're ready to deploy your application, you'll want to create a minified bundle of your application entry point with a build step.

ワークショップを通じて、例を眺めるために開発サーバを使っています。これは、ol パッケージでアプリケーションを開発するとき使うセットアップに似ています。アプリケーションをデプロイする準備ができているとき、ビルド段階でアプリケーションのエントリポイントの縮小版ビルドを作成したくなります。
(訳注:エントリーポイントとは、プログラムを実行するうえで、プログラムやサブルーチンの実行を開始する場所のこと。[ウィキペディア「エントリポイント:https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%83%BC%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88」より]

We've been using webpack for module bundling during development. The webpack.config.js at the root of the workshop directory includes our webpack configuration profile. When we started the development server with npm start, we were running webpack in development mode. In production mode, the bundle is minified. This provides a good starting point for your webpack configuration. Explore the other webpack plugins to see what else you might want to bring in.

開発する間、モジュールバンドルのウェブパックを使います。ワークショップディレクトリのルートにある webpack.config.js は、ウェブパックコンフィギュレーションプロファイルを含みます。npm start で開発サーバを開始したとき、development(開発)モードでウェブパックを運用しています。production(本番)モードで、バンドルは縮小されます。これはウェブパックコンフィギュレーションの良い開始点を提供します。他に取り入れたいものを確かめるために、他のウェブパックプラグインを探してください。

(訳注:広義のモジュールバンドルとは、正しい順番で、複数のモジュール(及び依存性)を1つ(あるいは複数)のファイルへとくっつけることを言います。[Qiita「[意訳]初学者のためのJavaScriptモジュール講座 Part2、モジュールバンドルとは:https://qiita.com/chuck0523/items/c88abe4fac828b7b5f4e」より]

To build assets for deployment, we run our build script from package.json:

デプロイのためのアセットをビルドするために、package.json から build スクリプトを実行します:

(訳注:asset(アセット)は、「資産、財産」という意味ですが、ここでは、作成した html や js ファイルを含む、デプロイに必要なものだと思われます。)

npm run build

This runs webpack --mode=production, but doesn't require that webpack is on our path.

これは、webpack --mode=production を実行しますが、webpack がパス上にある必要はありません。

After the build finishes, you'll have artifacts in the build directory. These are the assets that you would deploy to your production server (or S3, or wherever you want to host your application). You can see what the app looks like by opening the index.html file in your browser.

ビルドが終了した後、build ディレクトリにアーティファクトを得ます。これらは、本番サーバ(または S3、または、アプリケーションを提供したいところどこでも)にデプロイするアセットです。ブラウザで index.html ファイルを開くことによってアプリのようにみえることが確認できます。

(訳注:artifact(アーティファクト)は、「人工物、工芸品」という意味ですが、ここでは、ビルドで生成したしたファイルやフォルダだと思われます。)

open build/index.html

That's it. You're done!

それでおしまい。終了です!

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