OpenLayers

Feature Frenzy

[email protected]


[email protected]

New to OpenLayers?


npm create ol-app my-app
cd my-app
npm start
    

Let's dive in! ๐Ÿš€

ol@7 is here!

new in ol@7 ๐ŸŽ‰

webgl vector rendering ๐Ÿงช

low level style api
with default shaders for common use cases


import Layer from 'ol/layer/Layer.js';
import VectorLayerRenderer from 'ol/renderer/webgl/VectorLayer.js';
import {packColor} from 'ol/renderer/webgl/shaders.js';

class WebGLLayer extends Layer {
  createRenderer() {
    return new VectorLayerRenderer(this, {
      fill: {
        attributes: {
          color: (feature) => packColor(feature.get('color')),
          opacity: () => 0.6,
        },
      },
      stroke: {
        attributes: {
          color: () => packColor([0, 0, 0, 1]),
          width: () => 3,
        },
      },
    });
  }
}
    

default vertex shader (fill)


const DECODE_COLOR_EXPRESSION = `vec3(
  fract(floor(a_color / 256.0 / 256.0) / 256.0),
  fract(floor(a_color / 256.0) / 256.0),
  fract(a_color / 256.0)
);`;

const FILL_VERTEX_SHADER = `
  precision mediump float;
  uniform mat4 u_projectionMatrix;
  attribute vec2 a_position;
  attribute float a_color;
  attribute float a_opacity;
  varying vec3 v_color;
  varying float v_opacity;

  void main(void) {
    gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0);
    v_color = ${DECODE_COLOR_EXPRESSION}
    v_opacity = a_opacity;
  }`;
    

low level style api
building blocks


import VectorLayerRenderer from 'ol/renderer/webgl/VectorLayer.js';

new VectorLayerRenderer(this, {
  fill: {
    vertexShader: fillVertexShader,
    fragmentShader: fillFragmentShader,
    attributes: fillAttributes,
  },
  stroke: {
    vertexShader: strokeVertexShader,
    fragmentShader: strokeFragmentShader,
    attributes: strokeAttributes,
  },
  point: {
    vertexShader: poiontVertexShader,
    fragmentShader: pointFragmentShader,
    attributes: pointAttributes,
  },
  uniforms,
  postProcesses
});
    

graticule ๐ŸŒ


import Graticule from 'ol/Graticule.js';

const graticule = new Graticule({ showLabels: true });
map.addLayer(graticule);
    

vector editing ๐Ÿ’ช

old style


import Style from 'ol/style/Style';
import Fill from 'ol/style/Fill';
import Stroke from 'ol/style/Stroke';

// previously
layer.setStyle(
  new Style({
    fill: new Fill({
      color: 'orange',
    }),
    stroke: new Stroke({
      color: 'red',
      width: 5,
    }),
  })
);
    

new style ๐ŸŒฑ


// for static styles
layer.setStyle({
  'fill-color': 'orange',
  'stroke-color': 'red',
  'stroke-width': 5,
});
    

link interaction ๐ŸŒฑ


import Link from 'ol/interaction/Link';

// sync map state with the URL
map.addInteraction(new Link());
    

vector tiles
single vectortile source


import MapboxVectorLayer from 'ol/layer/MapboxVector';

new MapboxVectorLayer({
  styleUrl:
    'https://api.maptiler.com/maps/bright/style.json',
});
    

ol-mapbox-style
vector, geojson and raster ๐Ÿ˜ฒ


import {apply} 'ol-mapbox-style';
import LayerGroup from 'ol/layer/Group.js';

apply(map, 'https://api.maptiler.com/maps/topo/style.json');
    

can also apply to an ol/layer/Group ๐ŸŒฑ

label and symbol decluttering
also per-style ๐ŸŒฑ


import VectorTileLayer from 'ol/layer/VectorTile';

new VectorTileLayer({
  declutter: true,
  style: {
    'icon-declutter-mode': 'none', // or 'obstacle'
    'icon-src': '/data/icon.png',
  };
});
    

