/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the Clear BSD license. * See http://svn.openlayers.org/trunk/openlayers/license.txt for the * full text of the license. */ /** * @requires OpenLayers/Control.js * @requires OpenLayers/Feature/Vector.js */ /** * Class: OpenLayers.Control.Measure * Allows for drawing of features for measurements. * * Inherits from: * - */ OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { /** * Constant: EVENT_TYPES * {Array(String)} Supported application event types. Register a listener * for a particular event with the following syntax: * (code) * control.events.register(type, obj, listener); * (end) * * Listeners will be called with a reference to an event object. The * properties of this event depends on exactly what happened. * * Supported control event types (in addition to those from ): * measure - Triggered when a measurement sketch is complete. Listeners * will receive an event with measure, units, order, and geometry * properties. * measurepartial - Triggered when a new point is added to the * measurement sketch. Listeners receive an event with measure, * units, order, and geometry. */ EVENT_TYPES: ['measure', 'measurepartial'], /** * APIProperty: handlerOptions * {Object} Used to set non-default properties on the control's handler */ handlerOptions: null, /** * Property: callbacks * {Object} The functions that are sent to the handler for callback */ callbacks: null, /** * Property: displaySystem * {String} Display system for output measurements. Supported values * are 'english', 'metric', and 'geographic'. Default is 'metric'. */ displaySystem: 'metric', /** * Property: geodesic * {Boolean} Calculate geodesic metrics instead of planar metrics. This * requires that geometries can be transformed into Geographic/WGS84 * (if that is not already the map projection). Default is false. */ geodesic: false, /** * Property: displaySystemUnits * {Object} Units for various measurement systems. Values are arrays * of unit abbreviations (from OpenLayers.INCHES_PER_UNIT) in decreasing * order of length. */ displaySystemUnits: { geographic: ['dd'], english: ['mi', 'ft', 'in'], metric: ['km', 'm'] }, /** * Property: delay * {Number} Number of milliseconds between clicks before the event is * considered a double-click. The "measurepartial" event will not * be triggered if the sketch is completed within this time. This * is required for IE where creating a browser reflow (if a listener * is modifying the DOM by displaying the measurement values) messes * with the dblclick listener in the sketch handler. */ partialDelay: 300, /** * Property: delayedTrigger * {Number} Timeout id of trigger for measurepartial. */ delayedTrigger: null, /** * APIProperty: persist * {Boolean} Keep the temporary measurement sketch drawn after the * measurement is complete. The geometry will persist until a new * measurement is started, the control is deactivated, or is * called. */ persist: false, /** * Constructor: OpenLayers.Control.Measure * * Parameters: * handler - {} * options - {Object} */ initialize: function(handler, options) { // concatenate events specific to measure with those from the base this.EVENT_TYPES = OpenLayers.Control.Measure.prototype.EVENT_TYPES.concat( OpenLayers.Control.prototype.EVENT_TYPES ); OpenLayers.Control.prototype.initialize.apply(this, [options]); this.callbacks = OpenLayers.Util.extend( {done: this.measureComplete, point: this.measurePartial}, this.callbacks ); // let the handler options override, so old code that passes 'persist' // directly to the handler does not need an update this.handlerOptions = OpenLayers.Util.extend( {persist: this.persist}, this.handlerOptions ); this.handler = new handler(this, this.callbacks, this.handlerOptions); }, /** * APIMethod: cancel * Stop the control from measuring. If is true, the temporary * sketch will be erased. */ cancel: function() { this.handler.cancel(); }, /** * Method: updateHandler * * Parameters: * handler - {Function} One of the sketch handler constructors. * options - {Object} Options for the handler. */ updateHandler: function(handler, options) { var active = this.active; if(active) { this.deactivate(); } this.handler = new handler(this, this.callbacks, options); if(active) { this.activate(); } }, /** * Method: measureComplete * Called when the measurement sketch is done. * * Parameters: * geometry - {} */ measureComplete: function(geometry) { if(this.delayedTrigger) { window.clearTimeout(this.delayedTrigger); } this.measure(geometry, "measure"); }, /** * Method: measurePartial * Called each time a new point is added to the measurement sketch. * * Parameters: * point - {} The last point added. * geometry - {} The sketch geometry. */ measurePartial: function(point, geometry) { if (geometry.getLength() > 0) { geometry = geometry.clone(); this.delayedTrigger = window.setTimeout( OpenLayers.Function.bind(function() { this.measure(geometry, "measurepartial"); }, this), this.partialDelay ); } }, /** * Method: measure * * Parameters: * geometry - {} * eventType - {String} */ measure: function(geometry, eventType) { var stat, order; if(geometry.CLASS_NAME.indexOf('LineString') > -1) { stat = this.getBestLength(geometry); order = 1; } else { stat = this.getBestArea(geometry); order = 2; } this.events.triggerEvent(eventType, { measure: stat[0], units: stat[1], order: order, geometry: geometry }); }, /** * Method: getBestArea * Based on the returns the area of a geometry. * * Parameters: * geometry - {} * * Returns: * {Array([Float, String])} Returns a two item array containing the * area and the units abbreviation. */ getBestArea: function(geometry) { var units = this.displaySystemUnits[this.displaySystem]; var unit, area; for(var i=0, len=units.length; i 1) { break; } } return [area, unit]; }, /** * Method: getArea * * Parameters: * geometry - {} * units - {String} Unit abbreviation * * Returns: * {Float} The geometry area in the given units. */ getArea: function(geometry, units) { var area, geomUnits; if(this.geodesic) { area = geometry.getGeodesicArea(this.map.getProjectionObject()); geomUnits = "m"; } else { area = geometry.getArea(); geomUnits = this.map.getUnits(); } var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; if(inPerDisplayUnit) { var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; area *= Math.pow((inPerMapUnit / inPerDisplayUnit), 2); } return area; }, /** * Method: getBestLength * Based on the returns the length of a geometry. * * Parameters: * geometry - {} * * Returns: * {Array([Float, String])} Returns a two item array containing the * length and the units abbreviation. */ getBestLength: function(geometry) { var units = this.displaySystemUnits[this.displaySystem]; var unit, length; for(var i=0, len=units.length; i 1) { break; } } return [length, unit]; }, /** * Method: getLength * * Parameters: * geometry - {} * units - {String} Unit abbreviation * * Returns: * {Float} The geometry length in the given units. */ getLength: function(geometry, units) { var length, geomUnits; if(this.geodesic) { length = geometry.getGeodesicLength(this.map.getProjectionObject()); geomUnits = "m"; } else { length = geometry.getLength(); geomUnits = this.map.getUnits(); } var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; if(inPerDisplayUnit) { var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; length *= (inPerMapUnit / inPerDisplayUnit); } return length; }, CLASS_NAME: "OpenLayers.Control.Measure" });