Merge pull request #4069 from gberaudo/layer_zindex

Add Z-index to layers
This commit is contained in:
Éric Lemoine
2015-09-03 16:38:50 +02:00
11 changed files with 264 additions and 1 deletions

View 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
View 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);

View File

@@ -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}

View File

@@ -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);

View File

@@ -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);
};

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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;
};

View File

@@ -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) {

View File

@@ -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
});

View File

@@ -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');