rich text style ๐ŸŒฑ


textStyle.setText([
  feature.getId(),
  'bold 13px Calibri,sans-serif',
  ` ${feature.get('name')}`,
  '',
  '\n',
  '',
  `${feature.get('kWp')} kWp`,
  'italic 11px Calibri,sans-serif',
])
    

webgl tiles
(geotiff sources)


import GeoTIFF from 'ol/source/GeoTIFF';

const source = new GeoTIFF({
  sources: [
    {url: 'https://example.com/world.tif'},
  ]
});
    

webgl tiles
(geotiff sources)


import GeoTIFF from 'ol/source/GeoTIFF';

const source = new GeoTIFF({
  sources: [
    {url: 'https://example.com/B08.tif'},
    {url: 'https://example.com/B04.tif'},
    {url: 'https://example.com/B02.tif'},
  ]
});
    

webgl tiles
(band math)


const red = ['band', 3];
const nir = ['band', 4];
const diff = ['-', nir, red];
const sum = ['+', nir, red];

const ndvi = ['/', diff, sum];
    

webgl tiles
(style expressions)


const layer = new TileLayer({
  source: new GeoTIFF(options),
  style: {
    color: [
      'interpolate', ['linear'], ndvi,
      -1, 'rgb(100, 100, 100)',
      1, 'rgb(0, 69, 0)'
    ],
  }
})
    

webgl tiles
(variables)


const style = {
  variables: {
    seaLevel: 0,
  },
  color: [
    'case',
    ['<=', elevation, ['var', 'seaLevel']],
    [139, 212, 255, 1],
    [139, 212, 255, 0],
  ],
}
    

webgl tiles
(variables)


slider.addEventListener('input', () => {
  layer.updateStyleVariables({
    seaLevel: parseFloat(slider.value)
  });
});
    

resolving views ๐Ÿช„


import GeoTIFF from 'ol/source/GeoTIFF';

const source = new GeoTIFF(options);

const map = new Map({
  target: 'container',
  layers: [new TileLayer({source})],
  view: source.getView(),
});
    

pixel data ๐ŸŒฑ


map.on('pointermove', event => {

  // this next line is the new part!
  layer.getData(event.pixel);

  // do something with the pixel data
  console.log(data);
});
    

map load events ๐ŸŒฑ


const element = map.getTargetElement();

map.on('loadstart', () => {
  element.classList.add('spinner');
});

map.on('loadend', () => {
  element.classList.remove('spinner');
});
    

more new webgl tile features ๐ŸŒฑ

map composition history

splitting and mixing renderers

dom element structure


<div class="ol-layers"></div>
  <div class="ol-layer"></div>
  <div class="svg-layer"></div>
  <canvas class="webgl-layer"></canvas>
</div>
    

custom renderer ๐Ÿš€
interactive svg


import Layer from 'ol/layer/Layer.js';

const container = document.createElement('div');
fetch(url)
  .then(response => response.text())
  .then(svg => {
    container.innerHTML = svg;
  });

const svgLayer = new Layer({
  render(frameState) {
    // transform container to match frameState
    // (center, resolution, size)
    return container;
  },
});
    

webgl points layer
style expressions


import WebGLPointsLayer from 'ol/layer/WebGLPoints.js';

new WebGLPointsLayer({
  className: 'webgl-layer',
  source: source,
  style: {
    variables, // contains the current year of the animation
    filter, // only points within 10 years back from current year,
    symbol: {
      symbolType: 'circle',
      size, // size based on mass of the meteorite and decay
      color: 'rgb(255, 0, 0)',
      opacity: ['*', 0.5, decay],
    },
  },
});
    

DX

OpenLayers is JSDoc typed
We publish type definitions
You get type checking, autocomplete and hints! ๐Ÿคฉ

thanks

Consider becoming a sponsor

project:
https://github.com/sponsors/openlayers

developers: