Simple drag and drop panel : Panel « Ajax Layer « JavaScript DHTML






Simple drag and drop panel

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>js-graph.it homepage</title>

<script type="text/javascript">
/*********************
 * browser detection *
 *********************/

var ie=document.all;
var nn6=document.getElementById&&!document.all;

/*****************
 * drag and drop *
 *****************/
 
var isdrag=false;
var mouseStartX, mouseStartY;    // mouse position when drag starts
var elementStartX, elementStartY;  // element position when drag starts
var elementToMove;
var blockToMove;

// an array containing bounds to be respected while dragging elements,
// these bounds are left, top, left + width, top + height of the parent element.
var bounds = new Array(4);

function movemouse(e)
{
  if (isdrag)
  {
    var currentMouseX = nn6 ? e.clientX : event.clientX;
    var currentMouseY = nn6 ? e.clientY : event.clientY;
    var newElementX = elementStartX + currentMouseX - mouseStartX;
    var newElementY = elementStartY + currentMouseY - mouseStartY;

    // check bounds
    // note: the "-1" and "+1" is to avoid borders overlap
    if(newElementX < bounds[0])
      newElementX = bounds[0] + 1;
    if(newElementX + elementToMove.offsetWidth > bounds[2])
      newElementX = bounds[2] - elementToMove.offsetWidth - 1;
    if(newElementY < bounds[1])
      newElementY = bounds[1] + 1;
    if(newElementY + elementToMove.offsetHeight > bounds[3])
      newElementY = bounds[3] - elementToMove.offsetHeight - 1;
    
    // move element
    elementToMove.style.left = newElementX + 'px';
    elementToMove.style.top  = newElementY + 'px';

//    elementToMove.style.left = newElementX / elementToMove.parentNode.offsetWidth * 100 + '%';
//    elementToMove.style.top  = newElementY / elementToMove.parentNode.offsetHeight * 100 + '%';
  
    elementToMove.style.right = null;
    elementToMove.style.bottom = null;
    
    if(blockToMove)
      blockToMove.onMove();
    return false;
  }
}

/**
 * finds the innermost draggable element starting from the one that generated the event "e"
 * (i.e.: the html element under mouse pointer), then setup the document's onmousemove function to
 * move the element around.
 */
function selectmouse(e) 
{
  
  var eventSource = nn6 ? e.target : event.srcElement;
  
  while (eventSource != document.body && !hasClass(eventSource, "draggable"))
  {    
    eventSource = nn6 ? eventSource.parentNode : eventSource.parentElement;
  }

  // if a draggable element was found, calculate its actual position
  if (hasClass(eventSource, "draggable"))
  {
    isdrag = true;
    elementToMove = eventSource;
    
    // calculate start point
    //elementStartX = calculateOffsetLeft(elementToMove);
    //elementStartY = calculateOffsetTop(elementToMove);
    elementStartX = elementToMove.offsetLeft;
    elementStartY = elementToMove.offsetTop;
    
    // calculate mouse start point
    mouseStartX = nn6 ? e.clientX : event.clientX;
    mouseStartY = nn6 ? e.clientY : event.clientY;
    
    // calculate bounds as left, top, width, height of the parent element
    if(elementToMove.parentNode.style.position == 'absolute')
    {
      bounds[0] = 0;
      bounds[1] = 0;
    }
    else
    {
      bounds[0] = calculateOffsetLeft(elementToMove.parentNode);
      bounds[1] = calculateOffsetTop(elementToMove.parentNode);
    }
    bounds[2] = bounds[0] + elementToMove.parentNode.offsetWidth;
    bounds[3] = bounds[1] + elementToMove.parentNode.offsetHeight;
    
    
    // either find the block related to the dragging element to call its onMove method
    blockToMove = findBlock(eventSource.id);
    document.onmousemove = movemouse;
    
    return false;
  }
}

document.onmousedown=selectmouse;
document.onmouseup=new Function("isdrag=false");



/*************
 * Constants *
 *************/
var AUTO = 0;
var HORIZONTAL = 1;
var VERTICAL = 2;

/**************
 * Inspectors *
 **************/

var inspectors = new Array();

/**
 * The canvas class.
 * This class is built on a div html element.
 */
function Canvas(htmlElement)
{
  /*
   * initialization
   */
  this.id = htmlElement.id;
  this.htmlElement = htmlElement;
  this.blocks = new Array();
  this.connectors = new Array();
  
  this.initCanvas = function()
  {
    // inspect canvas children to identify first level blocks
    this.findNestedBlocksAndConnectors(this.htmlElement);
    
    // init connectors
    var i;
    for(i = 0; i < this.connectors.length; i++)
    {
      this.connectors[i].initConnector();
    }
  }
  
  this.findNestedBlocksAndConnectors = function(node)
  {
    var children = node.childNodes;
    var i;
    var offsetLeft = calculateOffsetLeft(this.htmlElement);
    var offsetTop = calculateOffsetTop(this.htmlElement);
    
    for(i = 0; i < children.length; i++)
    {
      // move element in a "correct relative" position and set it size as fixed
      if(getStyle(children[i], "position") == 'absolute')
      {
        children[i].style.left = children[i].offsetLeft + offsetLeft + "px";
        children[i].style.top = children[i].offsetTop + offsetTop + "px";
        children[i].style.width = children[i].offsetWidth;
        children[i].style.height = children[i].offsetHeight;
      }
    
      if(isBlock(children[i]))
      {
        // block found initialize it
        var newBlock = new Block(children[i], this);
        newBlock.initBlock();
        this.blocks.push(newBlock);
      }
      else if(isConnector(children[i]))
      {
        // connector found, just create it, source or destination blocks may not 
        // have been initialized yet
        var newConnector = new Connector(children[i], this);
        this.connectors.push(newConnector);
      }
      else
      {
        // continue searching nested elements
        this.findNestedBlocksAndConnectors(children[i]);
      }
    }    
  }
  
  /*
   * methods
   */  
  this.print = function()
  {
    var output = '<ul><legend>canvas: ' + this.id + '</legend>';
    var i;
    for(i = 0; i < this.blocks.length; i++)
    {
      output += '<li>';
      output += this.blocks[i].print();
      output += '</li>';
    }
    output += '</ul>';
    return output;
  }
  
  /*
   * This function searches for a nested block with a given id
   */
  this.findBlock = function(blockId)
  {
    var result;
    var i;
    for(i = 0; i < this.blocks.length && !result; i++)
    {
      result = this.blocks[i].findBlock(blockId);
    }
    
    return result;
  }
  
  this.toString = function()
  {
    return 'canvas: ' + this.id;
  }
}

/*
 * Block class
 */
function Block(htmlElement, canvas)
{  
  /*
   * initialization
   */
   
  this.canvas = canvas;
  this.htmlElement = htmlElement;
  this.id = htmlElement.id;
  this.blocks = new Array();
  this.moveListeners = new Array();  
  
  
  this.initBlock = function()
  {
    // inspect block children to identify nested blocks
    var children = this.htmlElement.childNodes;
    var i;    
    for(i = 0; i < children.length; i++)
    {
      if(isBlock(children[i]))
      {
        var innerBlock = new Block(children[i], this.canvas);
        innerBlock.initBlock();
        this.blocks.push(innerBlock);
        this.moveListeners.push(innerBlock);
      }
    }
    
    //this.htmlElement.onmousemove = new Function('if(isdrag) findBlock(\'' + this.id + '\').onMove();');
  }
  
  this.top = function()
  {
    return calculateOffsetTop(this.htmlElement);
  }
  
  this.left = function()
  {
    return calculateOffsetLeft(this.htmlElement);
  }
  
  this.width = function()
  {
    return this.htmlElement.offsetWidth;
  }
  
  this.height = function()
  {
    return this.htmlElement.offsetHeight;
  }
  
  /*
   * methods
   */  
  this.print = function()
  {
    var output = 'block: ' + this.id;
    if(this.blocks.length > 0)
    {
      output += '<ul>';
      var i;
      for(i = 0; i < this.blocks.length; i++)
      {
        output += '<li>';
        output += this.blocks[i].print();
        output += '</li>';
      }
      output += '</ul>';
    }
    return output;
  }
  
  /*
   * This function searches for a nested block (or the block itself) with a given id
   */
  this.findBlock = function(blockId)
  {
    if(this.id == blockId)
      return this;
      
    var result;
    var i;
    for(i = 0; i < this.blocks.length && !result; i++)
    {
      result = this.blocks[i].findBlock(blockId);
    }
    
    return result;
  }
  
  this.move = function(left, top)
  {    
    this.htmlElement.style.left = left;
    this.htmlElement.style.top = top;
    this.onMove();
  }
    
  this.onMove = function()
  {
    var i;
    
    // notify listeners
    for(i = 0; i < this.moveListeners.length; i++)
    {
      this.moveListeners[i].onMove();
    }
  }
  
  this.toString = function()
  {
    return 'block: ' + this.id;
  }
}

