Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More realistic canvas gradient/pattern example #15095

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 16 additions & 4 deletions examples/canvas-gradient-pattern.html
@@ -1,11 +1,23 @@
---
layout: example.html
title: Styling feature with CanvasGradient or CanvasPattern
shortdesc: Example showing a vector layer styled with a gradient.
shortdesc: Example showing a vector layer styled with a gradient pattern.
docs: >
This example creates a [`CanvasGradient`](https://developer.mozilla.org/en/docs/Web/API/CanvasGradient).
The vector data is loaded from a file and features are filled with the gradient.
The same technique can be used with a [`CanvasPattern`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern).
This example creates a [`CanvasPattern`](https://developer.mozilla.org/en/docs/Web/API/CanvasPattern).
The vector data is loaded from a file and features are filled with a repeating gradient pattern based on feature properties.
The same technique can also be used directly with a [`CanvasGradient`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient).
tags: "canvas, gradient, pattern, style"
---
<div id="map" class="map"></div>
<div id="info">&nbsp;<br>&nbsp;</div>
<div class="row">
<div class="col-auto">
<span class="input-group">
<label class="input-group-text" for="type">Gradient type:</label>
<select class="form-select" id="type">
<option value="linear">Linear</option>
<option value="radial" selected>Radial</option>
</select>
</span>
</div>
</div>
115 changes: 94 additions & 21 deletions examples/canvas-gradient-pattern.js
@@ -1,43 +1,96 @@
import KML from '../src/ol/format/KML.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import Map from '../src/ol/Map.js';
import VectorLayer from '../src/ol/layer/Vector.js';
import VectorSource from '../src/ol/source/Vector.js';
import View from '../src/ol/View.js';
import {DEVICE_PIXEL_RATIO} from '../src/ol/has.js';
import {Fill, Stroke, Style} from '../src/ol/style.js';
import {Fill, Style} from '../src/ol/style.js';
import {fromLonLat} from '../src/ol/proj.js';

// Gradient and pattern are in canvas pixel space, so we adjust for the
// renderer's pixel ratio
const pixelRatio = DEVICE_PIXEL_RATIO;

// Generate a rainbow gradient
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const gradient = context.createLinearGradient(0, 0, 1024 * pixelRatio, 0);
gradient.addColorStop(0, 'red');
gradient.addColorStop(1 / 6, 'orange');
gradient.addColorStop(2 / 6, 'yellow');
gradient.addColorStop(3 / 6, 'green');
gradient.addColorStop(4 / 6, 'aqua');
gradient.addColorStop(5 / 6, 'blue');
gradient.addColorStop(1, 'purple');

const createPatternMethods = {
linear: function (color1, color2) {
// set equal width and height for diagonal gradient
// set width or height 0 for horizontal or vertical gradient
const width = 8 * pixelRatio;
const height = width;
const gradient = context.createLinearGradient(0, 0, width, height);
gradient.addColorStop(2 / 16, color1);
gradient.addColorStop(3 / 16, color2);
gradient.addColorStop(5 / 16, color2);
gradient.addColorStop(6 / 16, color1);
gradient.addColorStop(10 / 16, color1);
gradient.addColorStop(11 / 16, color2);
gradient.addColorStop(13 / 16, color2);
gradient.addColorStop(14 / 16, color1);
canvas.width = Math.max(width, 1);
canvas.height = Math.max(height, 1);
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
return context.createPattern(canvas, 'repeat');
},

radial: function (color1, color2) {
const radius = 4 * pixelRatio;
const gradient = context.createRadialGradient(
radius,
radius,
0,
radius,
radius,
radius
);
gradient.addColorStop(3 / 8, color2);
gradient.addColorStop(5 / 8, color1);
canvas.width = radius * 2;
canvas.height = radius * 2;
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
return context.createPattern(canvas, 'repeat');
},
};

let createPatternFunction, styleCache;

const vectorLayer = new VectorLayer({
background: 'white',
background: '#1a2b39',
source: new VectorSource({
url: 'data/kml/states.kml',
format: new KML({extractStyles: false}),
}),
style: new Style({
fill: new Fill({color: gradient}),
stroke: new Stroke({
color: '#333',
width: 1,
}),
url: 'https://openlayers.org/data/vector/ecoregions.json',
format: new GeoJSON(),
}),

style: function (feature) {
const bioColor = feature.get('COLOR_BIO') || '#eee';
const nnhColor = feature.get('COLOR_NNH') || '#eee';

let style = styleCache[bioColor]?.[nnhColor];
if (!style) {
style = new Style({
fill: new Fill({color: createPatternFunction(bioColor, nnhColor)}),
});
if (!styleCache[bioColor]) {
styleCache[bioColor] = {};
}
styleCache[bioColor][nnhColor] = style;
}
return style;
},
});

const typeSelect = document.getElementById('type');
typeSelect.onchange = function () {
createPatternFunction = createPatternMethods[typeSelect.value];
styleCache = {};
vectorLayer.changed();
};
typeSelect.onchange();

const map = new Map({
layers: [vectorLayer],
target: 'map',
Expand All @@ -46,3 +99,23 @@ const map = new Map({
zoom: 4,
}),
});

const displayFeatureInfo = function (pixel) {
const feature = map.forEachFeatureAtPixel(pixel, function (feature) {
return feature;
});

const info = document.getElementById('info');

info.innerHTML =
(feature?.get('BIOME_NAME') || '&nbsp;') +
'<br>' +
(feature?.get('NNH_NAME') || '&nbsp;');
};

map.on(['click', 'pointermove'], function (evt) {
if (evt.dragging) {
return;
}
displayFeatureInfo(evt.pixel);
});