6

Openlayers draggable popups

Problem:

Recently I have been working on Openlayers, vector features where the user can draw different vector features on the Openlayers map and than show the results like area covered or radius of the polygon drawn.

The best way I could found was to use Openlayers Popup but in this case a ‘draggable popup‘ so that user can drag this information popup around to see the map and features around. I didn’t find any built-in property to do so, so I tried jQuery-ui draggable plugin to drag the popup. It worked fine other than, when you double click the popup and the popup will stick to your mouse pointer forever and there is no way but to refresh the page to get rid of it. Here is the code I was trying:

;(function($) {
  //Create Openlayers map object
  map = new OpenLayers.Map( 'map' );
  //Layer object
  layer = new OpenLayers.Layer.WMS(
              "OpenLayers WMS",
              "http://labs.metacarta.com/wms/vmap0",
                {layers: 'basic'} );
  //Add layer to the map
  map.addLayer(layer);
  //Zooms out to the maximum extent of the map
  map.zoomToMaxExtent();
  //Openlayers popup
  popup = new OpenLayers.Popup(
      "dragging-issue",
      new OpenLayers.LonLat(5,40),
      new OpenLayers.Size(80,60),
      "Drag Me:Single click, fineDouble click : ( ", true);
  //Add this popup to the map
  map.addPopup(popup);

  //Apply jQuery draggable to the map container of the popup
  $('.olPopup').draggable();
})(jQuery);

Live Demo of the problem

All I can think of this problem is that there is a conflict between double click event in jQuery and Openlayers. I tried to stop propagation for double click event on popup and tried few other ways but it didn’t help.

Solution:

Thanks to Matt Walker for the perfect solution by coding an extension for Openlayers popup which enables it to be draggable.

//In the above code, we will replace $('.olPopup').draggable(); with
  var dragPopup = new OpenLayers.Control.DragPopup(popup);
  map.addControl(dragPopup);

Live Demo of the solution

Here is code which enables an Openlayers popup to be draggable:

/*
 * Move a popup with a drag.
 *
 * @author Matt Walker
 * @class
 */
OpenLayers.Control.DragPopup = OpenLayers.Class(OpenLayers.Control, {

    down: false,

    popPnt: null,

    mapPnt: null,

    popup: null,

    docMouseUpProxy: null,

    /**
     * Constructor: OpenLayers.Control.DragPopup
     * Create a new control to drag a popup.
     *
     * Parameters:
     * @param {OpenLayers.Popup} popup
     * @param {Object} options
     */
    initialize: function(popup, options) {
        OpenLayers.Control.prototype.initialize.apply(this, [options]);
        this.popup = popup;
        this.popup.events.register('mousedown', this, this.mouseDown);
        this.popup.events.register('mouseup', this, this.mouseUp);
        this.popup.events.register('mousemove', this, this.mouseMove);
        // Define a function bound to this used to listen for
        // document mouseout events
        this.docMouseUpProxy = OpenLayers.Function.bind(this.mouseUp, this);
    },

    /**
     * Method: setMap
     * Set the map property for the control.
     *
     * Parameters:
     * map - {} The controls map.
     */
    setMap: function(map) {
        OpenLayers.Control.prototype.setMap.apply(this, [map]);
        this.map.events.register('mousemove', this, this.mouseMove);
    },

    mouseDown: function(evt) {
        //console.log('mouseDown');
        this.down = true;
        this.popPnt = this.popup.events.getMousePosition(evt);
        OpenLayers.Event.observe(document, 'mouseup', this.docMouseUpProxy);
        OpenLayers.Event.stop(evt);
    },

    mouseUp: function(evt) {
        //console.log('mouseUp');
        this.down = false;
        OpenLayers.Event.stopObserving(document, 'mouseup', this.docMouseUpProxy);
        OpenLayers.Event.stop(evt);
    },

    mouseOut: function(evt) {
        //console.log('map.mouseOut');
        this.down = false;
        OpenLayers.Event.stop(evt);
    },

    mouseMove: function(evt) {
        //console.log('mouseMove');
        if (this.down) {
            var mapPntPx = this.map.events.getMousePosition(evt);
            mapPntPx = mapPntPx.add((this.popPnt.x*-1), (this.popPnt.y*-1));
            this.popup.lonlat = this.map.getLonLatFromViewPortPx(mapPntPx);
            this.popup.updatePosition();
        }
        OpenLayers.Event.stop(evt);
    },

    destroy: function() {
        // Remove listeners
        this.popup.events.unregister('mousedown', this, this.mouseDown);
        this.popup.events.unregister('mouseup', this, this.mouseUp);
        this.popup.events.unregister('mousemove', this, this.mouseMove);
        this.map.events.unregister('mousemove', this, this.mouseMove);
        // Clear object references
        this.popup = null;
        this.popPnt = null;
        // allow our superclass to tidy up
        OpenLayers.Control.prototype.destroy.apply(this, []);
    },

    /** @final @type String */
    CLASS_NAME: "OpenLayers.Control.DragPopup"
});

Please comment if you know a better/easy way to make Openlayers popup draggable.

6 Responses

  • October 26, 2010 at 11:53 am

    Hey, I can’t view your site properly within Opera, I actually hope you look into fixing this.

    • October 26, 2010 at 11:57 am

      Thank you for informing me. I will make sure it work on Opera too.

  • Ivor
    January 9, 2012 at 1:14 pm

    Works like a charm. The Anchored/Framed/
    Cloud popups act weird while dragging because they’re being repositioned every time. I fixed this by using the ‘old’ moveTo method when the dragControl.down == true ;


    popup.moveTo = function() {
    if (dragPopup.down) {
    OpenLayers.Popup.prototype.moveTo.apply(this, arguments);
    } else {
    OpenLayers.Popup.Anchored.prototype.moveTo.apply(this, arguments);
    }
    }

  • Ivor
    January 10, 2012 at 3:44 pm

    Another problem for me: I use input elements in my popups and events are captured. Fixed by wrapping mouseUp and mouseDown:

    if ( ! $(evt.target).is(':input') ) { /* original code */}

    • January 18, 2012 at 4:19 pm

      Thanks Ivor for the updates.

      Can you please copy paste whole code (with your fixes) somewhere so I can update the post.

  • February 3, 2012 at 2:52 am

    Visitor recommendations…

    [...]one of our visitors recently recommended the following website[...]……

Leave a Reply

*
*
*

* (Just for the spam protection)

Copyright © 2012 — musings of Aamir Afridi
Aamir's QR code