/*
 * Connector class.
 * The init function takes two Block objects as arguments representing 
 * the source and destination of the connector
 */
function Connector(htmlElement, canvas)
{
  this.htmlElement = htmlElement;
  this.canvas = canvas;
  this.source = null;
  this.destination = null;
  this.startX = null;
  this.startY = null;
  this.destX = null;
  this.destY = null;
  this.segment1 = null;
  this.segment2 = null;
  this.segment3 = null;
  this.preferredOrientation = AUTO;
  this.orientation = HORIZONTAL;
  this.size = 1;
  this.color = 'black';
  this.moveListeners = new Array();
  
  this.initConnector = function()
  {
    // detect the connector id
    if(this.htmlElement.id)
      this.id = this.htmlElement.id;
    else
      this.id = this.htmlElement.className;
      
    // split the class name to get the ids of the source and destination blocks
    var splitted = htmlElement.className.split(' ');
    if(splitted.length < 3)
    {
      alert('Unable to create connector \'' + id + '\', class is not in the correct format: connector <sourceBlockId>, <destBlockId>');
      return;
    }
    
    var connectorClass = splitted[0] + ' ' + splitted[1] + ' ' + splitted[2];
    
    this.source = this.canvas.findBlock(splitted[1]);
    if(!this.source)
    {
      alert('cannot find source block with id \'' + splitted[1] + '\'');
      return;
    }
    
    this.destination = this.canvas.findBlock(splitted[2]);
    if(!this.destination)
    {
      alert('cannot find destination block with id \'' + splitted[2] + '\'');
      return;
    }
    
    // check preferred orientation
    if(hasClass(this.htmlElement, 'vertical'))
      this.preferredOrientation = VERTICAL;
    else if(hasClass(this.htmlElement, 'horizontal'))
      this.preferredOrientation = HORIZONTAL;
    else
      this.preferredOrientation = AUTO;
    
    // build the segments
    this.segment1 = document.createElement('div');
    this.segment1.id = this.id + "_1";    
    this.canvas.htmlElement.appendChild(this.segment1);

    this.segment1.style.position = 'absolute';
    this.segment1.style.overflow = 'hidden';
    
    if(!getStyle(this.segment1, 'background-color'))
      this.segment1.style.backgroundColor = this.color;
    this.segment1.className = connectorClass;
    
    this.segment2 = document.createElement('div');
    this.segment2.id = this.id + "_2";
    this.canvas.htmlElement.appendChild(this.segment2);

    this.segment2.className = connectorClass;    
    this.segment2.style.position = 'absolute';
    this.segment2.style.overflow = 'hidden';
    
    if(!getStyle(this.segment2, 'background-color'))
      this.segment2.style.backgroundColor = this.color;
    
    this.segment3 = document.createElement('div');
    this.segment3.id = this.id + "_3";
    this.canvas.htmlElement.appendChild(this.segment3);

    this.segment3.style.position = 'absolute';
    this.segment3.style.overflow = 'hidden';
    
    if(!getStyle(this.segment3, 'background-color'))
      this.segment3.style.backgroundColor = this.color;      
    this.segment3.className = connectorClass;
    
    this.repaint();
    
    this.source.moveListeners.push(this);
    this.destination.moveListeners.push(this);
    
    // call inspectors for this connector
    var i;
    for(i = 0; i < inspectors.length; i++)
    {
      inspectors[i].inspect(this);
    }
    
    // remove old html element
    this.htmlElement.parentNode.removeChild(this.htmlElement);
  }
  
  /**
   * Repaints the connector
   */
  this.repaint = function()
  {
    var sourceLeft = this.source.left();
    var sourceTop = this.source.top();
    var sourceWidth = this.source.width();
    var sourceHeight = this.source.height();
    
    var destinationLeft = this.destination.left();
    var destinationTop = this.destination.top();
    var destinationWidth = this.destination.width();
    var destinationHeight = this.destination.height();
    
    if(this.preferredOrientation == HORIZONTAL)
    {
      // use horizontal orientation except if it is impossible
      if((destinationLeft - sourceLeft - sourceWidth) *
        (sourceLeft - destinationLeft - destinationWidth) > 0)
        this.orientation = VERTICAL;
      else
        this.orientation = HORIZONTAL;
    }
    else if(this.preferredOrientation == VERTICAL)
    {
      // use vertical orientation except if it is impossible
      if((destinationTop - sourceTop - sourceHeight) *
        (sourceTop - destinationTop - destinationHeight) > 0)
        this.orientation = HORIZONTAL;
      else
        this.orientation = VERTICAL;
    }
    else
    {
      // auto orientation: change current orientation if it is impossible to maintain
      if(this.orientation == HORIZONTAL &&
        (destinationLeft - sourceLeft - sourceWidth) *
        (sourceLeft - destinationLeft - destinationWidth) > 0)
      {
        this.orientation = VERTICAL;
      }
      else if(this.orientation == VERTICAL &&
        (destinationTop - sourceTop - sourceHeight) *
        (sourceTop - destinationTop - destinationHeight) > 0)
      {
        this.orientation = HORIZONTAL;
      }
    }
    
    if(this.orientation == HORIZONTAL)
    {
      // deduce which face to use on source and destination blocks
      if(sourceLeft + sourceWidth / 2 < destinationLeft + destinationWidth / 2)
      {
        // use left side of the source block and right side of the destination block
        this.startX = sourceLeft + sourceWidth;
        this.destX = destinationLeft;
      }
      else
      {
        // use right side of the source block and left side of the destination block
        this.startX = sourceLeft;
        this.destX = destinationLeft + destinationWidth;
      }

      this.startY = sourceTop + sourceHeight / 2;
      this.destY = destinationTop + destinationHeight /2;
      
      // first horizontal segment positioning
      this.segment1.style.left = Math.min(this.startX, (this.destX + this.startX) / 2) + 'px';
      this.segment1.style.top = this.startY + 'px';
      this.segment1.style.width = Math.abs((this.startX - this.destX) / 2) + this.size + 'px';
      this.segment1.style.height = this.size + 'px';
      
      // vertical segment positioning
      this.segment2.style.left = ((this.startX + this.destX) /2) + 'px';
      this.segment2.style.top = Math.min(this.startY, this.destY) + 'px';
      this.segment2.style.width = this.size + 'px';
      this.segment2.style.height = Math.abs(this.destY - this.startY) + 'px';
      
      // second horizontal segment positioning
      this.segment3.style.left = Math.min((this.startX + this.destX) /2, this.destX) + 'px';
      this.segment3.style.top = this.destY + 'px';
      this.segment3.style.width = Math.abs((this.destX - this.startX) / 2) + 'px';
      this.segment3.style.height = this.size + 'px';
      
      // label positioning
      //this.htmlElement.style.left = this.startX + 'px';
      //this.htmlElement.style.top = this.startY + this.size + 'px';
    }
    else
    {
      // deduce which face to use on source and destination blocks
      if(sourceTop + sourceHeight / 2 < destinationTop + destinationHeight / 2)
      {
        // use bottom side of the sheightblock and top side of thtopestination block
        this.startY = sourceTop + sourceHeight;
        this.destY = destinationTop;
      }
      else
      {
        // use top side of the source block and bottom side of the destination block
        this.startY = sourceTop;
        this.destY = destinationTop + destinationHeight;
      }
      
      this.startX = sourceLeft + sourceWidth / 2;
      this.destX = destinationLeft + destinationWidth / 2;
      
      // first vertical segment positioning
      this.segment1.style.left = this.startX + 'px';
      this.segment1.style.top = Math.min(this.startY, (this.destY + this.startY)/2) + 'px';
      this.segment1.style.width = this.size + 'px';
      this.segment1.style.height = Math.abs((this.startY - this.destY) / 2) + this.size + 'px';
      
      // horizontal segment positioning
      this.segment2.style.left = Math.min(this.startX, this.destX) + 'px';
      this.segment2.style.top = ((this.startY + this.destY) /2) + 'px';
      this.segment2.style.width = Math.abs(this.destX - this.startX) + 'px';
      this.segment2.style.height = this.size + 'px';
      
      // second vertical segment positioning
      this.segment3.style.left = this.destX + 'px';
      this.segment3.style.top = Math.min(this.destY, (this.destY + this.startY) / 2) + 'px';
      this.segment3.style.width = this.size + 'px';
      this.segment3.style.height = Math.abs((this.destY - this.startY) / 2) + 'px';
      
      // label positioning
      //this.htmlElement.style.left = this.startX + 'px';
      //this.htmlElement.style.top = this.startY + this.size + 'px';
    }
  }
  
  this.onMove = function()
  {
    this.repaint();
    
    // notify listeners
    var i;
    for(i = 0; i < this.moveListeners.length; i++)
      this.moveListeners[i].onMove();
  }
}

