diff --git a/src/ol/render/webgl/VectorStyleRenderer.js b/src/ol/render/webgl/VectorStyleRenderer.js index 312fb802edf..8c38a78086e 100644 --- a/src/ol/render/webgl/VectorStyleRenderer.js +++ b/src/ol/render/webgl/VectorStyleRenderer.js @@ -4,6 +4,16 @@ import WebGLArrayBuffer from '../../webgl/Buffer.js'; import {ARRAY_BUFFER, DYNAMIC_DRAW, ELEMENT_ARRAY_BUFFER} from '../../webgl.js'; import {AttributeType} from '../../webgl/Helper.js'; +import { + BooleanType, + computeGeometryType, + newParsingContext, +} from '../../expr/expression.js'; +import { + UNKNOWN_VALUE, + buildExpression, + newEvaluationContext, +} from '../../expr/cpu.js'; import {WebGLWorkerMessageType} from './constants.js'; import {colorEncodeId} from './utils.js'; import { @@ -104,11 +114,13 @@ class VectorStyleRenderer { * @param {VectorStyle} styleOrShaders Literal style or custom shaders * @param {import('../../webgl/Helper.js').default} helper Helper * @param {boolean} enableHitDetection Whether to enable the hit detection (needs compatible shader) + * @param {import("../../expr/expression.js").ExpressionValue} [filter] Optional filter expression */ - constructor(styleOrShaders, helper, enableHitDetection) { + constructor(styleOrShaders, helper, enableHitDetection, filter) { this.helper_ = helper; this.hitDetectionEnabled_ = enableHitDetection; + let shaders = /** @type {StyleShaders} */ (styleOrShaders); const isShaders = 'builder' in styleOrShaders; if (!isShaders) { @@ -166,6 +178,31 @@ class VectorStyleRenderer { ); } + /** + * @type {function(import('../../Feature.js').FeatureLike): boolean} + * @private + */ + this.featureFilter_ = null; + if (filter) { + const parsingContext = newParsingContext(); + const compiled = buildExpression(filter, BooleanType, parsingContext); + const evalContext = newEvaluationContext(); + this.featureFilter_ = (feature) => { + evalContext.properties = feature.getPropertiesInternal(); + if (parsingContext.featureId) { + const id = feature.getId(); + if (id !== undefined) { + evalContext.featureId = id; + } else { + evalContext.featureId = null; + } + } + evalContext.geometryType = computeGeometryType(feature.getGeometry()); + const result = /** @type {boolean} */ (compiled(evalContext)); + return result === UNKNOWN_VALUE || result; + }; + } + const hitDetectionAttributes = this.hitDetectionEnabled_ ? { hitColor: { @@ -261,11 +298,18 @@ class VectorStyleRenderer { /** * @param {import('./MixedGeometryBatch.js').default} geometryBatch Geometry batch * @param {import("../../transform.js").Transform} transform Transform to apply to coordinates - * @return {Promise} A promise resolving to WebGL buffers + * @return {Promise} A promise resolving to WebGL buffers; returns null if buffers are empty */ async generateBuffers(geometryBatch, transform) { + let filteredBatch = geometryBatch; + if (this.featureFilter_) { + filteredBatch = filteredBatch.filter(this.featureFilter_); + if (filteredBatch.isEmpty()) { + return null; + } + } const renderInstructions = this.generateRenderInstructions_( - geometryBatch, + filteredBatch, transform ); const [polygonBuffers, lineStringBuffers, pointBuffers] = await Promise.all( diff --git a/src/ol/renderer/webgl/VectorTileLayer.js b/src/ol/renderer/webgl/VectorTileLayer.js index ac5f9866caf..47732d593f9 100644 --- a/src/ol/renderer/webgl/VectorTileLayer.js +++ b/src/ol/renderer/webgl/VectorTileLayer.js @@ -198,7 +198,8 @@ class WebGLVectorTileLayerRenderer extends WebGLBaseTileLayerRenderer { return new VectorStyleRenderer( shaders, this.helper, - this.hitDetectionEnabled_ + this.hitDetectionEnabled_, + 'filter' in style ? style.filter : null ); }); } @@ -339,6 +340,9 @@ class WebGLVectorTileLayerRenderer extends WebGLBaseTileLayerRenderer { for (let i = 0, ii = this.styleRenderers_.length; i < ii; i++) { const renderer = this.styleRenderers_[i]; const buffers = tileRepresentation.buffers[i]; + if (!buffers) { + continue; + } renderer.render(buffers, frameState, () => { this.applyUniforms_( alpha, diff --git a/src/ol/webgl/styleparser.js b/src/ol/webgl/styleparser.js index 1dea58fa757..356f3312892 100644 --- a/src/ol/webgl/styleparser.js +++ b/src/ol/webgl/styleparser.js @@ -921,6 +921,8 @@ export function parseLiteralStyle(style) { parseStrokeProperties(style, builder, uniforms, vertContext, fragContext); parseFillProperties(style, builder, uniforms, vertContext, fragContext); + // note that the style filter may have already been applied earlier when building the rendering instructions + // this is still needed in case a filter cannot be evaluated statically beforehand (e.g. depending on time) if (style.filter) { const parsedFilter = expressionToGlsl( fragContext,