增加淘宝群内容,修改部分文件组织
This commit is contained in:
		@@ -0,0 +1,309 @@
 | 
			
		||||
// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without modification, are
 | 
			
		||||
// permitted provided that the following conditions are met:
 | 
			
		||||
//
 | 
			
		||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
 | 
			
		||||
// conditions and the following disclaimer.
 | 
			
		||||
//
 | 
			
		||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
 | 
			
		||||
// of conditions and the following disclaimer in the documentation and/or other materials
 | 
			
		||||
// provided with the distribution.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 | 
			
		||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
//
 | 
			
		||||
// The views and conclusions contained in the software and documentation are those of the
 | 
			
		||||
// authors and should not be interpreted as representing official policies, either expressed
 | 
			
		||||
// or implied, of the University of San Francisco
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function AnimatedBTreeNode(id, widthPerElem, h, numElems,  fillColor, edgeColor)
 | 
			
		||||
{
 | 
			
		||||
	fillColor = (fillColor == undefined)? "#FFFFFF" : fillColor;
 | 
			
		||||
	edgeColor = (edgeColor == undefined)? "#000000" : edgeColor;
 | 
			
		||||
	this.init(id, widthPerElem, h, numElems,  fillColor, edgeColor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype = new AnimatedObject();
 | 
			
		||||
AnimatedBTreeNode.prototype.constructor = AnimatedBTreeNode;
 | 
			
		||||
AnimatedBTreeNode.superclass = AnimatedObject.prototype;
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.MIN_WIDTH = 10;
 | 
			
		||||
AnimatedBTreeNode.EDGE_POINTER_DISPLACEMENT = 5;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.init = function(id, widthPerElem, h, numElems,  fillColor, edgeColor)
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
	var  MIN_WIDTH = 10;
 | 
			
		||||
	AnimatedBTreeNode.superclass.init.call(this);
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.backgroundColor = fillColor;
 | 
			
		||||
	this.foregroundColor = edgeColor;
 | 
			
		||||
	
 | 
			
		||||
	this.widthPerElement = widthPerElem;
 | 
			
		||||
	this.nodeHeight = h;
 | 
			
		||||
	this.numLabels = numElems;
 | 
			
		||||
	this.labels = new Array(this.numLabels);
 | 
			
		||||
	this.labelColors = new Array(this.numLabels);
 | 
			
		||||
	for (var i = 0; i < this.numLabels; i++)
 | 
			
		||||
	{
 | 
			
		||||
		this.labelColors[i] = this.foregroundColor;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
	
 | 
			
		||||
AnimatedBTreeNode.prototype.getNumElements = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.numLabels;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.getWidth = function()
 | 
			
		||||
{
 | 
			
		||||
	if (this.numLabels > 0)
 | 
			
		||||
	{
 | 
			
		||||
		return  (this.widthPerElement * this.numLabels);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return AnimatedBTreeNode.MIN_WIDTH;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.setNumElements = function(newNumElements)
 | 
			
		||||
{
 | 
			
		||||
	var i;
 | 
			
		||||
	if (this.numLabels < newNumElements)
 | 
			
		||||
	{
 | 
			
		||||
		for (i = this.numLabels; i < newNumElements; i++)
 | 
			
		||||
		{
 | 
			
		||||
			this.labels[i] = "";
 | 
			
		||||
			this.labelColors[i] = this.foregroundColor;
 | 
			
		||||
		}
 | 
			
		||||
		this.numLabels = newNumElements;
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.numLabels > newNumElements)
 | 
			
		||||
	{
 | 
			
		||||
		for (i = newNumElements; i < this.numLabels; i++)
 | 
			
		||||
		{
 | 
			
		||||
			this.labels[i] = null;
 | 
			
		||||
		}
 | 
			
		||||
		this.numLabels = newNumElements;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.left = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.x  - this.getWidth() / 2.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.right = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.x  + this.getWidth() / 2.0;
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.top = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.y - this.nodeHeight / 2.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.bottom = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.y + this.nodeHeight / 2.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.draw = function(context)
 | 
			
		||||
{
 | 
			
		||||
	var startX;
 | 
			
		||||
	var startY;
 | 
			
		||||
	
 | 
			
		||||
	startX = this.left();
 | 
			
		||||
	if (startX == NaN)
 | 
			
		||||
	{
 | 
			
		||||
		startX  = 0;
 | 
			
		||||
	}
 | 
			
		||||
	startY = this.top();
 | 
			
		||||
	
 | 
			
		||||
	if (this.highlighted)
 | 
			
		||||
	{
 | 
			
		||||
		context.strokeStyle = "#ff0000";
 | 
			
		||||
		context.fillStyle = "#ff0000";
 | 
			
		||||
		
 | 
			
		||||
		context.beginPath();
 | 
			
		||||
		context.moveTo(startX - this.highlightDiff,startY- this.highlightDiff);
 | 
			
		||||
		context.lineTo(startX+this.getWidth() + this.highlightDiff,startY- this.highlightDiff);
 | 
			
		||||
		context.lineTo(startX+this.getWidth() + this.highlightDiff,startY+this.nodeHeight + this.highlightDiff);
 | 
			
		||||
		context.lineTo(startX - this.highlightDiff,startY+this.nodeHeight + this.highlightDiff);
 | 
			
		||||
		context.lineTo(startX - this.highlightDiff,startY - this.highlightDiff);				
 | 
			
		||||
		context.closePath();
 | 
			
		||||
		context.stroke();
 | 
			
		||||
		context.fill();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	context.strokeStyle = this.foregroundColor;
 | 
			
		||||
	context.fillStyle = this.backgroundColor;
 | 
			
		||||
	
 | 
			
		||||
	context.beginPath();
 | 
			
		||||
	context.moveTo(startX ,startY);
 | 
			
		||||
	context.lineTo(startX + this.getWidth(), startY);
 | 
			
		||||
	context.lineTo(startX + this.getWidth(), startY + this.nodeHeight);
 | 
			
		||||
	context.lineTo(startX, startY + this.nodeHeight);
 | 
			
		||||
	context.lineTo(startX, startY);
 | 
			
		||||
	context.closePath();
 | 
			
		||||
	context.stroke();
 | 
			
		||||
	context.fill();
 | 
			
		||||
	
 | 
			
		||||
	context.textAlign = 'center';
 | 
			
		||||
	context.textBaseline   = 'middle'; 
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	for (var i = 0; i < this.numLabels; i++)
 | 
			
		||||
	{
 | 
			
		||||
		var labelx  = this.x - this.widthPerElement * this.numLabels / 2 + this.widthPerElement / 2 + i * this.widthPerElement; 
 | 
			
		||||
		var labely = this.y			   
 | 
			
		||||
 | 
			
		||||
		context.fillStyle = this.labelColors[i];
 | 
			
		||||
		context.fillText(this.labels[i], labelx, labely); 
 | 
			
		||||
	}	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.getHeight = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.nodeHeight;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.setForegroundColor = function(newColor)
 | 
			
		||||
{
 | 
			
		||||
	this.foregroundColor = newColor;
 | 
			
		||||
	for (var i = 0; i < numLabels; i++)
 | 
			
		||||
	{
 | 
			
		||||
		labelColor[i] = newColor;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// TODO:  Kill the magic numbers here
 | 
			
		||||
AnimatedBTreeNode.prototype.getTailPointerAttachPos = function(fromX, fromY, anchor)
 | 
			
		||||
{
 | 
			
		||||
	if (anchor == 0)
 | 
			
		||||
	{
 | 
			
		||||
		return [this.left() + AnimatedBTreeNode.EDGE_POINTER_DISPLACEMENT, this.y + this.nodeHeight * 0.5];
 | 
			
		||||
	}
 | 
			
		||||
	else if (anchor == this.numLabels)
 | 
			
		||||
	{
 | 
			
		||||
		return [this.right() - AnimatedBTreeNode.EDGE_POINTER_DISPLACEMENT, this.y + this.nodeHeight * 0.5];	
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return [this.left() + anchor * this.widthPerElement, this.y + this.nodeHeight * 0.5]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.getHeadPointerAttachPos = function(fromX, fromY)
 | 
			
		||||
{
 | 
			
		||||
	if (fromY < this.y - this.nodeHeight / 2)
 | 
			
		||||
	{
 | 
			
		||||
		return [this.x, this.y - this.nodeHeight / 2];
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.fromY > this.y + this.nodeHeight /  2)
 | 
			
		||||
	{
 | 
			
		||||
		return [this.x, this.y + this.nodeHeight / 2];			
 | 
			
		||||
	}
 | 
			
		||||
	else if (fromX  <  this.x  - this.getWidth() / 2)
 | 
			
		||||
	{
 | 
			
		||||
		return [this.x - this.getWidth() / 2, this.y];
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return [this.x + this.getWidth() / 2, this.y];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.createUndoDelete = function()
 | 
			
		||||
{
 | 
			
		||||
	return new UndoDeleteBTreeNode(this.objectID, this.numLabels, this.labels, this.x, this.y, this.widthPerElement, this.nodeHeight, this.labelColors, this.backgroundColor, this.foregroundColor, this.layer, this.highlighted);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.getTextColor = function(textIndex)
 | 
			
		||||
{
 | 
			
		||||
	textIndex = (textIndex == undefined) ? 0 : textIndex;
 | 
			
		||||
	return this.labelColors[textIndex];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.getText = function(index)
 | 
			
		||||
{
 | 
			
		||||
	index = (index == undefined) ? 0 : index;
 | 
			
		||||
	return this.labels[index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.setTextColor = function(color, textIndex)
 | 
			
		||||
{
 | 
			
		||||
	textIndex = (textIndex == undefined) ? 0 : textIndex;
 | 
			
		||||
	this.labelColors[textIndex] = color;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedBTreeNode.prototype.setText = function(newText, textIndex)
 | 
			
		||||
{
 | 
			
		||||
	textIndex = (textIndex == undefined) ? 0 : textIndex;
 | 
			
		||||
	this.labels[textIndex] = newText;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
function UndoDeleteBTreeNode(id, numLab, labelText, x, y, wPerElement, nHeight, lColors, bgColor, fgColor, l, highlighted)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.posX = x;
 | 
			
		||||
	this.posY = y;
 | 
			
		||||
	this.widthPerElem = wPerElement;
 | 
			
		||||
	this.nodeHeight = nHeight;
 | 
			
		||||
	this.backgroundColor= bgColor;
 | 
			
		||||
	this.foregroundColor = fgColor;
 | 
			
		||||
	this.numElems = numLab;
 | 
			
		||||
	this.labels = labelText;
 | 
			
		||||
	
 | 
			
		||||
	this.labelColors = lColors;
 | 
			
		||||
	this.layer = l;
 | 
			
		||||
	this.highlighted = highlighted;
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
UndoDeleteBTreeNode.prototype = new UndoBlock();
 | 
			
		||||
UndoDeleteBTreeNode.prototype.constructor = UndoDeleteBTreeNode;
 | 
			
		||||
	
 | 
			
		||||
UndoDeleteBTreeNode.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
	world.addBTreeNode(this.objectID, this.widthPerElem, this.nodeHeight, this.numElems, this.backgroundColor, this.foregroundColor);
 | 
			
		||||
	world.setNodePosition(this.objectID, this.posX, this.posY);
 | 
			
		||||
	for (var i = 0; i < this.numElems; i++)
 | 
			
		||||
	{
 | 
			
		||||
		world.setText(this.objectID, this.labels[i], i);
 | 
			
		||||
		world.setTextColor(this.objectID, this.labelColors[i],i);
 | 
			
		||||
	}
 | 
			
		||||
	world.setHighlight(this.objectID, this.highlighted);
 | 
			
		||||
	world.setLayer(this.objectID, this.layer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,210 @@
 | 
			
		||||
// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without modification, are
 | 
			
		||||
// permitted provided that the following conditions are met:
 | 
			
		||||
//
 | 
			
		||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
 | 
			
		||||
// conditions and the following disclaimer.
 | 
			
		||||
//
 | 
			
		||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
 | 
			
		||||
// of conditions and the following disclaimer in the documentation and/or other materials
 | 
			
		||||
// provided with the distribution.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 | 
			
		||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
//
 | 
			
		||||
// The views and conclusions contained in the software and documentation are those of the
 | 
			
		||||
// authors and should not be interpreted as representing official policies, either expressed
 | 
			
		||||
// or implied, of the University of San Francisco
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var AnimatedCircle = function(objectID, objectLabel)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = objectID;
 | 
			
		||||
	this.label = objectLabel;
 | 
			
		||||
	this.radius = 20;
 | 
			
		||||
	this.thickness = 3;
 | 
			
		||||
	this.x = 0;
 | 
			
		||||
	this.y = 0;
 | 
			
		||||
	this.alpha = 1.0;
 | 
			
		||||
	this.addedToScene = true;
 | 
			
		||||
        this.highlightIndex = -1;
 | 
			
		||||
/*	this.foregroundColor  = '#007700';
 | 
			
		||||
	this.backgroundColor  = '#EEFFEE';
 | 
			
		||||
 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedCircle.prototype = new AnimatedObject();
 | 
			
		||||
AnimatedCircle.prototype.constructor = AnimatedCircle;
 | 
			
		||||
 | 
			
		||||
AnimatedCircle.prototype.getTailPointerAttachPos = function(fromX, fromY, anchorPoint)
 | 
			
		||||
{
 | 
			
		||||
	return this.getHeadPointerAttachPos(fromX, fromY);	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedCircle.prototype.getWidth = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.radius * 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.setWidth = function(newWidth)
 | 
			
		||||
{
 | 
			
		||||
	this.radius = newWidth / 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedCircle.prototype.getHeadPointerAttachPos = function(fromX, fromY)
 | 
			
		||||
{
 | 
			
		||||
	var xVec = fromX - this.x;
 | 
			
		||||
	var yVec = fromY - this.y;
 | 
			
		||||
	var len  = Math.sqrt(xVec * xVec + yVec*yVec);
 | 
			
		||||
	if (len == 0)
 | 
			
		||||
	{
 | 
			
		||||
		return [this.x, this.y];
 | 
			
		||||
	}
 | 
			
		||||
	return [this.x+(xVec/len)*(this.radius), this.y +(yVec/len)*(this.radius)];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedCircle.prototype.setHighlightIndex = function(hlIndex)
 | 
			
		||||
{
 | 
			
		||||
    this.highlightIndex = hlIndex;
 | 
			
		||||
    this.highlightIndexDirty = true;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedCircle.prototype.draw = function(ctx)
 | 
			
		||||
{
 | 
			
		||||
	ctx.globalAlpha = this.alpha;
 | 
			
		||||
 | 
			
		||||
	if (this.highlighted)
 | 
			
		||||
	{
 | 
			
		||||
		ctx.fillStyle = "#ff0000";
 | 
			
		||||
		ctx.beginPath();
 | 
			
		||||
		ctx.arc(this.x,this.y,this.radius + this.highlightDiff,0,Math.PI*2, true);
 | 
			
		||||
		ctx.closePath();
 | 
			
		||||
		ctx.fill();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	ctx.fillStyle = this.backgroundColor;
 | 
			
		||||
	ctx.strokeStyle = this.foregroundColor;
 | 
			
		||||
	ctx.lineWidth = 1;
 | 
			
		||||
	ctx.beginPath();
 | 
			
		||||
	ctx.arc(this.x,this.y,this.radius,0,Math.PI*2, true);
 | 
			
		||||
	ctx.closePath();
 | 
			
		||||
	ctx.fill();
 | 
			
		||||
	ctx.stroke();
 | 
			
		||||
	ctx.textAlign = 'center';
 | 
			
		||||
	ctx.font         = '16px Consolas';
 | 
			
		||||
	ctx.textBaseline   = 'middle'; 
 | 
			
		||||
	ctx.lineWidth = 1;
 | 
			
		||||
	ctx.fillStyle = this.foregroundColor;
 | 
			
		||||
	
 | 
			
		||||
	var strList = this.label.split("\n");
 | 
			
		||||
	if (strList.length == 1)
 | 
			
		||||
	{
 | 
			
		||||
             if (this.highlightIndexDirty && this.highlightIndex != -1)
 | 
			
		||||
             {
 | 
			
		||||
                  this.leftWidth = ctx.measureText(this.label.substring(0,this.highlightIndex)).width;
 | 
			
		||||
                  this.centerWidth = ctx.measureText(this.label.substring(this.highlightIndex, this.highlightIndex+1)).width;
 | 
			
		||||
                  this.textWidth = ctx.measureText(this.label).width;
 | 
			
		||||
                  this.highlightIndexDirty = false;
 | 
			
		||||
             }
 | 
			
		||||
             if (this.highlightIndex != -1 && this.highlightIndex < this.label.length) //this.highlghtIndex < this.label.length)
 | 
			
		||||
             {
 | 
			
		||||
                     var  startingXForHighlight = this.x - this.textWidth / 2;
 | 
			
		||||
    	             ctx.textAlign = 'left';
 | 
			
		||||
                    var leftStr = this.label.substring(0, this.highlightIndex);
 | 
			
		||||
                    var highlightStr = this.label.substring(this.highlightIndex, this.highlightIndex + 1)
 | 
			
		||||
                    var rightStr = this.label.substring(this.highlightIndex + 1)
 | 
			
		||||
                    ctx.fillText(leftStr, startingXForHighlight, this.y)
 | 
			
		||||
 	            ctx.strokeStyle = "#FF0000";
 | 
			
		||||
	            ctx.fillStyle = "#FF0000";
 | 
			
		||||
                    ctx.fillText(highlightStr, startingXForHighlight + this.leftWidth, this.y)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	            ctx.strokeStyle = this.labelColor;
 | 
			
		||||
	            ctx.fillStyle = this.labelColor;
 | 
			
		||||
                    ctx.fillText(rightStr, startingXForHighlight + this.leftWidth + this.centerWidth, this.y)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
              }
 | 
			
		||||
              else
 | 
			
		||||
              {
 | 
			
		||||
	    	   ctx.fillText(this.label, this.x, this.y); 		
 | 
			
		||||
              }
 | 
			
		||||
	}
 | 
			
		||||
	else if (strList.length % 2 == 0)
 | 
			
		||||
	{
 | 
			
		||||
		var i;
 | 
			
		||||
		var mid = strList.length / 2;
 | 
			
		||||
		for (i = 0; i < strList.length / 2; i++)
 | 
			
		||||
		{
 | 
			
		||||
			ctx.fillText(strList[mid - i - 1], this.x, this.y - (i + 0.5) * 12);
 | 
			
		||||
			ctx.fillText(strList[mid + i], this.x, this.y + (i + 0.5) * 12);
 | 
			
		||||
			
 | 
			
		||||
		}		
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		var mid = (strList.length - 1) / 2;
 | 
			
		||||
		var i;
 | 
			
		||||
		ctx.fillText(strList[mid], this.x, this.y);
 | 
			
		||||
		for (i = 0; i < mid; i++)
 | 
			
		||||
		{
 | 
			
		||||
			ctx.fillText(strList[mid - (i + 1)], this.x, this.y - (i + 1) * 12);			
 | 
			
		||||
			ctx.fillText(strList[mid + (i + 1)], this.x, this.y + (i + 1) * 12);			
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedCircle.prototype.createUndoDelete = function()
 | 
			
		||||
{
 | 
			
		||||
	return new UndoDeleteCircle(this.objectID, this.label, this.x, this.y, this.foregroundColor, this.backgroundColor, this.layer, this.radius);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
function UndoDeleteCircle(id, lab, x, y, foregroundColor, backgroundColor, l, radius)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.posX = x;
 | 
			
		||||
	this.posY = y;
 | 
			
		||||
	this.nodeLabel = lab;
 | 
			
		||||
	this.fgColor = foregroundColor;
 | 
			
		||||
	this.bgColor = backgroundColor;
 | 
			
		||||
	this.layer = l;
 | 
			
		||||
        this.radius = radius;
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
UndoDeleteCircle.prototype = new UndoBlock();
 | 
			
		||||
UndoDeleteCircle.prototype.constructor = UndoDeleteCircle;
 | 
			
		||||
 | 
			
		||||
UndoDeleteCircle.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.addCircleObject(this.objectID, this.nodeLabel);
 | 
			
		||||
        world.setWidth(this.objectID, this.radius * 2);
 | 
			
		||||
	world.setNodePosition(this.objectID, this.posX, this.posY);
 | 
			
		||||
	world.setForegroundColor(this.objectID, this.fgColor);
 | 
			
		||||
	world.setBackgroundColor(this.objectID, this.bgColor);
 | 
			
		||||
	world.setLayer(this.objectID, this.layer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,420 @@
 | 
			
		||||
// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without modification, are
 | 
			
		||||
// permitted provided that the following conditions are met:
 | 
			
		||||
//
 | 
			
		||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
 | 
			
		||||
// conditions and the following disclaimer.
 | 
			
		||||
//
 | 
			
		||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
 | 
			
		||||
// of conditions and the following disclaimer in the documentation and/or other materials
 | 
			
		||||
// provided with the distribution.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 | 
			
		||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
//
 | 
			
		||||
// The views and conclusions contained in the software and documentation are those of the
 | 
			
		||||
// authors and should not be interpreted as representing official policies, either expressed
 | 
			
		||||
// or implied, of the University of San Francisco
 | 
			
		||||
 | 
			
		||||
function AnimatedLabel(id, val, center, initialWidth)
 | 
			
		||||
{
 | 
			
		||||
	this.centering = center;
 | 
			
		||||
	this.label = val;
 | 
			
		||||
	this.highlighted = false;
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.alpha = 1.0;
 | 
			
		||||
	this.addedToScene = true;
 | 
			
		||||
	this.labelColor = "#000000";
 | 
			
		||||
	this.textWidth = 0;
 | 
			
		||||
	if (initialWidth != undefined)
 | 
			
		||||
	{
 | 
			
		||||
		this.textWidth = initialWidth;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        this.leftWidth = -1;
 | 
			
		||||
        this.centerWidth = -1;
 | 
			
		||||
        this.highlightIndex = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype = new AnimatedObject();
 | 
			
		||||
AnimatedLabel.prototype.constructor = AnimatedLabel;
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.alwaysOnTop = true;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.centered = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.centering;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.draw = function(ctx)
 | 
			
		||||
{
 | 
			
		||||
	if (!this.addedToScene)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	ctx.globalAlpha = this.alpha;
 | 
			
		||||
	ctx.font = '16px Consolas';
 | 
			
		||||
 | 
			
		||||
        var startingXForHighlight = this.x; 
 | 
			
		||||
 | 
			
		||||
        if (this.highlightIndex >= this.label.length)
 | 
			
		||||
        {
 | 
			
		||||
             this.highlightIndex = -1;
 | 
			
		||||
        }
 | 
			
		||||
        if (this.highlightIndexDirty && this.highlightIndex != -1)
 | 
			
		||||
        {
 | 
			
		||||
              this.leftWidth = ctx.measureText(this.label.substring(0,this.highlightIndex)).width;
 | 
			
		||||
              this.centerWidth = ctx.measureText(this.label.substring(this.highlightIndex, this.highlightIndex+1)).width;
 | 
			
		||||
	      this.highlightIndexDirty = false;
 | 
			
		||||
        }
 | 
			
		||||
	
 | 
			
		||||
	if (this.centering)
 | 
			
		||||
	{
 | 
			
		||||
                if (this.highlightIndex != -1)
 | 
			
		||||
                {
 | 
			
		||||
		    startingXForHighlight = this.x - this.width / 2;
 | 
			
		||||
                    ctx.textAlign = 'left';
 | 
			
		||||
                    ctx.textBaseline   = 'middle'; 
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
      		    ctx.textAlign = 'center';
 | 
			
		||||
                    ctx.textBaseline   = 'middle'; 
 | 
			
		||||
                }
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		ctx.textAlign = 'left';
 | 
			
		||||
		ctx.textBaseline   = 'top'; 
 | 
			
		||||
	}
 | 
			
		||||
	if (this.highlighted)
 | 
			
		||||
	{
 | 
			
		||||
	    ctx.strokeStyle = "#ffaaaa";
 | 
			
		||||
	    ctx.fillStyle = "#ff0000";
 | 
			
		||||
		ctx.lineWidth = this.highlightDiff;
 | 
			
		||||
		ctx.strokeText(this.label, this.x, this.y);		
 | 
			
		||||
		//ctx.fillText(this.label, this.x, this.y);
 | 
			
		||||
	}
 | 
			
		||||
	ctx.strokeStyle = this.labelColor;
 | 
			
		||||
	ctx.fillStyle = this.labelColor;
 | 
			
		||||
	ctx.lineWidth = 1;
 | 
			
		||||
	strList = this.label.split("\n");
 | 
			
		||||
	if (strList.length == 1)
 | 
			
		||||
	{
 | 
			
		||||
                if (this.highlightIndex == -1)
 | 
			
		||||
                {
 | 
			
		||||
                    ctx.fillText(this.label, this.x, this.y); 
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    var leftStr = this.label.substring(0, this.highlightIndex);
 | 
			
		||||
                    var highlightStr = this.label.substring(this.highlightIndex, this.highlightIndex + 1)
 | 
			
		||||
                    var rightStr = this.label.substring(this.highlightIndex + 1)
 | 
			
		||||
                    ctx.fillText(leftStr, startingXForHighlight, this.y)
 | 
			
		||||
 	            ctx.strokeStyle = "#FF0000";
 | 
			
		||||
	            ctx.fillStyle = "#FF0000";
 | 
			
		||||
                    ctx.fillText(highlightStr, startingXForHighlight + this.leftWidth, this.y)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	            ctx.strokeStyle = this.labelColor;
 | 
			
		||||
	            ctx.fillStyle = this.labelColor;
 | 
			
		||||
                    ctx.fillText(rightStr, startingXForHighlight + this.leftWidth + this.centerWidth, this.y)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
		//this.textWidth = ctx.measureText(this.label).width;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		var offset = (this.centering)?  (1.0 - strList.length) / 2.0 : 0;
 | 
			
		||||
		for (var i = 0; i < strList.length; i++)
 | 
			
		||||
		{
 | 
			
		||||
			ctx.fillText(strList[i], this.x, this.y + offset + i * 12);
 | 
			
		||||
			//this.textWidth = Math.max(this.textWidth, ctx.measureText(strList[i]).width);
 | 
			
		||||
		}		
 | 
			
		||||
	}
 | 
			
		||||
	ctx.closePath();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.getAlignLeftPos = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
    if (this.centering)
 | 
			
		||||
    {
 | 
			
		||||
	return [otherObject.left() - this.textWidth / 2, this.y = otherObject.centerY()];
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
	return [otherObject.left() - this.textWidth, otherObject.centerY() - 5];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.alignLeft = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
	if (this.centering)
 | 
			
		||||
	{
 | 
			
		||||
		this.y = otherObject.centerY();
 | 
			
		||||
		this.x = otherObject.left() - this.textWidth / 2;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		this.y = otherObject.centerY() - 5;
 | 
			
		||||
		this.x = otherObject.left() - this.textWidth;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.alignRight = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
	if (this.centering)
 | 
			
		||||
	{
 | 
			
		||||
		this.y = otherObject.centerY();
 | 
			
		||||
		this.x = otherObject.right() + this.textWidth / 2;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		this.y = otherObject.centerY() - 5;
 | 
			
		||||
		this.x = otherObject.right();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
AnimatedLabel.prototype.getAlignRightPos = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
    if (this.centering)
 | 
			
		||||
    {
 | 
			
		||||
	return [otherObject.right() + this.textWidth / 2, otherObject.centerY()];
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
	return [otherObject.right(), otherObject.centerY() - 5];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.alignTop = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
	if (this.centering)
 | 
			
		||||
	{
 | 
			
		||||
		this.y = otherObject.top() - 5;
 | 
			
		||||
		this.x = otherObject.centerX();
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		this.y = otherObject.top() - 10;
 | 
			
		||||
		this.x = otherObject.centerX() -this.textWidth / 2;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.getAlignTopPos = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
	if (this.centering)
 | 
			
		||||
	{
 | 
			
		||||
		return [otherObject.centerX(), otherObject.top() - 5];
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
	    return [otherObject.centerX() -this.textWidth / 2, otherObject.top() - 10];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.alignBottom = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
	if (this.centering)
 | 
			
		||||
	{
 | 
			
		||||
		this.y = otherObject.bottom() + 5;
 | 
			
		||||
		this.x = otherObject.centerX();
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		this.y = otherObject.bottom();
 | 
			
		||||
		this.x = otherObject.centerX() - this.textWidth / 2;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.getAlignBottomPos = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
	if (this.centering)
 | 
			
		||||
	{
 | 
			
		||||
	    return [otherObject.centerX(),  otherObject.bottom() + 5];
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
	    return [otherObject.centerX() - this.textWidth / 2,  otherObject.bottom()];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.getWidth = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.textWidth;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.getHeight = function()
 | 
			
		||||
{
 | 
			
		||||
	return 10;  // HACK!  HACK!  HACK!  HACK!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.setHighlight = function(value)
 | 
			
		||||
{
 | 
			
		||||
	this.highlighted = value;
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
AnimatedLabel.prototype.createUndoDelete = function()
 | 
			
		||||
{
 | 
			
		||||
	return new UndoDeleteLabel(this.objectID, this.label, this.x, this.y, this.centering, this.labelColor, this.layer, this.highlightIndex);
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
AnimatedLabel.prototype.centerX = function()
 | 
			
		||||
{
 | 
			
		||||
	if (this.centering)
 | 
			
		||||
	{
 | 
			
		||||
		return this.x;
 | 
			
		||||
	}
 | 
			
		||||
	else 
 | 
			
		||||
	{
 | 
			
		||||
		return this.x + this.textWidth; 
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
	   
 | 
			
		||||
AnimatedLabel.prototype.centerY = function()
 | 
			
		||||
{
 | 
			
		||||
	if (this.centering)
 | 
			
		||||
	{
 | 
			
		||||
		return this.y;
 | 
			
		||||
	}
 | 
			
		||||
	else 
 | 
			
		||||
	{
 | 
			
		||||
		return this.y + 5; // 
 | 
			
		||||
	}
 | 
			
		||||
   
 | 
			
		||||
}
 | 
			
		||||
	   
 | 
			
		||||
AnimatedLabel.prototype.top = function()	   
 | 
			
		||||
{
 | 
			
		||||
	   if (this.centering)
 | 
			
		||||
	   {
 | 
			
		||||
		   return  this.y - 5; //TODO: Un-Hardwire
 | 
			
		||||
	   }
 | 
			
		||||
	   else 
 | 
			
		||||
	   {
 | 
			
		||||
			return this.y;   
 | 
			
		||||
	   }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.bottom = function()
 | 
			
		||||
{
 | 
			
		||||
   if (this.centering)
 | 
			
		||||
   {
 | 
			
		||||
	   return  this.y + 5; // TODO: + height / 2;
 | 
			
		||||
   }
 | 
			
		||||
   else 
 | 
			
		||||
   {
 | 
			
		||||
	   return  this.y + 10; // TODO: + hieght;
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
	   
 | 
			
		||||
	   
 | 
			
		||||
AnimatedLabel.prototype.right = function()
 | 
			
		||||
{
 | 
			
		||||
   if (this.centering)
 | 
			
		||||
   {
 | 
			
		||||
	   return  this.x + this.textWidth / 2; // TODO: + width / 2;
 | 
			
		||||
   }
 | 
			
		||||
   else
 | 
			
		||||
   {
 | 
			
		||||
	   return  this.x + this.textWidth; // TODO: + width;
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.left = function()
 | 
			
		||||
{
 | 
			
		||||
   if (this.centering)
 | 
			
		||||
   {
 | 
			
		||||
	   return this. x - this.textWidth / 2;
 | 
			
		||||
   }
 | 
			
		||||
   else
 | 
			
		||||
   {
 | 
			
		||||
	   return  this.x; // TODO:  - a little?
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.setHighlightIndex = function(hlIndex)
 | 
			
		||||
{
 | 
			
		||||
    // Only allow highlight index for labels that don't have End-Of-Line
 | 
			
		||||
    if (this.label.indexOf("\n") == -1 && this.label.length > hlIndex)
 | 
			
		||||
    {
 | 
			
		||||
         this.highlightIndex = hlIndex;
 | 
			
		||||
         this.highlightIndexDirty = true;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
         this.highlightIndex = -1;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 AnimatedLabel.prototype.getTailPointerAttachPos = function(fromX, fromY, anchorPoint)
 | 
			
		||||
 {			 
 | 
			
		||||
	return this.getClosestCardinalPoint(fromX, fromY); 
 | 
			
		||||
 }
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.getHeadPointerAttachPos = function (fromX, fromY) 
 | 
			
		||||
{
 | 
			
		||||
	return this.getClosestCardinalPoint(fromX, fromY);			
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLabel.prototype.setText = function(newText, textIndex, initialWidth)
 | 
			
		||||
{
 | 
			
		||||
	this.label = newText;
 | 
			
		||||
	if (initialWidth != undefined)
 | 
			
		||||
	{
 | 
			
		||||
		this.textWidth = initialWidth;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function UndoDeleteLabel(id, lab, x, y, centered, color, l, hli)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.posX = x;
 | 
			
		||||
	this.posY = y;
 | 
			
		||||
	this.nodeLabel = lab;
 | 
			
		||||
	this.labCentered = centered;
 | 
			
		||||
	this.labelColor = color;
 | 
			
		||||
	this.layer = l;
 | 
			
		||||
        this.highlightIndex = hli;
 | 
			
		||||
        this.dirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoDeleteLabel.prototype = new UndoBlock();
 | 
			
		||||
UndoDeleteLabel.prototype.constructor = UndoDeleteLabel;
 | 
			
		||||
 | 
			
		||||
UndoDeleteLabel.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.addLabelObject(this.objectID, this.nodeLabel, this.labCentered);
 | 
			
		||||
	world.setNodePosition(this.objectID, this.posX, this.posY);
 | 
			
		||||
	world.setForegroundColor(this.objectID, this.labelColor);
 | 
			
		||||
	world.setLayer(this.objectID, this.layer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,473 @@
 | 
			
		||||
// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without modification, are
 | 
			
		||||
// permitted provided that the following conditions are met:
 | 
			
		||||
//
 | 
			
		||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
 | 
			
		||||
// conditions and the following disclaimer.
 | 
			
		||||
//
 | 
			
		||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
 | 
			
		||||
// of conditions and the following disclaimer in the documentation and/or other materials
 | 
			
		||||
// provided with the distribution.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 | 
			
		||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
//
 | 
			
		||||
// The views and conclusions contained in the software and documentation are those of the
 | 
			
		||||
// authors and should not be interpreted as representing official policies, either expressed
 | 
			
		||||
// or implied, of the University of San Francisco
 | 
			
		||||
 | 
			
		||||
function AnimatedLinkedList(id, val, wth, hgt, linkPer, verticalOrientation, linkPosEnd, numLab, fillColor, edgeColor)
 | 
			
		||||
{
 | 
			
		||||
	this.init(id, val, wth, hgt, linkPer, verticalOrientation, linkPosEnd, numLab, fillColor, edgeColor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype = new AnimatedObject();
 | 
			
		||||
AnimatedLinkedList.prototype.constructor = AnimatedLinkedList;
 | 
			
		||||
AnimatedLinkedList.superclass = AnimatedObject.prototype;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.init = function(id, val, wth, hgt, linkPer, verticalOrientation, linkPosEnd, numLab, fillColor, edgeColor)
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
	AnimatedLinkedList.superclass.init.call(this);
 | 
			
		||||
 | 
			
		||||
	this.w = wth;
 | 
			
		||||
	this.h = hgt;
 | 
			
		||||
	this.backgroundColor = fillColor;
 | 
			
		||||
	this.foregroundColor = edgeColor;
 | 
			
		||||
	
 | 
			
		||||
	this.vertical = verticalOrientation;
 | 
			
		||||
	this.linkPositionEnd = linkPosEnd;
 | 
			
		||||
	this.linkPercent = linkPer;
 | 
			
		||||
	
 | 
			
		||||
	this.numLabels = numLab;
 | 
			
		||||
	
 | 
			
		||||
	this.labels = [];
 | 
			
		||||
	this.labelPosX = [];
 | 
			
		||||
	this.labelPosY = [];
 | 
			
		||||
	this.labelColors = [];
 | 
			
		||||
	this.nullPointer = false;
 | 
			
		||||
	
 | 
			
		||||
	this.currentHeightDif = 6;
 | 
			
		||||
	this.maxHeightDiff = 5;
 | 
			
		||||
	this.minHeightDiff = 3;
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	for (var i = 0; i < this.numLabels; i++)
 | 
			
		||||
	{
 | 
			
		||||
		this.labels[i] = "";
 | 
			
		||||
		this.labelPosX[i] = 0;
 | 
			
		||||
		this.labelPosY[i] = 0;
 | 
			
		||||
		this.labelColors[i] = this.foregroundColor;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.labels[0] = val;
 | 
			
		||||
	this.highlighted = false;
 | 
			
		||||
	this.objectID = id;	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
AnimatedLinkedList.prototype.left = function()
 | 
			
		||||
{
 | 
			
		||||
	if (this.vertical)
 | 
			
		||||
	{
 | 
			
		||||
		return this.x - this.w / 2.0; 
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.linkPositionEnd)
 | 
			
		||||
	{
 | 
			
		||||
		return this.x - ((this.w * (1 - this.linkPercent)) / 2);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return this.x  - (this.w * (this.linkPercent + 1)) / 2;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.setNull = function(np)
 | 
			
		||||
{
 | 
			
		||||
	if (this.nullPointer != np)
 | 
			
		||||
	{		   
 | 
			
		||||
		this.nullPointer = np;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.getNull = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.nullPointer;   
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.right = function()
 | 
			
		||||
{
 | 
			
		||||
	if (this.vertical)
 | 
			
		||||
	{
 | 
			
		||||
		return this.x + this.w / 2.0; 
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.linkPositionEnd)
 | 
			
		||||
	{
 | 
			
		||||
		return this.x + ((this.w * (this.linkPercent + 1)) / 2);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return this.x + (this.w * (1 - this.linkPercent)) / 2;
 | 
			
		||||
	}
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.top = function()
 | 
			
		||||
{
 | 
			
		||||
	if (!this.vertical)
 | 
			
		||||
	{
 | 
			
		||||
		return this.y - this.h / 2.0; 			   
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.linkPositionEnd)
 | 
			
		||||
	{
 | 
			
		||||
		return this.y - (this.h * (1 -this.linkPercent)) / 2;   
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return this.y - (this.h * (1 + this.linkPercent)) / 2;   
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.bottom = function()
 | 
			
		||||
{
 | 
			
		||||
	if (!this.vertical)
 | 
			
		||||
	{
 | 
			
		||||
		return this.y + this.h / 2.0; 			   
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.linkPositionEnd)
 | 
			
		||||
	{
 | 
			
		||||
		return this.y + (this.h * (1 +this.linkPercent)) / 2;   
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return this.y + (this.h * (1 - this.linkPercent)) / 2;   
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// TODO: Should we move this to the draw function, and save the
 | 
			
		||||
//       space of the arrays?  Bit of a leftover from the Flash code,
 | 
			
		||||
//       which did drawing differently
 | 
			
		||||
AnimatedLinkedList.prototype.resetTextPosition = function()
 | 
			
		||||
{
 | 
			
		||||
	if (this.vertical)
 | 
			
		||||
	{
 | 
			
		||||
		this.labelPosX[0] = this.x;
 | 
			
		||||
		
 | 
			
		||||
		this.labelPosY[0] = this.y + this.h * (1-this.linkPercent)/2 *(1/this.numLabels - 1);				
 | 
			
		||||
		//				labelPosY[0] = -height * (1-linkPercent) / 2 + height*(1-linkPercent)/2*numLabels;
 | 
			
		||||
		for (var i = 1; i < this.numLabels; i++)
 | 
			
		||||
		{
 | 
			
		||||
			this.labelPosY[i] = this.labelPosY[i-1] +  this.h*(1-this.linkPercent)/this.numLabels;
 | 
			
		||||
			this.labelPosX[i] = this.x;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		this.labelPosY[0] = this.y;
 | 
			
		||||
		this.labelPosX[0] = this.x +  this.w * (1-this.linkPercent)/2*(1/this.numLabels - 1);
 | 
			
		||||
		for (var i = 1; i < this.numLabels; i++)
 | 
			
		||||
		{
 | 
			
		||||
			this.labelPosY[i] = this.y;
 | 
			
		||||
			this.labelPosX[i] = this.labelPosX[i-1] +  this.w*(1-this.linkPercent)/this.numLabels;
 | 
			
		||||
		}				
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.getTailPointerAttachPos = function(fromX, fromY, anchor)
 | 
			
		||||
{
 | 
			
		||||
	if (this.vertical && this.linkPositionEnd)
 | 
			
		||||
	{
 | 
			
		||||
		return [this.x, this.y + this.h / 2.0];				
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.vertical && !this.linkPositionEnd)
 | 
			
		||||
	{
 | 
			
		||||
		return [this.x, this.y - this.h / 2.0];							
 | 
			
		||||
	}
 | 
			
		||||
	else if  (!this.vertical && this.linkPositionEnd)
 | 
			
		||||
	{
 | 
			
		||||
		return [this.x + this.w / 2.0, this.y];								
 | 
			
		||||
	}
 | 
			
		||||
	else // (!this.vertical && !this.linkPositionEnd)
 | 
			
		||||
	{
 | 
			
		||||
		return [this.x - this.w / 2.0, this.y];								
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.getHeadPointerAttachPos = function(fromX, fromY) 
 | 
			
		||||
{
 | 
			
		||||
	return this.getClosestCardinalPoint(fromX, fromY);			
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.setWidth = function(wdth)
 | 
			
		||||
{
 | 
			
		||||
	this.w = wdth;
 | 
			
		||||
	this.resetTextPosition();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.setHeight = function(hght)
 | 
			
		||||
{
 | 
			
		||||
	this.h = hght;
 | 
			
		||||
	this.resetTextPosition();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.getWidth = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.w;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.getHeight = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.draw = function(context)
 | 
			
		||||
{
 | 
			
		||||
	var startX;
 | 
			
		||||
	var startY;
 | 
			
		||||
	
 | 
			
		||||
	startX = this.left();
 | 
			
		||||
	startY = this.top();
 | 
			
		||||
	
 | 
			
		||||
	if (this.highlighted)
 | 
			
		||||
	{
 | 
			
		||||
		context.strokeStyle = "#ff0000";
 | 
			
		||||
		context.fillStyle = "#ff0000";
 | 
			
		||||
		
 | 
			
		||||
		context.beginPath();
 | 
			
		||||
		context.moveTo(startX - this.highlightDiff,startY- this.highlightDiff);
 | 
			
		||||
		context.lineTo(startX+this.w + this.highlightDiff,startY- this.highlightDiff);
 | 
			
		||||
		context.lineTo(startX+this.w+ this.highlightDiff,startY+this.h + this.highlightDiff);
 | 
			
		||||
		context.lineTo(startX - this.highlightDiff,startY+this.h + this.highlightDiff);
 | 
			
		||||
		context.lineTo(startX - this.highlightDiff,startY - this.highlightDiff);				
 | 
			
		||||
		context.closePath();
 | 
			
		||||
		context.stroke();
 | 
			
		||||
		context.fill();
 | 
			
		||||
	}
 | 
			
		||||
	context.strokeStyle = this.foregroundColor;
 | 
			
		||||
	context.fillStyle = this.backgroundColor;
 | 
			
		||||
	
 | 
			
		||||
	context.beginPath();
 | 
			
		||||
	context.moveTo(startX ,startY);
 | 
			
		||||
	context.lineTo(startX + this.w, startY);
 | 
			
		||||
	context.lineTo(startX + this.w, startY + this.h);
 | 
			
		||||
	context.lineTo(startX, startY + this.h);
 | 
			
		||||
	context.lineTo(startX, startY);
 | 
			
		||||
	context.closePath();
 | 
			
		||||
	context.stroke();
 | 
			
		||||
	context.fill();
 | 
			
		||||
		
 | 
			
		||||
	var i;
 | 
			
		||||
	if (this.vertical)
 | 
			
		||||
	{
 | 
			
		||||
		startX = this.left();
 | 
			
		||||
		for (i= 1; i < this.numLabels; i++)
 | 
			
		||||
		{
 | 
			
		||||
			//TODO: this doesn't look right ...
 | 
			
		||||
			startY = this.y + this.h*(1-this.linkPercent)*(i / this.numLabels - 1/2);
 | 
			
		||||
			
 | 
			
		||||
			context.beginPath();
 | 
			
		||||
			context.moveTo(startX ,startY);
 | 
			
		||||
			context.lineTo(startX + this.w, startY);
 | 
			
		||||
			context.closePath();
 | 
			
		||||
			context.stroke();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		startY = this.top();
 | 
			
		||||
		for (i = 1; i < this.numLabels; i++)
 | 
			
		||||
		{
 | 
			
		||||
			startX = this.x + this.w*(1-this.linkPercent)*(i / this.numLabels - 1/2);
 | 
			
		||||
			context.beginPath();
 | 
			
		||||
			context.moveTo(startX ,startY);
 | 
			
		||||
			context.lineTo(startX, startY + this.h);
 | 
			
		||||
			context.closePath();
 | 
			
		||||
			context.stroke();
 | 
			
		||||
		}			
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (this.vertical && this.linkPositionEnd)
 | 
			
		||||
	{
 | 
			
		||||
		startX = this.left();
 | 
			
		||||
		startY = this.bottom() - this.h * this.linkPercent;
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
		context.beginPath();
 | 
			
		||||
		context.moveTo(startX + this.w ,startY);
 | 
			
		||||
		context.lineTo(startX, startY);
 | 
			
		||||
		if (this.nullPointer)
 | 
			
		||||
		{	
 | 
			
		||||
			context.lineTo(this.startX + this.w, this.bottom());
 | 
			
		||||
		}
 | 
			
		||||
		context.closePath();
 | 
			
		||||
		context.stroke();		
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.vertical && !this.linkPositionEnd)
 | 
			
		||||
	{
 | 
			
		||||
		startX = this.left();
 | 
			
		||||
		startY = this.top() + this.h * this.linkPercent;
 | 
			
		||||
 | 
			
		||||
		context.beginPath();
 | 
			
		||||
		context.moveTo(startX + this.w ,startY);
 | 
			
		||||
		context.lineTo(startX, startY);
 | 
			
		||||
		if (this.nullPointer)
 | 
			
		||||
		{	
 | 
			
		||||
			context.lineTo(startX + this.w, this.top());
 | 
			
		||||
		}
 | 
			
		||||
		context.closePath();
 | 
			
		||||
		context.stroke();	
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	else if  (!this.vertical && this.linkPositionEnd)
 | 
			
		||||
	{
 | 
			
		||||
		startX = this.right() - this.w * this.linkPercent;
 | 
			
		||||
		startY = this.top();
 | 
			
		||||
		
 | 
			
		||||
		context.beginPath();
 | 
			
		||||
		context.moveTo(startX, startY + this.h);
 | 
			
		||||
		context.lineTo(startX, startY);
 | 
			
		||||
		if (this.nullPointer)
 | 
			
		||||
		{	
 | 
			
		||||
			context.lineTo(this.right(), startY + this.h);
 | 
			
		||||
		}
 | 
			
		||||
		context.closePath();
 | 
			
		||||
		context.stroke();		
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	else // (!vertical && !linkPositionEnd)
 | 
			
		||||
	{
 | 
			
		||||
		startX = this.left()  + this.w * this.linkPercent;
 | 
			
		||||
		startY = this.top() ;
 | 
			
		||||
		
 | 
			
		||||
		context.beginPath();
 | 
			
		||||
		context.moveTo(startX, startY + this.h);
 | 
			
		||||
		context.lineTo(startX, startY);
 | 
			
		||||
		if (this.nullPointer)
 | 
			
		||||
		{	
 | 
			
		||||
			context.lineTo(this.left(), startY);
 | 
			
		||||
		}
 | 
			
		||||
		context.closePath();
 | 
			
		||||
		context.stroke();	
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	context.textAlign = 'center';
 | 
			
		||||
	context.font         = '16px Consolas';
 | 
			
		||||
	context.textBaseline   = 'middle'; 
 | 
			
		||||
	context.lineWidth = 1;
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.resetTextPosition();
 | 
			
		||||
	for (i = 0; i < this.numLabels; i++)
 | 
			
		||||
	{
 | 
			
		||||
		context.fillStyle = this.labelColors[i];
 | 
			
		||||
		context.fillText(this.labels[i], this.labelPosX[i], this.labelPosY[i]); 
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.setTextColor = function(color, textIndex)
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
	this.labelColors[textIndex] = color;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.getTextColor = function(textIndex)
 | 
			
		||||
{
 | 
			
		||||
	return this.labelColors[textIndex];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.getText = function(index)
 | 
			
		||||
{
 | 
			
		||||
	return this.labels[index];  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.setText = function(newText, textIndex)
 | 
			
		||||
{
 | 
			
		||||
	this.labels[textIndex] = newText;
 | 
			
		||||
	this.resetTextPosition();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.createUndoDelete = function() 
 | 
			
		||||
{		
 | 
			
		||||
	return new UndoDeleteLinkedList(this.objectID, this.numLabels, this.labels, this.x, this.y, this.w, this.h, this.linkPercent,
 | 
			
		||||
									this.linkPositionEnd, this.vertical, this.labelColors, this.backgroundColor, this.foregroundColor, 
 | 
			
		||||
									this.layer, this.nullPointer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedLinkedList.prototype.setHighlight = function(value)
 | 
			
		||||
{
 | 
			
		||||
	if (value != this.highlighted)
 | 
			
		||||
	{
 | 
			
		||||
		this.highlighted = value;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function UndoDeleteLinkedList(id, numlab, lab, x, y, w, h, linkper, posEnd, vert, labColors, bgColor, fgColor, l, np)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.posX = x;
 | 
			
		||||
	this.posY = y;
 | 
			
		||||
	this.width = w;
 | 
			
		||||
	this.height = h;
 | 
			
		||||
	this.backgroundColor= bgColor;
 | 
			
		||||
	this.foregroundColor = fgColor;
 | 
			
		||||
	this.labels = lab;
 | 
			
		||||
	this.linkPercent = linkper;
 | 
			
		||||
	this.verticalOrentation = vert;
 | 
			
		||||
	this.linkAtEnd = posEnd;
 | 
			
		||||
	this.labelColors = labColors
 | 
			
		||||
	this.layer = l;
 | 
			
		||||
	this.numLabels = numlab;
 | 
			
		||||
	this.nullPointer = np;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoDeleteLinkedList.prototype = new UndoBlock();
 | 
			
		||||
UndoDeleteLinkedList.prototype.constructor = UndoDeleteLinkedList;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
UndoDeleteLinkedList.prototype.undoInitialStep =function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.addLinkedListObject(this.objectID,this.labels[0], this.width, this.height, this.linkPercent, this.verticalOrentation, this.linkAtEnd, this.numLabels, this.backgroundColor, this.foregroundColor);
 | 
			
		||||
	world.setNodePosition(this.objectID, this.posX, this.posY);
 | 
			
		||||
	world.setLayer(this.objectID, this.layer);
 | 
			
		||||
	world.setNull(this.objectID, this.nullPointer);
 | 
			
		||||
	for (var i = 0; i < this.numLabels; i++)
 | 
			
		||||
	{
 | 
			
		||||
		world.setText(this.objectID, this.labels[i], i);
 | 
			
		||||
		world.setTextColor(this.objectID, this.labelColors[i], i);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,343 @@
 | 
			
		||||
// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without modification, are
 | 
			
		||||
// permitted provided that the following conditions are met:
 | 
			
		||||
//
 | 
			
		||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
 | 
			
		||||
// conditions and the following disclaimer.
 | 
			
		||||
//
 | 
			
		||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
 | 
			
		||||
// of conditions and the following disclaimer in the documentation and/or other materials
 | 
			
		||||
// provided with the distribution.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 | 
			
		||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
//
 | 
			
		||||
// The views and conclusions contained in the software and documentation are those of the
 | 
			
		||||
// authors and should not be interpreted as representing official policies, either expressed
 | 
			
		||||
// or implied, of the University of San Francisco
 | 
			
		||||
 | 
			
		||||
function AnimatedObject()
 | 
			
		||||
{
 | 
			
		||||
	this.init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.init  = function()
 | 
			
		||||
{
 | 
			
		||||
	this.backgroundColor = "#FFFFFF";
 | 
			
		||||
	this.foregroundColor = "#000000";
 | 
			
		||||
	this.highlighted = false;
 | 
			
		||||
	this.objectID = -1;
 | 
			
		||||
	this.layer = 0;
 | 
			
		||||
	this.addedToScene = true;
 | 
			
		||||
	this.label = "";
 | 
			
		||||
	this.labelColor = "#000000";
 | 
			
		||||
	this.alpha = 1.0;
 | 
			
		||||
	this.x = 0;
 | 
			
		||||
	this.y = 0;
 | 
			
		||||
	this.minHeightDiff = 3;
 | 
			
		||||
	this.range = 5;
 | 
			
		||||
    this.highlightIndex = -1;
 | 
			
		||||
    this.highlightIndexDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.alwaysOnTop = false;
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.setBackgroundColor = function(newColor)
 | 
			
		||||
{
 | 
			
		||||
	this.backgroundColor = newColor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.setForegroundColor = function(newColor)
 | 
			
		||||
{
 | 
			
		||||
	this.foregroundColor = newColor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.setNull = function()
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.getNull = function()
 | 
			
		||||
{
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.setAlpha = function(newAlpha)
 | 
			
		||||
{
 | 
			
		||||
	this.alpha = newAlpha;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.getAlpha = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.alpha;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.setForegroundColor = function(newColor)
 | 
			
		||||
{
 | 
			
		||||
	this.foregroundColor = newColor;
 | 
			
		||||
	this.labelColor = newColor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.getHighlight = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.highlighted;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.getWidth = function()
 | 
			
		||||
{
 | 
			
		||||
	// TODO:  Do we want to throw here?  Should always override this ...
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.getHeight = function()
 | 
			
		||||
{
 | 
			
		||||
	// TODO:  Do we want to throw here?  Should always override this ...
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.setHighlight = function(value)
 | 
			
		||||
{
 | 
			
		||||
	this.highlighted = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.centerX = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.setWidth = function(newWidth)
 | 
			
		||||
{
 | 
			
		||||
	// TODO:  Do we want to throw here?  Should always override this ... 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.centerY = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.getAlignLeftPos = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
    return [otherObject.right()+ this.getWidth() / 2, otherObject.centerY()];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.getAlignRightPos = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
    return [otherObject.left() - this.getWidth() / 2, otherObject.centerY()];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.getAlignTopPos = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    return [otherObject.centerX(), otherObject.top() - this.getHeight() / 2];
 | 
			
		||||
}
 | 
			
		||||
AnimatedObject.prototype.getAlignBottomPos = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
    return [otherObject.centerX(), otherObject.bottom() + this.getHeight() / 2];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.alignLeft = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
	// Assuming centering.  Overridden method could modify if not centered
 | 
			
		||||
	//  (See AnimatedLabel, for instance)
 | 
			
		||||
	this.y = otherObject.centerY();
 | 
			
		||||
	this.x = otherObject.right() + this.getWidth() / 2;	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.alignRight = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
	// Assuming centering.  Overridden method could modify if not centered
 | 
			
		||||
	//  (See AnimatedLabel, for instance)
 | 
			
		||||
	this.y = otherObject.centerY();
 | 
			
		||||
	this.x = otherObject.left() - this.getWidth() / 2;	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.alignTop = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
	// Assuming centering.  Overridden method could modify if not centered
 | 
			
		||||
	
 | 
			
		||||
	this.x = otherObject.centerX();
 | 
			
		||||
	this.y = otherObject.top() - this.getHeight() / 2;	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.alignBottom = function(otherObject)
 | 
			
		||||
{
 | 
			
		||||
	this.x = otherObject.centerX();
 | 
			
		||||
	this.y = otherObject.bottom() + this.getHeight() / 2;		
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* TODO:  Do we need these in the base? 		
 | 
			
		||||
		function left(): Number
 | 
			
		||||
		{
 | 
			
		||||
			return x - getWidth() / 2;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		function right():Number
 | 
			
		||||
		{
 | 
			
		||||
			return x + getWidth() / 2;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		function top():Number
 | 
			
		||||
		{
 | 
			
		||||
			return y - getHeight() / 2;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		function bottom():Number
 | 
			
		||||
		{
 | 
			
		||||
			return y + getHeight() / 2;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		function centerX():Number
 | 
			
		||||
		{
 | 
			
		||||
			return x;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		function centerY():Number
 | 
			
		||||
		{
 | 
			
		||||
			return y;
 | 
			
		||||
		}
 | 
			
		||||
		*/
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
AnimatedObject.prototype.getClosestCardinalPoint = function(fromX, fromY)
 | 
			
		||||
{
 | 
			
		||||
	var xDelta;
 | 
			
		||||
	var yDelta;
 | 
			
		||||
	var xPos;
 | 
			
		||||
	var yPos;
 | 
			
		||||
			
 | 
			
		||||
	if (fromX < this.left())
 | 
			
		||||
	{
 | 
			
		||||
		xDelta = this.left() - fromX;
 | 
			
		||||
		xPos = this.left();
 | 
			
		||||
 	}
 | 
			
		||||
	else if (fromX > this.right())
 | 
			
		||||
	{
 | 
			
		||||
		xDelta = fromX - this.right();
 | 
			
		||||
		xPos = this.right();
 | 
			
		||||
    }
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		xDelta = 0;
 | 
			
		||||
		xPos = this.centerX();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (fromY < this.top())
 | 
			
		||||
	{
 | 
			
		||||
		yDelta = this.top() - fromY;
 | 
			
		||||
		yPos = this.top();
 | 
			
		||||
	}
 | 
			
		||||
	else if (fromY > this.bottom())
 | 
			
		||||
	{
 | 
			
		||||
		yDelta = fromY - this.bottom();
 | 
			
		||||
		yPos = this.bottom();
 | 
			
		||||
    }
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		yDelta = 0;
 | 
			
		||||
		yPos = this.centerY();
 | 
			
		||||
	}
 | 
			
		||||
			
 | 
			
		||||
	if (yDelta > xDelta)
 | 
			
		||||
	{
 | 
			
		||||
		xPos = this.centerX();
 | 
			
		||||
	}
 | 
			
		||||
	else 
 | 
			
		||||
	{
 | 
			
		||||
		yPos  = this.centerY();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return [xPos, yPos];
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
AnimatedObject.prototype.centered = function()
 | 
			
		||||
{
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.pulseHighlight = function(frameNum)
 | 
			
		||||
{			
 | 
			
		||||
	if (this.highlighted)
 | 
			
		||||
	{
 | 
			
		||||
				var frameMod = frameNum / 7.0;
 | 
			
		||||
				var delta  = Math.abs((frameMod) % (2 * this.range  - 2) - this.range + 1)
 | 
			
		||||
				this.highlightDiff =  delta + this.minHeightDiff;
 | 
			
		||||
	}
 | 
			
		||||
			
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
AnimatedObject.prototype.getTailPointerAttachPos = function(fromX, fromY, anchorPoint) 
 | 
			
		||||
{
 | 
			
		||||
	return [this.x, this.y];
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
AnimatedObject.prototype.getHeadPointerAttachPos = function(fromX, fromY) 
 | 
			
		||||
{
 | 
			
		||||
	return [this.x, this.y];
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
/*public function createUndoDelete() : UndoBlock
 | 
			
		||||
{
 | 
			
		||||
			// Must be overriden!
 | 
			
		||||
			return null;
 | 
			
		||||
}
 | 
			
		||||
*/		
 | 
			
		||||
AnimatedObject.prototype.identifier = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.objectID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.getText = function(index)
 | 
			
		||||
{
 | 
			
		||||
	return this.label;
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
AnimatedObject.prototype.getTextColor = function(textIndex)
 | 
			
		||||
{			
 | 
			
		||||
	return this.labelColor
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
AnimatedObject.prototype.setTextColor = function(color, textIndex)
 | 
			
		||||
{
 | 
			
		||||
		this.labelColor = color;
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
AnimatedObject.prototype.setText = function(newText, textIndex)
 | 
			
		||||
{
 | 
			
		||||
	this.label = newText;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.setHighlightIndex = function(hlIndex)
 | 
			
		||||
{
 | 
			
		||||
   this.highlightIndex = hlIndex;
 | 
			
		||||
   this.highlightIndexDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedObject.prototype.getHighlightIndex = function()
 | 
			
		||||
{
 | 
			
		||||
   return this.highlightIndex;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,340 @@
 | 
			
		||||
// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without modification, are
 | 
			
		||||
// permitted provided that the following conditions are met:
 | 
			
		||||
//
 | 
			
		||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
 | 
			
		||||
// conditions and the following disclaimer.
 | 
			
		||||
//
 | 
			
		||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
 | 
			
		||||
// of conditions and the following disclaimer in the documentation and/or other materials
 | 
			
		||||
// provided with the distribution.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 | 
			
		||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
//
 | 
			
		||||
// The views and conclusions contained in the software and documentation are those of the
 | 
			
		||||
// authors and should not be interpreted as representing official policies, either expressed
 | 
			
		||||
// or implied, of the University of San Francisco
 | 
			
		||||
 | 
			
		||||
// Values for xJust / yJust:  "center", "left", "right", "top", "bottom"
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle = function(id, val, wth, hgt,  xJust, yJust, fillColor, edgeColor)
 | 
			
		||||
{
 | 
			
		||||
	this.w = wth;
 | 
			
		||||
	this.h = hgt;
 | 
			
		||||
	this.xJustify = xJust;
 | 
			
		||||
	this.yJustify = yJust;
 | 
			
		||||
	this.label = val;
 | 
			
		||||
	this.labelColor = edgeColor
 | 
			
		||||
	
 | 
			
		||||
	this.backgroundColor = fillColor;
 | 
			
		||||
	this.foregroundColor = edgeColor;
 | 
			
		||||
	this.labelColor = this.foregroundColor;
 | 
			
		||||
	this.highlighted = false;
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.nullPointer = false;
 | 
			
		||||
	this.alpha = 1.0;
 | 
			
		||||
	this.addedToScene = true;
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype = new AnimatedObject();
 | 
			
		||||
AnimatedRectangle.prototype.constructor = AnimatedRectangle;
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.setNull = function(np)
 | 
			
		||||
{
 | 
			
		||||
	this.nullPointer = np;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.getNull = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.nullPointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.left = function()
 | 
			
		||||
{
 | 
			
		||||
	if (this.xJustify == "left")
 | 
			
		||||
	{
 | 
			
		||||
		return  this.x;
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.xJustify == "center")
 | 
			
		||||
	{
 | 
			
		||||
		return this.x - this.w / 2.0;   
 | 
			
		||||
	}
 | 
			
		||||
	else // (this.xJustify == "right")
 | 
			
		||||
	{
 | 
			
		||||
		return this.x - this.w;   
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.centerX = function()
 | 
			
		||||
{
 | 
			
		||||
	if (this.xJustify == "center")
 | 
			
		||||
	{
 | 
			
		||||
		return this.x;
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.xJustify == "left")
 | 
			
		||||
	{
 | 
			
		||||
		return this.x + this.w / 2.0;
 | 
			
		||||
	}
 | 
			
		||||
	else // (this.xJustify == "right")
 | 
			
		||||
	{
 | 
			
		||||
		return this.x - this.w / 2.0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.centerY = function()
 | 
			
		||||
{
 | 
			
		||||
	if (this.yJustify == "center")
 | 
			
		||||
	{
 | 
			
		||||
		return this.y;
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.yJustify == "top")
 | 
			
		||||
	{
 | 
			
		||||
		return this.y + this.h / 2.0;
 | 
			
		||||
	}
 | 
			
		||||
	else // (this.xJustify == "bottom")
 | 
			
		||||
	{
 | 
			
		||||
		return this.y - this.w / 2.0;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.top = function()
 | 
			
		||||
{
 | 
			
		||||
	if (this.yJustify == "top")
 | 
			
		||||
	{
 | 
			
		||||
		return  this.y;
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.yJustify == "center")
 | 
			
		||||
	{
 | 
			
		||||
		return this.y - this.h / 2.0;   
 | 
			
		||||
	}
 | 
			
		||||
	else //(this.xJustify == "bottom")
 | 
			
		||||
	{
 | 
			
		||||
		return this.y - this.h;   
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.bottom = function()
 | 
			
		||||
{
 | 
			
		||||
	if (this.yJustify == "top")
 | 
			
		||||
	{
 | 
			
		||||
		return  this.y + this.h;
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.yJustify == "center")
 | 
			
		||||
	{
 | 
			
		||||
		return this.y + this.h / 2.0;   
 | 
			
		||||
	}
 | 
			
		||||
	else //(this.xJustify == "bottom")
 | 
			
		||||
	{
 | 
			
		||||
		return this.y;   
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.right = function()
 | 
			
		||||
{
 | 
			
		||||
	if (this.xJustify == "left")
 | 
			
		||||
	{
 | 
			
		||||
		return  this.x + this.w;
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.xJustify == "center")
 | 
			
		||||
	{
 | 
			
		||||
		return this.x + this.w / 2.0;   
 | 
			
		||||
	}
 | 
			
		||||
	else // (this.xJustify == "right")
 | 
			
		||||
	{
 | 
			
		||||
		return this.x;   
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.getHeadPointerAttachPos = function(fromX, fromY)
 | 
			
		||||
{
 | 
			
		||||
	return this.getClosestCardinalPoint(fromX, fromY);			
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.setWidth = function(wdth)
 | 
			
		||||
{
 | 
			
		||||
	this.w = wdth;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.setHeight = function(hght)
 | 
			
		||||
{
 | 
			
		||||
	this.h = hght;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.getWidth = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.w;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.getHeight = function()
 | 
			
		||||
{
 | 
			
		||||
	return this.h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// TODO:  Fix me!
 | 
			
		||||
AnimatedRectangle.prototype.draw = function(context)
 | 
			
		||||
{
 | 
			
		||||
	if (!this.addedToScene)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	var startX;
 | 
			
		||||
	var startY;
 | 
			
		||||
	var labelPosX;
 | 
			
		||||
	var labelPosY;
 | 
			
		||||
	
 | 
			
		||||
	context.globalAlpha = this.alpha;
 | 
			
		||||
	
 | 
			
		||||
	if (this.xJustify == "left")
 | 
			
		||||
	{
 | 
			
		||||
		startX = this.x;
 | 
			
		||||
		labelPosX = this.x + this.w / 2.0;
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.xJustify == "center")
 | 
			
		||||
	{
 | 
			
		||||
		startX = this.x-this.w / 2.0;
 | 
			
		||||
		labelPosX = this.x;
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.xJustify == "right")
 | 
			
		||||
	{
 | 
			
		||||
		startX = this.x-this.w;
 | 
			
		||||
		labelPosX = this.x - this.w / 2.0 
 | 
			
		||||
	}
 | 
			
		||||
	if (this.yJustify == "top")
 | 
			
		||||
	{
 | 
			
		||||
		startY = this.y;
 | 
			
		||||
		labelPosY = this.y + this.h / 2.0;
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.yJustify == "center")
 | 
			
		||||
	{
 | 
			
		||||
		startY = this.y - this.h / 2.0;
 | 
			
		||||
		labelPosY = this.y;
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	else if (this.yJustify == "bottom")
 | 
			
		||||
	{
 | 
			
		||||
		startY = this.y - this.h;
 | 
			
		||||
		labelPosY = this.y - this.h / 2.0;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	context.lineWidth = 1;
 | 
			
		||||
	
 | 
			
		||||
	if (this.highlighted)
 | 
			
		||||
	{
 | 
			
		||||
		context.strokeStyle = "#ff0000";
 | 
			
		||||
		context.fillStyle = "#ff0000";
 | 
			
		||||
		
 | 
			
		||||
		context.beginPath();
 | 
			
		||||
		context.moveTo(startX - this.highlightDiff,startY- this.highlightDiff);
 | 
			
		||||
		context.lineTo(startX+this.w + this.highlightDiff,startY- this.highlightDiff);
 | 
			
		||||
		context.lineTo(startX+this.w+ this.highlightDiff,startY+this.h + this.highlightDiff);
 | 
			
		||||
		context.lineTo(startX - this.highlightDiff,startY+this.h + this.highlightDiff);
 | 
			
		||||
		context.lineTo(startX - this.highlightDiff,startY - this.highlightDiff);				
 | 
			
		||||
		context.closePath();
 | 
			
		||||
		context.stroke();
 | 
			
		||||
		context.fill();
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	context.strokeStyle = this.foregroundColor;
 | 
			
		||||
	context.fillStyle = this.backgroundColor;
 | 
			
		||||
	
 | 
			
		||||
	context.beginPath();
 | 
			
		||||
	context.moveTo(startX ,startY);
 | 
			
		||||
	context.lineTo(startX + this.w, startY);
 | 
			
		||||
	context.lineTo(startX + this.w, startY + this.h);
 | 
			
		||||
	context.lineTo(startX, startY + this.h);
 | 
			
		||||
	context.lineTo(startX, startY);
 | 
			
		||||
	context.closePath();
 | 
			
		||||
	context.stroke();
 | 
			
		||||
	context.fill();
 | 
			
		||||
	
 | 
			
		||||
	if (this.nullPointer)
 | 
			
		||||
	{
 | 
			
		||||
		context.beginPath();
 | 
			
		||||
		context.moveTo(startX ,startY);
 | 
			
		||||
		context.lineTo(startX + this.w, startY + this.h);
 | 
			
		||||
		context.closePath();
 | 
			
		||||
		context.stroke();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	context.fillStyle = this.labelColor;
 | 
			
		||||
	
 | 
			
		||||
	context.textAlign = 'center';
 | 
			
		||||
	context.font         = '16px Consolas';
 | 
			
		||||
	context.textBaseline   = 'middle'; 
 | 
			
		||||
	context.lineWidth = 1;
 | 
			
		||||
	context.fillText(this.label, this.x, this.y); 
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.setText = function(newText, textIndex)
 | 
			
		||||
{
 | 
			
		||||
	this.label = newText;
 | 
			
		||||
	// TODO:  setting text position?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.createUndoDelete = function() 
 | 
			
		||||
{
 | 
			
		||||
	// TODO: Add color?
 | 
			
		||||
	return new UndoDeleteRectangle(this.objectID, this.label, this.x, this.y, this.w, this.h, this.xJustify, this.yJustify, this.backgroundColor, this.foregroundColor, this.highlighted, this.layer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnimatedRectangle.prototype.setHighlight = function(value)
 | 
			
		||||
{
 | 
			
		||||
	this.highlighted = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function UndoDeleteRectangle(id, lab, x, y, w, h, xJust, yJust, bgColor, fgColor, highlight, lay)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.posX = x;
 | 
			
		||||
	this.posY = y;
 | 
			
		||||
	this.width = w;
 | 
			
		||||
	this.height = h;
 | 
			
		||||
	this.xJustify = xJust;
 | 
			
		||||
	this.yJustify = yJust;
 | 
			
		||||
	this.backgroundColor= bgColor;
 | 
			
		||||
	this.foregroundColor = fgColor;
 | 
			
		||||
	this.nodeLabel = lab;
 | 
			
		||||
	this.layer = lay;
 | 
			
		||||
	this.highlighted = highlight;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoDeleteRectangle.prototype = new UndoBlock();
 | 
			
		||||
UndoDeleteRectangle.prototype.constructor = UndoDeleteRectangle;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
UndoDeleteRectangle.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.addRectangleObject(this.objectID, this.nodeLabel, this.width, this.height, this.xJustify, this.yJustify, this.backgroundColor, this.foregroundColor);
 | 
			
		||||
	world.setNodePosition(this.objectID, this.posX, this.posY);
 | 
			
		||||
	world.setLayer(this.objectID, this.layer);
 | 
			
		||||
	world.setHighlight(this.objectID, this.highlighted);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,176 @@
 | 
			
		||||
// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without modification, are
 | 
			
		||||
// permitted provided that the following conditions are met:
 | 
			
		||||
//
 | 
			
		||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
 | 
			
		||||
// conditions and the following disclaimer.
 | 
			
		||||
//
 | 
			
		||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
 | 
			
		||||
// of conditions and the following disclaimer in the documentation and/or other materials
 | 
			
		||||
// provided with the distribution.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 | 
			
		||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
//
 | 
			
		||||
// The views and conclusions contained in the software and documentation are those of the
 | 
			
		||||
// authors and should not be interpreted as representing official policies, either expressed
 | 
			
		||||
// or implied, of the University of San Francisco
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Function.prototype.bind = function() {
 | 
			
		||||
	var _function = this;
 | 
			
		||||
	
 | 
			
		||||
	var args = Array.prototype.slice.call(arguments);
 | 
			
		||||
	var scope = args.shift()
 | 
			
		||||
	return function() {
 | 
			
		||||
		for (var i = 0; i < arguments.length; i++)
 | 
			
		||||
		{
 | 
			
		||||
			args.push(arguments[i]);
 | 
			
		||||
		}
 | 
			
		||||
		return _function.apply(scope, args);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function EventListener()
 | 
			
		||||
{
 | 
			
		||||
	this.events = [];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
EventListener.prototype.removeListener = function(kind, scope, func)
 | 
			
		||||
{
 | 
			
		||||
	if (this.events[kind] == undefined)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	var scopeFunctions = null;
 | 
			
		||||
	var i;
 | 
			
		||||
	for (i = 0; i < this.events[kind].length; i++)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.events[kind][i].scope == scope)
 | 
			
		||||
		{
 | 
			
		||||
			scopeFunctions = this.events[kind][i];
 | 
			
		||||
			break;
 | 
			
		||||
		}	
 | 
			
		||||
	}
 | 
			
		||||
	if (scopeFunctions == null)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 0; i < scopeFunctions.functions.length; i++)
 | 
			
		||||
	{
 | 
			
		||||
		if (scopeFunctions.functions[i] == func)
 | 
			
		||||
		{
 | 
			
		||||
			scopeFunctions.functions.splice(i,1);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
EventListener.prototype.addListener = function(kind, scope, func)
 | 
			
		||||
{
 | 
			
		||||
	if (this.events[kind] === undefined)
 | 
			
		||||
	{
 | 
			
		||||
		this.events[kind] = [];
 | 
			
		||||
	}
 | 
			
		||||
	var i;
 | 
			
		||||
	var scopeFunctions = null;
 | 
			
		||||
	for (i = 0; i < this.events[kind].length; i++)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.events[kind][i].scope == scope)
 | 
			
		||||
		{
 | 
			
		||||
			scopeFunctions = this.events[kind][i];
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (scopeFunctions === null)
 | 
			
		||||
	{
 | 
			
		||||
		this.events[kind].push({scope:scope, functions:[] });
 | 
			
		||||
		scopeFunctions = this.events[kind][this.events[kind].length - 1];
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 0; i < scopeFunctions.functions.length; i++)
 | 
			
		||||
	{
 | 
			
		||||
		if (scopeFunctions.functions[i] == func)
 | 
			
		||||
		{
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	scopeFunctions.functions.push(func);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EventListener.prototype.fireEvent = function(kind, event)
 | 
			
		||||
{
 | 
			
		||||
	// TODO:  Should add a deep clone here ...
 | 
			
		||||
	if (this.events[kind] !== undefined)
 | 
			
		||||
	{
 | 
			
		||||
		for (var i = 0; i < this.events[kind].length; i++)
 | 
			
		||||
		{
 | 
			
		||||
			var objects = this.events[kind][i];
 | 
			
		||||
			var functs = objects.functions;
 | 
			
		||||
			var scope = objects.scope
 | 
			
		||||
			for (var j = 0; j <functs.length; j++)
 | 
			
		||||
			{
 | 
			
		||||
				var func = functs[j];
 | 
			
		||||
				func.call(scope,event);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
function Source()
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Source.prototype = new EventListener();
 | 
			
		||||
Source.prototype.constructor = Source;
 | 
			
		||||
Source.prototype.testFire = function()
 | 
			
		||||
{
 | 
			
		||||
	this.fireEvent("test","testcontents");
 | 
			
		||||
	this.fireEvent("test2","test2contents");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function Client(eventSource)
 | 
			
		||||
{
 | 
			
		||||
		
 | 
			
		||||
	this.first = function(blah)
 | 
			
		||||
	{
 | 
			
		||||
		alert("first:" + blah);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.second = function(blah)
 | 
			
		||||
	{
 | 
			
		||||
		alert("second:" + blah);
 | 
			
		||||
	}
 | 
			
		||||
	eventSource.addListener("test", this, this.first);
 | 
			
		||||
	eventSource.addListener("test", this, this.first);
 | 
			
		||||
	eventSource.addListener("test", this, this.second);
 | 
			
		||||
	eventSource.removeListener("test", this, this.first);
 | 
			
		||||
	
 | 
			
		||||
							
 | 
			
		||||
}
 | 
			
		||||
							
 | 
			
		||||
							
 | 
			
		||||
function init()
 | 
			
		||||
{
 | 
			
		||||
	var src = new Source;
 | 
			
		||||
	var c = new Client(src);
 | 
			
		||||
	src.testFire();
 | 
			
		||||
}
 | 
			
		||||
							
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,87 @@
 | 
			
		||||
// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without modification, are
 | 
			
		||||
// permitted provided that the following conditions are met:
 | 
			
		||||
//
 | 
			
		||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
 | 
			
		||||
// conditions and the following disclaimer.
 | 
			
		||||
//
 | 
			
		||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
 | 
			
		||||
// of conditions and the following disclaimer in the documentation and/or other materials
 | 
			
		||||
// provided with the distribution.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 | 
			
		||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
//
 | 
			
		||||
// The views and conclusions contained in the software and documentation are those of the
 | 
			
		||||
// authors and should not be interpreted as representing official policies, either expressed
 | 
			
		||||
// or implied, of the University of San Francisco
 | 
			
		||||
 | 
			
		||||
// "Class" animatedCircle
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var HighlightCircle = function(objectID, color, radius)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = objectID;
 | 
			
		||||
	this.radius = radius;
 | 
			
		||||
	this.thickness = 4;
 | 
			
		||||
	this.foregroundColor = color;
 | 
			
		||||
	this.x = 0;
 | 
			
		||||
	this.y = 0;
 | 
			
		||||
	this.alpha = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HighlightCircle.prototype = new AnimatedObject();
 | 
			
		||||
HighlightCircle.prototype.constructor = HighlightCircle;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
HighlightCircle.prototype.draw = function(ctx)
 | 
			
		||||
{
 | 
			
		||||
	ctx.globalAlpha = this.alpha;
 | 
			
		||||
	ctx.strokeStyle = this.foregroundColor;
 | 
			
		||||
	ctx.lineWidth = this.thickness;
 | 
			
		||||
	ctx.beginPath();
 | 
			
		||||
	ctx.arc(this.x,this.y,this.radius,0,Math.PI*2, true);
 | 
			
		||||
	ctx.closePath();
 | 
			
		||||
	ctx.stroke();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
HighlightCircle.prototype.createUndoDelete = function()
 | 
			
		||||
{
 | 
			
		||||
	return new UndoDeleteHighlightCircle(this.objectID, this.x, this.y, this.foregroundColor, this.radius, this.layer, this.alpha);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
function UndoDeleteHighlightCircle(objectID, x, y, circleColor, r, layer, alpha)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = objectID;
 | 
			
		||||
	this.x = x;
 | 
			
		||||
	this.y = y;
 | 
			
		||||
	this.color = circleColor;
 | 
			
		||||
	this.r = r;
 | 
			
		||||
	this.layer = layer;
 | 
			
		||||
	this.alpha = alpha
 | 
			
		||||
}
 | 
			
		||||
		
 | 
			
		||||
UndoDeleteHighlightCircle.prototype = new UndoBlock();
 | 
			
		||||
UndoDeleteHighlightCircle.prototype.constructor = UndoDeleteHighlightCircle;
 | 
			
		||||
 | 
			
		||||
UndoDeleteHighlightCircle.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.addHighlightCircleObject(this.objectID, this.color, this.r);
 | 
			
		||||
	world.setLayer(this.objectID, this.layer)
 | 
			
		||||
	world.setNodePosition(this.objectID, this.x, this.y);
 | 
			
		||||
	world.setAlpha(this.objectID, this.alpha)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,229 @@
 | 
			
		||||
// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without modification, are
 | 
			
		||||
// permitted provided that the following conditions are met:
 | 
			
		||||
//
 | 
			
		||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
 | 
			
		||||
// conditions and the following disclaimer.
 | 
			
		||||
//
 | 
			
		||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
 | 
			
		||||
// of conditions and the following disclaimer in the documentation and/or other materials
 | 
			
		||||
// provided with the distribution.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 | 
			
		||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
//
 | 
			
		||||
// The views and conclusions contained in the software and documentation are those of the
 | 
			
		||||
// authors and should not be interpreted as representing official policies, either expressed
 | 
			
		||||
// or implied, of the University of San Francisco
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// This class is somewhat poorly named -- it handles links between vertices in graphs,
 | 
			
		||||
//  pointers in linked lists, and so on. 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var LINE_maxHeightDiff = 5;
 | 
			
		||||
var LINE_minHeightDiff = 3;
 | 
			
		||||
var LINE_range= LINE_maxHeightDiff - LINE_minHeightDiff + 1;
 | 
			
		||||
var LINE_highlightDiff = 3;
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
function Line(n1, n2, color, cv, d, weight, anchorIndex)
 | 
			
		||||
{
 | 
			
		||||
	this.arrowHeight = 8;
 | 
			
		||||
	this.arrowWidth = 4;
 | 
			
		||||
 | 
			
		||||
	this.Node1 = n1;
 | 
			
		||||
	this.Node2 = n2;
 | 
			
		||||
	this.Dirty = false;
 | 
			
		||||
	this.directed = d;
 | 
			
		||||
	this.edgeColor = color;
 | 
			
		||||
	this.edgeLabel = weight;
 | 
			
		||||
	this.highlighted = false;
 | 
			
		||||
	this.addedToScene = true;
 | 
			
		||||
	this.anchorPoint = anchorIndex;
 | 
			
		||||
	this.highlightDiff = 0;
 | 
			
		||||
	this.curve = cv;
 | 
			
		||||
 | 
			
		||||
	this.alpha = 1.0;
 | 
			
		||||
	this.color = function color()
 | 
			
		||||
	{
 | 
			
		||||
		return this.edgeColor;   
 | 
			
		||||
	}
 | 
			
		||||
	   
 | 
			
		||||
	this.setColor = function(newColor)
 | 
			
		||||
	{
 | 
			
		||||
		this.edgeColor = newColor;
 | 
			
		||||
		Dirty = true;
 | 
			
		||||
	}
 | 
			
		||||
	   
 | 
			
		||||
	this.setHighlight = function(highlightVal)
 | 
			
		||||
	{
 | 
			
		||||
		this.highlighted = highlightVal;   
 | 
			
		||||
	}
 | 
			
		||||
		   
 | 
			
		||||
	this.pulseHighlight = function(frameNum)
 | 
			
		||||
	{
 | 
			
		||||
	   if (this.highlighted)
 | 
			
		||||
	   {
 | 
			
		||||
		   var frameMod = frameNum / 14.0;
 | 
			
		||||
		   var delta  = Math.abs((frameMod) % (2 * LINE_range  - 2) - LINE_range + 1)
 | 
			
		||||
		   this.highlightDiff =  delta + LINE_minHeightDiff;
 | 
			
		||||
		   Dirty = true;			   
 | 
			
		||||
	   }
 | 
			
		||||
	}
 | 
			
		||||
	   
 | 
			
		||||
	   
 | 
			
		||||
	this.hasNode = function(n)
 | 
			
		||||
	{
 | 
			
		||||
		return ((this.Node1 == n) || (this.Node2 == n));   
 | 
			
		||||
	}
 | 
			
		||||
	   
 | 
			
		||||
	   
 | 
			
		||||
	this.createUndoDisconnect  = function()
 | 
			
		||||
        {
 | 
			
		||||
		return new UndoConnect(this.Node1.objectID, this.Node2.objectID, true, this.edgeColor, this.directed, this.curve, this.edgeLabel, this.anchorPoint);
 | 
			
		||||
	}
 | 
			
		||||
	   
 | 
			
		||||
	   
 | 
			
		||||
	this.sign = function(n)
 | 
			
		||||
	{
 | 
			
		||||
	   if (n > 0)
 | 
			
		||||
	   {
 | 
			
		||||
		   return 1;
 | 
			
		||||
	   }
 | 
			
		||||
	   else
 | 
			
		||||
	   {
 | 
			
		||||
		   return -1;
 | 
			
		||||
	   }
 | 
			
		||||
	}
 | 
			
		||||
	   
 | 
			
		||||
	   
 | 
			
		||||
	this.drawArrow = function(pensize, color, context)
 | 
			
		||||
	{		
 | 
			
		||||
		context.strokeStyle = color;
 | 
			
		||||
		context.fillStyle = color;
 | 
			
		||||
		context.lineWidth = pensize;
 | 
			
		||||
		// var fromPos = this.Node1.getTailPointerAttachPos(this.Node2.x, this.Node2.y, this.anchorPoint);
 | 
			
		||||
		// var toPos = this.Node2.getHeadPointerAttachPos(this.Node1.x, this.Node1.y);
 | 
			
		||||
 | 
			
		||||
		var fromPos = this.Node1.getTailPointerAttachPos(this.Node2.x, this.Node2.y, this.anchorPoint);
 | 
			
		||||
		var toPos = this.Node2.getHeadPointerAttachPos(this.Node1.x, this.Node1.y);
 | 
			
		||||
 | 
			
		||||
		var deltaX = toPos[0] - fromPos[0];
 | 
			
		||||
		var deltaY = toPos[1] - fromPos[1];
 | 
			
		||||
		var midX = (deltaX) / 2.0 + fromPos[0];
 | 
			
		||||
		var midY = (deltaY) / 2.0 + fromPos[1];
 | 
			
		||||
		var controlX = midX - deltaY * this.curve;
 | 
			
		||||
 | 
			
		||||
		var controlY = midY + deltaX * this.curve;
 | 
			
		||||
 | 
			
		||||
		context.beginPath();
 | 
			
		||||
		context.moveTo(fromPos[0], fromPos[1]);
 | 
			
		||||
		context.quadraticCurveTo(controlX, controlY, toPos[0], toPos[1]);
 | 
			
		||||
		context.stroke();
 | 
			
		||||
		//context.closePath();
 | 
			
		||||
			
 | 
			
		||||
		// Position of the edge label:  First, we will place it right along the
 | 
			
		||||
		// middle of the curve (or the middle of the line, for curve == 0)
 | 
			
		||||
		var labelPosX = 0.25* fromPos[0] + 0.5*controlX + 0.25*toPos[0]; 
 | 
			
		||||
		var labelPosY =  0.25* fromPos[1] + 0.5*controlY + 0.25*toPos[1]; 
 | 
			
		||||
			
 | 
			
		||||
		// Next, we push the edge position label out just a little in the direction of
 | 
			
		||||
		// the curve, so that the label doesn't intersect the cuve (as long as the label
 | 
			
		||||
		// is only a few characters, that is)
 | 
			
		||||
		var midLen = Math.sqrt(deltaY*deltaY + deltaX*deltaX);
 | 
			
		||||
		if (midLen != 0)
 | 
			
		||||
		{
 | 
			
		||||
			labelPosX +=  (- deltaY * this.sign(this.curve))  / midLen * 10 
 | 
			
		||||
			labelPosY += ( deltaX * this.sign(this.curve))  / midLen * 10  
 | 
			
		||||
		}
 | 
			
		||||
			
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		context.textAlign = 'center';
 | 
			
		||||
		context.font         = '16px Consolas';
 | 
			
		||||
		context.textBaseline   = 'middle'; 
 | 
			
		||||
		context.fillText(this.edgeLabel, labelPosX, labelPosY);
 | 
			
		||||
 | 
			
		||||
		if (this.directed)
 | 
			
		||||
		{
 | 
			
		||||
			var xVec = controlX - toPos[0];
 | 
			
		||||
			var yVec = controlY - toPos[1];
 | 
			
		||||
			var len = Math.sqrt(xVec * xVec + yVec*yVec);
 | 
			
		||||
		
 | 
			
		||||
			if (len > 0)
 | 
			
		||||
			{
 | 
			
		||||
				xVec = xVec / len
 | 
			
		||||
				yVec = yVec / len;
 | 
			
		||||
				
 | 
			
		||||
				context.beginPath();
 | 
			
		||||
				context.moveTo(toPos[0], toPos[1]);
 | 
			
		||||
				context.lineTo(toPos[0] + xVec*this.arrowHeight - yVec*this.arrowWidth, toPos[1] + yVec*this.arrowHeight + xVec*this.arrowWidth);
 | 
			
		||||
				context.lineTo(toPos[0] + xVec*this.arrowHeight + yVec*this.arrowWidth, toPos[1] + yVec*this.arrowHeight - xVec*this.arrowWidth);
 | 
			
		||||
				context.lineTo(toPos[0], toPos[1]);
 | 
			
		||||
				context.closePath();
 | 
			
		||||
				context.stroke();
 | 
			
		||||
				context.fill();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		   
 | 
			
		||||
	   }
 | 
			
		||||
	   
 | 
			
		||||
	   
 | 
			
		||||
	   this.draw = function(ctx)
 | 
			
		||||
	   {
 | 
			
		||||
		   if (!this.addedToScene)
 | 
			
		||||
		   {
 | 
			
		||||
			   return;   
 | 
			
		||||
		   }
 | 
			
		||||
		   ctx.globalAlpha = this.alpha;
 | 
			
		||||
 | 
			
		||||
			if (this.highlighted)
 | 
			
		||||
				this.drawArrow(this.highlightDiff, "#FF0000", ctx);
 | 
			
		||||
			this.drawArrow(1, this.edgeColor, ctx);
 | 
			
		||||
	   }
 | 
			
		||||
	   
 | 
			
		||||
	   
 | 
			
		||||
}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function UndoConnect(from, to, createConnection, edgeColor, isDirected, cv, lab, anch)
 | 
			
		||||
{
 | 
			
		||||
	this.fromID = from;
 | 
			
		||||
	this.toID = to;
 | 
			
		||||
	this.connect = createConnection;
 | 
			
		||||
	this.color = edgeColor;
 | 
			
		||||
	this.directed = isDirected;
 | 
			
		||||
	this.curve = cv;
 | 
			
		||||
	this.edgeLabel = lab;
 | 
			
		||||
	this.anchorPoint = anch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
UndoConnect.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	if (this.connect)
 | 
			
		||||
	{
 | 
			
		||||
		world.connectEdge(this.fromID, this.toID, this.color, this.curve, this.directed, this.edgeLabel,this.anchorPoint);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		world.disconnect(this.fromID,this.toID);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
UndoConnect.prototype.addUndoAnimation = function(animationList)
 | 
			
		||||
{
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,858 @@
 | 
			
		||||
// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without modification, are
 | 
			
		||||
// permitted provided that the following conditions are met:
 | 
			
		||||
//
 | 
			
		||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
 | 
			
		||||
// conditions and the following disclaimer.
 | 
			
		||||
//
 | 
			
		||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
 | 
			
		||||
// of conditions and the following disclaimer in the documentation and/or other materials
 | 
			
		||||
// provided with the distribution.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 | 
			
		||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
//
 | 
			
		||||
// The views and conclusions contained in the software and documentation are those of the
 | 
			
		||||
// authors and should not be interpreted as representing official policies, either expressed
 | 
			
		||||
// or implied, of the University of San Francisco
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Object Manager
 | 
			
		||||
//
 | 
			
		||||
// Manage all of our animated objects.  Control any animated object should occur through
 | 
			
		||||
// this interface (not language enforced, because enforcing such things in Javascript is 
 | 
			
		||||
// problematic.)
 | 
			
		||||
//
 | 
			
		||||
// This class is only accessed through:
 | 
			
		||||
//
 | 
			
		||||
//  AnimationMain
 | 
			
		||||
//  Undo objects (which are themselves controlled by AnimationMain
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// TODO: 
 | 
			
		||||
//       1.  Add proper throws for all error conditions (perhaps guarded by
 | 
			
		||||
//           an assert-like structure that can be turned off for production?)
 | 
			
		||||
//       2.  Refactor this code so that it uses the same object syntax (with 
 | 
			
		||||
//           prototypes) as te rest of the code.  (low priority)
 | 
			
		||||
function ObjectManager()
 | 
			
		||||
{
 | 
			
		||||
	this.Nodes = [];
 | 
			
		||||
	this.Edges = [];
 | 
			
		||||
	this.BackEdges = [];
 | 
			
		||||
	this.activeLayers = [];
 | 
			
		||||
	this.activeLayers[0] = true;
 | 
			
		||||
	this.ctx = document.getElementById('canvas').getContext('2d');
 | 
			
		||||
	this.framenum = 0;
 | 
			
		||||
	this.width = 0;
 | 
			
		||||
	this.height = 0;
 | 
			
		||||
	this.statusReport = new AnimatedLabel(-1, "XXX", false, 30);
 | 
			
		||||
	this.statusReport.x = 30;
 | 
			
		||||
	
 | 
			
		||||
	this.draw = function()
 | 
			
		||||
	{
 | 
			
		||||
		this.framenum++;
 | 
			
		||||
		if (this.framenum > 1000)
 | 
			
		||||
			this.framenum = 0;
 | 
			
		||||
		
 | 
			
		||||
		this.ctx.clearRect(0,0,this.width,this.height); // clear canvas
 | 
			
		||||
		this.statusReport.y = this.height - 15;
 | 
			
		||||
		
 | 
			
		||||
		var i;
 | 
			
		||||
		var j;
 | 
			
		||||
		for (i = 0; i < this.Nodes.length; i++)
 | 
			
		||||
		{
 | 
			
		||||
			if (this.Nodes[i] != null && !this.Nodes[i].highlighted && this.Nodes[i].addedToScene && !this.Nodes[i].alwaysOnTop)
 | 
			
		||||
			{
 | 
			
		||||
				this.Nodes[i].draw(this.ctx);	
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for (i = 0; i < this.Nodes.length; i++)
 | 
			
		||||
		{
 | 
			
		||||
			if (this.Nodes[i] != null && (this.Nodes[i].highlighted && !this.Nodes[i].alwaysOnTop) && this.Nodes[i].addedToScene)
 | 
			
		||||
			{
 | 
			
		||||
				this.Nodes[i].pulseHighlight(this.framenum);
 | 
			
		||||
				this.Nodes[i].draw(this.ctx);	
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		for (i = 0; i < this.Nodes.length; i++)
 | 
			
		||||
		{
 | 
			
		||||
			if (this.Nodes[i] != null && this.Nodes[i].alwaysOnTop && this.Nodes[i].addedToScene)
 | 
			
		||||
			{
 | 
			
		||||
				this.Nodes[i].pulseHighlight(this.framenum);
 | 
			
		||||
				this.Nodes[i].draw(this.ctx);	
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
		for (i = 0; i < this.Edges.length; i++)
 | 
			
		||||
		{
 | 
			
		||||
			if (this.Edges[i] != null)
 | 
			
		||||
			{
 | 
			
		||||
				for (j = 0; j < this.Edges[i].length; j++)
 | 
			
		||||
				{
 | 
			
		||||
					if (this.Edges[i][j].addedToScene)
 | 
			
		||||
					{
 | 
			
		||||
						this.Edges[i][j].pulseHighlight(this.framenum);	
 | 
			
		||||
						this.Edges[i][j].draw(this.ctx);	
 | 
			
		||||
					}
 | 
			
		||||
					
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		this.statusReport.draw(this.ctx);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.update = function ()
 | 
			
		||||
	{
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.setLayers = function(shown,layers)
 | 
			
		||||
	{
 | 
			
		||||
		for (var i = 0; i < layers.length; i++)
 | 
			
		||||
		{
 | 
			
		||||
			this.activeLayers[layers[i]] = shown;
 | 
			
		||||
		}
 | 
			
		||||
		this.resetLayers();
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	this.addHighlightCircleObject = function(objectID, objectColor, radius)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
  	            throw "addHighlightCircleObject:Object with same ID (" + String(objectID) + ") already Exists!"
 | 
			
		||||
		}
 | 
			
		||||
		var newNode = new HighlightCircle(objectID, objectColor, radius)
 | 
			
		||||
		this.Nodes[objectID] = newNode;		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.setEdgeAlpha = function(fromID, toID, alphaVal)
 | 
			
		||||
	{
 | 
			
		||||
		var oldAlpha = 1.0; 
 | 
			
		||||
		if (this.Edges[fromID] != null &&
 | 
			
		||||
			this.Edges[fromID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			var len = this.Edges[fromID].length;
 | 
			
		||||
			for (var i = len - 1; i >= 0; i--)
 | 
			
		||||
			{
 | 
			
		||||
				if (this.Edges[fromID][i] != null &&
 | 
			
		||||
					this.Edges[fromID][i] != undefined &&
 | 
			
		||||
					this.Edges[fromID][i].Node2 == this.Nodes[toID])
 | 
			
		||||
				{
 | 
			
		||||
					oldAlpha = this.Edges[fromID][i].alpha
 | 
			
		||||
					this.Edges[fromID][i].alpha = alphaVal;		
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}	
 | 
			
		||||
		return oldAlpha;
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.setAlpha = function(nodeID, alphaVal) 
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] != null && this.Nodes[nodeID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			this.Nodes[nodeID].setAlpha(alphaVal);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.getAlpha = function(nodeID)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] != null && this.Nodes[nodeID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			return this.Nodes[nodeID].getAlpha();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.getTextColor = function(nodeID, index)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] != null && this.Nodes[nodeID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			return this.Nodes[nodeID].getTextColor(index);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			return "#000000";
 | 
			
		||||
		}
 | 
			
		||||
			
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.setTextColor = function(nodeID, color, index)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] != null && this.Nodes[nodeID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			this.Nodes[nodeID].setTextColor(color, index);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	this.setHighlightIndex = function(nodeID, index)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] != null && this.Nodes[nodeID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			this.Nodes[nodeID].setHighlightIndex(index);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.setAllLayers = function(layers)
 | 
			
		||||
	{
 | 
			
		||||
		this.activeLayers = [];
 | 
			
		||||
		for(var i = 0; i < layers.length; i++)
 | 
			
		||||
		{
 | 
			
		||||
			this.activeLayers[layers[i]] = true;
 | 
			
		||||
		}
 | 
			
		||||
		this.resetLayers();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.resetLayers = function()
 | 
			
		||||
	{
 | 
			
		||||
		var i
 | 
			
		||||
		for (i = 0; i <this.Nodes.length; i++)
 | 
			
		||||
		{
 | 
			
		||||
			if (this.Nodes[i] != null && this.Nodes[i] != undefined)
 | 
			
		||||
			{
 | 
			
		||||
				this.Nodes[i].addedToScene = this.activeLayers[this.Nodes[i].layer] == true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for (i = this.Edges.length - 1; i >= 0; i--)
 | 
			
		||||
		{
 | 
			
		||||
		    if (this.Edges[i] != null && this.Edges[i] != undefined)
 | 
			
		||||
			{
 | 
			
		||||
				for (var j = 0; j < this.Edges[i].length; j++)
 | 
			
		||||
				{
 | 
			
		||||
					if (this.Edges[i][j] != null && this.Edges[i][j] != undefined)
 | 
			
		||||
					{
 | 
			
		||||
							this.Edges[i][j].addedToScene =
 | 
			
		||||
								this.activeLayers[this.Edges[i][j].Node1.layer] == true &&
 | 
			
		||||
								this.activeLayers[this.Edges[i][j].Node2.layer] == true;
 | 
			
		||||
					}
 | 
			
		||||
					
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.setLayer = function(objectID, layer)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			this.Nodes[objectID].layer = layer;
 | 
			
		||||
			if (this.activeLayers[layer])
 | 
			
		||||
			{
 | 
			
		||||
				this.Nodes[objectID].addedToScene = true;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				this.Nodes[objectID].addedToScene = false;
 | 
			
		||||
			}
 | 
			
		||||
			if (this.Edges[objectID] != null && this.Edges[objectID] != undefined)
 | 
			
		||||
			{
 | 
			
		||||
				for (var i = 0; i < this.Edges[objectID].length; i++)
 | 
			
		||||
				{
 | 
			
		||||
					var nextEdge = this.Edges[objectID][i];
 | 
			
		||||
					if (nextEdge != null && nextEdge != undefined)
 | 
			
		||||
					{
 | 
			
		||||
						nextEdge.addedToScene = ((nextEdge.Node1.addedToScene) &&
 | 
			
		||||
												(nextEdge.Node2.addedToScene));
 | 
			
		||||
						
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (this.BackEdges[objectID] != null && this.BackEdges[objectID] != undefined)
 | 
			
		||||
			{
 | 
			
		||||
				for (var i = 0; i < this.BackEdges[objectID].length; i++)
 | 
			
		||||
				{
 | 
			
		||||
					var nextEdge = this.BackEdges[objectID][i];
 | 
			
		||||
					if (nextEdge != null && nextEdge != undefined)
 | 
			
		||||
					{
 | 
			
		||||
						nextEdge.addedToScene = ((nextEdge.Node1.addedToScene) &&
 | 
			
		||||
												 (nextEdge.Node2.addedToScene));
 | 
			
		||||
						
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}			
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.clearAllObjects = function()
 | 
			
		||||
	{
 | 
			
		||||
		this.Nodes = [];
 | 
			
		||||
		this.Edges = [];
 | 
			
		||||
		this.BackEdges = [];
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.setForegroundColor = function(objectID, color)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			this.Nodes[objectID].setForegroundColor(color);
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.setBackgroundColor = function(objectID, color)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[objectID] != null)
 | 
			
		||||
		{
 | 
			
		||||
			this.Nodes[objectID].setBackgroundColor(color);
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.setHighlight = function(nodeID, val)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] == null  || this.Nodes[nodeID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			// TODO:  Error here?
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		this.Nodes[nodeID].setHighlight(val);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.getHighlight = function(nodeID)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] == null  || this.Nodes[nodeID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			// TODO:  Error here?
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		return this.Nodes[nodeID].getHighlight();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	this.getHighlightIndex = function(nodeID)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] == null  || this.Nodes[nodeID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			// TODO:  Error here?
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		return this.Nodes[nodeID].getHighlightIndex();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.setWidth = function(nodeID, val)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] == null  || this.Nodes[nodeID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			// TODO:  Error here?
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		this.Nodes[nodeID].setWidth(val);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.setHeight = function(nodeID, val)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] == null  || this.Nodes[nodeID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			// TODO:  Error here?
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		this.Nodes[nodeID].setHeight(val);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.getHeight = function(nodeID)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] == null  || this.Nodes[nodeID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			// TODO:  Error here?
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		return this.Nodes[nodeID].getHeight();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.getWidth = function(nodeID)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] == null  || this.Nodes[nodeID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			// TODO:  Error here?
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		return this.Nodes[nodeID].getWidth();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.backgroundColor = function(objectID)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[objectID] != null)
 | 
			
		||||
		{
 | 
			
		||||
			return this.Nodes[objectID].backgroundColor;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			return '#000000';
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.foregroundColor = function(objectID)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[objectID] != null)
 | 
			
		||||
		{
 | 
			
		||||
			return this.Nodes[objectID].foregroundColor;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			return '#000000';
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
			
 | 
			
		||||
	this.disconnect = function(objectIDfrom,objectIDto)
 | 
			
		||||
	{
 | 
			
		||||
		var undo = null;
 | 
			
		||||
		var i;
 | 
			
		||||
		if (this.Edges[objectIDfrom] != null)
 | 
			
		||||
		{
 | 
			
		||||
			var len = this.Edges[objectIDfrom].length;
 | 
			
		||||
			for (i = len - 1; i >= 0; i--)
 | 
			
		||||
			{
 | 
			
		||||
				if (this.Edges[objectIDfrom][i] != null && this.Edges[objectIDfrom][i].Node2 == this.Nodes[objectIDto])
 | 
			
		||||
				{
 | 
			
		||||
					var deleted = this.Edges[objectIDfrom][i];
 | 
			
		||||
					undo = deleted.createUndoDisconnect();
 | 
			
		||||
					this.Edges[objectIDfrom][i] = this.Edges[objectIDfrom][len - 1];
 | 
			
		||||
					len -= 1;
 | 
			
		||||
					this.Edges[objectIDfrom].pop();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (this.BackEdges[objectIDto] != null)
 | 
			
		||||
		{
 | 
			
		||||
			len = this.BackEdges[objectIDto].length;
 | 
			
		||||
			for (i = len - 1; i >= 0; i--)
 | 
			
		||||
			{
 | 
			
		||||
				if (this.BackEdges[objectIDto][i] != null && this.BackEdges[objectIDto][i].Node1 == this.Nodes[objectIDfrom])
 | 
			
		||||
				{
 | 
			
		||||
					deleted = this.BackEdges[objectIDto][i];
 | 
			
		||||
					// Note:  Don't need to remove this child, did it above on the regular edge
 | 
			
		||||
					this.BackEdges[objectIDto][i] = this.BackEdges[objectIDto][len - 1];
 | 
			
		||||
					len -= 1;
 | 
			
		||||
					this.BackEdges[objectIDto].pop();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return undo;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.deleteIncident = function(objectID)
 | 
			
		||||
	{
 | 
			
		||||
		var undoStack = [];
 | 
			
		||||
 | 
			
		||||
		if (this.Edges[objectID] != null)
 | 
			
		||||
		{
 | 
			
		||||
			var len = this.Edges[objectID].length;
 | 
			
		||||
			for (var i = len - 1; i >= 0; i--)
 | 
			
		||||
			{
 | 
			
		||||
				var deleted = this.Edges[objectID][i];
 | 
			
		||||
				var node2ID = deleted.Node2.identifier();
 | 
			
		||||
				undoStack.push(deleted.createUndoDisconnect());
 | 
			
		||||
				
 | 
			
		||||
				var len2 = this.BackEdges[node2ID].length;
 | 
			
		||||
				for (var j = len2 - 1; j >=0; j--)
 | 
			
		||||
				{
 | 
			
		||||
					if (this.BackEdges[node2ID][j] == deleted)
 | 
			
		||||
					{
 | 
			
		||||
						this.BackEdges[node2ID][j] = this.BackEdges[node2ID][len2 - 1];
 | 
			
		||||
						len2 -= 1;
 | 
			
		||||
						this.BackEdges[node2ID].pop();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			this.Edges[objectID] = null;
 | 
			
		||||
		}
 | 
			
		||||
		if (this.BackEdges[objectID] != null)
 | 
			
		||||
		{
 | 
			
		||||
			len = this.BackEdges[objectID].length;
 | 
			
		||||
			for (i = len - 1; i >= 0; i--)
 | 
			
		||||
			{
 | 
			
		||||
				deleted = this.BackEdges[objectID][i];
 | 
			
		||||
				var node1ID = deleted.Node1.identifier();
 | 
			
		||||
				undoStack.push(deleted.createUndoDisconnect());
 | 
			
		||||
 | 
			
		||||
				len2 = this.Edges[node1ID].length;
 | 
			
		||||
				for (j = len2 - 1; j >=0; j--)
 | 
			
		||||
				{
 | 
			
		||||
					if (this.Edges[node1ID][j] == deleted)
 | 
			
		||||
					{
 | 
			
		||||
						this.Edges[node1ID][j] = this.Edges[node1ID][len2 - 1];
 | 
			
		||||
						len2 -= 1;
 | 
			
		||||
						this.Edges[node1ID].pop();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			this.BackEdges[objectID] = null;
 | 
			
		||||
		}
 | 
			
		||||
		return undoStack;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.removeObject = function(ObjectID)
 | 
			
		||||
	{
 | 
			
		||||
		var OldObject = this.Nodes[ObjectID];
 | 
			
		||||
		if (ObjectID == this.Nodes.length - 1)
 | 
			
		||||
		{
 | 
			
		||||
			this.Nodes.pop();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			this.Nodes[ObjectID] = null;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.getObject = function(objectID)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[objectID] == null || this.Nodes[objectID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			throw "getObject:Object with ID (" + String(objectID) + ") does not exist"
 | 
			
		||||
		}
 | 
			
		||||
		return this.Nodes[objectID];
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.addCircleObject = function (objectID, objectLabel)
 | 
			
		||||
	{
 | 
			
		||||
			if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
 | 
			
		||||
			{
 | 
			
		||||
				throw "addCircleObject:Object with same ID (" + String(objectID) + ") already Exists!"
 | 
			
		||||
			}
 | 
			
		||||
			var newNode = new AnimatedCircle(objectID, objectLabel);
 | 
			
		||||
			this.Nodes[objectID] = newNode;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.getNodeX = function(nodeID)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			throw "getting x position of an object that does not exit";
 | 
			
		||||
		}	
 | 
			
		||||
		return this.Nodes[nodeID].x;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.getTextWidth = function(text)
 | 
			
		||||
	{
 | 
			
		||||
		// TODO:  Need to make fonts more flexible, and less hardwired.
 | 
			
		||||
		this.ctx.font = '16px Consolas';
 | 
			
		||||
		if (text==undefined)
 | 
			
		||||
		{
 | 
			
		||||
			w = 3;
 | 
			
		||||
		}
 | 
			
		||||
		var strList = text.split("\n");
 | 
			
		||||
		var width = 0;
 | 
			
		||||
		if (strList.length == 1)
 | 
			
		||||
		{
 | 
			
		||||
 			width = this.ctx.measureText(text).width;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			for (var i = 0; i < strList.length; i++)
 | 
			
		||||
			{
 | 
			
		||||
				width = Math.max(width, this.ctx.measureText(strList[i]).width);
 | 
			
		||||
			}		
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return width;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.setText = function(nodeID, text, index)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			return;
 | 
			
		||||
			throw "setting text of an object that does not exit";
 | 
			
		||||
		}			
 | 
			
		||||
		this.Nodes[nodeID].setText(text, index, this.getTextWidth(text));
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.getText = function(nodeID, index)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			throw "getting text of an object that does not exit";
 | 
			
		||||
		}			
 | 
			
		||||
		return this.Nodes[nodeID].getText(index);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.getNodeY = function(nodeID)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			throw "getting y position of an object that does not exit";
 | 
			
		||||
		}	
 | 
			
		||||
		return this.Nodes[nodeID].y;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	this.connectEdge = function(objectIDfrom, objectIDto, color, curve, directed, lab, connectionPoint)
 | 
			
		||||
	{
 | 
			
		||||
		var fromObj = this.Nodes[objectIDfrom];
 | 
			
		||||
		var toObj = this.Nodes[objectIDto];
 | 
			
		||||
		if (fromObj == null || toObj == null)
 | 
			
		||||
		{
 | 
			
		||||
			throw "Tried to connect two nodes, one didn't exist!";
 | 
			
		||||
		}
 | 
			
		||||
		var l = new Line(fromObj,toObj, color, curve, directed, lab, connectionPoint);
 | 
			
		||||
		if (this.Edges[objectIDfrom] == null || this.Edges[objectIDfrom] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			this.Edges[objectIDfrom] = [];
 | 
			
		||||
		}
 | 
			
		||||
		if (this.BackEdges[objectIDto] == null || this.BackEdges[objectIDto] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			this.BackEdges[objectIDto] = [];
 | 
			
		||||
		}
 | 
			
		||||
		l.addedToScene = fromObj.addedToScene && toObj.addedToScene;
 | 
			
		||||
		this.Edges[objectIDfrom].push(l);
 | 
			
		||||
		this.BackEdges[objectIDto].push(l);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.setNull = function(objectID, nullVal)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			this.Nodes[objectID].setNull(nullVal);
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.getNull = function(objectID)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			return this.Nodes[objectID].getNull();
 | 
			
		||||
		}
 | 
			
		||||
		return false;  // TODO:  Error here?
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.setEdgeColor = function(fromID, toID, color) // returns old color
 | 
			
		||||
	{
 | 
			
		||||
		var oldColor ="#000000";
 | 
			
		||||
		if (this.Edges[fromID] != null &&
 | 
			
		||||
			this.Edges[fromID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			var len = this.Edges[fromID].length;
 | 
			
		||||
			for (var i = len - 1; i >= 0; i--)
 | 
			
		||||
			{
 | 
			
		||||
				if (this.Edges[fromID][i] != null &&
 | 
			
		||||
					this.Edges[fromID][i] != undefined &&
 | 
			
		||||
					this.Edges[fromID][i].Node2 == this.Nodes[toID])
 | 
			
		||||
				{
 | 
			
		||||
					oldColor = this.Edges[fromID][i].color();
 | 
			
		||||
					this.Edges[fromID][i].setColor(color);		
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}	
 | 
			
		||||
		return oldColor;
 | 
			
		||||
	}		
 | 
			
		||||
	
 | 
			
		||||
	this.alignTop = function(id1, id2)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[id1] == null || this.Nodes[id1] == undefined ||
 | 
			
		||||
			this.Nodes[id2] == null || this.Nodes[id2] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			throw "Tring to align two nodes, one doesn't exist: " + String(id1) + "," + String(id2);			
 | 
			
		||||
		}
 | 
			
		||||
		this.Nodes[id1].alignTop(this.Nodes[id2]);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.alignLeft = function(id1, id2)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[id1] == null || this.Nodes[id1] == undefined ||
 | 
			
		||||
			this.Nodes[id2] == null || this.Nodes[id2] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			throw "Tring to align two nodes, one doesn't exist: " + String(id1) + "," + String(id2);			
 | 
			
		||||
		}
 | 
			
		||||
		this.Nodes[id1].alignLeft(this.Nodes[id2]);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	this.alignRight = function(id1, id2)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[id1] == null || this.Nodes[id1] == undefined ||
 | 
			
		||||
			this.Nodes[id2] == null || this.Nodes[id2] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			throw "Tring to align two nodes, one doesn't exist: " + String(id1) + "," + String(id2);			
 | 
			
		||||
		}
 | 
			
		||||
		this.Nodes[id1].alignRight(this.Nodes[id2]);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	this.getAlignRightPos = function(id1, id2)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[id1] == null || this.Nodes[id1] == undefined ||
 | 
			
		||||
			this.Nodes[id2] == null || this.Nodes[id2] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			throw "Tring to align two nodes, one doesn't exist: " + String(id1) + "," + String(id2);			
 | 
			
		||||
		}
 | 
			
		||||
	        return this.Nodes[id1].getAlignRightPos(this.Nodes[id2]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.getAlignLeftPos = function(id1, id2)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[id1] == null || this.Nodes[id1] == undefined ||
 | 
			
		||||
			this.Nodes[id2] == null || this.Nodes[id2] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			throw "Tring to align two nodes, one doesn't exist: " + String(id1) + "," + String(id2);			
 | 
			
		||||
		}
 | 
			
		||||
	        return this.Nodes[id1].getAlignLeftPos(this.Nodes[id2]);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	this.alignBottom = function(id1, id2)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[id1] == null || this.Nodes[id1] == undefined ||
 | 
			
		||||
			this.Nodes[id2] == null || this.Nodes[id2] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			throw "Tring to align two nodes, one doesn't exist: " + String(id1) + "," + String(id2);			
 | 
			
		||||
		}
 | 
			
		||||
		this.Nodes[id1].alignBottom(this.Nodes[id2]);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.setEdgeHighlight = function(fromID, toID, val) // returns old color
 | 
			
		||||
	{
 | 
			
		||||
		var oldHighlight = false;
 | 
			
		||||
		if (this.Edges[fromID] != null &&
 | 
			
		||||
			this.Edges[fromID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			var len = this.Edges[fromID].length;
 | 
			
		||||
			for (var i = len - 1; i >= 0; i--)
 | 
			
		||||
			{
 | 
			
		||||
				if (this.Edges[fromID][i] != null && 
 | 
			
		||||
					this.Edges[fromID][i] != undefined && 
 | 
			
		||||
					this.Edges[fromID][i].Node2 == this.Nodes[toID])
 | 
			
		||||
				{
 | 
			
		||||
					oldHighlight = this.Edges[fromID][i].highlighted;
 | 
			
		||||
					this.Edges[fromID][i].setHighlight(val);		
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return oldHighlight;
 | 
			
		||||
	}
 | 
			
		||||
	this.addLabelObject = function(objectID, objectLabel, centering)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[objectID] != null && this.Nodes[objectID] != undefined)
 | 
			
		||||
		{
 | 
			
		||||
			throw new Error("addLabelObject: Object Already Exists!");
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		var newLabel = new AnimatedLabel(objectID, objectLabel, centering, this.getTextWidth(objectLabel));
 | 
			
		||||
		this.Nodes[objectID] = newLabel;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
		
 | 
			
		||||
	this.addLinkedListObject = function(objectID, nodeLabel, width, height, linkPer, verticalOrientation, linkPosEnd, numLabels, backgroundColor, foregroundColor)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[objectID] != null)
 | 
			
		||||
		{
 | 
			
		||||
			throw new Error("addLinkedListObject:Object with same ID already Exists!");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		var newNode  = new AnimatedLinkedList(objectID, nodeLabel, width, height, linkPer, verticalOrientation, linkPosEnd, numLabels, backgroundColor, foregroundColor);
 | 
			
		||||
		this.Nodes[objectID] = newNode;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	 
 | 
			
		||||
	this.getNumElements = function(objectID)
 | 
			
		||||
	{
 | 
			
		||||
		return this.Nodes[objectID].getNumElements();
 | 
			
		||||
	}
 | 
			
		||||
	 
 | 
			
		||||
	
 | 
			
		||||
	this.setNumElements = function(objectID, numElems)
 | 
			
		||||
	{
 | 
			
		||||
		this.Nodes[objectID].setNumElements(numElems);
 | 
			
		||||
	}
 | 
			
		||||
	this.addBTreeNode = function(objectID, widthPerElem, height, numElems, backgroundColor, foregroundColor)
 | 
			
		||||
	 {
 | 
			
		||||
		 backgroundColor = (backgroundColor == undefined) ? "#FFFFFF" : backgroundColor;
 | 
			
		||||
		 foregroundColor = (foregroundColor == undefined) ? "#FFFFFF" : foregroundColor;
 | 
			
		||||
		 
 | 
			
		||||
		 if (this.Nodes[objectID] != null && Nodes[objectID] != undefined)
 | 
			
		||||
		 {
 | 
			
		||||
			 throw "addBTreeNode:Object with same ID already Exists!";
 | 
			
		||||
		 }
 | 
			
		||||
 | 
			
		||||
		 var newNode = new AnimatedBTreeNode(objectID,widthPerElem, height, numElems, backgroundColor, foregroundColor);
 | 
			
		||||
		 this.Nodes[objectID] = newNode;
 | 
			
		||||
	 }
 | 
			
		||||
	
 | 
			
		||||
	 this.addRectangleObject = function(objectID,nodeLabel, width, height, xJustify , yJustify , backgroundColor, foregroundColor)
 | 
			
		||||
	 {
 | 
			
		||||
		 if (this.Nodes[objectID] != null || this.Nodes[objectID] != undefined)
 | 
			
		||||
		 {
 | 
			
		||||
			 throw new Error("addRectangleObject:Object with same ID already Exists!");
 | 
			
		||||
		 }
 | 
			
		||||
		 var newNode = new AnimatedRectangle(objectID, nodeLabel, width, height, xJustify, yJustify, backgroundColor, foregroundColor);
 | 
			
		||||
		 this.Nodes[objectID] = newNode;
 | 
			
		||||
		 
 | 
			
		||||
	 }
 | 
			
		||||
	 
 | 
			
		||||
	 
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	this.setNodePosition = function(nodeID, newX, newY)
 | 
			
		||||
	{
 | 
			
		||||
		if (this.Nodes[nodeID] == null || this.Nodes[nodeID] == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			// TODO:  Error here?
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (newX == undefined || newY == undefined)
 | 
			
		||||
		{
 | 
			
		||||
			
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		this.Nodes[nodeID].x = newX;
 | 
			
		||||
		this.Nodes[nodeID].y = newY;
 | 
			
		||||
		/* Don't need to dirty anything, since we repaint everything every frame
 | 
			
		||||
		 (TODO:  Revisit if we do conditional redraws)
 | 
			
		||||
		 }*/
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
@@ -0,0 +1,398 @@
 | 
			
		||||
// Copyright 2011 David Galles, University of San Francisco. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without modification, are
 | 
			
		||||
// permitted provided that the following conditions are met:
 | 
			
		||||
//
 | 
			
		||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
 | 
			
		||||
// conditions and the following disclaimer.
 | 
			
		||||
//
 | 
			
		||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
 | 
			
		||||
// of conditions and the following disclaimer in the documentation and/or other materials
 | 
			
		||||
// provided with the distribution.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
 | 
			
		||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
//
 | 
			
		||||
// The views and conclusions contained in the software and documentation are those of the
 | 
			
		||||
// authors and should not be interpreted as representing official policies, either expressed
 | 
			
		||||
// or implied, of the University of San Francisco
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Base "class": UndoBlock
 | 
			
		||||
 | 
			
		||||
function UndoBlock()
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoBlock.prototype.addUndoAnimation = function(animationList)
 | 
			
		||||
{
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoBlock.prototype.undoInitialStep = function(world) 
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoMove
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoMove(id, fmX, fmy, tx, ty)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.fromX = fmX;
 | 
			
		||||
	this.fromY = fmy;
 | 
			
		||||
	this.toX = tx;
 | 
			
		||||
	this.toY = ty;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
UndoMove.prototype = new UndoBlock();
 | 
			
		||||
UndoMove.prototype.constructor = UndoMove;
 | 
			
		||||
 | 
			
		||||
UndoMove.prototype.addUndoAnimation = function (animationList)
 | 
			
		||||
{
 | 
			
		||||
	var nextAnim = new SingleAnimation(this.objectID, this.fromX, this.fromY, this.toX, this.toY);
 | 
			
		||||
	animationList.push(nextAnim);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoCreate
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoCreate(id)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoCreate.prototype = new UndoBlock();
 | 
			
		||||
UndoCreate.prototype.constructor = UndoCreate;
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
UndoCreate.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
			world.removeObject(this.objectID);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoHighlight
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoHighlight(id, val)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.highlightValue = val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoHighlight.prototype = new UndoBlock();
 | 
			
		||||
UndoHighlight.prototype.constructor = UndoHighlight;
 | 
			
		||||
 | 
			
		||||
UndoHighlight.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.setHighlight(this.objectID, this.highlightValue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetHeight
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoSetHeight(id, val)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.height = val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetHeight.prototype = new UndoBlock();
 | 
			
		||||
UndoSetHeight.prototype.constructor = UndoSetHeight;
 | 
			
		||||
 | 
			
		||||
UndoSetHeight.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.setHeight(this.objectID, this.height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetWidth
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoSetWidth(id, val)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.width = val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetWidth.prototype = new UndoBlock();
 | 
			
		||||
UndoSetWidth.prototype.constructor = UndoSetWidth;
 | 
			
		||||
 | 
			
		||||
UndoSetWidth.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.setWidth(this.objectID, this.width);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetNumElements
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
function UndoSetNumElements(obj, newNumElems)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = obj.objectID;
 | 
			
		||||
	this.sizeBeforeChange = obj.getNumElements();
 | 
			
		||||
	this.sizeAfterChange = newNumElems;
 | 
			
		||||
	if (this.sizeBeforeChange > this.sizeAfterChange)
 | 
			
		||||
	{
 | 
			
		||||
		this.labels = new Array(this.sizeBeforeChange - this.sizeAfterChange);
 | 
			
		||||
		this.colors = new Array(this.sizeBeforeChange - this.sizeAfterChange);
 | 
			
		||||
		for (var i = 0; i < this.sizeBeforeChange - this.sizeAfterChange; i++)
 | 
			
		||||
		{
 | 
			
		||||
			this.labels[i] = obj.getText(i+this.sizeAfterChange);
 | 
			
		||||
			this.colors[i] = obj.getTextColor(i+this.sizeAfterChange);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
	}	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetNumElements.prototype = new UndoBlock();
 | 
			
		||||
UndoSetNumElements.prototype.constructor = UndoSetNumElements;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
UndoSetNumElements.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.setNumElements(this.objectID, this.sizeBeforeChange);
 | 
			
		||||
	if (this.sizeBeforeChange > this.sizeAfterChange)
 | 
			
		||||
	{
 | 
			
		||||
		for (var i = 0; i < this.sizeBeforeChange - this.sizeAfterChange; i++)
 | 
			
		||||
		{
 | 
			
		||||
			world.setText(this.objectID, this.labels[i], i+this.sizeAfterChange);
 | 
			
		||||
			world.setTextColor(this.objectID, this.colors[i], i+this.sizeAfterChange);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetAlpha
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoSetAlpha(id, alph)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.alphaVal = alph;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetAlpha.prototype = new UndoBlock();
 | 
			
		||||
UndoSetAlpha.prototype.constructor = UndoSetAlpha;
 | 
			
		||||
 | 
			
		||||
UndoSetAlpha.prototype.undoInitialStep = function(world) 
 | 
			
		||||
{
 | 
			
		||||
	world.setAlpha(this.objectID, this.alphaVal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetNull
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoSetNull(id, nv)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.nullVal = nv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetNull.prototype = new UndoBlock();
 | 
			
		||||
UndoSetNull.prototype.constructor = UndoSetNull;
 | 
			
		||||
 | 
			
		||||
UndoSetNull.prototype.undoInitialStep = function(world) 
 | 
			
		||||
{
 | 
			
		||||
	world.setNull(this.objectID, this.nullVal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetForegroundColor
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoSetForegroundColor(id, color)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.color = color;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetForegroundColor.prototype = new UndoBlock();
 | 
			
		||||
UndoSetForegroundColor.prototype.constructor = UndoSetForegroundColor;
 | 
			
		||||
 | 
			
		||||
UndoSetForegroundColor.prototype.undoInitialStep =  function (world)
 | 
			
		||||
{
 | 
			
		||||
	world.setForegroundColor(this.objectID, this.color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetBackgroundColor
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoSetBackgroundColor(id, color)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.color = color;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetBackgroundColor.prototype = new UndoBlock();
 | 
			
		||||
UndoSetBackgroundColor.prototype.constructor = UndoSetBackgroundColor;
 | 
			
		||||
 | 
			
		||||
UndoSetBackgroundColor.prototype.undoInitialStep =  function (world)
 | 
			
		||||
{
 | 
			
		||||
	world.setBackgroundColor(this.objectID, this.color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetHighlightIndex
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoSetHighlightIndex(id, index)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.index = index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetHighlightIndex.prototype = new UndoBlock();
 | 
			
		||||
UndoSetHighlightIndex.prototype.constructor = UndoSetHighlightIndex;
 | 
			
		||||
 | 
			
		||||
UndoSetHighlightIndex.prototype.undoInitialStep =  function (world)
 | 
			
		||||
{
 | 
			
		||||
	world.setHighlightIndex(this.objectID, this.index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetText
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function UndoSetText(id, str, index)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.newText = str;
 | 
			
		||||
	this.labelIndex = index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetText.prototype = new UndoBlock();
 | 
			
		||||
UndoSetText.prototype.constructor = UndoSetText;
 | 
			
		||||
 | 
			
		||||
UndoSetText.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.setText(this.objectID, this.newText, this.labelIndex);
 | 
			
		||||
}
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetTextColor
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function UndoSetTextColor(id, color, index)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.color = color;
 | 
			
		||||
	this.index = index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetTextColor.prototype = new UndoBlock();
 | 
			
		||||
UndoSetTextColor.prototype.constructor = UndoSetTextColor;
 | 
			
		||||
 | 
			
		||||
UndoSetTextColor.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.setTextColor(this.objectID, this.color, this.index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoHighlightEdge
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoHighlightEdge(from, to, val)
 | 
			
		||||
{
 | 
			
		||||
	this.fromID = from;
 | 
			
		||||
	this.toID = to;
 | 
			
		||||
	this.highlightValue = val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoHighlightEdge.prototype = new UndoBlock();
 | 
			
		||||
UndoHighlightEdge.prototype.constructor = UndoHighlightEdge;
 | 
			
		||||
 | 
			
		||||
UndoHighlightEdge.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.setEdgeHighlight(this.fromID, this.toID, this.highlightValue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetEdgeColor
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoSetEdgeColor(from, to, oldColor)
 | 
			
		||||
{
 | 
			
		||||
	this.fromID = from;
 | 
			
		||||
	this.toID = to;
 | 
			
		||||
	this.color = oldColor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetEdgeColor.prototype = new UndoBlock();
 | 
			
		||||
UndoSetEdgeColor.prototype.constructor = UndoSetEdgeColor;
 | 
			
		||||
 | 
			
		||||
UndoSetEdgeColor.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.setEdgeColor(this.fromID, this.toID, this.color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetEdgeAlpha
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoSetEdgeAlpha(from, to, oldAplha)
 | 
			
		||||
{
 | 
			
		||||
	this.fromID = from;
 | 
			
		||||
	this.toID = to;
 | 
			
		||||
	this.alpha  = oldAplha;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetEdgeAlpha.prototype = new UndoBlock();
 | 
			
		||||
UndoSetEdgeAlpha.prototype.constructor = UndoSetEdgeAlpha;
 | 
			
		||||
 | 
			
		||||
UndoSetEdgeAlpha.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.setEdgeAlpha(this.fromID, this.toID, this.alpha);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
// UndoSetPosition
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
function UndoSetPosition(id, x, y)
 | 
			
		||||
{
 | 
			
		||||
	this.objectID = id;
 | 
			
		||||
	this.x = x; 
 | 
			
		||||
	this.y = y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UndoSetPosition.prototype = new UndoBlock();
 | 
			
		||||
UndoSetPosition.prototype.constructor = UndoSetPosition;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
UndoSetPosition.prototype.undoInitialStep = function(world)
 | 
			
		||||
{
 | 
			
		||||
	world.setNodePosition(this.objectID, this.x, this.y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user