function ConnectorEnd(connector, htmlElement, segment)
{
  this.connector = connector;
  this.htmlElement = htmlElement;
  this.connector.segment1.parentNode.appendChild(htmlElement);
  // strip extension
  this.src = this.htmlElement.src.substring(0, this.htmlElement.src.lastIndexOf('.'));
  this.srcExtension = this.htmlElement.src.substring(this.htmlElement.src.lastIndexOf('.'));
  
  this.orientation;
  
  this.repaint = function()
  {
    this.htmlElement.style.position = 'absolute';
    
    var orientation;
    var left;
    var top;
    
    if(connector.orientation == HORIZONTAL)
    {
      left = segment.offsetLeft;
      orientation = "l";
      if(segment.offsetLeft == connector.segment2.offsetLeft)
      {
        left += segment.offsetWidth - this.htmlElement.offsetWidth;
        var orientation = "r";
      }
  
      top = segment.offsetTop - (this.htmlElement.offsetHeight / 2);
    }
    else
    {
      top = segment.offsetTop;
      orientation = "u";
      if(segment.offsetTop == connector.segment2.offsetTop)
      {
        top += segment.offsetHeight - this.htmlElement.offsetHeight;
        var orientation = "d";
      }
  
      left = segment.offsetLeft - (this.htmlElement.offsetWidth / 2);
    }
    
    this.htmlElement.style.left = Math.ceil(left) + "px";
    this.htmlElement.style.top = Math.ceil(top) + "px";
    
    if(this.htmlElement.tagName.toLowerCase() == "img" && this.orientation != orientation)
    {        
      this.htmlElement.src = this.src + "_" + orientation + this.srcExtension;
    }
    this.orientation = orientation;
  }
  
  this.onMove = function()
  {
    this.repaint();
  }
}

