Skip to content

Latest commit

 

History

History
869 lines (734 loc) · 16.7 KB

slides.md

File metadata and controls

869 lines (734 loc) · 16.7 KB
title layout favicon contextMenu fonts
OpenLayers Feature Frenzy
fact
false
sans
Open Sans

OpenLayers Feature Frenzy

circa 2024


layout: center zoom: 1.5

New to OpenLayers?

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

Let's dive in


title: Basic Map layout: center

Basic Map

```js
import {Map, View} from 'ol';
import Layer from 'ol/layer/Tile';
import Source from 'ol/source/OSM';

const map = new Map({
  target: 'map',
  layers: [
    new Layer({source: new Source()})
  ],
  view: new View({center: [0, 0], zoom: 2})
});
```
```js
import {Map, View} from 'ol';
import Layer from 'ol/layer/WebGLTile';
import Source from 'ol/source/ImageTile';
import {useGeographic} from 'ol/proj';

useGeographic();

const map = new Map({
  target: 'map',
  layers: [
    new Layer({source: new Source({
      url: 'https://example.com/{z}/{x}/{y}.png'
    })})
  ],
  view: new View({center: [-58, 0], zoom: 2})
});
```

title: Basic Map Example layout: iframe-unscaled url: ./examples/basic-map.html


title: A Bit of History layout: fact

A bit of history


title: Google Maps layout: image image: /google-maps.png backgroundSize: contain



title: Google Maps (cont.) layout: center

Google Maps is Back

import Google from 'ol/source/Google.js';

const source = new Google({
  key: 'your key here',
  mapType: 'roadmap',
  scale: 'scaleFactor2x',
  highDpi: true,
});

title: Google Maps Example layout: iframe-unscaled url: ./examples/google-maps.html


title: OGC Tiles layout: center

And Standards Too

```js
import Source from 'ol/source/OGCMapTile.js';
import Layer from 'ol/layer/Tile.js';

const layer = new Layer({
  source: new Source({
    url: 'https://example.com/ogc/raster/tiles',
  })
});
```
```js
import Source from 'ol/source/OGCVectorTile.js';
import Layer from 'ol/layer/VectorTile.js';
import MVT from 'ol/format/MVT.js';

const layer = new Layer({
  source: new Source({
    url: 'https://example.com/ogc/vector/tiles',
    format: new MVT(),
  })
});
```

title: OGC Map Tiles Example layout: iframe-unscaled url: ./examples/ogc-map-tiles.html


title: Projections layout: fact

What about

projections?


title: GeoTIFF Reprojection Example layout: iframe-unscaled url: ./examples/geotiff-reprojection.html


title: GeoTIFF Reprojection layout: center

Projections

