Source: BKGWebMap/Control/Measurement.js

/*
 * Copyright (c) 2013 Bundesamt für Kartographie und Geodäsie.
 * See license.txt in the BKG WebMap distribution or repository for the
 * full text of the license.
 *
 * Author: Dirk Thalheim
 */

/**
 * @requires OpenLayers/BaseTypes/Class.js
 * @requires OpenLayers/Util.js
 * @requires OpenLayers/Style.js
 * @requires OpenLayers/Rule.js
 * @requires OpenLayers/StyleMap.js
 * @requires OpenLayers/Control/Measure.js
 * @requires OpenLayers/Handler/Path.js
 * @requires OpenLayers/Handler/Polygon.js
 * @requires OpenLayers/Layer/Vector.js
 * @requires BKGWebMap/Util.js
 * @requires BKGWebMap/Control.js
 */

/**
 * @classdesc  Tool zum Messen von Entfernungen und Flächen
 *
 * @constructor BKGWebMap.Control.Measurement
 * @param {object} options - Optionen für das Werkzeug
 * @param {object} options.styles - Der Visualisierungstil
 * @param {HTMLElement} options.target - HTML-Element zur Anzeige der Messwertes
 */
BKGWebMap.Control.Measurement = OpenLayers.Class( OpenLayers.Control, {
    /**
     * Visualisierung der Messung
     * @type object
     * @memberOf BKGWebMap.Control.Measurement
     */
    styles : null,


    /**
     * HTML-Element für Moduswahl und Messausgabe
     * @type HTMLElement
     * @memberOf BKGWebMap.Control.Measurement
     */
    target : null,

    /**
     * Selectbox für Messmodus.
     * @type HTMLElement
     * @memberOf BKGWebMap.Control.Measurement
     */
    modeSelectBox : null,

    /**
     * HTML-Element zur Anzeige des Messwertes
     * @type HTMLElement
     * @memberOf BKGWebMap.Control.Measurement
     */
    output : null,

    /**
     * Labels für Beschriftung.
     * @type object
     * @memberOf BKGWebMap.Control.Measurement
     */
    labels : {
        line : 'Entfernung',
        polygon : 'Fläche'
    },

    // type: OpenLayers.Control.TYPE_TOGGLE,
    type: OpenLayers.Control.TYPE_TOOL,

    initialize: function(options) {
        options = OpenLayers.Util.applyDefaults(options, { styles: BKGWebMap.Control.Measurement.STYLES.GELB });
    	// Erweitere Labels, um alle vordefinierten Felder zu erhalten.
    	if('labels' in options) {
    		OpenLayers.Util.extend(this.labels, options.labels);
    		delete options.labels;
    	}
        OpenLayers.Control.prototype.initialize.apply(this, [options]);

        // add style for measure tool
        var style = new OpenLayers.Style();
        style.addRules([new OpenLayers.Rule({symbolizer: this.styles})]);
        var styleMap = new OpenLayers.StyleMap({"default": style});

        // Kontrollen für Messmodi initiieren
        var measureOptions = { persist: true, immediate : true, handlerOptions: {layerOptions: {styleMap: styleMap}}};
        this.measureControls = {
        	line: new OpenLayers.Control.Measure(OpenLayers.Handler.Path, measureOptions),
            polygon: new OpenLayers.Control.Measure(OpenLayers.Handler.Polygon, measureOptions)
        };

        // Messeventhandler registrieren
        for(var key in this.measureControls) {
            var control = this.measureControls[key];
            control.events.on({
                measure: this.handleMeasurements,
                measurepartial: this.handleMeasurements,
                scope: this
            });
        }
    },

    draw: function (px) {
    	var div = OpenLayers.Control.prototype.draw.apply(this, arguments);

        if(!this.target) {
        	this.target = document.createElement('div');
            if(this.map) {
                this.map.viewPortDiv.appendChild( this.target );
                // Damit die Selectbox in der Karte ausgewählt werden kann
                OpenLayers.Event.observe( this.target, "mousedown", BKGWebMap.Util.stopEvent );
                OpenLayers.Event.observe( this.target, "mouseup", BKGWebMap.Util.stopEvent );
                OpenLayers.Event.observe( this.target, "click", BKGWebMap.Util.stopEvent );
            }
        }
        OpenLayers.Element.addClass(this.target, this.displayClass + 'Wrapper');
        this.target.style.display = 'none';

    	// Auswahl für Messmodus
    	this.modeSelectBox = document.createElement('select');
        OpenLayers.Element.addClass(this.modeSelectBox, this.displayClass + 'Select');
        this.target.appendChild(this.modeSelectBox);
        for(var key in this.measureControls) {
    	    var option = document.createElement('option');
            option.innerHTML = this.labels[key];
            option.value = key;
    	    this.modeSelectBox.appendChild(option);
        }
        OpenLayers.Event.observe(this.modeSelectBox, "change", OpenLayers.Function.bindAsEventListener(this.toggleMeasure, this));

    	// Ausgabebereich für Messwerte
    	this.output = document.createElement('span');
    	this.target.appendChild(this.output);

    	return div;
    },

    /**
     * Fügt zusätzlich Subcontrols hinzu
     * @memberOf BKGWebMap.Control.Measurement
     * @param {OpenLayers.Map} map
     */
    setMap: function(map) {
        OpenLayers.Control.prototype.setMap.apply(this, arguments);
        for(var key in this.measureControls) {
        	map.addControl(this.measureControls[key]);
        }

        // Navigationstool ermitteln. Das soll automatisch aktiviert werden wenn Messen aktiviert wird
        var navControls = map.getControlsByClass("OpenLayers.Control.Navigation")
        this._navControl = navControls.length > 0 ? navControls[0] : null;
    },

    /**
     * Aktiviert das Messwerkzeug und wählt den Messmodus entsprechend der Auswahl in der SelectBox
     * @memberOf BKGWebMap.Control.Measurement
     */
    activate: function() {
        if (this._navControl) this._navControl.activate();

        this.target.style.display = '';
        this.toggleMeasure({target: this.modeSelectBox.options[this.modeSelectBox.selectedIndex]});
        return OpenLayers.Control.prototype.activate.apply(this, arguments);
    },

    /**
     * Deaktiviert das Messwerkzeug
     * @memberOf BKGWebMap.Control.Measurement
     */
    deactivate: function() {
        this.target.style.display = 'none';
        for(var key in this.measureControls) {
            var control = this.measureControls[key];
            control.deactivate();
        }
        return OpenLayers.Control.prototype.deactivate.apply(this, arguments);
    },


    /**
     * Reagiert auf Messereignisse und aktualisiert die Anzeige.
     *
     * @memberOf BKGWebMap.Control.Measurement
     * @param {Event} event
     */
    handleMeasurements : function(event) {
//        var geometry = event.geometry;
        var out = "";
        if(event.order == 1) {
            out += event.measure.toFixed(3) + " " + event.units;
        } else {
            out += event.measure.toFixed(3) + " " + event.units + "<sup>2</sup>";
        }
        this.output.innerHTML = out;

    },

    /**
     * Reagiert auf Änderungen in der SelectBox und setzt den gewählten Messmodus
     *
     * @memberOf BKGWebMap.Control.Measurement
     * @param {{target: *}} event
     */
    toggleMeasure : function(event) {
    	var value = event.target.value;
    	this.output.innerHTML = '';
        for(var key in this.measureControls) {
            var control = this.measureControls[key];
            if(value == key) {
                control.activate();
            } else {
                control.deactivate();
            }
        }
    },

    CLASS_NAME: "BKGWebMap.Control.Measurement"
});

