Support zoom limits for layers

This commit is contained in:
Tim Schaub
2019-08-06 13:27:32 -04:00
parent c767091faf
commit 65ad4932f4
11 changed files with 424 additions and 86 deletions
+2 -3
View File
@@ -7,7 +7,7 @@ import {CLASS_CONTROL, CLASS_UNSELECTABLE, CLASS_COLLAPSED} from '../css.js';
import {removeChildren, replaceNode} from '../dom.js';
import {listen} from '../events.js';
import EventType from '../events/EventType.js';
import {visibleAtResolution} from '../layer/Layer.js';
import {inView} from '../layer/Layer.js';
/**
@@ -170,10 +170,9 @@ class Attribution extends Control {
const visibleAttributions = [];
const layerStatesArray = frameState.layerStatesArray;
const resolution = frameState.viewState.resolution;
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
const layerState = layerStatesArray[i];
if (!visibleAtResolution(layerState, resolution)) {
if (!inView(layerState, frameState.viewState)) {
continue;
}
+54
View File
@@ -23,6 +23,10 @@ import {assign} from '../obj.js';
* visible.
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
* be visible.
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
*/
@@ -57,6 +61,10 @@ class BaseLayer extends BaseObject {
options.maxResolution !== undefined ? options.maxResolution : Infinity;
properties[LayerProperty.MIN_RESOLUTION] =
options.minResolution !== undefined ? options.minResolution : 0;
properties[LayerProperty.MIN_ZOOM] =
options.minZoom !== undefined ? options.minZoom : -Infinity;
properties[LayerProperty.MAX_ZOOM] =
options.maxZoom !== undefined ? options.maxZoom : Infinity;
/**
* @type {string}
@@ -103,6 +111,8 @@ class BaseLayer extends BaseObject {
state.zIndex = this.getZIndex() || (state.managed === false ? Infinity : 0);
state.maxResolution = this.getMaxResolution();
state.minResolution = Math.max(this.getMinResolution(), 0);
state.minZoom = this.getMinZoom();
state.maxZoom = this.getMaxZoom();
this.state_ = state;
return state;
@@ -161,6 +171,26 @@ class BaseLayer extends BaseObject {
return /** @type {number} */ (this.get(LayerProperty.MIN_RESOLUTION));
}
/**
* Return the minimum zoom level of the layer.
* @return {number} The minimum zoom level of the layer.
* @observable
* @api
*/
getMinZoom() {
return /** @type {number} */ (this.get(LayerProperty.MIN_ZOOM));
}
/**
* Return the maximum zoom level of the layer.
* @return {number} The maximum zoom level of the layer.
* @observable
* @api
*/
getMaxZoom() {
return /** @type {number} */ (this.get(LayerProperty.MAX_ZOOM));
}
/**
* Return the opacity of the layer (between 0 and 1).
* @return {number} The opacity of the layer.
@@ -231,6 +261,30 @@ class BaseLayer extends BaseObject {
this.set(LayerProperty.MIN_RESOLUTION, minResolution);
}
/**
* Set the maximum zoom (exclusive) at which the layer is visible.
* Note that the zoom levels for layer visibility are based on the
* view zoom level, which may be different from a tile source zoom level.
* @param {number} maxZoom The maximum zoom of the layer.
* @observable
* @api
*/
setMaxZoom(maxZoom) {
this.set(LayerProperty.MAX_ZOOM, maxZoom);
}
/**
* Set the minimum zoom (inclusive) at which the layer is visible.
* Note that the zoom levels for layer visibility are based on the
* view zoom level, which may be different from a tile source zoom level.
* @param {number} minZoom The minimum zoom of the layer.
* @observable
* @api
*/
setMinZoom(minZoom) {
this.set(LayerProperty.MIN_ZOOM, minZoom);
}
/**
* Set the opacity of the layer, allowed values range from 0 to 1.
* @param {number} opacity The opacity of the layer.
+8
View File
@@ -29,6 +29,10 @@ import SourceState from '../source/State.js';
* visible.
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
* be visible.
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
* visible.
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
* be visible.
* @property {Array<import("./Base.js").default>|import("../Collection.js").default<import("./Base.js").default>} [layers] Child layers.
*/
@@ -215,6 +219,10 @@ class LayerGroup extends BaseLayer {
layerState.maxResolution, ownLayerState.maxResolution);
layerState.minResolution = Math.max(
layerState.minResolution, ownLayerState.minResolution);
layerState.minZoom = Math.max(
layerState.minZoom, ownLayerState.minZoom);
layerState.maxZoom = Math.min(
layerState.maxZoom, ownLayerState.maxZoom);
if (ownLayerState.extent !== undefined) {
if (layerState.extent !== undefined) {
layerState.extent = getIntersection(layerState.extent, ownLayerState.extent);
+16 -9
View File
@@ -50,6 +50,8 @@ import SourceState from '../source/State.js';
* @property {number} zIndex
* @property {number} maxResolution
* @property {number} minResolution
* @property {number} minZoom
* @property {number} maxZoom
*/
/**
@@ -277,17 +279,22 @@ class Layer extends BaseLayer {
/**
* Return `true` if the layer is visible, and if the passed resolution is
* between the layer's minResolution and maxResolution. The comparison is
* inclusive for `minResolution` and exclusive for `maxResolution`.
* Return `true` if the layer is visible and if the provided view state
* has resolution and zoom levels that are in range of the layer's min/max.
* @param {State} layerState Layer state.
* @param {number} resolution Resolution.
* @return {boolean} The layer is visible at the given resolution.
* @param {import("../View.js").State} viewState View state.
* @return {boolean} The layer is visible at the given view state.
*/
export function visibleAtResolution(layerState, resolution) {
return layerState.visible && resolution >= layerState.minResolution &&
resolution < layerState.maxResolution;
export function inView(layerState, viewState) {
if (!layerState.visible) {
return false;
}
const resolution = viewState.resolution;
if (resolution < layerState.minResolution || resolution >= layerState.maxResolution) {
return false;
}
const zoom = viewState.zoom;
return zoom > layerState.minZoom && zoom <= layerState.maxZoom;
}
export default Layer;
+2
View File
@@ -12,5 +12,7 @@ export default {
Z_INDEX: 'zIndex',
MAX_RESOLUTION: 'maxResolution',
MIN_RESOLUTION: 'minResolution',
MAX_ZOOM: 'maxZoom',
MIN_ZOOM: 'minZoom',
SOURCE: 'source'
};
+4 -5
View File
@@ -2,7 +2,7 @@
* @module ol/renderer/Composite
*/
import {CLASS_UNSELECTABLE} from '../css.js';
import {visibleAtResolution} from '../layer/Layer.js';
import {inView} from '../layer/Layer.js';
import RenderEvent from '../render/Event.js';
import RenderEventType from '../render/EventType.js';
import MapRenderer from './Map.js';
@@ -95,7 +95,7 @@ class CompositeMapRenderer extends MapRenderer {
const layerStatesArray = frameState.layerStatesArray.sort(function(a, b) {
return a.zIndex - b.zIndex;
});
const viewResolution = frameState.viewState.resolution;
const viewState = frameState.viewState;
this.children_.length = 0;
let hasOverlay = false;
@@ -104,7 +104,7 @@ class CompositeMapRenderer extends MapRenderer {
const layerState = layerStatesArray[i];
hasOverlay = hasOverlay || layerState.hasOverlay;
frameState.layerIndex = i;
if (!visibleAtResolution(layerState, viewResolution) ||
if (!inView(layerState, viewState) ||
(layerState.sourceState != SourceState.READY && layerState.sourceState != SourceState.UNDEFINED)) {
continue;
}
@@ -142,7 +142,6 @@ class CompositeMapRenderer extends MapRenderer {
*/
forEachLayerAtPixel(pixel, frameState, hitTolerance, callback, layerFilter) {
const viewState = frameState.viewState;
const viewResolution = viewState.resolution;
const layerStates = frameState.layerStatesArray;
const numLayers = layerStates.length;
@@ -150,7 +149,7 @@ class CompositeMapRenderer extends MapRenderer {
for (let i = numLayers - 1; i >= 0; --i) {
const layerState = layerStates[i];
const layer = layerState.layer;
if (layer.hasRenderer() && visibleAtResolution(layerState, viewResolution) && layerFilter(layer)) {
if (layer.hasRenderer() && inView(layerState, viewState) && layerFilter(layer)) {
const layerRenderer = layer.getRenderer();
const data = layerRenderer.getDataAtPixel(pixel, frameState, hitTolerance);
if (data) {
+2 -3
View File
@@ -5,7 +5,7 @@ import {abstract, getUid} from '../util.js';
import Disposable from '../Disposable.js';
import {getWidth} from '../extent.js';
import {TRUE} from '../functions.js';
import {visibleAtResolution} from '../layer/Layer.js';
import {inView} from '../layer/Layer.js';
import {shared as iconImageCache} from '../style/IconImageCache.js';
import {compose as composeTransform, makeInverse} from '../transform.js';
import {renderDeclutterItems} from '../render.js';
@@ -87,7 +87,6 @@ class MapRenderer extends Disposable {
) {
let result;
const viewState = frameState.viewState;
const viewResolution = viewState.resolution;
/**
* @param {boolean} managed Managed layer.
@@ -126,7 +125,7 @@ class MapRenderer extends Disposable {
for (i = numLayers - 1; i >= 0; --i) {
const layerState = layerStates[i];
const layer = /** @type {import("../layer/Layer.js").default} */ (layerState.layer);
if (layer.hasRenderer() && visibleAtResolution(layerState, viewResolution) && layerFilter.call(thisArg2, layer)) {
if (layer.hasRenderer() && inView(layerState, viewState) && layerFilter.call(thisArg2, layer)) {
const layerRenderer = layer.getRenderer();
const source = layer.getSource();
if (layerRenderer && source) {