```js
import GeoTIFF from 'ol/source/GeoTIFF.js';
import Map from 'ol/Map.js';
import TileLayer from 'ol/layer/WebGLTile.js';
import View from 'ol/View.js';
import proj4 from 'proj4';
import {register} from 'ol/proj/proj4.js';

// prior to [email protected]
proj4.defs('EPSG:32636', '+proj=utm +zone=36 +datum=WGS84 +units=m ...');
register(proj4);

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

const map = new Map({
  target: 'map',
  layers: [new TileLayer({source})],
  view: new View({
    zoom: 12, center: [3730842, 1884545]}),
});
```
```js
import GeoTIFF from 'ol/source/GeoTIFF.js';
import Map from 'ol/Map.js';
import TileLayer from 'ol/layer/WebGLTile.js';
import View from 'ol/View.js';
import proj4 from 'proj4';
import {register} from 'ol/proj/proj4.js';

// with [email protected], prior to [email protected]
register(proj4);

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

const map = new Map({
  target: 'map',
  layers: [new TileLayer({source})],
  view: new View({
    zoom: 12, center: [3730842, 1884545],
  }),
});
```
```js
import GeoTIFF from 'ol/source/GeoTIFF.js';
import Map from 'ol/Map.js';
import TileLayer from 'ol/layer/WebGLTile.js';
import View from 'ol/View.js';

// built-in support for utm transforms
const source = new GeoTIFF({
  sources: [{url: 'https://example.com/cog.tif'}],
});

const map = new Map({
  target: 'map',
  layers: [new TileLayer({source})],
  view: new View({
    zoom: 12, center: [3730842, 1884545],
  }),
});
```
```js
import GeoTIFF from 'ol/source/GeoTIFF.js';
import Map from 'ol/Map.js';
import TileLayer from 'ol/layer/WebGLTile.js';
import View from 'ol/View.js';
import {useGeographic} from 'ol/proj.js';

useGeographic();

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

const map = new Map({
  target: 'map',
  layers: [new TileLayer({source})],
  view: new View({
    zoom: 12, center: [33.514, 16.688],
  }),
});
```
```js
import GeoTIFF from 'ol/source/GeoTIFF.js';
import Map from 'ol/Map.js';
import TileLayer from 'ol/layer/WebGLTile.js';
import View from 'ol/View.js';

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

const map = new Map({
  target: 'map',
  layers: [new TileLayer({source})],
  view: new View({zoom: 12}),
});

source.getView().then(({center}) => {
  map.getView().setCenter(center);
});
```

layout: fact

How else can raster data be manipulated?


title: Band Math layout: center

Band Math

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

title: Band Math (cont.) layout: center

Band Math

import GeoTIFF from 'ol/source/GeoTIFF.js';
import TileLayer from 'ol/layer/WebGLTile.js';

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

title: Band Math Example layout: iframe-unscaled url: ./examples/band-math.html


title: Sentinel Hub layout: center

Sentinel Hub

import SentinelHub from 'ol/source/SentinelHub.js';
const source = new SentinelHub({
  data: [{
    type: 'sentinel-2-l2a',
    dataFilter: {
      timeRange: {from: '2024-08-29T00:00:00Z', to: '2024-08-30T00:00:00Z'},
    },
  }],
  evalscript: {
    setup: () => ({input: ['B12', 'B08', 'B04'], output: {bands: 3}}),
    evaluatePixel: (sample) => [2 * sample.B12, 2 * sample.B08, 2 * sample.B04],
  },
});

title: Sentinel Hub Example layout: iframe-unscaled url: ./examples/sentinel-hub.html


title: Copernicus Browser layout: center

Copernicus Data Space Ecosystem

import SentinelHub from 'ol/source/SentinelHub.js';

const source = new SentinelHub({
  url: 'https://sh.dataspace.copernicus.eu/api/v1/process',
  auth: {
    clientId: 'YOUR-CLIENT-ID',
    clientSecret: 'YOUR-CLIENT-SECRET',
    tokenUrl:
      'https://identity.dataspace.copernicus.eu/auth/' +
      'realms/CDSE/protocol/openid-connect/token',
  },
  data: [],
  evalscript: '...',
});

layout: fact

What else is new?


title: Flow Layer layout: image image: /windy.png

<style> h1.big { text-align: center; font-size: 10rem; margin: 10% 0; font-weight: bold; font-style: italic; } </style>

Wind!


title: Flow Layer Example layout: iframe-unscaled url: ./examples/flow-layer.html


title: Continuous Improvements layout: fact

Continuous improvements


title: (Text) Style and Rendering layout: center

(Text) Style and Rendering

```js
new VectorLayer({
  style: (feature) => new Style({
    text: new Text({
      text: feature.get('name')
    })
  })
});
```
```js
new VectorLayer({
  style: (feature) => new Style({
    text: new Text({
      text: feature.get('name'),
      // v4.4.0 - September 2017
      placement: 'line'
    })
  })
});
```
```js
new VectorLayer({
  // v4.5.0 - November 2017
  declutter: true,
  style: (feature) => new Style({
    text: new Text({
      text: feature.get('name'),
      // v4.4.0 - September 2017
      placement: 'line'
    })
  })
});
```

title: Decluttering layout: image image: /declutter.png backgroundSize: contain



title: (Text) Style and Rendering layout: center

(Text) Style and Rendering

```js
new VectorLayer({
  // v4.5.0 - November 2017
  declutter: true,
  style: (feature) => new Style({
    text: new Text({
      text: feature.get('name'),
      // v4.4.0 - September 2017
      placement: 'line'
    })
  })
});
```
```js
new VectorLayer({
  // v4.5.0 - November 2017
  declutter: true,
  style: (feature) => new Style({
    font: '13px Calibri,sans-serif'
    text: new Text({
      // v6.13.0 - February 2022
      text: [
        feature.getId(),
        'bold 13px Calibri,sans-serif',
        ` ${feature.get('name')}`,
        ''
      ],
      // v4.4.0 - September 2017
      placement: 'line'
    })
  })
});
```
```js
new VectorLayer({
  // v9.0.0 - February 2024
  declutter: 'group-1',
  style: (feature) => new Style({
    font: '13px Calibri,sans-serif'
    text: new Text({
      // v9.0.0 - February 2024
      declutterMode: 'obstacle',
      // v6.13.0 - February 2022
      text: [
        feature.getId(),
        'bold 13px Calibri,sans-serif',
        ` ${feature.get('name')}`,
        ''
      ],
      // v4.4.0 - September 2017
      placement: 'line'
    })
  })
});
```

title: Label Rendering Example layout: iframe-unscaled url: ./examples/declutter.html


title: (Text) Style and Rendering layout: center

(Text) Style – One More Thing

```js
new VectorLayer({
  style: (feature) => new Style({
    text: new Text({
      font: '13px Calibri,sans-serif',
      text: feature.get('name'),
      placement: 'line',
      fill: new Fill({
        color: 'black'
      }),
      stroke: new Stroke({
        color: 'white',
        width: 2
      })
    })
  })
});
```
```js
new VectorLayer({
  style: {
    'text-font': '13px Calibri,sans-serif',
    'text-value': ['get', 'name'],
    'text-placement': 'line',
    'text-fill-color': 'black',
    'text-stroke-color': 'white',
    'text-stroke-width': 2
  }
});
```

layout: fact

API Simplifications


title: Custom tile loaders layout: center

Custom Tile Loaders

```js
import Source from 'ol/source/XYZ.js';

const source = new Source({
  tileUrlFunction([z, x, y]) {
    return `${z}/${x}/${y}.png`;
  },
  tileLoadFunction(tile, url) {
    tile.getImage().src = url;
  }
});
```
```js
import Source from 'ol/source/ImageTile.js';

const source = new Source({
  loader(z, x, y, {signal}) {
    const image = new Image();
    image.src = `${z}/${x}/${y}.png`};
    return image.decode().then(() => createImageBitmap(image));
  }
});
```

title: Custom image loaders layout: center

Image Loaders Too!

```js
import Source from 'ol/source/Image.js';

const source = new Source({
  loader(extent, resolution, pixelRatio) {
    const image = new Image();
    const params = new URLSearchParams({
      'mm-per-pixel': resolution * 1000,
      bbox: extent.join(','),
    });
    image.src = `map?crs=[EPSG:3857]&scale-denominator=1&${query.toString()}`;
    return {image: image.decode().then(() => createImageBitmap(image)), pixelRatio: 1};
  }
});
```
```js
import Source from 'ol/source/Image.js';
import { createLoader } from 'ol/source/static.js';
import { load } from 'ol/Image.js';

const source = new Source({
  loader: createLoader({
    url: 'map.svg',
    load,
  })
});
```

title: Scaled SVG Example layout: iframe-unscaled url: ./examples/scaled-svg.html


layout: fact

Easy upgrades despite breaking changes


