Nokia Maps API Reference

Contents

Interface nokia.maps.dom.DragEventTarget

Interface Summary

This class is a virtual interface that does exist for documentation purposes. Each class implementing this interface delcares that it can act as the target for certain events. Each event in this interface (and therefore also within the classes implementing the interface) represents an event of a specific type.

The following example shows event handling for events of the type "click":

// Note that "obj" can be either a DOM node or any other JavaScript object.
var obj = nokia.maps.dom.EventTarget( {} );
obj.addListener("click", function (evt) {
	console.log("This is the '"+evt.type+"' event!");
});

obj.dispatch( new nokia.maps.dom.Event({
	type: "click"
});

The example creates an instant of nokia.maps.dom.EventTarget, adds a listener for "click" events to it, and dispatches a "click" event to all registered listeners (in this case one) - the listeners receive the object that represents the target of the event.

For more information about dispatching events, please refer to the documentation of the nokia.maps.dom.EventTarget.

Drag and drop in a nutshell

The following description discusses event handling for drag and drop events. These are likely to be the most complex events, although once you have understood them, you should find them quite straightforward to process. The W3C homepage offers a very detailed explanation of drag and drop - please see http://dev.w3.org/html5/spec/dnd.html. Our text attempts to capture the information you need in a nutshell, plus it covers some information about the non-standard not lifted dragging, which is an arbitrary extension to the W3C specification and should help you use drag and drop events for certain special cases (such as implementing sliders).

Drag and drop concerns seven events, three of them (dragstart, drag and dragend) are fired at the DOM node that is dragged and four (dragenter, dragover, dragleave and drop) are fired at the DOM node over which the source node is dragged or onto which the source node is dropped (this does not occur in not lifted dragging, but more about that later).

Before we start

First, however, please note that the following code is always expected to be executed before the small code examples we provide below:

 // Create a few shortcuts.
 var Page = nokia.maps.dom.Page,
	  EventTarget = nokia.maps.dom.EventTarget;

 // Query page support for the document. This is very 
 // important, but needs only to be done once. 
 Page(document);

Dragging Basics The first step is to ensure that the DOM node to be dragged is draggable. The class nokia.maps.dom.EventTarget offers support in this respect through a method that takes care of all browser-specific details:

 // Make a DOM node an event target and draggable.
 EventTarget(node).enableDrag();

This simple code guarantess that the browser fires a dragstart event as soon as the user tries to drag node or any of its children. What is more, this is valid for touch screens (for example the iPhone). If the event is canceled, then dragging is disallowed, otherwise it is allowed (by default). While a drag operation is in progress, no other mouse, touch or keyboard events are fired.

Note that the above applies also to the mouseup and click events. You can get a mousedown event, but no mouseup or click event follow it if the mousedown event started a drag operation and dragstart event is not canceled with a call to preventDefault(). Therefore, it is best not only to register a listener for mousedown and mouseup (assuming you want to track these two events), but also for dragend in the capture phase. A mousedown followed by a dragend indicates the mouse button has been released -- a mouseup is not generated. This means you can simply use the dragend as a mouseup event. If you recieved a mousedown at a node, you can be sure that you will receive a dragend at the same node at least within the capture phase.

Each of the seven drag events has a special property called dataTransfer, which holds an instance of nokia.maps.dom.DataTransfer. This object contains information about the drag operation and is used to control it. In addition, the object can be used to transfer data between the different drag listeners, as it is guaranteed that the object itself is attached to all drag events from dragstart to dragend. However, the next drag sequence has a new dataTransfer object associated with it (so you cannot transfer data between to separate drag sequences).

Dragging from the point of view of drag target

The event dragstart has a property named effectAllowed. It determines what kind of operation can be performed on the dragged object, for example, whether the object can be copied, linked and/or moved. The value of this property is set by the event handler to one of the following strings: "uninitialized", "none", "copy", "copyLink", "copyMove", "all", "link", "linkMove" or "move". The default value is "uninitialized" and has the same meaning as "all".

The dragstart event allows you to define the visual feedback of the drag as well. There are two methods available on the data transfer object for this purpose: setDragImage(node, offsetX, offsetY) and addElement(node). You can only have one drag image (a picture visible while dragging is in progress), so a second call to setDragImage() overwrites the previously set image node. addElement() adds an unlimited number of additional elements to the visual feedback. The visual feedback (all added elements and/or the drag image) is rendered relative to the hot spot of the mouse cursor or the touch point of the finger on a touch screen and is shown stretching to the right and down from the mouse pointer or the dragging finger. You can fine-tune where the drag image appears via its offset coordinates. The offset has no effect for the elements added using the addElement(), but their style property position can be set to "absolute" and then they can be offset using the CSS properties style.left and style.top.

While dragging is in progress, the brower fires a "drag" event every few milliseconds at the source node that is being dragged. If the event is canceled (preventDefault is called), dragging is aborted, otherwise it continues. In most cases, the drag event can be ignored, except, for example, for not lifted dragging to which we return shortly.

When dragging is finished, the source node (the drag target) receives a dragend event with information reflecting the action that was performed when the dragged object reached the drop zone. The information is stored in the property dropEffect of the data transfer object and is "none", "copy", "move" or "link". If the drop was aborted or failed, the effect is none. This is important information in the example that follows, because if the dragged element was not moved, the node must be re-inserted into the document at the position it occupied before draggin began:

 // This function makes an image node draggable.
 var makeImageDraggable = function ( node ) {
	// Create a closure so that every call to this method 
	// can handle it's own node.
	(function (node) {
	  // Make the image draggable.
	  EventTarget(node).enableDrag();
 
	  // These variables are used later to put the image
	  // back where it was should dragging fail.
	  var sourceNodeParent;
	  var sourceNodeNextSibling;

	  // Register a dragstart listener.
	  node.addListener("dragstart", function (evt) {
		// Remember the parent node and next sibling of the image.
		sourceNodeParent = node.parentNode;
		sourceNodeNextSilbing = sourceNode.nextSilbing;
		
		// Detach the image from the document.
		sourceNodeParent.removeChild (node);
		
		// Attach the image to the cursor so that it is dragged around.
		evt.dataTransfer.setDragImage( sourceNode, -evt.targetX || 0, -evt.targetY || 0);
		
		// Allow all kinds of drag operations.
		evt.dataTransfer.effectAllowed = "all";
		
		// Prevent any other drag handlers from receiving this event,
		// but do not cancel the event, because that would abort 
		// dragging.
		evt.stopImmediatePropagation();
	  }, false);
	  
	  // Register a dragend listener.
	  node.addListener("dragend", function (evt) {
		// If the image was not moved somewhere else
		if (evt.dataTransfer.dropEffect!=="move") {
		  // we have to move the image back to where it was.
		  if (sourceNodeNextSilbing)
			sourceNodeParent.insertBefore(node, sourceNodeNextSilbing);
		  else
			sourceNodeParent.appendChild(node);
		}
		// Note: If the image was moved, we don't need to do anything!

		// Let's cancel the event now that we have processed it. The event
		// must not be processed by the browser or any other listener.
		event.cancel();
	  }, false);
	})(node);
 };

So far we have explained one aspect of drag and drop: what you need to do if you want to make a DOM node draggable. Next, we consider how to create a drop zone, where the dragged object can be dropped. Our next example extends the previous one by allowing the image to be dropped anywhere within the document.

The drag from the drop target perspective

A dropzone can be any DOM node or JavaScript object that is an instance of nokia.maps.dom.EventTarget. Whenever the mouse is moved onto such a node, the browser fires a dragenter event at that node. If the event is not canceled (by calling preventDefault), the browser estimates that a drop is not handled by the node and disallows a drop to it. If the event is canceled (preventDefault has been called), the listener must set the property dropEffect on the data transfer object to indicate the operation that the node wants to perform with the dragged element. If an image is dragged, dropEffect must be said to "move".

The next event to be fired is dragover. It is fired regularly like the drag event, but it is fired at the current drop target. This event must be canceled (by calling preventDefault) and the property dropEffect on the data transfer object must be updated to indicate the desired operation ("none", "copy", "link" or "move". If the event is not canceled, the drop is denied and the dropEffect is set to "none".

Finally if the user releases the mouse button or finger (touch screen) above a drop target that has set the dropEffect to "copy", "link" or "move", a drop event is fired at the drop target. The drop handler executes the required drop effect and cancels the event (by calling preventDefault). If the event is not canceled, the browser automatically executes the drop action (which only works for very specific nodes).

The following code shows a complete drag and drop example for the image:

<html>
<head>
 <!-- please load the API here -->
 <script language="JavaScript">
	// NOTE: This is very important, otherwise no event handling at all 
	// is possible!
	var page = nokia.maps.dom.Page(document);

	// Create a shortcut to the event target class.
	var EventTarget = nokia.maps.dom.EventTarget;

	// This function makes an image node draggable.
	var makeImageDraggable = function ( node ) {
	  // Create a closure so that every call to this method 
	  // can handle its own node.
	  (function (node) {
		// Make the image draggable.
		EventTarget(node).enableDrag();
 
		// These variables are used later to put the image
		// back to where it was originally, if dragging fails.
		var sourceNodeParent;
		var sourceNodeNextSibling;

		// Register a dragstart listener.
		node.addListener("dragstart", function (evt) {
		  // Remember the parent node and next sibling of the image.
		  sourceNodeParent = node.parentNode;
		  sourceNodeNextSilbing = node.nextSilbing;
		
		  // Detach the image from the document
		  sourceNodeParent.removeChild (node);
		
		  // Attach the image to the cursor so that it is dragged around.
		  evt.dataTransfer.setDragImage( node, -evt.targetX || 0, -evt.targetY || 0);
		
		  // Allow all drag operations.
		  evt.dataTransfer.effectAllowed = "all";

		  // Add the image node into the data transfer for the drop zone.
		  evt.dataTransfer.setData("image/gif", node);

		  // Prevent that any other drag handler to receive this event,
		  // but we must not cancel the event, otherwise the 
		  // dragging is aborted.
		  evt.stopImmediatePropagation();
		}, false);
	  
		// Register a dragend listener.
		node.addListener("dragend", function (evt) {
		  // If the image was not moved somewhere else
		  if (evt.dataTransfer.dropEffect!=="move") {
			// we have to move the image back to where it was.
			if (sourceNodeNextSilbing)
			  sourceNodeParent.insertBefore(node, sourceNodeNextSilbing);
			else
			  sourceNodeParent.appendChild(node);
		  }
		  
		  // Note: If the image was moved, we don't need to do anything!

		// Let's cancel the event now that we have processed it. The event
		// must not be processed by the browser or any other listener.
		  evt.cancel();
		}, false);
	  })(node);
	};
	
	function initDnD() {
	  // First of all make the image draggable.
	  makeImageDraggable (document.getElementById("draggableImage") );
	  
	  // Get the DOM node for our drop zone.
	  var dropZone = EventTarget(document.getElementById("dropzone"));
	  
	  // If the draggable image is dragged into our drop zone
	  dropZone.addListener("dragenter", function (evt) {
		// Allow all GIF images to be moved here.
		if (evt.dataTransfer.hasData("image/gif")) {
		  evt.dataTransfer.dropEffect = "move";
		  evt.cancel();
		}
		}, false);

	  // While the draggable image is moved onto the drop zone
	  dropZone.addListener("dragover", function (evt) {
		// Allow all GIF images to be moved here.
		if (evt.dataTransfer.hasData("image/gif")) {
		  evt.dataTransfer.dropEffect = "move";
		  evt.cancel();
		}
		}, false);
	  
	  // If the draggable image is dropped onto our drop zone
	  dropZone.addListener("drop", function (evt) {
		// If the GIF image is dropped here, add it into our drop zone
		// and set the drop effect to "move".
		if (evt.dataTransfer.hasData("image/gif")) {
		  dropZone.appendChild (evt.dataTransfer.getData("image/gif"));
		  evt.dataTransfer.dropEffect = "move";
		  evt.cancel();
		}
		}, false);
	}
 </script>
</head>
<body onload="initDnD()">
 <div>
	<img id="draggableImage" src="http://www.w3.org/Icons/WWW/w3c_home_nb.gif" />
 </div>
 <div id="dropzone" style="width:400px; height:300px; background-color:#eee;">
	<p>Drop the image here</p>
 </div>
</body>
</html>

The not lifted drag and drop

The not lifted drag and drop is a simplified and optimized drag and drop. It is useful if you want to make draggable an element that is confined to a specific area and cannot leave that area, such as the thumb shift of a scroll bar -- once dragging begins, it must not follow the mouse freely, but must move only along the scroll bar. You can make this happen by setting the property lift on the data transfer object of the dragstart event to false. This causes three things:

  1. The dragenter, dragover, dragleave and drop events are no longer be fired, therefore there is no drop zone for the dragged element.
  2. The cursor visible while dragging can be defined by the listener of the dragstart and drag event, ignoring the effectAllowed and dropEffect properties. This can be done by modifying the property cursor property of the dataTransfer object.
  3. A not lifted drag is always a pure soft event, which means simulated. The native browser drag and drop events are not be used, therefore such an event is confined to the document in which it is fired and no other element or external application can 'notice' the drag.

The following example shows how not lifted drag can be used to implement a slider:

<html>
<head>
 <!-- please load API here -->
 <script language="JavaScript">
	// NOTE: This is very important, otherwise no event handling is possible!
	var page = nokia.maps.dom.Page(document);

	// Create a shortcut to the event target class.
	var EventTarget = nokia.maps.dom.EventTarget;
	
	function initDnD() {
	  // Let's make the scrollbar and the thumb shift draggable.
	  var scrollbar = EventTarget(page.$("scrollbar") ).enableDrag();
	  var knob = EventTarget(page.$("knob") ).enableDrag();

	  // Attach a dragstart listener to the scrollbar.
	  scrollbar.addListener("dragstart", function (evt) {
		// If the know is being dragged.
		if (evt.target===knob) {
		  // Remember that the thumb shift is dragged and set the value to the offset
		  // of the dragstart relative to the top-left corner of the target.
		  evt.dataTransfer.setData("application/slider", evt.targetY || 0);
		  
		  // Switch to not lifted dragging and make the cursor a hand.
		  evt.dataTransfer.lift = false;
		  evt.dataTransfer.cursor = "hand";
		} else
		// If the user tries to drag the scalebar, cancel the event and 
		// disallow dragging
		  evt.cancel();
		}, false);

	  // Attach a drag listener to the scrollbar.
	  scrollbar.addListener("drag", function (evt) {
		// If the know is dragged
		if (evt.dataTransfer.hasData("application/slider")) {
		  var targetY = evt.dataTransfer.getData("application/slider");

		  // Calculate the absolute position of the scrollbar
		  // within the document.
		  var scrollbarPos = page.getClientRect(scrollbar);
		  
		  // Calculate the position of the thumb shift relative 
		  // to the scrollbar, parallel to the mouse cursor.
		  var y = evt.pageY - scrollbarPos.top - targetY;
		  
		  // Do not allow the thumb shift to be moved outside of the scrollbar.
		  if (y<0) y = 0;
		  if (y+knob.offsetHeight >= scrollbar.offsetHeight)
			y = scrollbar.offsetHeight - knob.offsetHeight - 1;
		  
		  // Move the thumb shift.
		  knob.style.top = y+"px";
		}
	  }, false);
	}
 </script>
</head>
<body onload="initDnD()">
 <div id="scrollbar" style="position:absolute; top:10px; left:10px; width:30px; height: 200px; background-color:#eee; border:1px solid black;">
	<div id="knob" style="position:absolute; top:0; left:3px; width:24px; height:40px; background-color:black;"> </div>
 </div>
</body>
</html>

Events
drag(evt)
This event is fired at the target object of the dragstart event while a drag operation is in propgress. This event is fired every few milliseconds during the drag operation. The relatedTarget property contains a reference to the object that is currently under the mouse/finger (only for simulated drag events, not for the native onces).

Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.

Parameters:
{nokia.maps.dom.DragEvent} evt An object representing the event
dragend(evt)
This event is fired at the end of a drag operation at the object that was dragged (the target of the dragstart event). The event is fired if the drop was aborted, failed or successful. The event signals the end of a drag operation. The state of the drop operation can be read from the dropEffect which can be "none", "move", "copy" or "link" and reflects the action performed at the drop target. This information can be used either to remove the dragged object (for "move") or to do nothing (for the other drop effects).

Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.

Parameters:
{nokia.maps.dom.DragEvent} evt An object representing the event
dragenter(evt)
This event is fired at an object if the mouse/finger is moved into the visible area of the object during a drag operation. If the event is canceled (preventDefault method was called at the event object), a drop at the target is allowed, otherwise a drop is cannot occur. If the drop is allowed, the target becomes the current drop target.

Note that despite the event name, its behavior is more similar to that of mouseover than mouseenter.

Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.

Parameters:
{nokia.maps.dom.DragEvent} evt An object representing the event
dragleave(evt)
This event is fired at the current drop target if the the mouse/finger leaves the visible area of the target. Note that despite the name of the event, its behavior is more like that one of mouseout than mouseleave.

Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.

Parameters:
{nokia.maps.dom.DragEvent} evt An object representing the event
dragover(evt)
This event is fired at the current drop target while the mouse/finger is on/above the drop target. Note that the dragenter event must be canceled (preventDefault must be called) to make the object the current drop target. So if the dragenter event is not canceled, then no dragover events are fired at all. This is event is fired every few milliseconds as long as the mouse cursor is on/above the drop target. If this event is not canceled (via preventDefault) the dropEffect property is set to "none", which disallows a drop into the drop target. If the event is canceled and the dropEffect is not "none", then a drop into this drop target is allowed.

Note that in spite of the name of this event, its behavior is very different from the behavior of the mouseover event.

Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.

Parameters:
{nokia.maps.dom.DragEvent} evt An object representing the event
dragstart(evt)
This event is fired at an object that has the property draggable set to true and after a mousedown/touch has occurred and the mouse/finger was moved at least three pixels. If the event is not canceled (preventDefault of the event was not called), the drag operation is permitted. The property dataTransfer can be used to keep track of information while a drag operation is in progress.

Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.

Parameters:
{nokia.maps.dom.DragEvent} evt An object representing the event
drop(evt)
This event is fired at the current drop target if the mouse button or finger is released on/above it, which means that the dragenter event and the dragover events were canceled, so their preventDefault methods were called and the allowedEffect property matches the dropEffect property.

If the event is not canceled (preventDefault is called) and the drop target is a text field (for example, a textarea or input element), then the content of the "text/plain" format is inserted into the area to which the mouse point is pointing or added to the end of that area. Otherwise, the dropEffect is set to "none" and no action takes place. If preventDefault was called, the sequence described above does not take place.

Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.

Parameters:
{nokia.maps.dom.DragEvent} evt An object representing the event
Documentation generated on Mon Oct 24 2011 14:24:30 GMT+0200 (CEST).