[OpenLayers-Dev] A kind of MultiLayer container

Ivan Grcic ivan.grcic at geofoto.hr
Tue Aug 4 05:38:27 EDT 2009


Merci Didier, I'll give it a look!

On Tue, Aug 4, 2009 at 10:32 AM, RICHARD Didier<didier.richard at ign.fr> wrote:
>
>> On Tue, Aug 4, 2009 at 6:04 AM, Eric Lemoine<eric.lemoine at camptocamp.com>
>> wrote:
>>> On Monday, August 3, 2009, Ivan Grcic <ivan.grcic at geofoto.hr> wrote:
>>>> Hi devs,
>>>>
>>>> I want to ask if anyone has made something like Vector/RootContainer,
>>>> a layer that would contain several layers, and every layer would
>>>> activate/deactivate on different zoomLevels.
>>>>
>>>> Simple case: 3 (or more) layers combined in one ContainerLayer
>>>> small scale: WMS raster layer
>>>> larger scales: other WMS  raster layer
>>>> large scale: WFS vector layer
>>>>
>>>>  Usually I always register zoomend event on map, and manually activate
>>>> or deactivate layers...but it got little bit boring to do that on
>>>> application level every time.
>>>>
>>>> I remember Alexandre did something like that but for Vector layer
>>>>  or http://openlayers.org/pipermail/users/2009-January/009666.html
>>>>
>>>> Anyone did something like that? (does mapfish maybe has soemthing like
>>>> that)
>>>>  If not, can anyone just give few tips, so I could start developing
>>>> it...
>>>
>>>
>>> Hi Ivan
>>>
>>> Can't you just set different resolution ranges in the layers?
>>>
>>> Cheers,
>>>
>>>
>> Tnx for replies guys,
>>
>>
>> Yes yes, im setting ranges for my layers, but I want to have only one
>> layer shown in layerSwitcher for group of layers.
>>
>> I guess I just have to create one dummy layer with inLayerSwitcher:
>> true, and other layers to false. And then just register activate,
>> deactivate events that will turn off/on all group layers. (as alex
>> suggested, tnx)
>>
>> I was just wondering if it would have sense to have it included in
>> API, not to do it manually all the time...
>> Cheers
>>
>
> Hi all,
>
> For our portal API, we have develop something really close :
>
>
> /*
>  * Copyright 2008-2009 Institut Geographique National France, released
> under the
>  * BSD license.
>  */
> /**
>  * Class: Geoportal.Layer.Aggregate
>  * A container of layers. The idea is to group layers to avoid big list to be
>  * displayed in the LayerSwitcher. This aggregation also helps in grouping
>  * spread OGC services into a compound one.
>  *      This feature is experimental.
>  *
>  * Inherits from:
>  * - {<OpenLayers.Layer>}
>  */
> Geoportal.Layer.Aggregate=
>    OpenLayers.Class( Geoportal.Layer, {
>
>    /**
>     * APIProperty: layers
>     * {Array(<Geoportal.Layer>)} Ordered list of layers in the aggregation.
>     */
>    layers: null,
>
>    /**
>     * Constructor: Geoportal.Layer.Aggregate
>     * Build an aggregation of layers.
>     *
>     * Parameters:
>     * name - {String} The aggregation name.
>     * layers - {Array(<Geoportal.Layer>)} Ordered list of layers to push
> into
>     *      the aggregation.
>     * options - {Object} Hash table of options.
>     */
>    initialize: function(name, layers, options) {
>        Geoportal.Layer.prototype.initialize.apply(this,[name, options]);
>        this.layers= [];
>        this.addLayers(layers);
>    },
>
>    /**
>     * APIMethod: destroy
>     * Clean up the compound layer.
>     *
>     * Parameters:
>     * setNewBaseLayer - {Boolean} Set a new base layer when this layer has
>     *     been destroyed.  Default is true.
>     */
>    destroy: function(setNewBaseLayer) {
>        if (this.map) {
>            this.map.events.unregister("removelayer",this,this.remove);
>        }
>        if (this.layers) {
>            for (var i= 0, len= this.layers.length; i<len; i++) {
>                this.layers[i].aggregate= null;
>            }
>            this.layers= null;
>        }
>        Geoportal.Layer.prototype.destroy.apply(this,arguments);
>    },
>
>    /**
>     * Method: remove
>     * Remove the aggregation from the map.
>     *
>     * Parameters:
>     * evt - {Event}
>     */
>    remove: function(evt) {
>        if (evt.layer != this) { return; }
>        if (this.layers) {
>            var layer;
>            for (var i= 0, len= this.layers.length; i<len; i++) {
>                layer= this.layers[i];
>                layer.map.removeLayer(this.layers[i],false);
>            }
>        }
>    },
>
>    /**
>     * Method: clone
>     *
>     * Returns:
>     * {<Geoportal.Layer>} An exact clone of this <Geoportal.Layer>
>     */
>    clone: function() {
>        var obj= Geoportal.Layer.prototype.clone.apply(this,arguments);
>        // FIXME: a layer may belong to multiple aggregates ?
>        obj.addLayers(this.layers);
>    },
>
>    /**
>     * Method: setMap
>     * Set the map property for the layer. This is done through an accessor
>     *     so that subclasses can override this and take special action once
>     *     they have their map variable set.
>     *
>     *     Here we take care to bring over any of the necessary default
>     *     properties from the map.
>     *
>     * Parameters:
>     * map - {<OpenLayers.Map>}
>     */
>    setMap: function(map) {
>        if (this.map != null) { return; }
>        if (!this.layers) { return; }
>        var layer;
>        for (var i= 0, len= this.layers.length; i<len; i++) {
>            layer= this.layers[i];
>            if (layer.map == null) {
>                map.addLayer(layer);
>            }
>        }
>        var me= this.maxExtent == null;
>        Geoportal.Layer.prototype.setMap.apply(this,arguments);
>        if (me) {
>            this.maxExtent= null;
>            for (var i= 0, len= this.layers.length; i<len; i++) {
>                layer= this.layers[i];
>                if (i==0) {
>                    this.maxExtent= layer.maxExtent.clone();
>                } else {
>                    this.maxExtent.extend(layer);
>                }
>            }
>        }
>        // update layers' z-index :
>        this.setZIndex(this.getZIndex());
>        this.map.events.register("removelayer",this,this.remove);
>    },
>
>    /**
>     * APIMethod: removeMap
>     * The layer has been removed from the map.
>     *
>     * Parameters:
>     * map - {<OpenLayers.Map>}
>     */
>    removeMap: function(map) {
>        if (this.map == null) { return; }
>        if (this.layers) {
>            var layer;
>            for (var i= 0, len= this.layers.length; i<len; i++) {
>                layer= this.layers[i];
>                if (layer.map != null) {
>                    layer.map.removeLayer(layer);
>                }
>            }
>        }
>    },
>
>    /**
>     * APIMethod: setVisibility
>     * Set the visibility flag for the layer and hide/show & redraw
>     *     accordingly. Fire event unless otherwise specified
>     *
>     * Note that visibility is no longer simply whether or not the layer's
>     *     style.display is set to "block". Now we store a 'visibility' state
>     *     property on the layer class, this allows us to remember whether or
>     *     not we *desire* for a layer to be visible. In the case where the
>     *     map's resolution is out of the layer's range, this desire may be
>     *     subverted.
>     *
>     * Parameters:
>     * visible - {Boolean} Whether or not to display the layer (if in range)
>     */
>    setVisibility: function(visibility) {
>        if (visibility != this.visibility) {
>            this.visibility= visibility;
>            Geoportal.Layer.prototype.display.apply(this,arguments);
>            if (this.layers && this.map!=null) {
>                var layer, lproj;
>                for (var i= 0, len= this.layers.length; i<len; i++) {
>                    layer= this.layers[i];
>                    if (layer.isBaseLayer) { continue; }
>                    if (layer.territory!==undefined &&
> this.map.baseLayer.territory!==undefined) {
>                        if (layer.territory==this.map.baseLayer.territory) {
>                            if (visibility) {
>                                layer.setVisibility(layer.calculateInRange());
>                            } else {
>                                layer.setVisibility(false);
>                            }
>                        }
>                        continue;
>                    }
>                    lproj= layer.getNativeProjection();
>                    if (!lproj) { continue; }
>                    if
> (!(lproj.equals(this.map.baseLayer.nativeProjection)
> ||
>                          (lproj.proj.projName=='longlat' &&
>                           lproj.isCompatibleWith(this.map.baseLayer.nativeProjection))))
> { continue; }
>                    if (!(layer.restrictedExtent || layer.maxExtent) ||
>                          this.map.baseLayer.maxExtent.containsBounds(
>                            layer.restrictedExtent ||
> layer.maxExtent,true,true)) {
>                        if (visibility) {
>                            layer.setVisibility(layer.calculateInRange());
>                        } else {
>                            layer.setVisibility(false);
>                        }
>                    }
>                }
>            }
>            if (this.map != null) {
>                this.map.events.triggerEvent("changelayer", {
>                    layer: this,
>                    property: "visibility"
>                });
>            }
>            this.events.triggerEvent("visibilitychanged");
>        }
>    },
>
>    /**
>     * APIMethod: display
>     * Hide or show the Layer.
>     *
>     * Parameters:
>     * display - {Boolean}
>     */
>    display: function(display) {
>        var inRange = this.calculateInRange();
>        if (display != (this.div.style.display != "none")) {
>            this.div.style.display = (display && inRange) ? "block" : "none";
>            if (this.layers) {
>                var layer;
>                for (var i= 0, len= this.layers.length; i<len; i++) {
>                    layer= this.layers[i];
>                    layer.display(display);
>                }
>            }
>        }
>    },
>
>    /**
>     * Method: initResolutions
>     * This method's responsibility is to set up the 'resolutions' array
>     *     for the layer -- this array is what the layer will use to
> interface
>     *     between the zoom levels of the map and the resolution display
>     *     of the layer.
>     *
>     * The user has several options that determine how the array is set up.
>     *
>     * For a detailed explanation, see the following wiki from the
>     *     openlayers.org homepage:
>     *     http://trac.openlayers.org/wiki/SettingZoomLevels
>     */
>    initResolutions: function() {
>        if (this.layers) {
>            var layer;
>            var mnz= typeof(this.options.minZoomLevel) == 'number';
>            var mxz= typeof(this.options.maxZoomLevel) == 'number';
>            for (var i= 0, len= this.layers.length; i<len; i++) {
>                layer= this.layers[i];
>                if (i==0) {
>                    if (!mnz && typeof(layer.minZoomLevel) == 'number') {
>                        this.options.minZoomLevel= layer.minZoomLevel;
>                    }
>                    if (!mxz && typeof(layer.maxZoomLevel) == 'number') {
>                        this.options.maxZoomLevel= layer.maxZoomLevel;
>                    }
>                } else {
>                    if (!mnz && typeof(layer.minZoomLevel) == 'number') {
>                        this.options.minZoomLevel=
> Math.min(this.options.minZoomLevel,
> layer.minZoomLevel);
>                    }
>                    if (!mxz && typeof(layer.maxZoomLevel) == 'number') {
>                        this.options.maxZoomLevel=
> Math.max(this.options.maxZoomLevel,
> layer.maxZoomLevel);
>                    }
>                }
>            }
>        }
>        Geoportal.Layer.prototype.initResolutions.apply(this,arguments);
>    },
>
>    /**
>     * Method: getDataExtent
>     * Calculates the max extent which includes all of the data for the
> layer.
>     *     This function is to be implemented by subclasses.
>     *
>     * Returns:
>     * {<OpenLayers.Bounds>}
>     */
>    getDataExtent: function () {
>        var de= null;
>        if (this.layers) {
>            var layer;
>            for (var i= 0, len= this.layers.length; i<len; i++) {
>                layer= this.layers[i];
>                if (i==0) {
>                    de= layer.getDataExtent();
>                } else {
>                    de.extend(layer.getDataExtent());
>                }
>            }
>        }
>        return de;
>    },
>
>    /**
>     * APIMethod: setOpacity
>     * Sets the opacity for the entire layer (all images)
>     *
>     * Parameter:
>     * opacity - {Float}
>     */
>    setOpacity: function(opacity) {
>        if (opacity != this.opacity) {
>            Geoportal.Layer.prototype.setOpacity.apply(this,arguments);
>            if (this.layers) {
>                var layer;
>                for (var i= 0, len= this.layers.length; i<len; i++) {
>                    layer= this.layers[i];
>                    layer.setOpacity(opacity);
>                }
>            }
>        }
>    },
>
>    /**
>     * Method: setZIndex
>     * Assign the aggregation z-index.
>     *      Aggregated layers have their z-index numbered from the
> aggregation's
>     *      z-index by decrementing their rank to the base z-index.
>     *
>     * Parameters:
>     * zIndex - {Integer}
>     */
>    setZIndex: function (zIndex) {
>        this.div.style.zIndex = zIndex;
>        if (this.layers) {
>            var layer;
>            for (var i= 0, len= this.layers.length; i<len; i++) {
>                layer= this.layers[i];
>                // sub-layers are added before the aggregation to the map
>                // the first sub-layer has z-index Z_INDEX_BASE['Overlay']
> + rank * 5
>                // the last sub-layer's z-index is augmented by
> layers.length * 5
>                // the aggregation's z-index is augmentented by
> (layers.length + 1) * 5
>                if (layer.div) {
>                    // on destroying the map, the sub-layer are destroyed
>                    // before the aggregation ... if which case layer's
> div is
>                    // null !
>                    layer.setZIndex(zIndex-i-1);
>                }
>            }
>        }
>    },
>
>    /**
>     * APIMethod: addLayer
>     * Add a layer to an aggregation.
>     *
>     * Parameters:
>     * layer - {<OpenLayers.Layer>}
>     */
>    addLayer: function(layer) {
>        var lyr;
>        for (var i= 0, len= this.layers.length; i<len; i++) {
>            lyr= this.layers[i];
>            if (lyr == layer) {
>                var msg= OpenLayers.i18n('layerAlreadyAdded',
> {'layerName':layer.name});
>                OpenLayers.Console.warn(msg);
>                return;
>            }
>        }
>        layer.displayInLayerSwitcher= false;
>        layer.visibility= this.visibility;
>        // FIXME: a layer may belong to multiple aggregates ?
>        layer.aggregate= this;
>        this.layers.push(layer);
>        if (this.map) {
>            if (layer.map == null) {
>                this.map.addLayer(layer);
>            }
>            this.initResolutions();
>            this.setZIndex(this.getZIndex());
>        }
>    },
>
>    /**
>     * APIMethod: addLayers
>     * Add layers to an aggregation.
>     *
>     * Parameters:
>     * layers - {Array(<OpenLayers.Layer>)}
>     */
>    addLayers: function(layers) {
>        if (!layers) { return; }
>        if (!(layers instanceof Array)) {
>            this.addLayer(layers);
>            return;
>        }
>        for (var i= 0, len= layers.length; i<len; i++) {
>            this.addLayer(layers[i]);
>        }
>    },
>
>    /**
>     * Constant: CLASS_NAME
>     * {String} *"Geoportal.Layer.Aggregate"*
>     */
>    CLASS_NAME:"Geoportal.Layer.Aggregate"
> });
>
>
> Note that Geoportal.Layer is just a synonym of OpenLayers.Layer
>
> Regards,
>
> didier
>>
>>>>
>>>> Tnx&Cheers,
>>>>
>>>>
>>>> --
>>>> Ivan Grcic
>>>> _______________________________________________
>>>> Dev mailing list
>>>> Dev at openlayers.org
>>>> http://openlayers.org/mailman/listinfo/dev
>>>>
>>>
>>> --
>>> Eric Lemoine
>>>
>>> Camptocamp France SAS
>>> Savoie Technolac, BP 352
>>> 73377 Le Bourget du Lac, Cedex
>>>
>>> Tel : 00 33 4 79 44 44 96
>>> Mail : eric.lemoine at camptocamp.com
>>> http://www.camptocamp.com
>>> _______________________________________________
>>> Dev mailing list
>>> Dev at openlayers.org
>>> http://openlayers.org/mailman/listinfo/dev
>>>
>>
>>
>>
>> --
>> Ivan Grcic
>> _______________________________________________
>> Dev mailing list
>> Dev at openlayers.org
>> http://openlayers.org/mailman/listinfo/dev
>>
>
>
> --
> RICHARD Didier - Chef du pôle technique du Géoportail
> 2/4, avenue Pasteur - 94165 Saint Mandé Cedex
> Tél : +33 (0) 1 43 98 83 23
> _______________________________________________
> Dev mailing list
> Dev at openlayers.org
> http://openlayers.org/mailman/listinfo/dev
>



-- 
Ivan Grcic



More information about the Dev mailing list