function SideConnectorLabel(connector, htmlElement, side)
{
  this.connector = connector;
  this.htmlElement = htmlElement;
  this.connector.segment1.parentNode.appendChild(htmlElement);
  if(side == 'source')
    this.segment = connector.segment1;
  else
    this.segment = connector.segment3;
  this.side = side;
    
  this.repaint = function()
  {
    this.htmlElement.style.position = 'absolute';
    
    var segmentOrientation;
    if(this.segment.offsetWidth < this.segment.offsetHeight)
      segmentOrientation = VERTICAL;
    else
      segmentOrientation = HORIZONTAL;
      
    var left = this.segment.offsetLeft;
    var top = this.segment.offsetTop;

    if(segmentOrientation == VERTICAL)
    {
      if(this.segment.offsetTop == connector.segment2.offsetTop)
      {
        // put label on the bottom of the connector (segment goes downward)
        top += this.segment.offsetHeight - this.htmlElement.offsetHeight;
      }
    }
    else
    {
      if(this.segment.offsetLeft == connector.segment2.offsetLeft)
      {
        // anchor the label on its right side to avoid overlap with the block
        left += this.segment.offsetWidth - this.htmlElement.offsetWidth;
      }
      if(this.segment.offsetTop < (this.side == 'source' ? connector.segment3.offsetTop : connector.segment1.offsetTop))
      {
        // put label over the connector rather than below
        top -= this.htmlElement.offsetHeight;
      }      
    }
    
    this.htmlElement.style.left = Math.ceil(left) + "px";
    this.htmlElement.style.top = Math.ceil(top) + "px";
  }
  
  this.onMove = function()
  {
    this.repaint();
  }
}

