2018年10月31日水曜日

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



0 件のコメント: