859 行
21 KiB
JavaScript
859 行
21 KiB
JavaScript
// 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)
|
|
}*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|