Source: BKGWebMap/Layer/MarkerLayer.js

/*
 * Copyright (c) 2013 Bundesamt by 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/Feature.js
 * @requires OpenLayers/Layer/Markers.js
 * @requires BKGWebMap/Util.js
 * @requires BKGWebMap/Popup.js
 * @requires BKGWebMap/Layer.js
 */

/**
 * @classdesc Klasse für Layer zum Hinzufügen von Markern mit Popupfunktion
 *
 * @constructor BKGWebMap.Layer.MarkerLayer
 * @param {string} name - Der Layername
 * @param {object} options - weitere Optionen für den Layer
 **/
BKGWebMap.Layer.MarkerLayer = OpenLayers.Class(OpenLayers.Layer.Markers, {

    /**
     * @memberOf BKGWebMap.Layer.MarkerLayer
     * @type Array<OpenLayers.Feature.Vector>
     */
    features: null,

    initialize:function(name, options) {
      OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments);
      this.features = [];

      // Touch Event für Mobilgeräte registrieren
      this.events.register("touchstart", this, function(e) { /* ??? */ });
    },

    destroy: function() {
        this.removeAllFeatures();
        this.features = null;
        OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments);
    },

    clearMarkers: function() {
        this.removeAllFeatures();
        OpenLayers.Layer.Markers.prototype.clearMarkers.apply(this, arguments);
    },

    /**
     * Erzeugt ein OpenLayers.Marker Objekt zum Einfügen in den Layer.
     * @memberOf BKGWebMap.Layer.MarkerLayer
     * @param {Array|OpenLayers.LonLat} coords - Die Koordinaten des Markers
     * @param {string} contentHTML - HTML-Inhalt für das Popup
     * @param {Object} options - weitere Eigenschaften für das Popup.
     * @param {boolean} options.closeBox - <code>true</code> wenn Icon zum Schließen des Popups angezeigt werden soll.
     * @param {OpenLayers.Size} options.popupSize - Größe für Popup
     * @param {string} options.overflow - CSS-Wert für Overflow verhalten.
     * @return {OpenLayers.Marker}
     */
    createMarker: function(coords, contentHTML, options) {
        if( !(coords instanceof OpenLayers.LonLat) ) {
            coords = new OpenLayers.LonLat(coords);
        }

        options = options ? options : {overflow: 'auto', closeBox: 'true'};
        options.popupContentHTML = contentHTML;
        var feature = new OpenLayers.Feature(this, coords, options);
        return this.createFeatureMarker(feature);
    },

    /**
     * Generiert einen Marker für ein Feature.
     *
     * @memberOf BKGWebMap.Layer.MarkerLayer
     * @param {OpenLayers.Feature} feature - Das Feature, für das der Marker generiert werden soll
     * @param {OpenLayers.Class} popupClass - Klasse für Popup, das geöffnet werden soll, wenn der Marker geklickt wird.
     * @returns {OpenLayers.Marker}
     */
    createFeatureMarker: function(feature, popupClass) {
        feature.popupClass = popupClass || BKGWebMap.Popup;

        var marker = feature.createMarker();
        // Fallback für OpenLayers.Feature.Vector
        if(!marker) {
            // Mitte der Geometrie ermitteln:
            var center = feature.geometry.getCentroid();
            feature.lonlat = new OpenLayers.LonLat(center.x, center.y);
            marker = new OpenLayers.Marker(feature.lonlat, feature.data.icon);
        }
        if(!marker) return null;

        marker.feature = feature;
        feature.marker = marker;

        marker.events.register("mousedown", feature, function(evt) {
            BKGWebMap.Layer.MarkerLayer.togglePopup(this);
            OpenLayers.Event.stop(evt);
        });

        return marker;
    },

    /**
     * Fügt einen Marker in den Layer ein.
     *
     * Im Gegensatz zu addMarker wird hier ein neues OpenLayers.Marker Objekt dynamisch erzeugt.
     *
     * @memberOf BKGWebMap.Layer.MarkerLayer
     *
     * @param {Array|OpenLayers.LonLat} coords - Die Koordinaten des Markers
     * @param {string} contentHTML - HTML-Inhalt für das Popup
     * @param {Object} options - weitere Eigenschaften für das Popup.
     * @param {boolean} options.closeBox - <code>true</code> wenn Icon zum Schließen des Popups angezeigt werden soll.
     * @param {OpenLayers.Size} options.popupSize - Größe für Popup
     * @param {string} options.overflow - CSS-Wert für Overflow verhalten.
     */
    mark: function(coords, contentHTML, options) {
        var marker = this.createMarker(coords, contentHTML, options);
        this.addMarker(marker);
    },

    /**
     * Markiert alle Features mit einem Marker. Verwendet dazu die Mitte der Geometrie.
     *
     * @memberOf BKGWebMap.Layer.MarkerLayer
     * @param {Array<OpenLayers.Feature.Vector>} features - die hinzuzufügenden Features
     * @param {function} getContent - optionale Funktion zur Generierung des HTML-Inhalts für ein Popup
     */
    addFeatures: function(features, getContent) {
        if (!(OpenLayers.Util.isArray(features))) {
            features = [features];
        }

        for (var i=0, len=features.length; i<len; i++) {
            var feature = features[i];

            // Gib Feature Referenz zu diesem Layer
            // TODO: sollte hier anderer Propertyname verwendet werden, falls Features in mehrere Layer eingefügt wird?
            feature.layer = this;

            var marker = this.createFeatureMarker(feature);
            if(!marker) {
                continue;
            }

            // zusätzliche Popup-Optionen setzen falls nötig
            feature.data = OpenLayers.Util.applyDefaults(feature.data, {overflow: 'auto', closeBox: 'true'});
            // generiere Popup-Inhalt
            if(!feature.data.popupContentHTML && getContent) {
                feature.data.popupContentHTML = getContent(feature, i);
            }

            this.features.push(feature);
            this.addMarker(marker);
        }
    },

    /**
     * Löscht alle Features und deren Marker
     * @memberOf BKGWebMap.Layer.MarkerLayer
     */
    removeAllFeatures: function() {
        if(!this.features) return;

        var features = this.features;

        var feature;
        for (var i = features.length-1; i >= 0; i--) {
            feature = features[i];
            feature.layer = null;
            this.removeMarker(feature.marker);
            feature.marker = null;

            if(this.map && feature.popup) {
                this.map.removePopup(feature.popup);
            }
            feature.popup = null;
        }

        this.features = [];
    },

    CLASS_NAME: "BKGWebMap.Layer.MarkerLayer"
});

/**
 * Blended das Popup eines Markers ein oder aus.
 *
 * @memberOf BKGWebMap.Layer.MarkerLayer
 * @param {Event} evt - der Mousedown-Event
 */
BKGWebMap.Layer.MarkerLayer.togglePopup = function (feature) {
    if (feature.popup == null) {
        feature.popup = feature.createPopup(feature.data.closeBox);
        // Fallback für OpenLayers.Feature.Vector
        if (!feature.popup) {
            feature.popup = OpenLayers.Feature.prototype.createPopup.apply(feature, [feature.data.closeBox]);
        }

        if (!feature.popup) return;

        // autoSize abstellen falls explizit Größe übergeben wurde.
        if (feature.data.popupSize) {
            feature.popup.autoSize = false;
        }

        feature.layer.map.addPopup(feature.popup);
        feature.popup.show();
    } else {
        feature.popup.toggle();
    }

};