Merge pull request #13085 from ahocevar/layer-background

Add layer background
This commit is contained in:
Andreas Hocevar
2021-12-06 20:39:19 +01:00
committed by GitHub
12 changed files with 216 additions and 93 deletions

View File

@@ -213,7 +213,7 @@ export function toString(color) {
if (b != (b | 0)) {
b = (b + 0.5) | 0;
}
const a = color[3] === undefined ? 1 : color[3];
const a = color[3] === undefined ? 1 : Math.round(color[3] * 100) / 100;
return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
}

View File

@@ -8,6 +8,13 @@ import {assert} from '../asserts.js';
import {assign} from '../obj.js';
import {clamp} from '../math.js';
/**
* A css color, or a function called with a view resolution returning a css color.
*
* @typedef {string|function(number):string} BackgroundColor
* @api
*/
/**
* @typedef {import("../ObjectEventType").Types|'change:extent'|'change:maxResolution'|'change:maxZoom'|
* 'change:minResolution'|'change:minZoom'|'change:opacity'|'change:visible'|'change:zIndex'} BaseLayerObjectEventTypes
@@ -39,6 +46,8 @@ import {clamp} from '../math.js';
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {BackgroundColor} [background] Background color for the layer. If not specified, no background
* will be rendered.
* @property {Object<string, *>} [properties] Arbitrary observable properties. Can be accessed with `#get()` and `#set()`.
*/
@@ -74,6 +83,12 @@ class BaseLayer extends BaseObject {
*/
this.un;
/**
* @type {BackgroundColor|false}
* @private
*/
this.background_ = options.background;
/**
* @type {Object<string, *>}
*/
@@ -116,6 +131,14 @@ class BaseLayer extends BaseObject {
this.state_ = null;
}
/**
* Get the background for this layer.
* @return {BackgroundColor|false} Layer background.
*/
getBackground() {
return this.background_;
}
/**
* @return {string} CSS class name.
*/
@@ -265,6 +288,15 @@ class BaseLayer extends BaseObject {
return /** @type {number} */ (this.get(LayerProperty.Z_INDEX));
}
/**
* Sets the backgrlound color.
* @param {BackgroundColor} [opt_background] Background color.
*/
setBackground(opt_background) {
this.background_ = opt_background;
this.changed();
}
/**
* Set the extent at which the layer is visible. If `undefined`, the layer
* will be visible at all extents.

View File

@@ -48,6 +48,8 @@ import {
* @property {import("../style/Style.js").StyleLike|null} [style] Layer style. When set to `null`, only
* features that have their own style will be rendered. See {@link module:ol/style/Style~Style} for the default style
* which will be used if this is not set.
* @property {import("./Base.js").BackgroundColor} [background] Background color for the layer. If not specified, no background
* will be rendered.
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will
* be recreated during animations. This means that no vectors will be shown clipped, but the
* setting will have a performance impact for large amounts of vector data. When set to `false`,

View File

@@ -3,17 +3,11 @@
*/
import BaseEvent from '../events/Event.js';
import EventType from '../events/EventType.js';
import GeometryType from '../geom/GeometryType.js';
import MVT from '../format/MVT.js';
import RenderFeature from '../render/Feature.js';
import SourceState from '../source/State.js';
import TileEventType from '../source/TileEventType.js';
import VectorTileLayer from '../layer/VectorTile.js';
import VectorTileSource from '../source/VectorTile.js';
import {Fill, Style} from '../style.js';
import {applyStyle, setupVectorSource} from 'ol-mapbox-style';
import {fromExtent} from '../geom/Polygon.js';
import {getValue} from 'ol-mapbox-style/dist/stylefunction.js';
import {applyBackground, applyStyle, setupVectorSource} from 'ol-mapbox-style';
const mapboxBaseUrl = 'https://api.mapbox.com';
@@ -188,6 +182,9 @@ const SourceType = {
* is defined by the z-index of the layer, the `zIndex` of the style and the render order of features.
* Higher z-index means higher priority. Within the same z-index, a feature rendered before another has
* higher priority.
* @property {import("./Base.js").BackgroundColor|false} [background] Background color for the layer.
* If not specified, the background from the Mapbox style object will be used. Set to `false` to prevent
* the Mapbox style's background from being used.
* @property {string} [className='ol-layer'] A CSS class name to set to the layer element.
* @property {number} [opacity=1] Opacity (0, 1).
* @property {boolean} [visible=true] Visibility.
@@ -283,6 +280,7 @@ class MapboxVectorLayer extends VectorTileLayer {
super({
source: source,
background: options.background,
declutter: declutter,
className: options.className,
opacity: options.opacity,
@@ -489,57 +487,8 @@ class MapboxVectorLayer extends VectorTileLayer {
targetSource.setTileLoadFunction(source.getTileLoadFunction());
targetSource.tileGrid = source.tileGrid;
}
const background = style.layers.find(
(layer) => layer.type === 'background'
);
if (
background &&
(!background.layout || background.layout.visibility !== 'none')
) {
const style = new Style({
fill: new Fill(),
});
targetSource.addEventListener(TileEventType.TILELOADEND, (event) => {
const tile = /** @type {import("../VectorTile.js").default} */ (
/** @type {import("../source/Tile.js").TileSourceEvent} */ (event)
.tile
);
const styleFuntion = () => {
const opacity =
/** @type {number} */ (
getValue(
background,
'paint',
'background-opacity',
tile.tileCoord[0]
)
) || 1;
const color = /** @type {*} */ (
getValue(background, 'paint', 'background-color', tile.tileCoord[0])
);
style
.getFill()
.setColor([
color.r * 255,
color.g * 255,
color.b * 255,
color.a * opacity,
]);
return style;
};
const extentGeometry = fromExtent(
targetSource.tileGrid.getTileCoordExtent(tile.tileCoord)
);
const renderFeature = new RenderFeature(
GeometryType.POLYGON,
extentGeometry.getFlatCoordinates(),
extentGeometry.getEnds(),
{layer: background.id},
undefined
);
renderFeature.styleFunction = styleFuntion;
tile.getFeatures().unshift(renderFeature);
});
if (this.getBackground() === undefined) {
applyBackground(this, style);
}
if (this.setMaxResolutionFromTileGrid_) {
const tileGrid = targetSource.getTileGrid();

View File

@@ -65,6 +65,8 @@ import {assign} from '../obj.js';
* @property {import("../style/Style.js").StyleLike|null} [style] Layer style. When set to `null`, only
* features that have their own style will be rendered. See {@link module:ol/style/Style~Style} for the default style
* which will be used if this is not set.
* @property {import("./Base.js").BackgroundColor|false} [background] Background color for the layer. If not specified, no
* background will be rendered.
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will be
* recreated during animations. This means that no vectors will be shown clipped, but the setting
* will have a performance impact for large amounts of vector data. When set to `false`, batches
@@ -145,6 +147,20 @@ class VectorTileLayer extends BaseVectorLayer {
? options.useInterimTilesOnError
: true
);
/**
* @return {import("./Base.js").BackgroundColor} Background color.
* @function
* @api
*/
this.getBackground;
/**
* @param {import("./Base.js").BackgroundColor} background Background color.
* @function
* @api
*/
this.setBackground;
}
createRenderer() {

View File

@@ -9,6 +9,7 @@ import {
compose as composeTransform,
create as createTransform,
} from '../../transform.js';
import {asArray} from '../../color.js';
import {
containsCoordinate,
getBottomLeft,
@@ -17,6 +18,7 @@ import {
getTopRight,
} from '../../extent.js';
import {createCanvasContext2D} from '../../dom.js';
import {equals} from '../../array.js';
/**
* @abstract
@@ -83,20 +85,39 @@ class CanvasLayerRenderer extends LayerRenderer {
this.pixelContext_ = null;
}
/**
* @param {import('../../PluggableMap.js').FrameState} frameState Frame state.
* @return {string} Background color.
*/
getBackground(frameState) {
const layer = this.getLayer();
let background = layer.getBackground();
if (typeof background === 'function') {
background = background(frameState.viewState.resolution);
}
return background || undefined;
}
/**
* Get a rendering container from an existing target, if compatible.
* @param {HTMLElement} target Potential render target.
* @param {string} transform CSS Transform.
* @param {number} opacity Opacity.
* @param {string} [opt_backgroundColor] Background color.
*/
useContainer(target, transform, opacity) {
useContainer(target, transform, opacity, opt_backgroundColor) {
const layerClassName = this.getLayer().getClassName();
let container, context;
if (
target &&
target.className === layerClassName &&
target.style.opacity === '' &&
opacity === 1
opacity === 1 &&
(!opt_backgroundColor ||
equals(
asArray(target.style.backgroundColor),
asArray(opt_backgroundColor)
))
) {
const canvas = target.firstElementChild;
if (canvas instanceof HTMLCanvasElement) {
@@ -121,6 +142,9 @@ class CanvasLayerRenderer extends LayerRenderer {
style.position = 'absolute';
style.width = '100%';
style.height = '100%';
if (opt_backgroundColor) {
style.backgroundColor = opt_backgroundColor;
}
context = createCanvasContext2D();
const canvas = context.canvas;
container.appendChild(canvas);

View File

@@ -283,7 +283,12 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
const canvasTransform = toTransformString(this.pixelTransform);
this.useContainer(target, canvasTransform, layerState.opacity);
this.useContainer(
target,
canvasTransform,
layerState.opacity,
this.getBackground(frameState)
);
const context = this.context;
const canvas = context.canvas;