function MiddleConnectorLabel(connector, htmlElement)
{
  this.connector = connector;
  this.htmlElement = htmlElement;
  this.connector.segment2.parentNode.appendChild(htmlElement);
  
  this.repaint = function()
  {
    this.htmlElement.style.position = 'absolute';
    
    var segmentOrientation;
    if(connector.segment2.offsetWidth < connector.segment2.offsetHeight)
      segmentOrientation = VERTICAL;
    else
      segmentOrientation = HORIZONTAL;
      
    var left;
    var top;

    if(segmentOrientation == VERTICAL)
    {
      // put label at middle height on right side of the connector
      top = connector.segment2.offsetTop + (connector.segment2.offsetHeight - this.htmlElement.offsetHeight) / 2;
      left = connector.segment2.offsetLeft;
    }
    else
    {
      // put connector below the connector at middle widths
      top = connector.segment2.offsetTop;
      left = connector.segment2.offsetLeft + (connector.segment2.offsetWidth - this.htmlElement.offsetWidth) / 2;;
    }
    
    this.htmlElement.style.left = Math.ceil(left) + "px";
    this.htmlElement.style.top = Math.ceil(top) + "px";
  }
  
  this.onMove = function()
  {
    this.repaint();
  }
}

/*
 * Inspector classes
 */

function ConnectorEndsInspector()
{
  this.inspect = function(connector)
  {
    var children = connector.htmlElement.childNodes;
    var i;
    for(i = 0; i < children.length; i++)
    {
      if(hasClass(children[i], "connector-end"))
      {
        var newElement = new ConnectorEnd(connector, children[i], connector.segment3);
        newElement.repaint();
        connector.moveListeners.push(newElement);
      }
      else if(hasClass(children[i], "connector-start"))
      {
        var newElement = new ConnectorEnd(connector, children[i], connector.segment1);
        newElement.repaint();
        connector.moveListeners.push(newElement);
      }
    }
  }
}

function ConnectorLabelsInspector()
{
  this.inspect = function(connector)
  {
    var children = connector.htmlElement.childNodes;
    var i;
    for(i = 0; i < children.length; i++)
    {
      if(hasClass(children[i], "source-label"))
      {
        var newElement = new SideConnectorLabel(connector, children[i], "source");
        newElement.repaint();
        connector.moveListeners.push(newElement);
      }
      else if(hasClass(children[i], "middle-label"))
      {
        var newElement = new MiddleConnectorLabel(connector, children[i]);
        newElement.repaint();
        connector.moveListeners.push(newElement);
      }
      else if(hasClass(children[i], "destination-label"))
      {
        var newElement = new SideConnectorLabel(connector, children[i], "destination");
        newElement.repaint();
        connector.moveListeners.push(newElement);
      }
    }
  }
}

/*
 * Inspector registration
 */

inspectors.push(new ConnectorEndsInspector());
inspectors.push(new ConnectorLabelsInspector());

/*
 * an array containing all the canvases in document
 */
var canvases = new Array();

/*
 * This function initializes the js_graph objects inspecting the html document
 */
function initPageObjects()
{
  if(isCanvas(document.body))
  {
    var newCanvas = new Canvas(document.body);
    newCanvas.initCanvas();
    canvases.push(newCanvas);
  }
  else
  {
  
  var divs = document.getElementsByTagName('div');
  var i;
  for(i = 0; i < divs.length; i++)
  {
    if(isCanvas(divs[i]))
    {
      var newCanvas = new Canvas(divs[i]);
      newCanvas.initCanvas();
      canvases.push(newCanvas);
    }
  }
  }
}


/*
 * Utility functions
 */


function findCanvas(canvasId)
{  
  var i;
  for(i = 0; i < canvases.length; i++)
    if(canvases[i].id == canvasId)
      return canvases[i];
  return null;
}

function findBlock(blockId)
{
  var i;
  for(i = 0; i < canvases.length; i++)
  {
    var block = canvases[i].findBlock(blockId);
    if(block)
      return block;
  }
  return null;
}
 
/*
 * This function determines whether a html element is to be considered a canvas
 */
function isBlock(htmlElement)
{
  return hasClass(htmlElement, 'block');
}

/*
 * This function determines whether a html element is to be considered a block
 */
function isCanvas(htmlElement)
{
  return hasClass(htmlElement, 'canvas');
}

/*
 * This function determines whether a html element is to be considered a connector
 */
function isConnector(htmlElement)
{
  return htmlElement.className && htmlElement.className.match(new RegExp('connector .*'));
}

