Align patterns and gradients to a grid

This commit is contained in:
ahocevar
2018-05-22 16:05:32 +02:00
parent c32bd2274c
commit 7cfa65b8c3
6 changed files with 24 additions and 25 deletions

View File

@@ -2,6 +2,10 @@
### Next release
#### `ol/style/Fill` with `CanvasGradient` or `CanvasPattern`
The origin for gradients and patterns has changed from the top-left corner of the extent of the geometry being filled to 512 css pixel increments from map coordinate `[0, 0]`. This allows repeat patterns to be aligned properly with vector tiles. For seamless repeat patterns, width and height of the pattern image must be a factor of two (2, 4, 8, ..., 512).
#### Removal of the renderer option for maps
The `renderer` option has been removed from the `Map` constructor. The purpose of this change is to avoid bundling code in your application that you do not need. Previously, code for both the Canvas and WebGL renderers was included in all applications - even though most people only use one renderer. The `Map` constructor now gives you a Canvas (2D) based renderer. If you want to try the WebGL renderer, you can import the constructor from `ol/WebGLMap`.

View File

@@ -3,10 +3,11 @@ layout: example.html
title: Styling feature with CanvasGradient or CanvasPattern
shortdesc: Example showing the countries vector layer styled with patterns and gradients.
docs: >
First this example creates a reusable [`CanvasPattern`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern)
This example creates a [`CanvasPattern`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern)
and a [`CanvasGradient`](https://developer.mozilla.org/en/docs/Web/API/CanvasGradient). The countries are loaded from
a GeoJSON file. A style function determines for each country whether to use a fill with the pregenerated
CanvasGradient (rainbow colors) or a CanvasPattern (repeating stacked circles).
a GeoJSON file. A style function determines for each country whether to use a fill with the
CanvasGradient (rainbow colors) or a CanvasPattern (repeating stacked circles). **Note**: For seamless repeat patterns,
image width and height of the pattern image must be a factor of two (2, 4, 8, ..., 512).
tags: "canvas, gradient, pattern, style"
---
<div id="map" class="map"></div>

View File

@@ -1,6 +1,5 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {getWidth} from '../src/ol/extent.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import {DEVICE_PIXEL_RATIO} from '../src/ol/has.js';
import VectorLayer from '../src/ol/layer/Vector.js';
@@ -16,14 +15,8 @@ const context = canvas.getContext('2d');
const pixelRatio = DEVICE_PIXEL_RATIO;
// Generate a rainbow gradient
function gradient(feature, resolution) {
const extent = feature.getGeometry().getExtent();
// Gradient starts on the left edge of each feature, and ends on the right.
// Coordinate origin is the top-left corner of the extent of the geometry, so
// we just divide the geometry's extent width by resolution and multiply with
// pixelRatio to match the renderer's pixel coordinate system.
const grad = context.createLinearGradient(0, 0,
getWidth(extent) / resolution * pixelRatio, 0);
const gradient = (function() {
const grad = context.createLinearGradient(0, 0, 512 * pixelRatio, 0);
grad.addColorStop(0, 'red');
grad.addColorStop(1 / 6, 'orange');
grad.addColorStop(2 / 6, 'yellow');
@@ -32,24 +25,24 @@ function gradient(feature, resolution) {
grad.addColorStop(5 / 6, 'blue');
grad.addColorStop(1, 'purple');
return grad;
}
})();
// Generate a canvasPattern with two circles on white background
const pattern = (function() {
canvas.width = 11 * pixelRatio;
canvas.height = 11 * pixelRatio;
canvas.width = 8 * pixelRatio;
canvas.height = 8 * pixelRatio;
// white background
context.fillStyle = 'white';
context.fillRect(0, 0, canvas.width, canvas.height);
// outer circle
context.fillStyle = 'rgba(102, 0, 102, 0.5)';
context.beginPath();
context.arc(5 * pixelRatio, 5 * pixelRatio, 4 * pixelRatio, 0, 2 * Math.PI);
context.arc(4 * pixelRatio, 4 * pixelRatio, 3 * pixelRatio, 0, 2 * Math.PI);
context.fill();
// inner circle
context.fillStyle = 'rgb(55, 0, 170)';
context.beginPath();
context.arc(5 * pixelRatio, 5 * pixelRatio, 2 * pixelRatio, 0, 2 * Math.PI);
context.arc(4 * pixelRatio, 4 * pixelRatio, 1.5 * pixelRatio, 0, 2 * Math.PI);
context.fill();
return context.createPattern(canvas, 'repeat');
}());
@@ -69,12 +62,11 @@ const style = new Style({
* which either contains the aboove gradient or pattern.
*
* @param {module:ol/Feature~Feature} feature The feature to style.
* @param {number} resolution Resolution.
* @return {module:ol/style/Style} The style to use for the feature.
*/
const getStackedStyle = function(feature, resolution) {
const getStackedStyle = function(feature) {
const id = feature.getId();
fill.setColor(id > 'J' ? gradient(feature, resolution) : pattern);
fill.setColor(id > 'J' ? gradient : pattern);
return style;
};
@@ -94,7 +86,7 @@ const map = new Map({
],
target: 'map',
view: new View({
center: fromLonLat([7, 52]),
center: fromLonLat([16, 48]),
zoom: 3
})
});

View File

@@ -8,8 +8,9 @@ import {toString} from './color.js';
* A type accepted by CanvasRenderingContext2D.fillStyle
* or CanvasRenderingContext2D.strokeStyle.
* Represents a color, pattern, or gradient. The origin for patterns and
* gradients as fill style is the top-left corner of the extent of the geometry
* being filled.
* gradients as fill style is an increment of 512 css pixels from map coordinate
* `[0, 0]`. For seamless repeat patterns, width and height of the pattern image
* must be a factor of two (2, 4, 8, ..., 512).
*
* @typedef {string|CanvasPattern|CanvasGradient} ColorLike
* @api

View File

@@ -456,8 +456,9 @@ CanvasReplay.prototype.beginGeometry = function(geometry, feature) {
*/
CanvasReplay.prototype.fill_ = function(context) {
if (this.fillOrigin_) {
const origin = applyTransform(this.renderedTransform_, this.fillOrigin_.slice());
context.translate(origin[0], origin[1]);
const origin = applyTransform(this.renderedTransform_, [0, 0]);
const repeatSize = 512 * this.pixelRatio;
context.translate(origin[0] % repeatSize, origin[1] % repeatSize);
context.rotate(this.viewRotation_);
}
context.fill();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB