Merge pull request #4069 from gberaudo/layer_zindex
Add Z-index to layers
This commit is contained in:
28
examples/layer-z-index.html
Normal file
28
examples/layer-z-index.html
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
template: example.html
|
||||
title: Z-index layer ordering example
|
||||
shortdesc: Example of ordering layers using Z-index.
|
||||
docs: >
|
||||
|
||||
tags: "layer, ordering, z-index"
|
||||
---
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div id="map" class="map"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
There are are two managed layers (square and triangle) and one unmanaged layer (star).</br>
|
||||
The Z-index determines the rendering order; with {square: 1, triangle: 0, star: unmanaged} indices, the rendering order is triangle, square and star on top.
|
||||
</div>
|
||||
<div>
|
||||
<label for="idx1">
|
||||
<input type="number" id="idx1"></input>
|
||||
Square layer Z-index
|
||||
</label></br>
|
||||
|
||||
<label for="idx2">
|
||||
<input type="number" id="idx2"></input>
|
||||
Triangle layer Z-index
|
||||
</label>
|
||||
</div>
|
||||
92
examples/layer-z-index.js
Normal file
92
examples/layer-z-index.js
Normal file
@@ -0,0 +1,92 @@
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.Map');
|
||||
goog.require('ol.View');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.source.Vector');
|
||||
goog.require('ol.style.Fill');
|
||||
goog.require('ol.style.RegularShape');
|
||||
goog.require('ol.style.Stroke');
|
||||
goog.require('ol.style.Style');
|
||||
|
||||
|
||||
var stroke = new ol.style.Stroke({color: 'black', width: 1});
|
||||
|
||||
var styles = {
|
||||
'square': [new ol.style.Style({
|
||||
image: new ol.style.RegularShape({
|
||||
fill: new ol.style.Fill({color: 'blue'}),
|
||||
stroke: stroke,
|
||||
points: 4,
|
||||
radius: 80,
|
||||
angle: Math.PI / 4
|
||||
})
|
||||
})],
|
||||
'triangle': [new ol.style.Style({
|
||||
image: new ol.style.RegularShape({
|
||||
fill: new ol.style.Fill({color: 'red'}),
|
||||
stroke: stroke,
|
||||
points: 3,
|
||||
radius: 80,
|
||||
rotation: Math.PI / 4,
|
||||
angle: 0
|
||||
})
|
||||
})],
|
||||
'star': [new ol.style.Style({
|
||||
image: new ol.style.RegularShape({
|
||||
fill: new ol.style.Fill({color: 'green'}),
|
||||
stroke: stroke,
|
||||
points: 5,
|
||||
radius: 80,
|
||||
radius2: 4,
|
||||
angle: 0
|
||||
})
|
||||
})]
|
||||
};
|
||||
|
||||
|
||||
function createLayer(coordinates, styles, zIndex) {
|
||||
var feature = new ol.Feature(new ol.geom.Point(coordinates));
|
||||
feature.setStyle(styles);
|
||||
|
||||
var source = new ol.source.Vector({
|
||||
features: [feature]
|
||||
});
|
||||
|
||||
var vectorLayer = new ol.layer.Vector({
|
||||
source: source
|
||||
});
|
||||
vectorLayer.setZIndex(zIndex);
|
||||
|
||||
return vectorLayer;
|
||||
}
|
||||
|
||||
var layer0 = createLayer([40, 40], styles['star'], 0);
|
||||
var layer1 = createLayer([0, 0], styles['square'], 1);
|
||||
var layer2 = createLayer([0, 40], styles['triangle'], 0);
|
||||
|
||||
var layers = [];
|
||||
layers.push(layer1);
|
||||
layers.push(layer2);
|
||||
|
||||
var map = new ol.Map({
|
||||
layers: layers,
|
||||
target: 'map',
|
||||
view: new ol.View({
|
||||
center: [0, 0],
|
||||
zoom: 18
|
||||
})
|
||||
});
|
||||
|
||||
layer0.setMap(map);
|
||||
|
||||
|
||||
function bindInputs(id, layer) {
|
||||
var idxInput = $('#idx' + id);
|
||||
idxInput.on('input change', function() {
|
||||
layer.setZIndex(parseInt(this.value, 10) || 0);
|
||||
});
|
||||
idxInput.val(String(layer.getZIndex()));
|
||||
}
|
||||
bindInputs(1, layer1);
|
||||
bindInputs(2, layer2);
|
||||
@@ -2927,6 +2927,7 @@ olx.layer;
|
||||
* saturation: (number|undefined),
|
||||
* visible: (boolean|undefined),
|
||||
* extent: (ol.Extent|undefined),
|
||||
* zIndex: (number|undefined),
|
||||
* minResolution: (number|undefined),
|
||||
* maxResolution: (number|undefined)}}
|
||||
* @api
|
||||
@@ -2991,6 +2992,15 @@ olx.layer.BaseOptions.prototype.visible;
|
||||
olx.layer.BaseOptions.prototype.extent;
|
||||
|
||||
|
||||
/**
|
||||
* The z-index for layer rendering. At rendering time, the layers will be
|
||||
* ordered, first by Z-index and then by position. The default Z-index is 0.
|
||||
* @type {number|undefined}
|
||||
* @api
|
||||
*/
|
||||
olx.layer.BaseOptions.prototype.zIndex;
|
||||
|
||||
|
||||
/**
|
||||
* The minimum resolution (inclusive) at which this layer will be visible.
|
||||
* @type {number|undefined}
|
||||
@@ -3016,6 +3026,7 @@ olx.layer.BaseOptions.prototype.maxResolution;
|
||||
* source: (ol.source.Source|undefined),
|
||||
* visible: (boolean|undefined),
|
||||
* extent: (ol.Extent|undefined),
|
||||
* zIndex: (number|undefined),
|
||||
* minResolution: (number|undefined),
|
||||
* maxResolution: (number|undefined)}}
|
||||
* @api
|
||||
@@ -3090,6 +3101,15 @@ olx.layer.LayerOptions.prototype.visible;
|
||||
olx.layer.LayerOptions.prototype.extent;
|
||||
|
||||
|
||||
/**
|
||||
* The z-index for layer rendering. At rendering time, the layers will be
|
||||
* ordered, first by Z-index and then by position. The default Z-index is 0.
|
||||
* @type {number|undefined}
|
||||
* @api
|
||||
*/
|
||||
olx.layer.LayerOptions.prototype.zIndex;
|
||||
|
||||
|
||||
/**
|
||||
* The minimum resolution (inclusive) at which this layer will be visible.
|
||||
* @type {number|undefined}
|
||||
@@ -3114,6 +3134,7 @@ olx.layer.LayerOptions.prototype.maxResolution;
|
||||
* saturation: (number|undefined),
|
||||
* visible: (boolean|undefined),
|
||||
* extent: (ol.Extent|undefined),
|
||||
* zIndex: (number|undefined),
|
||||
* minResolution: (number|undefined),
|
||||
* maxResolution: (number|undefined),
|
||||
* layers: (Array.<ol.layer.Base>|ol.Collection.<ol.layer.Base>|undefined)}}
|
||||
@@ -3179,6 +3200,15 @@ olx.layer.GroupOptions.prototype.visible;
|
||||
olx.layer.GroupOptions.prototype.extent;
|
||||
|
||||
|
||||
/**
|
||||
* The z-index for layer rendering. At rendering time, the layers will be
|
||||
* ordered, first by Z-index and then by position. The default Z-index is 0.
|
||||
* @type {number|undefined}
|
||||
* @api
|
||||
*/
|
||||
olx.layer.GroupOptions.prototype.zIndex;
|
||||
|
||||
|
||||
/**
|
||||
* The minimum resolution (inclusive) at which this layer will be visible.
|
||||
* @type {number|undefined}
|
||||
|
||||
@@ -172,6 +172,7 @@ ol.layer.Layer.prototype.setMap = function(map) {
|
||||
map, ol.render.EventType.PRECOMPOSE, function(evt) {
|
||||
var layerState = this.getLayerState();
|
||||
layerState.managed = false;
|
||||
layerState.zIndex = Infinity;
|
||||
evt.frameState.layerStatesArray.push(layerState);
|
||||
evt.frameState.layerStates[goog.getUid(this)] = layerState;
|
||||
}, false, this);
|
||||
|
||||
@@ -19,6 +19,7 @@ ol.layer.LayerProperty = {
|
||||
SATURATION: 'saturation',
|
||||
VISIBLE: 'visible',
|
||||
EXTENT: 'extent',
|
||||
Z_INDEX: 'zIndex',
|
||||
MAX_RESOLUTION: 'maxResolution',
|
||||
MIN_RESOLUTION: 'minResolution',
|
||||
SOURCE: 'source'
|
||||
@@ -36,6 +37,7 @@ ol.layer.LayerProperty = {
|
||||
* visible: boolean,
|
||||
* managed: boolean,
|
||||
* extent: (ol.Extent|undefined),
|
||||
* zIndex: number,
|
||||
* maxResolution: number,
|
||||
* minResolution: number}}
|
||||
*/
|
||||
@@ -76,6 +78,8 @@ ol.layer.Base = function(options) {
|
||||
goog.isDef(options.saturation) ? options.saturation : 1;
|
||||
properties[ol.layer.LayerProperty.VISIBLE] =
|
||||
goog.isDef(options.visible) ? options.visible : true;
|
||||
properties[ol.layer.LayerProperty.Z_INDEX] =
|
||||
goog.isDef(options.zIndex) ? options.zIndex : 0;
|
||||
properties[ol.layer.LayerProperty.MAX_RESOLUTION] =
|
||||
goog.isDef(options.maxResolution) ? options.maxResolution : Infinity;
|
||||
properties[ol.layer.LayerProperty.MIN_RESOLUTION] =
|
||||
@@ -131,6 +135,7 @@ ol.layer.Base.prototype.getLayerState = function() {
|
||||
var sourceState = this.getSourceState();
|
||||
var visible = this.getVisible();
|
||||
var extent = this.getExtent();
|
||||
var zIndex = this.getZIndex();
|
||||
var maxResolution = this.getMaxResolution();
|
||||
var minResolution = this.getMinResolution();
|
||||
return {
|
||||
@@ -144,6 +149,7 @@ ol.layer.Base.prototype.getLayerState = function() {
|
||||
visible: visible,
|
||||
managed: true,
|
||||
extent: extent,
|
||||
zIndex: zIndex,
|
||||
maxResolution: maxResolution,
|
||||
minResolution: Math.max(minResolution, 0)
|
||||
};
|
||||
@@ -242,6 +248,18 @@ ol.layer.Base.prototype.getVisible = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the Z-index of the layer, which is used to order layers before
|
||||
* rendering. The default Z-index is 0.
|
||||
* @return {number} The Z-index of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
ol.layer.Base.prototype.getZIndex = function() {
|
||||
return /** @type {number} */ (this.get(ol.layer.LayerProperty.Z_INDEX));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adjust the layer brightness. A value of -1 will render the layer completely
|
||||
* black. A value of 0 will leave the brightness unchanged. A value of 1 will
|
||||
@@ -364,3 +382,15 @@ ol.layer.Base.prototype.setSaturation = function(saturation) {
|
||||
ol.layer.Base.prototype.setVisible = function(visible) {
|
||||
this.set(ol.layer.LayerProperty.VISIBLE, visible);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set Z-index of the layer, which is used to order layers before rendering.
|
||||
* The default Z-index is 0.
|
||||
* @param {number} zindex The z-index of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
ol.layer.Base.prototype.setZIndex = function(zindex) {
|
||||
this.set(ol.layer.LayerProperty.Z_INDEX, zindex);
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
goog.provide('ol.renderer.canvas.Map');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.style');
|
||||
@@ -168,6 +169,8 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
|
||||
this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState);
|
||||
|
||||
var layerStatesArray = frameState.layerStatesArray;
|
||||
goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex);
|
||||
|
||||
var viewResolution = frameState.viewState.resolution;
|
||||
var i, ii, layer, layerRenderer, layerState;
|
||||
for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
goog.provide('ol.renderer.dom.Map');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
@@ -222,6 +223,8 @@ ol.renderer.dom.Map.prototype.renderFrame = function(frameState) {
|
||||
this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState);
|
||||
|
||||
var layerStatesArray = frameState.layerStatesArray;
|
||||
goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex);
|
||||
|
||||
var viewResolution = frameState.viewState.resolution;
|
||||
var i, ii, layer, layerRenderer, layerState;
|
||||
for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {
|
||||
|
||||
@@ -375,3 +375,13 @@ ol.renderer.Map.prototype.scheduleRemoveUnusedLayerRenderers =
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.LayerState} state1
|
||||
* @param {ol.layer.LayerState} state2
|
||||
* @return {number}
|
||||
*/
|
||||
ol.renderer.Map.sortByZIndex = function(state1, state2) {
|
||||
return state1.zIndex - state2.zIndex;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
goog.provide('ol.renderer.webgl.Map');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
@@ -471,6 +472,8 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) {
|
||||
/** @type {Array.<ol.layer.LayerState>} */
|
||||
var layerStatesToDraw = [];
|
||||
var layerStatesArray = frameState.layerStatesArray;
|
||||
goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex);
|
||||
|
||||
var viewResolution = frameState.viewState.resolution;
|
||||
var i, ii, layerRenderer, layerState;
|
||||
for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {
|
||||
|
||||
@@ -66,6 +66,7 @@ describe('ol.layer.Layer', function() {
|
||||
managed: true,
|
||||
sourceState: ol.source.State.READY,
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
maxResolution: Infinity,
|
||||
minResolution: 0
|
||||
});
|
||||
@@ -86,6 +87,7 @@ describe('ol.layer.Layer', function() {
|
||||
opacity: 0.5,
|
||||
saturation: 5,
|
||||
visible: false,
|
||||
zIndex: 10,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25,
|
||||
foo: 42
|
||||
@@ -111,6 +113,7 @@ describe('ol.layer.Layer', function() {
|
||||
managed: true,
|
||||
sourceState: ol.source.State.READY,
|
||||
extent: undefined,
|
||||
zIndex: 10,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25
|
||||
});
|
||||
@@ -194,6 +197,7 @@ describe('ol.layer.Layer', function() {
|
||||
layer.setVisible(false);
|
||||
layer.setMaxResolution(500);
|
||||
layer.setMinResolution(0.25);
|
||||
layer.setZIndex(10);
|
||||
expect(layer.getLayerState()).to.eql({
|
||||
layer: layer,
|
||||
brightness: -0.7,
|
||||
@@ -205,6 +209,7 @@ describe('ol.layer.Layer', function() {
|
||||
managed: true,
|
||||
sourceState: ol.source.State.READY,
|
||||
extent: undefined,
|
||||
zIndex: 10,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25
|
||||
});
|
||||
@@ -228,6 +233,7 @@ describe('ol.layer.Layer', function() {
|
||||
managed: true,
|
||||
sourceState: ol.source.State.READY,
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
maxResolution: Infinity,
|
||||
minResolution: 0
|
||||
});
|
||||
@@ -249,6 +255,7 @@ describe('ol.layer.Layer', function() {
|
||||
managed: true,
|
||||
sourceState: ol.source.State.READY,
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
maxResolution: Infinity,
|
||||
minResolution: 0
|
||||
});
|
||||
|
||||
@@ -54,6 +54,7 @@ describe('ol.layer.Group', function() {
|
||||
managed: true,
|
||||
sourceState: ol.source.State.READY,
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
maxResolution: Infinity,
|
||||
minResolution: 0
|
||||
});
|
||||
@@ -160,6 +161,7 @@ describe('ol.layer.Group', function() {
|
||||
opacity: 0.5,
|
||||
saturation: 5,
|
||||
visible: false,
|
||||
zIndex: 10,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25
|
||||
});
|
||||
@@ -183,6 +185,7 @@ describe('ol.layer.Group', function() {
|
||||
managed: true,
|
||||
sourceState: ol.source.State.READY,
|
||||
extent: undefined,
|
||||
zIndex: 10,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25
|
||||
});
|
||||
@@ -235,6 +238,7 @@ describe('ol.layer.Group', function() {
|
||||
managed: true,
|
||||
sourceState: ol.source.State.READY,
|
||||
extent: groupExtent,
|
||||
zIndex: 0,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25
|
||||
});
|
||||
@@ -266,6 +270,7 @@ describe('ol.layer.Group', function() {
|
||||
layerGroup.setOpacity(0.3);
|
||||
layerGroup.setSaturation(0.3);
|
||||
layerGroup.setVisible(false);
|
||||
layerGroup.setZIndex(10);
|
||||
var groupExtent = [-100, 50, 100, 50];
|
||||
layerGroup.setExtent(groupExtent);
|
||||
layerGroup.setMaxResolution(500);
|
||||
@@ -281,6 +286,7 @@ describe('ol.layer.Group', function() {
|
||||
managed: true,
|
||||
sourceState: ol.source.State.READY,
|
||||
extent: groupExtent,
|
||||
zIndex: 10,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25
|
||||
});
|
||||
@@ -304,6 +310,7 @@ describe('ol.layer.Group', function() {
|
||||
managed: true,
|
||||
sourceState: ol.source.State.READY,
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
maxResolution: Infinity,
|
||||
minResolution: 0
|
||||
});
|
||||
@@ -325,6 +332,7 @@ describe('ol.layer.Group', function() {
|
||||
managed: true,
|
||||
sourceState: ol.source.State.READY,
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
maxResolution: Infinity,
|
||||
minResolution: 0
|
||||
});
|
||||
@@ -500,6 +508,7 @@ describe('ol.layer.Group', function() {
|
||||
managed: true,
|
||||
sourceState: ol.source.State.READY,
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
maxResolution: 150,
|
||||
minResolution: 0.25
|
||||
});
|
||||
@@ -507,14 +516,60 @@ describe('ol.layer.Group', function() {
|
||||
goog.dispose(layerGroup);
|
||||
});
|
||||
|
||||
it('let order of layers without Z-index unchanged', function() {
|
||||
var layerGroup = new ol.layer.Group({
|
||||
layers: [layer1, layer2]
|
||||
});
|
||||
|
||||
var layerStatesArray = layerGroup.getLayerStatesArray();
|
||||
var initialArray = layerStatesArray.slice();
|
||||
goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex);
|
||||
expect(layerStatesArray[0]).to.eql(initialArray[0]);
|
||||
expect(layerStatesArray[1]).to.eql(initialArray[1]);
|
||||
|
||||
goog.dispose(layerGroup);
|
||||
});
|
||||
|
||||
it('orders layer with higher Z-index on top', function() {
|
||||
var layer10 = new ol.layer.Layer({
|
||||
source: new ol.source.Source({
|
||||
projection: 'EPSG:4326'
|
||||
})
|
||||
});
|
||||
layer10.setZIndex(10);
|
||||
|
||||
var layerM1 = new ol.layer.Layer({
|
||||
source: new ol.source.Source({
|
||||
projection: 'EPSG:4326'
|
||||
})
|
||||
});
|
||||
layerM1.setZIndex(-1);
|
||||
|
||||
var layerGroup = new ol.layer.Group({
|
||||
layers: [layer1, layer10, layer2, layerM1]
|
||||
});
|
||||
|
||||
var layerStatesArray = layerGroup.getLayerStatesArray();
|
||||
var initialArray = layerStatesArray.slice();
|
||||
goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex);
|
||||
expect(layerStatesArray[0]).to.eql(initialArray[3]);
|
||||
expect(layerStatesArray[1]).to.eql(initialArray[0]);
|
||||
expect(layerStatesArray[2]).to.eql(initialArray[2]);
|
||||
expect(layerStatesArray[3]).to.eql(initialArray[1]);
|
||||
|
||||
goog.dispose(layer10);
|
||||
goog.dispose(layerM1);
|
||||
goog.dispose(layerGroup);
|
||||
});
|
||||
|
||||
goog.dispose(layer1);
|
||||
goog.dispose(layer2);
|
||||
goog.dispose(layer3);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.dispose');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.events.Listener');
|
||||
@@ -523,6 +578,7 @@ goog.require('ol.ObjectEventType');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.layer.Layer');
|
||||
goog.require('ol.layer.Group');
|
||||
goog.require('ol.renderer.Map');
|
||||
goog.require('ol.source.Source');
|
||||
goog.require('ol.source.State');
|
||||
goog.require('ol.Collection');
|
||||
|
||||
Reference in New Issue
Block a user