Skip to content

Commit

Permalink
Merge pull request #164 from openlayers/2024
Browse files Browse the repository at this point in the history
Workshop for 2024 (English)
  • Loading branch information
tschaub authored Dec 1, 2024
2 parents 3da50a6 + 2395a3d commit 1dcf56d
Show file tree
Hide file tree
Showing 51 changed files with 2,898 additions and 3,111 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run archive:en
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
Binary file modified doc/en/basics/map.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/cog/colormap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/cog/false-color.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/cog/ndvi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 7 additions & 5 deletions doc/en/cog/simplified-view.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Simplifying the map's view configuration

In the previous example, we had to configure the map's view with information about the spatial reference system and coordinate location of the image.
In the previous example, we had to configure the map's view with information about the spatial reference system and location of the image.

The first thing we needed to know was an identifier for the spatial reference system. This is used to create an OpenLayers `Projection` (which also needs to know the units):
The first thing we needed to know was an identifier for the spatial reference system. In this case, the GeoTIFF is accompanied by [STAC metadata][stac-metadata] that includes this projection information (see the `proj:epsg` property).

[import:'projection'](../../../src/en/examples/cog/true-color-parts.js)

The second thing we needed to know about the imagery was its coordinate location. This is used to create a bounding box or extent array:
The second piece of metadata we needed to know was the bounding box or extent of the image. This is also included in the [STAC metadata][stac-metadata] in geographic coordinates (see the `bbox` array). We needed to transform this from geographic coordinates into EPSG:32721 (or WGS 84 / UTM zone 21S). OpenLayers has support for transforming coordinates to and from UTM projections, so we used this to transform the image extent.

[import:'extent'](../../../src/en/examples/cog/true-color-parts.js)

With this information, we were finally able to configure the view for the map:
With this information, we were able to configure the view for the map:

[import:'map'](../../../src/en/examples/cog/true-color-parts.js)

Expand All @@ -22,8 +22,10 @@ Update your `main.js` so that the map constructor uses this new method for getti

[import:'map'](../../../src/en/examples/cog/simplified-view.js)

Now you can remove the `projection`, `extent`, and related imports (`View`, `Projection`, and `getCenter`) from your `main.js` file.
Now you can remove the `projection`, `extent`, and related imports (`View`, `transformExtent`, and `getCenter`) from your `main.js` file.

You should find the same result as before at {{book.workshopUrl}}/ – only this time we had to write less code!

![A true color rendering of a Sentinel-2 GeoTIFF](true-color.png)

[stac-metadata]: https://s3.us-west-2.amazonaws.com/sentinel-cogs/sentinel-s2-l2a-cogs/21/H/UB/2021/9/S2B_21HUB_20210915_0_L2A/S2B_21HUB_20210915_0_L2A.json
Binary file modified doc/en/cog/true-color.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/cog/visualizations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/cog/viz-plus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/mobile/compass.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion doc/en/mobile/compass.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Add heading and make thing look nice
# Add heading and make things look nice

Most mobile devices are equipped with a gyroscope, which we are going to use as a compass to show our heading on the map.

Expand Down
Binary file modified doc/en/mobile/geolocation.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/mobile/map.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/vector/download.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions doc/en/vector/drag-n-drop.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

For our feature editor, we want users to be able to import their own data for editing. We'll use the `DragAndDrop` interaction for this. As before, we'll stick with the GeoJSON format for parsing features, but the interaction can be configured to work with any number of feature formats.

We're going to be passing our map to a number of other components in this exercise, so make sure you have assigned the map to a variable named `map`:
Start by editing the map configuration in your `main.js` file so that there are no layers added. We're going to be passing our map to a number of other components in this exercise, so make sure you have assigned the map to a variable named `map`.:

[import:'map-const'](../../../src/en/examples/vector/drag-n-drop.js)
[import:'map'](../../../src/en/examples/vector/drag-n-drop.js)

Import the drag and drop interaction into your `main.js`:
Next, import the drag and drop interaction into your `main.js`:

[import:'import'](../../../src/en/examples/vector/drag-n-drop.js)