title: From ol@7 to ol@10 layout: center

From ol@7 to ol@10

```js
// ol@7
import VectorLayer from 'ol/layer/Vector.js';
import VectorSource from 'ol/source/Vector.js';
import MapboxVectorLayer from 'ol/layer/MapboxVector.js';
import {fromExtent} from 'ol/geom/Polygon.js';
import {fromLonLat} from 'ol/proj.js';
import {map} from './map.js';

const box = [...fromLonLat([16.1, 48.1]), ...fromLonLat([16.2, 48.2])];

const layer = new MapboxVectorLayer({
  styleUrl: 'mapbox://styles/mapbox/bright-v9',
  accessToken: 'Your Mapbox access token from https://mapbox.com/ here',
});
map.addLayer(layer);
const overlay = new VectorLayer({
  source: new VectorSource({
    features: [fromExtent(box)],
  }),
});
overlay.on('prerender', () => map.flushDeclutterItems());
map.addLayer(overlay);

const features = layer.getSource().getFeaturesInExtent(box);
```
```js
// ol@8
import VectorLayer from 'ol/layer/Vector.js';
import VectorSource from 'ol/source/Vector.js';
import {MapboxVectorLayer} from 'ol-mapbox-style';
import {fromExtent} from 'ol/geom/Polygon.js';
import {fromLonLat} from 'ol/proj.js';
import {map} from './map.js';

const box = [...fromLonLat([16.1, 48.1]), ...fromLonLat([16.2, 48.2])];

const layer = new MapboxVectorLayer({
  styleUrl: 'mapbox://styles/mapbox/bright-v9',
  accessToken: 'Your Mapbox access token from https://mapbox.com/ here',
});
map.addLayer(layer);
const overlay = new VectorLayer({
  source: new VectorSource({
    features: [fromExtent(box)],
  }),
});
overlay.on('prerender', () => map.flushDeclutterItems());
map.addLayer(overlay);

const features = layer.getSource().getFeaturesInExtent(box);
```
```js
// ol@9
import VectorLayer from 'ol/layer/Vector.js';
import VectorSource from 'ol/source/Vector.js';
import {MapboxVectorLayer} from 'ol-mapbox-style';
import {fromExtent} from 'ol/geom/Polygon.js';
import {fromLonLat} from 'ol/proj.js';
import {map} from './map.js';

const box = [...fromLonLat([16.1, 48.1]), ...fromLonLat([16.2, 48.2])];

const layer = new MapboxVectorLayer({
  styleUrl: 'mapbox://styles/mapbox/bright-v9',
  accessToken: 'Your Mapbox access token from https://mapbox.com/ here',
});
map.addLayer(layer);
const overlay = new VectorLayer({
  source: new VectorSource({
    features: [fromExtent(box)],
  }),
});
map.addLayer(overlay);

const features = layer.getSource().getFeaturesInExtent(box);
```
```js
// ol@10
import VectorLayer from 'ol/layer/Vector.js';
import VectorSource from 'ol/source/Vector.js';
import {MapboxVectorLayer} from 'ol-mapbox-style';
import {fromExtent} from 'ol/geom/Polygon.js';
import {fromLonLat} from 'ol/proj.js';
import {map} from './map.js';

const box = [...fromLonLat([16.1, 48.1]), ...fromLonLat([16.2, 48.2])];

const layer = new MapboxVectorLayer({
  styleUrl: 'mapbox://styles/mapbox/bright-v9',
  accessToken: 'Your Mapbox access token from https://mapbox.com/ here',
});
map.addLayer(layer);
const overlay = new VectorLayer({
  source: new VectorSource({
    features: [fromExtent(box)],
  }),
});
map.addLayer(overlay);

const features = layer.getFeaturesInExtent(box);
```

title: Thanks layout: fact

Thanks!


[email protected]

[email protected]

https://openlayers.org/feature-frenzy/

https://github.com/openlayers/feature-frenzy/