6

The markers are draggable, but I cannot have a custom div on a marker which changes on hover click etc. hence I thought of using custom overlays, but I am not able to find out if custom overlay support drag. There is already an answer to this, but the demo itself does not work,

how to make a Custom Overlays draggable using google-maps v3

I didn't find anything on code reference for overlayView class.

Community
  • 1
  • 1
123Fork
  • 75
  • 1
  • 6

1 Answers1

17

Yes, we can.

DraggableOverlay.prototype = new google.maps.OverlayView();

DraggableOverlay.prototype.onAdd = function() {
  var container=document.createElement('div'),
      that=this;

  if(typeof this.get('content').nodeName!=='undefined'){
    container.appendChild(this.get('content'));
  }
  else{
    if(typeof this.get('content')==='string'){
      container.innerHTML=this.get('content');
    }
    else{
      return;
    }
  }
  container.style.position='absolute';
  container.draggable=true;
      google.maps.event.addDomListener(this.get('map').getDiv(),
                                       'mouseleave',
                                        function(){
          google.maps.event.trigger(container,'mouseup');
        }
      );


      google.maps.event.addDomListener(container,
                                       'mousedown',
                                   function(e){
        this.style.cursor='move';
        that.map.set('draggable',false);
        that.set('origin',e);

        that.moveHandler  = 
              google.maps.event.addDomListener(that.get('map').getDiv(),   
                                               'mousemove',
                                               function(e){
             var origin = that.get('origin'),
                 left   = origin.clientX-e.clientX,
                 top    = origin.clientY-e.clientY,
                 pos    = that.getProjection()
                               .fromLatLngToDivPixel(that.get('position')),
                 latLng = that.getProjection()
                          .fromDivPixelToLatLng(new google.maps.Point(pos.x-left,
                                                                    pos.y-top));
                 that.set('origin',e);
                 that.set('position',latLng);
                 that.draw();
            });


        }
     );

      google.maps.event.addDomListener(container,'mouseup',function(){
        that.map.set('draggable',true);
        this.style.cursor='default';
        google.maps.event.removeListener(that.moveHandler);
      });


  this.set('container',container)
  this.getPanes().floatPane.appendChild(container);
};

function DraggableOverlay(map,position,content){
  if(typeof draw==='function'){
    this.draw=draw;
  }
  this.setValues({
                 position:position,
                 container:null,
                 content:content,
                 map:map
                 });
}



DraggableOverlay.prototype.draw = function() {
  var pos = this.getProjection().fromLatLngToDivPixel(this.get('position'));
  this.get('container').style.left = pos.x + 'px';
  this.get('container').style.top = pos.y + 'px';
};

DraggableOverlay.prototype.onRemove = function() {
  this.get('container').parentNode.removeChild(this.get('container'));
  this.set('container',null)
};

It observes the mousemove-event and modifies the top/left-style of the overlay based on the distance from the last mouse-position.


Usage:

new DraggableOverlay( 
       map,//maps-instance
       latLng,//google.maps.LatLng
       'content',//HTML-String or DOMNode
       function(){}//optional, function that ovverrides the draw-method
       );

The top-left-corner of the overlay by default will be placed at the position provided via the latLng-argument.

To apply a custom drawing use the optional draw-argument of the constructor .


Demo: http://jsfiddle.net/doktormolle/QRuW8/


Edit: This solution will only work up to version 3.27 of the google maps api. Within the release of 3.28 there were changes made on the draggable option of the map.

Release Notes: https://developers.google.com/maps/documentation/javascript/releases#328

aschi
  • 197
  • 1
  • 1
  • 8
Dr.Molle
  • 116,463
  • 16
  • 195
  • 201
  • This code worked (thanks!), but it's terrible to read based on whitespace. Thankfully there's a jsfiddle to prove it works, and you can use the 'TidyUp' button. – Tyler Collier Jan 15 '15 at 16:37
  • It binds a `mousedown` event on the whole `container`, which makes binding click event on the container itself or its children impossible. For example, if the container has a ` – Ding Yu Oct 07 '16 at 01:39
  • @FelixDing : I have no problems with binding of a click http://jsfiddle.net/QRuW8/116/ – Dr.Molle Oct 07 '16 at 23:34
  • @Dr.Molle Thanks. Can you bind the event using an event listener? Like `document.getElementById('button'). addEventListener('click', function(){})` – Ding Yu Oct 10 '16 at 10:15
  • Not directly, because the content is not part of the DOM when you call the constructor. But you may use the onAdd-method to implement it. http://jsfiddle.net/QRuW8/119/ – Dr.Molle Oct 10 '16 at 11:47
  • @Felix Ding: Note: I've modified the constructor, the call of the constructor(added a 4th argument) and the onAdd-method. The scope of the onadd-callback is the container(the DOM-node which represents the draggable overlay) – Dr.Molle Oct 10 '16 at 11:49
  • Hi, any chance to use this with Firefox? As I got some strange behaviour when trying to move the div - no mouseup event and the map is always draggable. Thanks! – SERG Jul 16 '17 at 07:06