/**
 * Visualisierungsstile
 * @type object
 * @constant
 */
BKGWebMap.Control.Measurement.STYLES = BKGWebMap.STYLES;

/**
 * Gelber Visualisierungsstil
 * @deprecated
 * @type object
 * @constant
 */
BKGWebMap.Control.Measurement.STYLE_YELLOW = BKGWebMap.Control.Measurement.STYLES.GELB;

/**
 * roter Visualisierungsstil
 * @deprecated
 * @type object
 * @constant
 */
BKGWebMap.Control.Measurement.STYLE_RED = BKGWebMap.Control.Measurement.STYLE_YELLOW = BKGWebMap.Control.Measurement.STYLES.ROT;

/**
 * Factory-Funktion zur Generierung eines Mesurement Steuerelement.
 * @param {Array<OpenLayers.Control>} controls - Liste der Steuerelemente, in die die neue erzeugten Steuerelemente
 *                                               eingefügt werden sollen.
 * @param {object} config - Konfiguration für Steuerelement (s. Konstruktor BKGWebMap.Control.Measurement)
 * @param {object|string} config.styles - Stylekonfiguration oder key aus BKGWebMap.Control.Measurement.STYLES
 */
BKGWebMap.Control.FACTORIES['measure'] = function(controls, config) {
    if (!config) return;

    config = (typeof config === 'boolean') ? {} : config;

    if (config.styles &&  typeof config.styles === 'string') {
        config.styles = BKGWebMap.Control.Measurement.STYLES[config.styles];
    }

    if (config.target && typeof config.target === 'string') {
        config.target = OpenLayers.Util.getElement(config.target);
    }
    controls.push(new BKGWebMap.Control.Measurement(config));
};