/* Copyright (c) 2006-2007 MetaCarta, Inc., published under the BSD license. * See http://svn.openlayers.org/trunk/openlayers/release-license.txt * for the full text of the license. */ /** * @requires OpenLayers/Layer.js * @requires OpenLayers/Renderer.js * @requires OpenLayers/Feature/Vector.js * * Class: OpenLayers.Layer.Vector * Instances of OpenLayers.Layer.Vector are used to render vector data from * a variety of sources. Create a new image layer with the * constructor. * * Inherits from: * - */ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, { /** * APIProperty: isBaseLayer * {Boolean} The layer is a base layer. Default is true. Set this property * in the layer options */ isBaseLayer: false, /** * APIProperty: isFixed * {Boolean} Whether the layer remains in one place while dragging the * map. */ isFixed: false, /** * APIProperty: isVector * {Boolean} Whether the layer is a vector layer. */ isVector: true, /** * APIProperty: features * Array({}) */ features: null, /** * Property: selectedFeatures * Array({}) */ selectedFeatures: null, /** * APIProperty: reportError * {Boolean} report error message via alert() when loading of renderers * fails. */ reportError: true, /** * APIProperty: style * {Object} Default style for the layer */ style: null, /** * Property: renderers * Array({String}) List of supported Renderer classes. Add to this list to * add support for additional renderers. This list is ordered: * the first renderer which returns true for the 'supported()' * method will be used, if not defined in the 'renderer' option. */ renderers: ['SVG', 'VML'], /** * Property: renderer * {} */ renderer: null, /** * APIProperty: geometryType * {String} geometryType allows you to limit the types of geometries this * layer supports. This should be set to something like * "OpenLayers.Geometry.Point" to limit types. */ geometryType: null, /** * Property: drawn * {Boolean} Whether the Vector Layer features have been drawn yet. */ drawn: false, /** * Constructor: OpenLayers.Layer.Vector * Create a new vector layer * * Parameters: * name - {String} A name for the layer * options - {Object} options Object with non-default properties to set on * the layer. * * Returns: * {} A new vector layer */ initialize: function(name, options) { var defaultStyle = OpenLayers.Feature.Vector.style['default']; this.style = OpenLayers.Util.extend({}, defaultStyle); OpenLayers.Layer.prototype.initialize.apply(this, arguments); // allow user-set renderer, otherwise assign one if (!this.renderer || !this.renderer.supported()) { this.assignRenderer(); } // if no valid renderer found, display error if (!this.renderer || !this.renderer.supported()) { this.renderer = null; this.displayError(); } this.features = []; this.selectedFeatures = []; }, /** * APIMethod: destroy * Destroy this layer */ destroy: function() { OpenLayers.Layer.prototype.destroy.apply(this, arguments); this.destroyFeatures(); this.features = null; this.selectedFeatures = null; if (this.renderer) { this.renderer.destroy(); } this.renderer = null; this.geometryType = null; this.drawn = null; }, /** * Method: assignRenderer * Iterates through the available renderer implementations and selects * and assigns the first one whose "supported()" function returns true. */ assignRenderer: function() { for (var i = 0; i < this.renderers.length; i++) { var rendererClass = OpenLayers.Renderer[this.renderers[i]]; if (rendererClass && rendererClass.prototype.supported()) { this.renderer = new rendererClass(this.div); break; } } }, /** * Method: displayError * Let the user know their browser isn't supported. */ displayError: function() { if (this.reportError) { var message = "Your browser does not support vector rendering. " + "Currently supported renderers are:\n"; message += this.renderers.join("\n"); alert(message); } }, /** * Method: setMap * The layer has been added to the map. * * If there is no renderer set, the layer can't be used. Remove it. * Otherwise, give the renderer a reference to the map and set its size. * * Parameters: * map - {} */ setMap: function(map) { OpenLayers.Layer.prototype.setMap.apply(this, arguments); if (!this.renderer) { this.map.removeLayer(this); } else { this.renderer.map = this.map; this.renderer.setSize(this.map.getSize()); } }, /** * Method: onMapResize * Notify the renderer of the change in size. * */ onMapResize: function() { OpenLayers.Layer.prototype.onMapResize.apply(this, arguments); this.renderer.setSize(this.map.getSize()); }, /** * Method: moveTo * Reset the vector layer's div so that it once again is lined up with * the map. Notify the renderer of the change of extent, and in the * case of a change of zoom level (resolution), have the * renderer redraw features. * * If the layer has not yet been drawn, cycle through the layer's * features and draw each one. * * Parameters: * bounds - {} * zoomChanged - {Boolean} * dragging - {Boolean} */ moveTo: function(bounds, zoomChanged, dragging) { OpenLayers.Layer.prototype.moveTo.apply(this, arguments); if (!dragging) { this.div.style.left = - parseInt(this.map.layerContainerDiv.style.left) + "px"; this.div.style.top = - parseInt(this.map.layerContainerDiv.style.top) + "px"; var extent = this.map.getExtent(); this.renderer.setExtent(extent); } if (!this.drawn || zoomChanged) { this.drawn = true; for(var i = 0; i < this.features.length; i++) { var feature = this.features[i]; this.drawFeature(feature); } } }, /** * APIMethod: addFeatures * Add Features to the layer. * * Parameters: * features - {Array()} */ addFeatures: function(features) { if (!(features instanceof Array)) { features = [features]; } for (var i = 0; i < features.length; i++) { var feature = features[i]; if (this.geometryType && !(feature.geometry instanceof this.geometryType)) { var throwStr = "addFeatures : component should be an " + this.geometryType.prototype.CLASS_NAME; throw throwStr; } this.features.push(feature); //give feature reference to its layer feature.layer = this; if (!feature.style) { feature.style = OpenLayers.Util.extend({}, this.style); } this.preFeatureInsert(feature); if (this.drawn) { this.drawFeature(feature); } this.onFeatureInsert(feature); } }, /** * APIMethod: removeFeatures * * Parameters: * features - {Array()} */ removeFeatures: function(features) { if (!(features instanceof Array)) { features = [features]; } for (var i = features.length - 1; i >= 0; i--) { var feature = features[i]; this.features = OpenLayers.Util.removeItem(this.features, feature); if (feature.geometry) { this.renderer.eraseGeometry(feature.geometry); } //in the case that this feature is one of the selected features, // remove it from that array as well. if (OpenLayers.Util.indexOf(this.selectedFeatures, feature) != -1){ OpenLayers.Util.removeItem(this.selectedFeatures, feature); } } }, /** * APIMethod: destroyFeatures * Destroy all features on the layer and empty the selected features array. */ destroyFeatures: function () { this.selectedFeatures = []; for (var i = this.features.length - 1; i >= 0; i--) { this.features[i].destroy(); } }, /** * Method: drawFeature * Draw (or redraw) a feature on the layer. If the optional style argument * is included, this style will be used. If no style is included, the * feature's style will be used. If the feature doesn't have a style, * the layer's style will be used. * * Parameters: * feature - {} * style - {Object} */ drawFeature: function(feature, style) { if(style == null) { if(feature.style) { style = feature.style; } else { style = this.style; } } this.renderer.drawFeature(feature, style); }, /** * Method: eraseFeatures * Erase features from the layer. * * Parameters: * features - {Array()} */ eraseFeatures: function(features) { this.renderer.eraseFeatures(features); }, /** * Method: getFeatureFromEvent * Given an event, return a feature if the event occurred over one. * Otherwise, return null. * * Parameters: * evt - {Event} * * Returns: * {} A feature if one was under the event. */ getFeatureFromEvent: function(evt) { if (!this.renderer) { OpenLayers.Console.error("getFeatureFromEvent called on layer with no renderer. This usually means you destroyed a layer, but not some handler which is associated with it."); return null; } var featureId = this.renderer.getFeatureIdFromEvent(evt); return this.getFeatureById(featureId); }, /** * APIMethod: getFeatureById * Given a feature id, return the feature if it exists in the features array * * Parameters: * featureId - {String} * * Returns: * {} A feature corresponding to the given * featureId */ getFeatureById: function(featureId) { //TBD - would it be more efficient to use a hash for this.features? var feature = null; for(var i=0; i if(this.features[i].id == featureId) { feature = this.features[i]; break; } } return feature; }, /** * Unselect the selected features * i.e. clears the featureSelection array * change the style back clearSelection: function() { var vectorLayer = this.map.vectorLayer; for (var i = 0; i < this.map.featureSelection.length; i++) { var featureSelection = this.map.featureSelection[i]; vectorLayer.drawFeature(featureSelection, vectorLayer.style); } this.map.featureSelection = []; }, */ /** * APIMethod: onFeatureInsert * method called after a feature is inserted. * Does nothing by default. Override this if you * need to do something on feature updates. * * Paarameters: * feature - {} */ onFeatureInsert: function(feature) { }, /** * APIMethod: preFeatureInsert * method called before a feature is inserted. * Does nothing by default. Override this if you * need to do something when features are first added to the * layer, but before they are drawn, such as adjust the style. * * Parameters: * feature - {} */ preFeatureInsert: function(feature) { }, CLASS_NAME: "OpenLayers.Layer.Vector" });