/*
 * This function calculates the absolute 'top' value for a html node
 */
function calculateOffsetTop(obj)
{
  var curtop = 0;
  if (obj.offsetParent)
  {
    while (obj.offsetParent)
    {
      curtop += obj.offsetTop;
      obj = obj.offsetParent;
    }
  }
  else if (obj.y)
    curtop += obj.y;
  return curtop;  
}

/*
 * This function calculates the absolute 'left' value for a html node
 */
function calculateOffsetLeft(obj)
{
  var curleft = 0;
  if (obj.offsetParent)
  {
    while (obj.offsetParent)
    {
      curleft += obj.offsetLeft;
      obj = obj.offsetParent;
    }
  }
  else if (obj.x)
    curleft += obj.x;
  return curleft;              
}


function hasClass(element, className)
{
  if(!element.className)
    return false;
    
  var classes = element.className.split(' ');
  var i;
  for(i = 0; i < classes.length; i++)
    if(classes[i] == className)
      return true;
  return false;
}

/**
 * This function retrieves the actual value of a style property even if it is set via css.
 */
function getStyle(node, styleProp)
{
  // if not an element
  if( node.nodeType != 1)
    return;
    
  var value;
  if (node.currentStyle)
  {
    // ie case
    styleProp = replaceDashWithCamelNotation(styleProp);
    value = node.currentStyle[styleProp];
  }
  else if (window.getComputedStyle)
  {
    // mozilla case
    value = document.defaultView.getComputedStyle(node, null).getPropertyValue(styleProp);
  }
  
  return value;
}

function replaceDashWithCamelNotation(value)
{
  var pos = value.indexOf('-');
  while(pos > 0 && value.length > pos + 1)
  {
    value = value.substring(0, pos) + value.substring(pos + 1, pos + 2).toUpperCase() + value.substring(pos + 2);
    pos = value.indexOf('-');
  }
  return value;
}

</script>


<style rel="stylesheet" type="text/css">
.draggable
{
  position: absolute;
  cursor: move;
}

.connector
{
  background-color: black;
}

.dock_point
{
  height: 1px;
  width: 1px;
  overflow: hidden;
  padding: 0px !important;
  border: none !important;
  margin: 0px;
  position: absolute;
  font-size: 1px;
  visibility: hidden;
}

div.block
{
  border: 1px solid #262A37;
  background-color: #E0E8FF;
  padding: 5px;
  font-size: 11px;
}

html
{
  padding: 0px;
  margin: 0px;
}

body
{
  font-family: verdana;
  color: #33333F;
  padding: 3px;
  margin: 0px;
  background-color: white;
}

h1
{
  color: #FF7521;
  margin: 0px;
}

h2
{
  font-size: 15px;
  margin: 0px;
}

.middle-label, .source-label, .destination-label
{
  font-size: 11px;
  font-weight: bold;
  padding: 5px;
}

div.connector
{
  background-color: #FF9900;
}

table.main_table 
{
  width: 100%; 
  border-collapse: separate;
}
  
td.menu
{
  padding: 5px;
}

.menu ul
{
  margin: 0px;
  padding: 0px;
  list-style-type: none;
  list-style-position: outside;
}

.menu li
{
  border: none;
  padding: 0px;
  font-size: 12px;
  margin-bottom: 3px;
}

.menu li a
{
  display: block;
  border: 1px solid #262A37;
  width: 100px;
  color: #262A37;
  text-decoration: none;
  padding: 1px;
  background-color: #E0E8FF;
}

.menu li a#active_menu
{
  color: #FF9900;
  border-color: #FF9900;
}

.menu li a:hover
{
  color: #FF9900;
  border-color: #FF9900;
}
</style>




</head>
<body onload="initPageObjects();">
  <table class="main_table">
    <tr>
      <td style="vertical-align: top; padding: 0px;">
      <div id="mainCanvas" class="canvas block" style="width: 100%; height: 400px; background-color: white; padding: 0px;">
        <div id="title_block" class="block draggable" style="top: 100px; left: 100px;">
          <h2>Coming soon...</h2>
        </div>
      </td>
    </tr>
  </table>
  <div class="connector active_menu mainCanvas">
  </div>
  </body>
</html>

           
       








dragdrop.zip( 15 k)

Related examples in the same category

1.View Pane and Load Panel
2.Rounded Corners
3.ViewPane and Explorer