Expand Down
Binary file modified doc/en/vector/drag-n-drop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/vector/draw.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 0 additions & 4 deletions doc/en/vector/geojson.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ In our `main.js` we'll import the new interaction:

[import:'import'](../../../src/en/examples/vector/sync.js)

We next need to assign our map to a variable (named `map`) so we can add the interaction to it:

[import:'map-const'](../../../src/en/examples/vector/drag-n-drop.js)

And now we can add a new link interaction to our map:

[import:'sync'](../../../src/en/examples/vector/sync.js)
Expand Down
Binary file modified doc/en/vector/geojson.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/vector/modify.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/vector/snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/vector/style.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 7 additions & 10 deletions doc/en/vectortile/bright.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,27 @@ Mapbox finally came up with Mapbox Studio, a very user-friendly style editor, an

## Using a Mapbox Style definition

There are two ways to use vector tile layers with Mapbox styles in OpenLayers. The easiest is the `MapboxVector` layer. It is configured with an url that points to a Mapbox Style document. Let's try it out.
With the additional [ol-mapbox-style](https://npmjs.com/package/ol-mapbox-style/) library, there are several ways to use vector tile layers with Mapbox styles in OpenLayers. The easiest is the `MapboxVector` layer from the `ol-mapbox-style` import. It is configured with a url that points to a Mapbox Style document. Let's try it out.

First, add the required import:

[import:'import'](../../../src/en/examples/vectortile/bright.js)

The tile dataset we are going to use is https://cloud.maptiler.com/maps/bright/. To add it to our example, you'll need a MapTiler account (please replace the key in the code below with yours). Alternatively, if you have a Mapbox account, you could use the original of that map from Mapbox (see comments in the code below).
The tile dataset we are going to use is https://tiles.openfreemap.org/styles/bright. Alternatively, if you have a Mapbox account, you could use the ancestor of that map from Mapbox (see comments in the code below).

[import:'layer'](../../../src/en/examples/vectortile/bright.js)

The above code replaces the `VectorTileLayer` from the previous step. When everything works as expected, we can finally enjoy a nice looking world map, and zoom in to Buenos Aires!
The above code replaces the `VectorTileLayer` from the previous step. When everything works as expected, we can finally enjoy a nice looking world map, and zoom in to Belém!

![A bright map of Buenos Aires](bright.png)
![A bright map of Belém](bright.png)

## Build a complete map from a Mapbox Style definition

The Mapbox Style format was not just made for styling vector data. It was made to describe an entire map, with all its sources and layers, and its initial view configuration (e.g. center and zoom level).

The [ol-mapbox-style](https://npmjs.com/package/ol-mapbox-style/) package (that is part of the workshop dependencies) adds support for the Mapbox Style format to OpenLayers. So the second way to use a vector tile layer with OpenLayers would be to let `ol-mapbox-style` create the whole map. If you want to try that, you could replace the whole code in `main.js` with this:
With `ol-mapbox-style`'s `apply()` function, it is also possible to create a whole map from a Mapbox Style. If you want to try that, you could replace the whole code in `main.js` with this:
```js
import olms from 'ol-mapbox-style';
olms(
'map-container',
'https://api.maptiler.com/maps/bright/style.json?key=lirfd6Fegsjkvs0lshxe'
);
import {apply} from 'ol-mapbox-style';
apply('map-container', 'https://tiles.openfreemap.org/styles/bright');
```
After trying this, switch back to the previous code, as we will be looking into how to interact with a vector tile map.
Binary file modified doc/en/vectortile/bright.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/vectortile/interact.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/vectortile/map.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 8 additions & 6 deletions doc/en/webgl/animated.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ Now, back in `main.js`, we'll declare some variables to represent the time range

[import:'years'](../../../src/en/examples/webgl/animated.js)

To be able to access the current year in style expressions, we need the `styleVariables` as `variables` property on the layer's `style` object:
To be able to access the current year in style expressions, we need to use the `variables` constructor option on the meteorites layer and include the `currentYear` (whose value will start with `minYear`):

[import:'variables'](../../../src/en/examples/webgl/animated.js)

Variables in a style object are numeric values that are available in expressions for calculations.
Style variables are values that are available in `var` expressions in the layer `style`.

Next we need to assign our map instance to a `map` variable that we can reference later:

[import:'declaration'](../../../src/en/examples/webgl/animated.js)

Below the map configuration, add the following `render` function to get the animation loop started.
Below the map configuration, add the following `render` function to get the animation loop started. In this function, we'll update the current year and call `updateStyleVariables()` on the meteorites layer to update the year used in the style expressions.

[import:'animate'](../../../src/en/examples/webgl/animated.js)

Expand All @@ -46,16 +46,18 @@ The filter references a `periodStart` variable, which is an expression on its ow

[import:'expressions'](../../../src/en/examples/webgl/animated.js)

The `decay` is an expression we're going to use to fade out circles by reducing their size and opacity. It gives us a value between `0` and `1`, which we can apply as multiplier for the fade effect. To use it for reducing the size over time, we have to modify the `size` in the `style` object:
The `decay` is an expression we're going to use to fade out circles by reducing their size and opacity. It gives us a value between `0` and `1`, which we can apply as multiplier for the fade effect. To use it for reducing the size over time, we have to modify the `circle-radius` in the `style` object:

[import:'size'](../../../src/en/examples/webgl/animated.js)

The existing expression is the fourth line of the new `size` expression.
The existing expression is the fourth line of the new `circle-radius` expression.

For reducing the opacity over time, we also apply the `decay` to the `opacity`:
For reducing the opacity over time, we also apply the `decay` to the `circle-fill-color`:

[import:'opacity'](../../../src/en/examples/webgl/animated.js)

Previously we had an `rgba` color, now we use a `color` expression consisting of `r`, `g`, `b` and `alpha` values. The `alpha` value is now dynamic and considers the decay.

![Meteor shower](shower.gif)

Congratulations!
Binary file modified doc/en/webgl/circles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/webgl/dynamic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions doc/en/webgl/meteorites.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Rendering meteorites with Canvas 2D

In OpenLayers 6, each layer in a map has an independent renderer. Previously, all layer rendering was managed by a single map renderer and depended on a single rendering strategy. So prior to OpenLayers 6, you needed to choose between Canvas 2D or WebGL rendering for all layers. In OpenLayers 6, you can have a map composed of layers with different rendering strategies. For example, you can render some layers with a Canvas 2D renderer and others with a WebGL renderer.
Starting with OpenLayers 6, each layer in a map has an independent renderer. Previously, all layer rendering was managed by a single map renderer and depended on a single rendering strategy. So prior to OpenLayers 6, you needed to choose between Canvas 2D or WebGL rendering for all layers. In recent OpenLayers versions, you can have a map composed of layers with different rendering strategies. For example, you can render some layers with a Canvas 2D renderer and others with a WebGL renderer.

The `ol/layer/Vector` class uses Canvas 2D to render points, lines, or polygons. This layer has a full featured renderer with a ton of flexibility in feature styling. For very large numbers of features, WebGL is a more appropriate technology. In this module, we'll start by using Canvas 2D to render 45,000 meteorite locations and then migrate the example to WebGL.
The `ol/layer/Vector` class uses Canvas 2D to render points, lines, or polygons. This layer has a full featured renderer with a ton of flexibility in feature styling. For very large numbers of features, WebGL might be a more appropriate technology. In this module, we'll start by using Canvas 2D to render 45,000 meteorite locations and then migrate the example to WebGL.

First, edit your `index.html` so we're ready to render a full page map:

Expand All @@ -23,6 +23,6 @@ Update your `main.js` to load and render a local CSV file with data representing

[import](../../../src/en/examples/webgl/meteorites.js)

After fetching and parsing the data, features are added to a vector source. This source is rendered in a vector layer over a tile layer. We aren't doing any custom styling of the features here, the point is just to see how it feels to use the map with 45,000 features rendered with Canvas 2D.
After fetching and parsing the data, features are added to a vector source. This source is rendered in a vector layer over a tile layer. We're applying very simple styling here - red, semi-transparent circles. The point is just to see how it feels to use the map with 45,000 features rendered with Canvas 2D.

![Meteorite impact sites](meteorites.png)
Binary file modified doc/en/webgl/meteorites.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 8 additions & 8 deletions doc/en/webgl/points.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
# Rendering points with WebGL

In the previous step, we rendered point features with the normal vector layer. This layer uses the 2D canvas context for rendering. With this layer, you can render tens of thousands of points – as long as you are careful about writing efficient styling code. For rendering larger numbers of points, or to do more efficient dynamic styling, WebGL is a good solution. OpenLayers has a growing set of utilities for rendering with WebGL. In this exercise we'll use it to render point geometries.
In the previous step, we rendered point features with the normal vector layer. This layer uses the 2D canvas context for rendering. With that layer, you can render tens of thousands of points – as long as you are careful about writing efficient styling code. For rendering larger numbers of points, or to do more efficient dynamic styling, WebGL is a good solution. OpenLayers has a growing set of utilities for rendering with WebGL. In this exercise we'll use it to render point geometries.

First, we'll import the constructor of the WebGL-enabled points layer. This layer is an easy-to-use entry point for leveraging the advantages of the WebGL technology.

[import:'import'](../../../src/en/examples/webgl/circles.js)

This is a replacement for the `VectorLayer` import, which you can now remove.

Replace the `const meteorites...` assignment with an instance of your `WebGLPointsLayer` using the same vector source as before.
Replace the `const meteorites...` assignment with an instance of your `WebGLVectorLayer` using the same vector source as before.

[import:'layer'](../../../src/en/examples/webgl/circles.js)

Tada! Meteorite impact locations rendered with WebGL.

![Impact sites rendered as circles](circles.png)

You can see that we specified a `style` parameter when creating the layer, and that this style allowed us to specify the appearance of the points (red, semi-transparent circles).
Like in the previous version, we specified a `style` parameter when creating the layer, and that style allowed us to specify the appearance of the points (red, semi-transparent circles).

Changing the style of a WebGL layer is quite different from the rest of the library. Instead of using the `Fill`, `Stroke` and `Image` classes like other vector layers, we simply have to provide an object with the style parameters. The supported properties for this object are pretty straightforward: `opacity`, `color`, `size`, `offset`, `src` (for images) and `symbolType` (which can be `circle`, `square`, `triangle` or `image`).
This concept of 'flat styles' is available for both Canvas 2D and WebGL layers, although the supported range of features differs a bit.

> WebGL layers use a completely different rendering system, and the style object is actually transformed dynamically into fragment and vertex shaders.
By navigating in the map you might already notice a performance improvement from the previous step where we were using a standard Canvas 2D layer.
By navigating the map you might notice a performance improvement from the previous step where we were using a standard Canvas 2D layer. This would be more pronounced if we had hundreds of thousands of points to render.

Now, I think we can all agree on the fact that this map isn't great to look at: that is probably because *each and every point* has the same styling.

Let's begin by sizing our circles depending on the mass of the meteorite. To achieve this, we're replacing the `size` of the style with the following expression:
Let's begin by sizing our circles depending on the mass of the meteorite. To achieve this, we're replacing the `circle-radius` of the style with the following expression:

[import:'size'](../../../src/en/examples/webgl/dynamic.js)

This expression results in a minimum size of 8 pixels, which can grow by 18 pixels depending on the mass of the meteorite,
This expression results in a minimum radius of 4 pixels, which can grow by 9 pixels depending on the mass of the meteorite,

The `WebGLPointsLayer` class supports this kind of expression for the numerical attributes of its style (size, opacity, color components, etc.).
The `WebGLVectorLayer` class supports this kind of expression for the numerical attributes of its style (size, opacity, color components, etc.).

An expression is composed of **operators** that are expressed as *arrays* like so:

Expand Down
Binary file modified doc/en/webgl/shower.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/webgl/years.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 1dcf56d

Please sign in to comment.