docs: function Canvas(htmlElement) {
  	/*
  	 * initialization
  	 */
  	this.id = htmlElement.id;
  	this.htmlElement = htmlElement;
  	this.blocks = new Array();
  	this.connectors = new Array();
  	this.offsetLeft = calculateOffsetLeft(this.htmlElement);
  	this.offsetTop = calculateOffsetTop(this.htmlElement);	
  	
  	this.width;
  	this.height;
  
  	// create the inner div element
  	this.innerDiv = document.createElement ("div");
  	
  	this.initCanvas = function() {
  		// setup the inner div
  		var children = this.htmlElement.childNodes;
  		var el;
  		var n = children.length;
  		for(var i = 0; i < n; i++) {
  			el = children[0];
  			this.htmlElement.removeChild(el);
  			this.innerDiv.appendChild(el);
  			if(el.style)
  				el.style.zIndex = "2";
  		}
  		this.htmlElement.appendChild(this.innerDiv);
  
  		this.htmlElement.style.overflow = "auto";
  		this.htmlElement.style.position = "relative";
  		this.innerDiv.id = this.id + "_innerDiv";
  		this.innerDiv.style.border = "none";
  		this.innerDiv.style.padding = "0px";
  		this.innerDiv.style.margin = "0px";
  		this.innerDiv.style.position = "absolute";
  		this.innerDiv.style.top = "0px";
  		this.innerDiv.style.left = "0px";
  		this.width = 0;
  		this.height = 0;
  		this.offsetLeft = calculateOffsetLeft(this.innerDiv);
  		this.offsetTop = calculateOffsetTop(this.innerDiv);
  
  		// inspect canvas children to identify first level blocks
  		new DocumentScanner(this, true).scan(this.htmlElement);
  		
  		// now this.width and this.height are populated with minimum values needed for the inner
  		// blocks to fit, add 2 to avoid border overlap;
  		this.height += 2;
  		this.width += 2;
  		
  		var visibleWidth = this.htmlElement.offsetWidth - 2; // - 2 is to avoid border overlap
  		var visibleHeight = this.htmlElement.offsetHeight - 2; // - 2 is to avoid border overlap
  		
  		// consider the scrollbars width calculating the inner div size
  		if(this.height > visibleHeight)
  			visibleWidth -= SCROLLBARS_WIDTH;
  		if(this.width > visibleWidth)
  			visibleHeight -= SCROLLBARS_WIDTH;
  			
  		this.height = Math.max(this.height, visibleHeight);
  		this.width = Math.max(this.width, visibleWidth);
  		
  		this.innerDiv.style.width = this.width + "px";
  		this.innerDiv.style.height = this.height + "px";
  		
  		// init connectors
  		for(i = 0; i < this.connectors.length; i++) {
  			this.connectors[i].initConnector();
  		}
  	}
  	
  	this.visit = function(element) {
  		if (element == this.htmlElement)
  			return true;
  	
  		// check the element dimensions against the acutal size of the canvas
  		this.width = Math.max(this.width, calculateOffsetLeft(element) - this.offsetLeft + element.offsetWidth);
  		this.height = Math.max(this.height, calculateOffsetTop(element) - this.offsetTop + element.offsetHeight);
  		
  		if(isBlock(element)) {
  			// block found initialize it
  			var newBlock = new Block(element, this);
  			newBlock.initBlock();
  			this.blocks.push(newBlock);
  			return false;
  		} else if(isConnector(element)) {
  			// connector found, just create it, source or destination blocks may not 
  			// have been initialized yet
  			var newConnector = new Connector(element, this);
  			this.connectors.push(newConnector);
  			return false;
  		} else {
  			// continue searching nested elements
  			return true;
  		}
  	}
  	
  	/*
  	 * 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.alignBlocks = function() {
  		var i;
  		var roof = 0;
  		// TODO: implement proper layout
  		for (i = 0; i < this.blocks.length ; i++) {
  			var b = this.blocks[i]; //.findBlock(blockId);
  			b.onMove();
  			b.htmlElement.style.top =roof;
  			roof += b.htmlElement.style.height+20;
  			// TODO: alert ("align "+b);
  		}
  		for (i = 0; i < this.connectors.length; i++) {
  			this.connectors[i].repaint();
  			console.log( this.connectors[i]);
  		}
  	}
  
  	this.fitBlocks = function() {
  		for (var i = 0; i < this.blocks.length ; i++) {
  			var b = this.blocks[i]; //.findBlock(blockId);
  			this.blocks[i].fit ();
  		}
  	}
  	/*
  	 * This function searches for a nested block with a given id
  	 */
  	this.findBlock = function(blockId) {
  		var result;
  		for(var i = 0; i < this.blocks.length && !result; i++)
  			result = this.blocks[i].findBlock(blockId);
  		return result;
  	}
  	
  	this.toString = function() {
  		return 'canvas: ' + this.id;		
  	}
  }