mirror of
https://github.com/UnickSoft/graphonline.git
synced 2026-02-16 02:30:51 +00:00
first commit
This commit is contained in:
219
script/Algorithms.js
Normal file
219
script/Algorithms.js
Normal file
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* File for algorithms.
|
||||
*
|
||||
*/
|
||||
|
||||
// Return list of vertex with connected vertex.
|
||||
function getVertexToVertexArray(graph, ignoryDirection)
|
||||
{
|
||||
res = {};
|
||||
|
||||
for (var i = 0; i < graph.edges.length; i ++)
|
||||
{
|
||||
edge = graph.edges[i];
|
||||
if (!res.hasOwnProperty(edge.vertex1.id))
|
||||
{
|
||||
res[edge.vertex1.id] = [];
|
||||
}
|
||||
res[edge.vertex1.id].push(edge.vertex2);
|
||||
if (!edge.isDirect || ignoryDirection)
|
||||
{
|
||||
if (!res.hasOwnProperty(edge.vertex2.id))
|
||||
{
|
||||
res[edge.vertex2.id] = [];
|
||||
}
|
||||
|
||||
res[edge.vertex2.id].push(edge.vertex1);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Global array of all algorithms.
|
||||
var g_Algorithms = [];
|
||||
var g_AlgorithmIds = [];
|
||||
|
||||
// Call this function to register your factory algoritm.
|
||||
function RegisterAlgorithm (factory)
|
||||
{
|
||||
g_Algorithms.push(factory);
|
||||
g_AlgorithmIds.push(factory(null).getId());
|
||||
}
|
||||
|
||||
// Base algorithm class.
|
||||
function BaseAlgorithm (graph, app)
|
||||
{
|
||||
this.graph = graph;
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
// @return name of algorthm. For now we supports only 2 locals: "ru" and "en"
|
||||
BaseAlgorithm.prototype.getName = function(local)
|
||||
{
|
||||
return "unknown_name_" + local;
|
||||
}
|
||||
|
||||
// @return id of algorthm. Please use format: "your id"."algorithm id". Ex. "OlegSh.ConnectedComponent"
|
||||
BaseAlgorithm.prototype.getId = function()
|
||||
{
|
||||
return "unknown.unknown";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
BaseAlgorithm.prototype.getMessage = function(local)
|
||||
{
|
||||
return "unknown_message_" + local;
|
||||
}
|
||||
|
||||
// calls when user select vertex.
|
||||
// @return true if you allow to select this object or false.
|
||||
BaseAlgorithm.prototype.selectVertex = function(vertex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// calls when user select edge.
|
||||
// @return true if you allow to select this object or false.
|
||||
BaseAlgorithm.prototype.selectEdge = function(edge)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// user click to workspace.
|
||||
// @return true if you allow to deselect all
|
||||
BaseAlgorithm.prototype.deselectAll = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// get result of algorithm.
|
||||
// If result if not ready, please return null.
|
||||
// It will be called after each user action.
|
||||
// Please return true, if you done.
|
||||
BaseAlgorithm.prototype.result = function(resultCallback)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// If you no need to get feedback from user, return true.
|
||||
// In this case result will calls once.
|
||||
BaseAlgorithm.prototype.instance = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// @return false, if you change up text and do not want to restore it back.
|
||||
BaseAlgorithm.prototype.needRestoreUpText = function()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// @return 0, if object is not selected, in other case return groupe of selection.
|
||||
BaseAlgorithm.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This methos is called, when messages was updated on html page.
|
||||
BaseAlgorithm.prototype.messageWasChanged = function() {}
|
||||
|
||||
|
||||
/**
|
||||
* Default handler.
|
||||
* Select using mouse, drag.
|
||||
*
|
||||
*/
|
||||
function BaseAlgorithmEx(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
BaseAlgorithmEx.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
BaseAlgorithmEx.prototype.CalculateAlgorithm = function(queryString, resultCallback)
|
||||
{
|
||||
var graph = this.graph;
|
||||
var creator = new GraphMLCreater(graph.vertices, graph.edges);
|
||||
var pathObjects = [];
|
||||
var properties = {};
|
||||
var result = [];
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/cgi-bin/GraphCGI.exe?" + queryString,
|
||||
data: creator.GetXMLString(),
|
||||
dataType: "text",
|
||||
})
|
||||
.done(function( msg )
|
||||
{
|
||||
console.log(msg);
|
||||
$('#debug').text(msg);
|
||||
xmlDoc = $.parseXML( msg );
|
||||
var $xml = $( xmlDoc );
|
||||
|
||||
$results = $xml.find( "result" );
|
||||
|
||||
$results.each(function(){
|
||||
$values = $(this).find( "value" );
|
||||
|
||||
$values.each(function(){
|
||||
var type = $(this).attr('type');
|
||||
var value = $(this).text();
|
||||
var res = {};
|
||||
res.type = type;
|
||||
res.value = value;
|
||||
result.push(res);
|
||||
});
|
||||
});
|
||||
|
||||
$nodes = $xml.find( "node" );
|
||||
|
||||
$nodes.each(function(){
|
||||
var id = $(this).attr('id');
|
||||
$data = $(this).find("data");
|
||||
$data.each(function(){
|
||||
if ("hightlightNode" == $(this).attr('key') && $(this).text() == "1")
|
||||
{
|
||||
pathObjects.push(graph.FindVertex(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!properties[id])
|
||||
{
|
||||
properties[id] = {};
|
||||
}
|
||||
properties[id][$(this).attr('key')] = $(this).text();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$edges = $xml.find( "edge" );
|
||||
|
||||
$edges.each(function(){
|
||||
var source = $(this).attr('source');
|
||||
var target = $(this).attr('target');
|
||||
pathObjects.push(graph.FindEdge(source, target));
|
||||
});
|
||||
|
||||
console.log(result);
|
||||
|
||||
resultCallback(pathObjects, properties, result);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
BaseAlgorithmEx.prototype.GetNodesPath = function(array, start, count)
|
||||
{
|
||||
var res = [];
|
||||
for (var index = start; index < start + count; index++)
|
||||
{
|
||||
res.push(array[index].value);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
1121
script/Appilcation.js
Normal file
1121
script/Appilcation.js
Normal file
File diff suppressed because it is too large
Load Diff
57
script/BaseEdge.js
Normal file
57
script/BaseEdge.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* This is base arc.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
function BaseEdge(vertex1, vertex2, isDirect, weight, useWeight)
|
||||
{
|
||||
this.vertex1 = vertex1;
|
||||
this.vertex2 = vertex2;
|
||||
this.isDirect = isDirect;
|
||||
this.weight = Number(weight);
|
||||
// For direct graph, has pair edge or not.
|
||||
this.hasPair = false;
|
||||
this.useWeight = useWeight;
|
||||
this.id = 0;
|
||||
}
|
||||
|
||||
BaseEdge.prototype.model = new EdgeModel();
|
||||
|
||||
BaseEdge.prototype.SaveToXML = function ()
|
||||
{
|
||||
return "<edge " +
|
||||
"vertex1=\"" + this.vertex1.id + "\" " +
|
||||
"vertex2=\"" + this.vertex2.id + "\" " +
|
||||
"isDirect=\"" + this.isDirect + "\" " +
|
||||
"weight=\"" + this.weight + "\" " +
|
||||
"useWeight=\"" + this.useWeight + "\" " +
|
||||
"hasPair=\"" + this.hasPair + "\" " +
|
||||
"id=\"" + this.id + "\" " +
|
||||
"></edge>";
|
||||
}
|
||||
|
||||
BaseEdge.prototype.LoadFromXML = function (xml, graph)
|
||||
{
|
||||
var attr = xml.attr('vertex1');
|
||||
this.vertex1 = graph.FindVertex(parseInt(typeof attr !== 'undefined' ? attr : xml.attr('graph1')));
|
||||
var attr = xml.attr('vertex2');
|
||||
this.vertex2 = graph.FindVertex(parseInt(typeof attr !== 'undefined' ? attr : xml.attr('graph2')));
|
||||
this.isDirect = xml.attr('isDirect') == "true";
|
||||
this.weight = parseFloat(xml.attr('weight'));
|
||||
this.hasPair = xml.attr('hasPair') == "true";
|
||||
this.useWeight = xml.attr('useWeight') == "true";
|
||||
this.id = parseInt(xml.attr('id'));
|
||||
}
|
||||
|
||||
BaseEdge.prototype.GetPixelLength = function ()
|
||||
{
|
||||
if (this.vertex1 == this.vertex2)
|
||||
{
|
||||
return (new CommonEdgeStyle()).sizeOfLoop * 2 * Math.PI;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Point.distance(this.vertex1.position, this.vertex2.position);
|
||||
}
|
||||
}
|
||||
311
script/BaseEdgeDrawer.js
Normal file
311
script/BaseEdgeDrawer.js
Normal file
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* Graph drawer.
|
||||
*/
|
||||
|
||||
|
||||
function CommonEdgeStyle()
|
||||
{
|
||||
this.strokeStyle = '#c7b7c7';
|
||||
this.weightText = '#f0d543';
|
||||
this.fillStyle = '#68aeba';
|
||||
this.textPadding = 4;
|
||||
this.textStrockeWidth = 2;
|
||||
this.sizeOfLoop = 24;
|
||||
this.loopShiftAngel = Math.PI / 6;
|
||||
}
|
||||
|
||||
|
||||
function SelectedEdgeStyle0()
|
||||
{
|
||||
CommonEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#f0d543';
|
||||
this.weightText = '#f0d543';
|
||||
this.fillStyle = '#c7627a';
|
||||
}
|
||||
SelectedEdgeStyle0.prototype = Object.create(CommonEdgeStyle.prototype);
|
||||
|
||||
function ProgressEdgeStyle()
|
||||
{
|
||||
CommonEdgeStyle.apply(this, arguments);
|
||||
|
||||
var selectedStyle = new SelectedEdgeStyle0();
|
||||
this.strokeStyle = selectedStyle.fillStyle;
|
||||
this.weightText = '#000000';
|
||||
this.fillStyle = '#000000';
|
||||
}
|
||||
ProgressEdgeStyle.prototype = Object.create(CommonEdgeStyle.prototype);
|
||||
|
||||
function SelectedEdgeStyle1()
|
||||
{
|
||||
CommonEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#8FBF83';
|
||||
this.weightText = '#8FBF83';
|
||||
this.fillStyle = '#F9F9D5';
|
||||
}
|
||||
SelectedEdgeStyle1.prototype = Object.create(CommonEdgeStyle.prototype);
|
||||
|
||||
|
||||
function SelectedEdgeStyle2()
|
||||
{
|
||||
CommonEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#8C4C86';
|
||||
this.weightText = '#8C4C86';
|
||||
this.fillStyle = '#253267';
|
||||
}
|
||||
SelectedEdgeStyle2.prototype = Object.create(CommonEdgeStyle.prototype);
|
||||
|
||||
|
||||
function SelectedEdgeStyle3()
|
||||
{
|
||||
CommonEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#6188FF';
|
||||
this.weightText = '#6188FF';
|
||||
this.fillStyle = '#E97CF9';
|
||||
}
|
||||
SelectedEdgeStyle3.prototype = Object.create(CommonEdgeStyle.prototype);
|
||||
|
||||
|
||||
function SelectedEdgeStyle4()
|
||||
{
|
||||
CommonEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#C6B484';
|
||||
this.weightText = '#C6B484';
|
||||
this.fillStyle = '#E0DEE1';
|
||||
}
|
||||
SelectedEdgeStyle4.prototype = Object.create(CommonEdgeStyle.prototype);
|
||||
|
||||
var selectedEdgeStyles = [new SelectedEdgeStyle0(), new SelectedEdgeStyle1(),
|
||||
new SelectedEdgeStyle2(), new SelectedEdgeStyle3(), new SelectedEdgeStyle4()];
|
||||
|
||||
|
||||
function BaseEdgeDrawer(context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.Draw = function(baseEdge, arcStyle)
|
||||
{
|
||||
this.SetupStyle(baseEdge, arcStyle);
|
||||
|
||||
var positions = this.GetArcPositions(baseEdge.vertex1.position, baseEdge.vertex2.position, baseEdge.vertex1.model.diameter);
|
||||
|
||||
this.DrawArc (positions[0], positions[1], arcStyle);
|
||||
if (baseEdge.useWeight)
|
||||
{
|
||||
this.DrawWeight(positions[0], positions[1], baseEdge.weight, arcStyle, baseEdge.hasPair);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BaseEdgeDrawer.prototype.SetupStyle = function(baseEdge, arcStyle)
|
||||
{
|
||||
this.context.lineWidth = baseEdge.model.width;
|
||||
this.context.strokeStyle = arcStyle.strokeStyle;
|
||||
this.context.fillStyle = arcStyle.fillStyle;
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.DrawArc = function(position1, position2, arcStyle)
|
||||
{
|
||||
if (position1.equals(position2))
|
||||
{
|
||||
this.context.beginPath();
|
||||
this.context.arc(position1.x - Math.cos(arcStyle.loopShiftAngel) * arcStyle.sizeOfLoop,
|
||||
position1.y - Math.sin(arcStyle.loopShiftAngel) * arcStyle.sizeOfLoop, arcStyle.sizeOfLoop, 0, 2 * Math.PI);
|
||||
this.context.closePath();
|
||||
this.context.stroke();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(position1.x, position1.y);
|
||||
this.context.lineTo(position2.x, position2.y);
|
||||
this.context.closePath();
|
||||
this.context.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.DrawWeight = function(position1, position2, text, arcStyle, hasPair)
|
||||
{
|
||||
var textShift = Math.min(12 / position1.subtract(position2).length(), 0.4);
|
||||
var centerPoint = Point.interpolate(position1, position2, 0.5 + (hasPair ? textShift : 0));
|
||||
if (position1.equals(position2))
|
||||
{
|
||||
centerPoint.y = centerPoint.y - Math.cos(arcStyle.loopShiftAngel) * arcStyle.sizeOfLoop * 2;
|
||||
centerPoint.x = centerPoint.x - Math.sin(arcStyle.loopShiftAngel) * arcStyle.sizeOfLoop * 2;
|
||||
}
|
||||
this.context.font = "bold 16px sans-serif";
|
||||
this.context.textBaseline = "middle";
|
||||
this.context.lineWidth = arcStyle.textStrockeWidth;
|
||||
this.context.fillStyle = arcStyle.fillStyle;
|
||||
|
||||
var widthText = this.context.measureText(text).width;
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.rect(centerPoint.x - widthText / 2 - arcStyle.textPadding / 2,
|
||||
centerPoint.y - 8 - arcStyle.textPadding / 2,
|
||||
widthText + arcStyle.textPadding, 16 + arcStyle.textPadding);
|
||||
this.context.closePath();
|
||||
this.context.fill();
|
||||
this.context.stroke ();
|
||||
|
||||
this.context.fillStyle = arcStyle.weightText;
|
||||
this.context.fillText(text, centerPoint.x - widthText / 2, centerPoint.y);
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.GetArcPositions = function(position1, position2, diameter)
|
||||
{
|
||||
var direction = position1.subtract(position2);
|
||||
direction.normalize(1.0);
|
||||
direction = direction.multiply(0.5);
|
||||
|
||||
var res = [];
|
||||
res.push(position1.subtract(direction.multiply(diameter)));
|
||||
res.push(position2.subtract(direction.multiply(-diameter)));
|
||||
return res;
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.GetArcPositionsShift = function(position1, position2, diameter, shift)
|
||||
{
|
||||
if (shift == 0)
|
||||
{
|
||||
return this.GetArcPositions(position1, position2, diameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
var direction = position1.subtract(position2);
|
||||
direction.normalize(1.0);
|
||||
var normal = direction.normal();
|
||||
direction = direction.multiply(0.5);
|
||||
position1 = position1.subtract(normal.multiply(shift));
|
||||
position2 = position2.subtract(normal.multiply(shift));
|
||||
diameter = Math.sqrt(diameter * diameter - shift * shift);
|
||||
var res = [];
|
||||
res.push(position1.subtract(direction.multiply(diameter)));
|
||||
res.push(position2.subtract(direction.multiply(-diameter)));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Direct Arc drawer.
|
||||
*/
|
||||
function DirectArcDrawer(context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
DirectArcDrawer.prototype = Object.create(BaseEdgeDrawer.prototype);
|
||||
|
||||
DirectArcDrawer.prototype.Draw = function(baseEdge, arcStyle)
|
||||
{
|
||||
baseDrawer = this.CreateBase();
|
||||
baseDrawer.SetupStyle(baseEdge, arcStyle);
|
||||
|
||||
var length = baseEdge.model.width * 4;
|
||||
var width = baseEdge.model.width * 2;
|
||||
var position1 = baseEdge.vertex1.position;
|
||||
var position2 = baseEdge.vertex2.position;
|
||||
var direction = position1.subtract(position2);
|
||||
var pairShift = baseEdge.vertex1.model.diameter * 0.25;
|
||||
var realShift = (baseEdge.hasPair ? pairShift : 0);
|
||||
direction.normalize(1.0);
|
||||
var positions = this.GetArcPositionsShift(baseEdge.vertex1.position,
|
||||
baseEdge.vertex2.position, baseEdge.vertex1.model.diameter, realShift);
|
||||
|
||||
baseDrawer.DrawArc (positions[0], positions[1].subtract(direction.multiply(-length / 2)), arcStyle);
|
||||
|
||||
this.context.fillStyle = this.context.strokeStyle;
|
||||
this.context.lineWidth = 0;
|
||||
this.DrawArrow(positions[0], positions[1], length, width);
|
||||
|
||||
if (baseEdge.useWeight)
|
||||
{
|
||||
baseDrawer.DrawWeight(positions[0], positions[1], baseEdge.weight, arcStyle, baseEdge.hasPair);
|
||||
}
|
||||
}
|
||||
|
||||
DirectArcDrawer.prototype.DrawArrow = function(position1, position2, length, width)
|
||||
{
|
||||
var direction = position2.subtract(position1);
|
||||
direction.normalize(1.0);
|
||||
var normal = direction.normal();
|
||||
|
||||
var pointOnLine = position2.subtract(direction.multiply(length));
|
||||
var point1 = pointOnLine.add(normal.multiply(width));
|
||||
var point2 = pointOnLine.add(normal.multiply(-width));
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(position2.x, position2.y);
|
||||
this.context.lineTo(point1.x, point1.y);
|
||||
this.context.lineTo(point2.x, point2.y);
|
||||
this.context.lineTo(position2.x, position2.y);
|
||||
this.context.closePath();
|
||||
this.context.fill();
|
||||
}
|
||||
|
||||
DirectArcDrawer.prototype.CreateBase = function()
|
||||
{
|
||||
return new BaseEdgeDrawer(this.context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function ProgressArcDrawer(context, baseDrawer, progress)
|
||||
{
|
||||
this.context = context;
|
||||
this.baseDrawer = baseDrawer;
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
ProgressArcDrawer.prototype = Object.create(BaseEdgeDrawer.prototype);
|
||||
|
||||
|
||||
ProgressArcDrawer.prototype.Draw = function(baseEdge, arcStyle)
|
||||
{
|
||||
this.baseDrawer.Draw(baseEdge, arcStyle);
|
||||
|
||||
this.SetupStyle(baseEdge, new ProgressEdgeStyle());
|
||||
|
||||
this.context.lineWidth = 10;
|
||||
|
||||
var pairShift = baseEdge.vertex1.model.diameter * 0.25;
|
||||
var realShift = (baseEdge.hasPair ? pairShift : 0);
|
||||
var positions = this.GetArcPositionsShift(baseEdge.vertex1.position,
|
||||
baseEdge.vertex2.position, baseEdge.vertex1.model.diameter, realShift);
|
||||
var progressSize = 10;
|
||||
|
||||
if (positions[0].equals(positions[1]))
|
||||
{
|
||||
var sizeInRadian = progressSize / (2 * Math.PI * arcStyle.sizeOfLoop) * 6;
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.arc(positions[0].x - Math.cos(arcStyle.loopShiftAngel) * arcStyle.sizeOfLoop,
|
||||
positions[0].y - Math.sin(arcStyle.loopShiftAngel) * arcStyle.sizeOfLoop, arcStyle.sizeOfLoop, this.progress * 2 * Math.PI, this.progress * 2 * Math.PI + sizeInRadian);
|
||||
this.context.closePath();
|
||||
this.context.stroke();
|
||||
}
|
||||
else
|
||||
{
|
||||
var startPosition = Point.interpolate(positions[0], positions[1], this.progress);
|
||||
var vectorOffset = positions[0].subtract(positions[1]).normalizeCopy(progressSize);
|
||||
var finishPosition = startPosition.add(vectorOffset);
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(startPosition.x, startPosition.y);
|
||||
this.context.lineTo(finishPosition.x, finishPosition.y);
|
||||
this.context.closePath();
|
||||
this.context.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
48
script/BaseVertex.js
Normal file
48
script/BaseVertex.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Base node class.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
function BaseVertex(x, y, vertexEnumType)
|
||||
{
|
||||
this.position = new Point(x, y);
|
||||
this.id = 0;
|
||||
this.mainText = "";
|
||||
this.upText = "";
|
||||
this.vertexEnumType = vertexEnumType;
|
||||
};
|
||||
|
||||
BaseVertex.prototype.position = new Point(0, 0);
|
||||
BaseVertex.prototype.model = new VertexModel();
|
||||
|
||||
BaseVertex.prototype.SaveToXML = function ()
|
||||
{
|
||||
return "<node " +
|
||||
"positionX=\"" + this.position.x + "\" " +
|
||||
"positionY=\"" + this.position.y + "\" " +
|
||||
"id=\"" + this.id + "\" " +
|
||||
"mainText=\"" + this.mainText + "\" " +
|
||||
"upText=\"" + this.upText + "\" " +
|
||||
"></node>";
|
||||
|
||||
}
|
||||
|
||||
BaseVertex.prototype.LoadFromXML = function (xml)
|
||||
{
|
||||
this.position = new Point(parseFloat(xml.attr('positionX')), parseFloat(xml.attr('positionY')));
|
||||
this.id = parseInt(xml.attr('id'));
|
||||
this.mainText = xml.attr('mainText');
|
||||
this.upText = xml.attr('upText');
|
||||
}
|
||||
|
||||
BaseVertex.prototype.SetId = function (id)
|
||||
{
|
||||
this.id = id;
|
||||
this.mainText = this.vertexEnumType.GetVertexText(id);
|
||||
}
|
||||
|
||||
BaseVertex.prototype.diameterFactor = function ()
|
||||
{
|
||||
return 1.0 + (this.mainText.length ? this.mainText.length / 8.0 : 0);
|
||||
}
|
||||
137
script/BaseVertexDrawer.js
Normal file
137
script/BaseVertexDrawer.js
Normal file
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* Graph drawer.
|
||||
*/
|
||||
|
||||
// Common style of Graphs.
|
||||
function CommonVertexStyle()
|
||||
{
|
||||
this.lineWidth = 1;
|
||||
this.strokeStyle = '#c7b7c7';
|
||||
this.fillStyle = '#68aeba';
|
||||
this.mainTextColor = '#f0d543';
|
||||
}
|
||||
|
||||
// Selected style of Graphs.
|
||||
function SelectedVertexStyle0()
|
||||
{
|
||||
CommonVertexStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#f0d543';
|
||||
this.mainTextColor = '#f0d543';
|
||||
this.fillStyle = '#c7627a';
|
||||
}
|
||||
|
||||
SelectedVertexStyle0.prototype = Object.create(CommonVertexStyle.prototype);
|
||||
|
||||
function SelectedVertexStyle1()
|
||||
{
|
||||
CommonVertexStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#7a9ba0';
|
||||
this.mainTextColor = '#7a9ba0';
|
||||
this.fillStyle = '#534641';
|
||||
}
|
||||
|
||||
SelectedVertexStyle1.prototype = Object.create(CommonVertexStyle.prototype);
|
||||
|
||||
function SelectedVertexStyle2()
|
||||
{
|
||||
CommonVertexStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#8C4C86';
|
||||
this.mainTextColor = '#8C4C86';
|
||||
this.fillStyle = '#253267';
|
||||
}
|
||||
|
||||
SelectedVertexStyle2.prototype = Object.create(CommonVertexStyle.prototype);
|
||||
|
||||
function SelectedVertexStyle3()
|
||||
{
|
||||
CommonVertexStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#6188FF';
|
||||
this.mainTextColor = '#6188FF';
|
||||
this.fillStyle = '#E97CF9';
|
||||
}
|
||||
|
||||
SelectedVertexStyle3.prototype = Object.create(CommonVertexStyle.prototype);
|
||||
|
||||
function SelectedVertexStyle4()
|
||||
{
|
||||
CommonVertexStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#C6B484';
|
||||
this.mainTextColor = '#C6B484';
|
||||
this.fillStyle = '#E0DEE1';
|
||||
}
|
||||
|
||||
SelectedVertexStyle4.prototype = Object.create(CommonVertexStyle.prototype);
|
||||
|
||||
var selectedGraphStyles = [new SelectedVertexStyle0(), new SelectedVertexStyle1(),
|
||||
new SelectedVertexStyle2(), new SelectedVertexStyle3(), new SelectedVertexStyle4()];
|
||||
|
||||
function BaseVertexDrawer(context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
BaseVertexDrawer.prototype.Draw = function(baseGraph, graphStyle)
|
||||
{
|
||||
this.SetupStyle(graphStyle);
|
||||
this.DrawShape(baseGraph);
|
||||
this.context.stroke();
|
||||
this.context.fill();
|
||||
|
||||
this.DrawCenterText(baseGraph.position, baseGraph.mainText, graphStyle.mainTextColor, graphStyle.fillStyle, true, true, 16);
|
||||
|
||||
// Top text
|
||||
this.DrawCenterText(baseGraph.position.add(new Point(0, - baseGraph.model.diameter / 2.0 - 9.0)),
|
||||
baseGraph.upText, graphStyle.fillStyle, graphStyle.strokeStyle, false, false, 12.0);
|
||||
/*
|
||||
// Bottom text
|
||||
this.DrawCenterText(baseGraph.position.add(new Point(0, + baseGraph.model.diameter / 2.0 + 7.0)),
|
||||
"Text 2", graphStyle.fillStyle, false, 12.0);
|
||||
*/
|
||||
}
|
||||
|
||||
BaseVertexDrawer.prototype.SetupStyle = function(style)
|
||||
{
|
||||
this.context.lineWidth = style.lineWidth;
|
||||
this.context.strokeStyle = style.strokeStyle;
|
||||
this.context.fillStyle = style.fillStyle;
|
||||
}
|
||||
|
||||
BaseVertexDrawer.prototype.DrawShape = function(baseGraph)
|
||||
{
|
||||
this.context.lineWidth = 2;
|
||||
this.context.beginPath();
|
||||
this.context.arc(baseGraph.position.x, baseGraph.position.y, baseGraph.model.diameter / 2.0, 0, 2 * Math.PI);
|
||||
this.context.closePath();
|
||||
}
|
||||
|
||||
BaseVertexDrawer.prototype.DrawText = function(position, text, color, outlineColor, outline, font)
|
||||
{
|
||||
this.context.fillStyle = color;
|
||||
this.context.font = font;
|
||||
this.context.lineWidth = 4;
|
||||
this.context.strokeStyle = outlineColor;
|
||||
|
||||
if (outline)
|
||||
{
|
||||
this.context.save();
|
||||
this.context.lineJoin = 'round';
|
||||
this.context.strokeText(text, position.x, position.y);
|
||||
this.context.restore();
|
||||
}
|
||||
|
||||
this.context.fillText(text, position.x, position.y);
|
||||
}
|
||||
|
||||
BaseVertexDrawer.prototype.DrawCenterText = function(position, text, color, outlineColor, bold, outline, size)
|
||||
{
|
||||
this.context.textBaseline="middle";
|
||||
this.context.font = (bold ? "bold " : "") + size + "px sans-serif";
|
||||
var textWidth = this.context.measureText(text).width;
|
||||
this.DrawText(new Point(position.x - textWidth / 2, position.y), text, color, outlineColor, outline, this.context.font);
|
||||
}
|
||||
|
||||
9
script/EdgeModel.js
Normal file
9
script/EdgeModel.js
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* This is edge model
|
||||
*
|
||||
*/
|
||||
|
||||
function EdgeModel()
|
||||
{
|
||||
this.width = 4;
|
||||
}
|
||||
198
script/EnumVertices.js
Normal file
198
script/EnumVertices.js
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
Classes for create text for vertexs.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Base Enum Vertexs.
|
||||
*
|
||||
*/
|
||||
function BaseEnumVertices(app)
|
||||
{
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
BaseEnumVertices.prototype.GetVertexText = function(id)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
BaseEnumVertices.prototype.GetVertexTextAsync = function(callback)
|
||||
{
|
||||
callback (this);
|
||||
}
|
||||
|
||||
BaseEnumVertices.prototype.GetText = function()
|
||||
{
|
||||
return "1, 2, 3...";
|
||||
}
|
||||
|
||||
BaseEnumVertices.prototype.GetValue = function()
|
||||
{
|
||||
return "Numbers";
|
||||
}
|
||||
|
||||
function TextEnumTitle(app, title)
|
||||
{
|
||||
BaseEnumVertices.apply(this, arguments);
|
||||
this.pattern = "";
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
TextEnumTitle.prototype = Object.create(BaseEnumVertices.prototype);
|
||||
|
||||
TextEnumTitle.prototype.GetVertexText = function(id)
|
||||
{
|
||||
return this.title;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Text Enum
|
||||
*
|
||||
*/
|
||||
function TextEnumVertexs(app)
|
||||
{
|
||||
BaseEnumVertices.apply(this, arguments);
|
||||
this.pattern = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
TextEnumVertexs.prototype = Object.create(BaseEnumVertices.prototype);
|
||||
|
||||
TextEnumVertexs.prototype.GetVertexText = function(id)
|
||||
{
|
||||
var res = "";
|
||||
|
||||
res = this.pattern[id % this.pattern.length] + res;
|
||||
|
||||
while (id >= this.pattern.length)
|
||||
{
|
||||
id = Math.floor(id / this.pattern.length) - 1;
|
||||
res = this.pattern[id % this.pattern.length] + res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
TextEnumVertexs.prototype.GetText = function()
|
||||
{
|
||||
return "A, B, ... Z";
|
||||
}
|
||||
|
||||
TextEnumVertexs.prototype.GetValue = function()
|
||||
{
|
||||
return "Latin";
|
||||
}
|
||||
|
||||
/**
|
||||
* Text Enum
|
||||
*
|
||||
*/
|
||||
function TextEnumVertexsCyr(app)
|
||||
{
|
||||
TextEnumVertexs.apply(this, arguments);
|
||||
this.pattern = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
TextEnumVertexsCyr.prototype = Object.create(TextEnumVertexs.prototype);
|
||||
|
||||
TextEnumVertexsCyr.prototype.GetText = function()
|
||||
{
|
||||
return "А, Б, ... Я";
|
||||
}
|
||||
|
||||
TextEnumVertexsCyr.prototype.GetValue = function()
|
||||
{
|
||||
return "Cyrillic";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Text Enum
|
||||
*
|
||||
*/
|
||||
function TextEnumVertexsGreek(app)
|
||||
{
|
||||
TextEnumVertexs.apply(this, arguments);
|
||||
this.pattern = "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ";
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
TextEnumVertexsGreek.prototype = Object.create(TextEnumVertexs.prototype);
|
||||
|
||||
TextEnumVertexsGreek.prototype.GetText = function()
|
||||
{
|
||||
return "Α, Β, ... Ω";
|
||||
}
|
||||
|
||||
TextEnumVertexsGreek.prototype.GetValue = function()
|
||||
{
|
||||
return "Greek";
|
||||
}
|
||||
|
||||
/**
|
||||
* Text Enum
|
||||
*
|
||||
*/
|
||||
function TextEnumVertexsCustom(app)
|
||||
{
|
||||
BaseEnumVertices.apply(this, arguments);
|
||||
this.pattern = "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
// inheritance.
|
||||
TextEnumVertexsCustom.prototype = Object.create(BaseEnumVertices.prototype);
|
||||
|
||||
TextEnumVertexsCustom.prototype.GetText = function()
|
||||
{
|
||||
return g_customEnumVertex;
|
||||
}
|
||||
|
||||
TextEnumVertexsCustom.prototype.GetValue = function()
|
||||
{
|
||||
return "Custom";
|
||||
}
|
||||
|
||||
TextEnumVertexsCustom.prototype.GetVertexTextAsync = function(callback)
|
||||
{
|
||||
this.ShowDialog(callback, g_addVertex, g_addVertex, "A");
|
||||
}
|
||||
|
||||
|
||||
TextEnumVertexsCustom.prototype.ShowDialog = function(callback, buttonText, titleTitle, title)
|
||||
{
|
||||
var dialogButtons = {};
|
||||
app = this.app;
|
||||
dialogButtons[buttonText] = function() {
|
||||
callback(new TextEnumTitle(app, $("#VertexTitle").val()));
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
|
||||
$( "#addVertex" ).dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: "auto",
|
||||
modal: true,
|
||||
title: titleTitle,
|
||||
buttons: dialogButtons,
|
||||
dialogClass: 'EdgeDialog',
|
||||
open: function () {
|
||||
$(this).off('submit').on('submit', function () {
|
||||
return false;
|
||||
});
|
||||
$("#VertexTitle").val(title);
|
||||
$("#VertexTitle").focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
848
script/EventHandlers.js
Normal file
848
script/EventHandlers.js
Normal file
@@ -0,0 +1,848 @@
|
||||
/**
|
||||
*
|
||||
* This event handlers.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base Handler.
|
||||
*
|
||||
*/
|
||||
|
||||
function BaseHandler(app)
|
||||
{
|
||||
this.app = app;
|
||||
this.app.setRenderPath([]);
|
||||
}
|
||||
|
||||
// Need redraw or nor.
|
||||
BaseHandler.prototype.needRedraw = false;
|
||||
BaseHandler.prototype.objects = [];
|
||||
BaseHandler.prototype.message = "";
|
||||
|
||||
|
||||
BaseHandler.prototype.IsNeedRedraw = function(object)
|
||||
{
|
||||
return this.needRedraw;
|
||||
}
|
||||
|
||||
BaseHandler.prototype.RestRedraw = function(object)
|
||||
{
|
||||
this.needRedraw = false;
|
||||
}
|
||||
|
||||
BaseHandler.prototype.SetObjects = function(objects)
|
||||
{
|
||||
this.objects = objects;
|
||||
}
|
||||
|
||||
BaseHandler.prototype.GetSelectedGraph = function(pos)
|
||||
{
|
||||
// Selected Graph.
|
||||
for (var i = 0; i < this.app.graph.vertices.length; i ++)
|
||||
{
|
||||
if (this.app.graph.vertices[i].position.distance(pos) < this.app.graph.vertices[i].model.diameter / 2.0)
|
||||
{
|
||||
return this.app.graph.vertices[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
BaseHandler.prototype.GetSelectedArc = function(pos)
|
||||
{
|
||||
// Selected Arc.
|
||||
for (var i = 0; i < this.app.graph.edges.length; i ++)
|
||||
{
|
||||
var pos1 = this.app.graph.edges[i].vertex1.position;
|
||||
var pos2 = this.app.graph.edges[i].vertex2.position;
|
||||
var pos0 = new Point(pos.x, pos.y);
|
||||
|
||||
var r1 = pos0.distance(pos1);
|
||||
var r2 = pos0.distance(pos2);
|
||||
var r12 = pos1.distance(pos2);
|
||||
|
||||
if (r1 >= (new Point(r2, r12)).length() || r2 >= (new Point(r1,r12)).length())
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
var distance = ((pos1.y - pos2.y) * pos0.x + (pos2.x - pos1.x) * pos0.y + (pos1.x * pos2.y - pos2.x * pos1.y)) / r12;
|
||||
|
||||
if (Math.abs(distance) <= this.app.graph.edges[i].model.width * 1.5)
|
||||
{
|
||||
return this.app.graph.edges[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
BaseHandler.prototype.GetSelectedObject = function(pos)
|
||||
{
|
||||
var graphObject = this.GetSelectedGraph(pos);
|
||||
if (graphObject)
|
||||
{
|
||||
return graphObject;
|
||||
}
|
||||
|
||||
var arcObject = this.GetSelectedArc(pos);
|
||||
if (arcObject)
|
||||
{
|
||||
return arcObject;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
BaseHandler.prototype.GetUpText = function(object)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
BaseHandler.prototype.GetMessage = function()
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
|
||||
BaseHandler.prototype.MouseMove = function(pos) {;}
|
||||
|
||||
BaseHandler.prototype.MouseDown = function(pos) {;}
|
||||
|
||||
BaseHandler.prototype.MouseUp = function(pos) {;}
|
||||
|
||||
BaseHandler.prototype.GetSelectedGroup = function(object)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
BaseHandler.prototype.InitControls = function()
|
||||
{
|
||||
}
|
||||
|
||||
BaseHandler.prototype.GetNodesPath = function(array, start, count)
|
||||
{
|
||||
var res = [];
|
||||
for (var index = start; index < start + count; index++)
|
||||
{
|
||||
res.push(this.app.graph.FindVertex(array[index].value));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
BaseHandler.prototype.RestoreAll = function()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Default handler.
|
||||
* Select using mouse, drag.
|
||||
*
|
||||
*/
|
||||
function DefaultHandler(app)
|
||||
{
|
||||
BaseHandler.apply(this, arguments);
|
||||
this.message = g_textsSelectAndMove;
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
DefaultHandler.prototype = Object.create(BaseHandler.prototype);
|
||||
// Current drag object.
|
||||
DefaultHandler.prototype.dragObject = null;
|
||||
// Selected object.
|
||||
DefaultHandler.prototype.selectedObject = null;
|
||||
// Is pressed
|
||||
DefaultHandler.prototype.pressed = false;
|
||||
// Prev position.
|
||||
DefaultHandler.prototype.prevPosition = false;
|
||||
// Is binded event for rename
|
||||
DefaultHandler.prototype.bindedRename = false;
|
||||
// Is binded event for edit edge
|
||||
DefaultHandler.prototype.editEdgeRename = false;
|
||||
|
||||
DefaultHandler.prototype.MouseMove = function(pos)
|
||||
{
|
||||
if (this.dragObject)
|
||||
{
|
||||
this.dragObject.position.x = pos.x;
|
||||
this.dragObject.position.y = pos.y;
|
||||
this.needRedraw = true;
|
||||
}
|
||||
else if (this.pressed)
|
||||
{
|
||||
this.app.onCanvasMove((new Point(pos.x, pos.y)).subtract(this.prevPosition).multiply(this.app.canvasScale));
|
||||
this.needRedraw = true;
|
||||
//this.prevPosition = pos;
|
||||
}
|
||||
}
|
||||
|
||||
DefaultHandler.prototype.MouseDown = function(pos)
|
||||
{
|
||||
this.selectedObject = null;
|
||||
this.dragObject = null;
|
||||
var selectedObject = this.GetSelectedObject(pos);
|
||||
if (selectedObject != null)
|
||||
{
|
||||
this.selectedObject = selectedObject;
|
||||
}
|
||||
if ((selectedObject instanceof BaseVertex) && selectedObject != null)
|
||||
{
|
||||
this.dragObject = selectedObject;
|
||||
this.message = g_moveCursorForMoving;
|
||||
}
|
||||
this.needRedraw = true;
|
||||
this.pressed = true;
|
||||
this.prevPosition = pos;
|
||||
this.app.canvas.style.cursor = "move";
|
||||
}
|
||||
|
||||
DefaultHandler.prototype.RenameVertex = function(text)
|
||||
{
|
||||
if (this.selectedObject != null && (this.selectedObject instanceof BaseVertex))
|
||||
{
|
||||
this.selectedObject.mainText = text;
|
||||
this.app.redrawGraph();
|
||||
}
|
||||
}
|
||||
|
||||
DefaultHandler.prototype.MouseUp = function(pos)
|
||||
{
|
||||
this.message = g_textsSelectAndMove;
|
||||
this.dragObject = null;
|
||||
this.pressed = false;
|
||||
this.app.canvas.style.cursor = "auto";
|
||||
if (this.selectedObject != null && (this.selectedObject instanceof BaseVertex))
|
||||
{
|
||||
this.message = g_textsSelectAndMove + " <button type=\"button\" id=\"renameButton\" class=\"btn btn-default btn-xs\" style=\"float:right;z-index:1;position: relative;\">" + g_renameVertex + "</button>";
|
||||
|
||||
var handler = this;
|
||||
if (!this.bindedRename)
|
||||
{
|
||||
var callback = function (enumType) {
|
||||
handler.RenameVertex(enumType.GetVertexText(0));
|
||||
userAction("RenameVertex");
|
||||
};
|
||||
$('#message').on('click', '#renameButton', function(){
|
||||
var customEnum = new TextEnumVertexsCustom();
|
||||
customEnum.ShowDialog(callback, g_rename, g_renameVertex, handler.selectedObject.mainText);
|
||||
});
|
||||
this.bindedRename = true;
|
||||
}
|
||||
}
|
||||
else if (this.selectedObject != null && (this.selectedObject instanceof BaseEdge))
|
||||
{
|
||||
this.message = g_textsSelectAndMove + " <button type=\"button\" id=\"editEdge\" class=\"btn btn-default btn-xs\" style=\"float:right;z-index:1;position: relative;\">" + g_editWeight + "</button>";
|
||||
var handler = this;
|
||||
if (!this.editEdgeRename)
|
||||
{
|
||||
$('#message').on('click', '#editEdge', function(){
|
||||
var direct = false;
|
||||
var dialogButtons = {};
|
||||
|
||||
dialogButtons[g_save] = function() {
|
||||
|
||||
handler.app.DeleteObject(handler.selectedObject);
|
||||
handler.selectedObject = handler.app.graph.edges[handler.app.CreateNewArc(handler.selectedObject.vertex1, handler.selectedObject.vertex2, handler.selectedObject.isDirect, document.getElementById('EdgeWeight').value)];
|
||||
|
||||
handler.needRedraw = true;
|
||||
handler.app.redrawGraph();
|
||||
|
||||
userAction("ChangeWeight");
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
|
||||
document.getElementById('EdgeWeight').value = handler.selectedObject.useWeight ? handler.selectedObject.weight : g_noWeight;
|
||||
document.getElementById('EdgeWeightSlider').value = handler.selectedObject.useWeight ? handler.selectedObject.weight : 0;
|
||||
|
||||
$( "#addEdge" ).dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: "auto",
|
||||
modal: true,
|
||||
title: g_editWeight,
|
||||
buttons: dialogButtons,
|
||||
dialogClass: 'EdgeDialog',
|
||||
open: function () {
|
||||
$(handler).off('submit').on('submit', function () {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.editEdgeRename = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DefaultHandler.prototype.GetSelectedGroup = function(object)
|
||||
{
|
||||
return (object == this.dragObject) || (object == this.selectedObject) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add Graph handler.
|
||||
*
|
||||
*/
|
||||
function AddGraphHandler(app)
|
||||
{
|
||||
BaseHandler.apply(this, arguments);
|
||||
this.message = g_clickToAddVertex;
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
AddGraphHandler.prototype = Object.create(BaseHandler.prototype);
|
||||
|
||||
AddGraphHandler.prototype.MouseDown = function(pos)
|
||||
{
|
||||
this.app.CreateNewGraph(pos.x, pos.y);
|
||||
this.needRedraw = true;
|
||||
this.inited = false;
|
||||
}
|
||||
|
||||
AddGraphHandler.prototype.InitControls = function()
|
||||
{
|
||||
var enumVertexsText = document.getElementById("enumVertexsText");
|
||||
if (enumVertexsText)
|
||||
{
|
||||
var enumsList = this.app.GetEnumVertexsList();
|
||||
for (var i = 0; i < enumsList.length; i ++)
|
||||
{
|
||||
var option = document.createElement('option');
|
||||
option.text = enumsList[i]["text"];
|
||||
option.value = enumsList[i]["value"];
|
||||
enumVertexsText.add(option, i);
|
||||
if (enumsList[i]["select"])
|
||||
{
|
||||
enumVertexsText.selectedIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
var addGraphHandler = this;
|
||||
enumVertexsText.onchange = function () {
|
||||
addGraphHandler.ChangedType();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
AddGraphHandler.prototype.ChangedType = function()
|
||||
{
|
||||
var enumVertexsText = document.getElementById("enumVertexsText");
|
||||
|
||||
this.app.SetEnumVertexsType(enumVertexsText.options[enumVertexsText.selectedIndex].value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Connection Graph handler.
|
||||
*
|
||||
*/
|
||||
function ConnectionGraphHandler(app)
|
||||
{
|
||||
BaseHandler.apply(this, arguments);
|
||||
this.message = g_selectFisrtVertexToConnect;
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
ConnectionGraphHandler.prototype = Object.create(BaseHandler.prototype);
|
||||
// First selected.
|
||||
ConnectionGraphHandler.prototype.firstObject = null;
|
||||
|
||||
ConnectionGraphHandler.prototype.AddNewEdge = function(selectedObject, isDirect)
|
||||
{
|
||||
this.app.CreateNewArc(this.firstObject, selectedObject, isDirect, document.getElementById('EdgeWeight').value);
|
||||
this.firstObject = null;
|
||||
this.message = g_selectFisrtVertexToConnect;
|
||||
this.app.NeedRedraw();
|
||||
}
|
||||
|
||||
ConnectionGraphHandler.prototype.MouseDown = function(pos)
|
||||
{
|
||||
var selectedObject = this.GetSelectedGraph(pos);
|
||||
if (selectedObject && (selectedObject instanceof BaseVertex))
|
||||
{
|
||||
if (this.firstObject)
|
||||
{
|
||||
var direct = false;
|
||||
var handler = this;
|
||||
var dialogButtons = {};
|
||||
dialogButtons[g_orintEdge] = function() {
|
||||
handler.AddNewEdge(selectedObject, true);
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
dialogButtons[g_notOrintEdge] = function() {
|
||||
handler.AddNewEdge(selectedObject, false);
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
$( "#addEdge" ).dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: "auto",
|
||||
modal: true,
|
||||
title: g_addEdge,
|
||||
buttons: dialogButtons,
|
||||
dialogClass: 'EdgeDialog',
|
||||
open: function () {
|
||||
$(this).off('submit').on('submit', function () {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.firstObject = selectedObject;
|
||||
this.message = g_selectSecondVertexToConnect;
|
||||
}
|
||||
this.needRedraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
ConnectionGraphHandler.prototype.GetSelectedGroup = function(object)
|
||||
{
|
||||
return (object == this.firstObject) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete Graph handler.
|
||||
*
|
||||
*/
|
||||
function DeleteGraphHandler(app)
|
||||
{
|
||||
BaseHandler.apply(this, arguments);
|
||||
this.message = g_selectObjectToDelete;
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
DeleteGraphHandler.prototype = Object.create(BaseHandler.prototype);
|
||||
|
||||
DeleteGraphHandler.prototype.MouseDown = function(pos)
|
||||
{
|
||||
var selectedObject = this.GetSelectedObject(pos);
|
||||
|
||||
this.app.DeleteObject(selectedObject);
|
||||
|
||||
this.needRedraw = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Graph handler.
|
||||
*
|
||||
*/
|
||||
function DeleteAllHandler(app)
|
||||
{
|
||||
BaseHandler.apply(this, arguments);
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
DeleteAllHandler.prototype = Object.create(BaseHandler.prototype);
|
||||
|
||||
DeleteAllHandler.prototype.clear = function()
|
||||
{
|
||||
// Selected Graph.
|
||||
this.app.graph = new Graph();
|
||||
this.app.savedGraphName = "";
|
||||
this.needRedraw = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save/Load graph from matrix.
|
||||
*
|
||||
*/
|
||||
function ShowAdjacencyMatrix(app)
|
||||
{
|
||||
BaseHandler.apply(this, arguments);
|
||||
this.message = "";
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
ShowAdjacencyMatrix.prototype = Object.create(BaseHandler.prototype);
|
||||
// First selected.
|
||||
ShowAdjacencyMatrix.prototype.firstObject = null;
|
||||
// Path
|
||||
ShowAdjacencyMatrix.prototype.pathObjects = null;
|
||||
|
||||
ShowAdjacencyMatrix.prototype.show = function()
|
||||
{
|
||||
var handler = this;
|
||||
var dialogButtons = {};
|
||||
|
||||
$( "#AdjacencyMatrixField" ).on('keyup change', function (eventObject)
|
||||
{
|
||||
if (!handler.app.TestAdjacencyMatrix($( "#AdjacencyMatrixField" ).val(), [], []))
|
||||
{
|
||||
$( "#BadMatrixFormatMessage" ).show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$( "#BadMatrixFormatMessage" ).hide();
|
||||
}
|
||||
});
|
||||
|
||||
dialogButtons[g_save] = function() {
|
||||
handler.app.SetAdjacencyMatrixSmart($( "#AdjacencyMatrixField" ).val());
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
dialogButtons[g_cancel] = function() {
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
|
||||
$( "#AdjacencyMatrixField" ).val(this.app.GetAdjacencyMatrix());
|
||||
$( "#BadMatrixFormatMessage" ).hide();
|
||||
|
||||
$( "#adjacencyMatrix" ).dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: "auto",
|
||||
modal: true,
|
||||
title: g_adjacencyMatrixText,
|
||||
buttons: dialogButtons,
|
||||
dialogClass: 'EdgeDialog'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save/Load graph from Incidence matrix.
|
||||
*
|
||||
*/
|
||||
function ShowIncidenceMatrix(app)
|
||||
{
|
||||
BaseHandler.apply(this, arguments);
|
||||
this.message = "";
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
ShowIncidenceMatrix.prototype = Object.create(BaseHandler.prototype);
|
||||
// First selected.
|
||||
ShowIncidenceMatrix.prototype.firstObject = null;
|
||||
// Path
|
||||
ShowIncidenceMatrix.prototype.pathObjects = null;
|
||||
|
||||
ShowIncidenceMatrix.prototype.show = function()
|
||||
{
|
||||
var handler = this;
|
||||
var dialogButtons = {};
|
||||
|
||||
$( "#IncidenceMatrixField" ).on('keyup change', function (eventObject)
|
||||
{
|
||||
if (!handler.app.TestIncidenceMatrix($( "#IncidenceMatrixField" ).val(), [], []))
|
||||
{
|
||||
$( "#BadIncidenceMatrixFormatMessage" ).show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$( "#BadIncidenceMatrixFormatMessage" ).hide();
|
||||
}
|
||||
});
|
||||
|
||||
dialogButtons[g_save] = function() {
|
||||
handler.app.SetIncidenceMatrixSmart($( "#IncidenceMatrixField" ).val());
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
dialogButtons[g_cancel] = function() {
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
|
||||
$( "#IncidenceMatrixField" ).val(this.app.GetIncidenceMatrix());
|
||||
$( "#BadIncidenceMatrixFormatMessage" ).hide();
|
||||
|
||||
$( "#incidenceMatrix" ).dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: "auto",
|
||||
modal: true,
|
||||
title: g_incidenceMatrixText,
|
||||
buttons: dialogButtons,
|
||||
dialogClass: 'EdgeDialog'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save dialog Graph handler.
|
||||
*
|
||||
*/
|
||||
function SavedDialogGraphHandler(app)
|
||||
{
|
||||
BaseHandler.apply(this, arguments);
|
||||
this.message = "";
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
SavedDialogGraphHandler.prototype = Object.create(BaseHandler.prototype);
|
||||
// First selected.
|
||||
SavedDialogGraphHandler.prototype.firstObject = null;
|
||||
// Path
|
||||
SavedDialogGraphHandler.prototype.pathObjects = null;
|
||||
// Objects.
|
||||
SavedDialogGraphHandler.prototype.objects = null;
|
||||
|
||||
SavedDialogGraphHandler.prototype.show = function(object)
|
||||
{
|
||||
this.app.SaveGraphOnDisk();
|
||||
|
||||
var dialogButtons = {};
|
||||
|
||||
dialogButtons[g_close] = function() {
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
|
||||
document.getElementById('GraphName').value = "http://" + window.location.host + window.location.pathname +
|
||||
"?graph=" + this.app.GetGraphName();
|
||||
|
||||
document.getElementById('GraphName').select();
|
||||
|
||||
document.getElementById("ShareSavedGraph").innerHTML =
|
||||
document.getElementById("ShareSavedGraph").innerHTML.replace(/graph=([A-Za-z]*)/g, "graph=" + this.app.GetGraphName());
|
||||
|
||||
$( "#saveDialog" ).dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: "auto",
|
||||
modal: true,
|
||||
title: g_save_dialog,
|
||||
buttons: dialogButtons,
|
||||
dialogClass: 'EdgeDialog'
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Save dialog Graph handler.
|
||||
*
|
||||
*/
|
||||
function SavedDialogGraphImageHandler(app)
|
||||
{
|
||||
BaseHandler.apply(this, arguments);
|
||||
this.message = "";
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
SavedDialogGraphImageHandler.prototype = Object.create(BaseHandler.prototype);
|
||||
// First selected.
|
||||
SavedDialogGraphImageHandler.prototype.firstObject = null;
|
||||
// Path
|
||||
SavedDialogGraphImageHandler.prototype.pathObjects = null;
|
||||
// Objects.
|
||||
SavedDialogGraphImageHandler.prototype.objects = null;
|
||||
|
||||
SavedDialogGraphImageHandler.prototype.show = function(object)
|
||||
{
|
||||
var imageName = this.app.SaveGraphImageOnDisk();
|
||||
|
||||
var dialogButtons = {};
|
||||
|
||||
dialogButtons[g_close] = function() {
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
|
||||
var fileLocation = "tmp/saved/" + imageName.substr(0, 2) + "/"+ imageName + ".png"
|
||||
|
||||
|
||||
document.getElementById("ShareSavedImageGraph").innerHTML =
|
||||
document.getElementById("ShareSavedImageGraph").innerHTML.replace(/tmp\/saved\/([A-Za-z]*)\/([A-Za-z]*).png/g, fileLocation);
|
||||
|
||||
document.getElementById("SaveImageLinks").innerHTML =
|
||||
document.getElementById("SaveImageLinks").innerHTML.replace(/tmp\/saved\/([A-Za-z]*)\/([A-Za-z]*).png/g, fileLocation);
|
||||
|
||||
$( "#saveImageDialog" ).dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: "auto",
|
||||
modal: true,
|
||||
title: g_save_image_dialog,
|
||||
buttons: dialogButtons,
|
||||
dialogClass: 'EdgeDialog'
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Algorithm Graph handler.
|
||||
*
|
||||
*/
|
||||
function AlgorithmGraphHandler(app, algorithm)
|
||||
{
|
||||
BaseHandler.apply(this, arguments);
|
||||
this.algorithm = algorithm;
|
||||
this.SaveUpText();
|
||||
|
||||
this.UpdateResultAndMesasge();
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
AlgorithmGraphHandler.prototype = Object.create(BaseHandler.prototype);
|
||||
|
||||
// Rest this handler.
|
||||
AlgorithmGraphHandler.prototype.MouseMove = function(pos) {}
|
||||
|
||||
AlgorithmGraphHandler.prototype.MouseDown = function(pos)
|
||||
{
|
||||
this.app.setRenderPath([]);
|
||||
|
||||
if (this.algorithm.instance())
|
||||
{
|
||||
this.app.SetDefaultHandler();
|
||||
}
|
||||
else
|
||||
{
|
||||
var selectedObject = this.GetSelectedGraph(pos);
|
||||
if (selectedObject && (selectedObject instanceof BaseVertex))
|
||||
{
|
||||
if (this.algorithm.selectVertex(selectedObject))
|
||||
{
|
||||
this.needRedraw = true;
|
||||
}
|
||||
|
||||
this.UpdateResultAndMesasge();
|
||||
}
|
||||
else if (selectedObject && (selectedObject instanceof BaseEdge))
|
||||
{
|
||||
if (this.algorithm.selectEdge(selectedObject))
|
||||
{
|
||||
this.needRedraw = true;
|
||||
}
|
||||
|
||||
this.UpdateResultAndMesasge();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.algorithm.deselectAll())
|
||||
{
|
||||
this.needRedraw = true;
|
||||
this.UpdateResultAndMesasge();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AlgorithmGraphHandler.prototype.MouseUp = function(pos) {}
|
||||
|
||||
AlgorithmGraphHandler.prototype.GetSelectedGroup = function(object)
|
||||
{
|
||||
return this.algorithm.getObjectSelectedGroup(object);
|
||||
}
|
||||
|
||||
AlgorithmGraphHandler.prototype.RestoreAll = function()
|
||||
{
|
||||
this.app.setRenderPath([]);
|
||||
|
||||
if (this.algorithm.needRestoreUpText())
|
||||
{
|
||||
this.RestoreUpText();
|
||||
}
|
||||
}
|
||||
|
||||
AlgorithmGraphHandler.prototype.SaveUpText = function()
|
||||
{
|
||||
this.vertexUpText = {};
|
||||
var graph = this.app.graph;
|
||||
for (i = 0; i < graph.vertices.length; i ++)
|
||||
{
|
||||
this.vertexUpText[graph.vertices[i].id] = graph.vertices[i].upText;
|
||||
}
|
||||
}
|
||||
|
||||
AlgorithmGraphHandler.prototype.RestoreUpText = function()
|
||||
{
|
||||
var graph = this.app.graph;
|
||||
|
||||
for (i = 0; i < graph.vertices.length; i ++)
|
||||
{
|
||||
if (graph.vertices[i].id in this.vertexUpText)
|
||||
{
|
||||
graph.vertices[i].upText = this.vertexUpText[graph.vertices[i].id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AlgorithmGraphHandler.prototype.UpdateResultAndMesasge = function()
|
||||
{
|
||||
var self = this;
|
||||
result = this.algorithm.result(function (result)
|
||||
{
|
||||
self.message = self.algorithm.getMessage(g_language);
|
||||
self.app.resultCallback(result);
|
||||
});
|
||||
|
||||
this.app.resultCallback(result);
|
||||
|
||||
this.message = this.algorithm.getMessage(g_language);
|
||||
}
|
||||
|
||||
AlgorithmGraphHandler.prototype.InitControls = function()
|
||||
{
|
||||
this.algorithm.messageWasChanged();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Groupe rename vertices.
|
||||
*
|
||||
*/
|
||||
function GroupRenameVertices(app)
|
||||
{
|
||||
BaseHandler.apply(this, arguments);
|
||||
this.message = "";
|
||||
}
|
||||
|
||||
// inheritance.
|
||||
GroupRenameVertices.prototype = Object.create(BaseHandler.prototype);
|
||||
// First selected.
|
||||
GroupRenameVertices.prototype.firstObject = null;
|
||||
// Path
|
||||
GroupRenameVertices.prototype.pathObjects = null;
|
||||
|
||||
GroupRenameVertices.prototype.show = function()
|
||||
{
|
||||
var handler = this;
|
||||
var dialogButtons = {};
|
||||
var graph = this.app.graph;
|
||||
var app = this.app;
|
||||
|
||||
dialogButtons[g_save] = function() {
|
||||
var titlesList = $( "#VertextTitleList" ).val().split('\n');
|
||||
for (i = 0; i < Math.min(graph.vertices.length, titlesList.length); i ++)
|
||||
{
|
||||
graph.vertices[i].mainText = titlesList[i];
|
||||
}
|
||||
app.redrawGraph();
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
dialogButtons[g_cancel] = function() {
|
||||
$( this ).dialog( "close" );
|
||||
};
|
||||
|
||||
var titleList = "";
|
||||
for (i = 0; i < graph.vertices.length; i ++)
|
||||
{
|
||||
titleList = titleList + graph.vertices[i].mainText + "\n";
|
||||
}
|
||||
|
||||
$( "#VertextTitleList" ).val(titleList);
|
||||
|
||||
$( "#GroupRenameDialog" ).dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: "auto",
|
||||
modal: true,
|
||||
title: g_groupRename,
|
||||
buttons: dialogButtons,
|
||||
dialogClass: 'EdgeDialog'
|
||||
});
|
||||
}
|
||||
835
script/Graph.js
Normal file
835
script/Graph.js
Normal file
@@ -0,0 +1,835 @@
|
||||
/**
|
||||
* Graph class.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
function Graph()
|
||||
{
|
||||
// List of vertex.
|
||||
this.vertices = [];
|
||||
// List of arcs.
|
||||
this.edges = [];
|
||||
// Unique Id of new graph.
|
||||
this.uidGraph = 0;
|
||||
// Unique Id of new edge.
|
||||
this.uidEdge = 10000;
|
||||
// Has direction edge.
|
||||
this.hasDirect = false;
|
||||
};
|
||||
|
||||
|
||||
Graph.prototype.AddNewVertex = function(vertex)
|
||||
{
|
||||
if (this.vertices.length < 300)
|
||||
{
|
||||
vertex.SetId (this.uidGraph);
|
||||
this.uidGraph = this.uidGraph + 1;
|
||||
this.vertices.push(vertex);
|
||||
}
|
||||
return this.vertices.length - 1;
|
||||
}
|
||||
|
||||
Graph.prototype.AddNewEdgeSafe = function(graph1, graph2, isDirect, weight)
|
||||
{
|
||||
var useWeight = false;
|
||||
if (!isNaN(parseInt(weight, 10)))
|
||||
{
|
||||
useWeight = true;
|
||||
}
|
||||
weight = (!isNaN(parseInt(weight, 10)) && weight >= 0) ? weight : 1;
|
||||
return this.AddNewEdge(new BaseEdge(graph1, graph2, isDirect, weight, useWeight, 0));
|
||||
}
|
||||
|
||||
Graph.prototype.AddNewEdge = function(edge)
|
||||
{
|
||||
edge.id = this.uidEdge;
|
||||
this.uidEdge = this.uidEdge + 1;
|
||||
|
||||
var edge1 = this.FindEdge(edge.vertex1.id, edge.vertex2.id);
|
||||
var edgeRevert = this.FindEdge(edge.vertex2.id, edge.vertex1.id);
|
||||
if (!edge.isDirect)
|
||||
{
|
||||
if (edge1 != null)
|
||||
{
|
||||
this.DeleteEdge(edge1);
|
||||
}
|
||||
if (edgeRevert != null)
|
||||
{
|
||||
this.DeleteEdge(edgeRevert);
|
||||
}
|
||||
this.edges.push(edge);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (edge1 != null)
|
||||
{
|
||||
this.DeleteEdge(edge1);
|
||||
}
|
||||
if (edgeRevert != null && !edgeRevert.isDirect)
|
||||
{
|
||||
this.DeleteEdge(edgeRevert);
|
||||
}
|
||||
else if (edgeRevert != null)
|
||||
{
|
||||
edgeRevert.hasPair = true;
|
||||
edge.hasPair = true;
|
||||
}
|
||||
|
||||
this.edges.push(edge);
|
||||
}
|
||||
|
||||
return this.edges.length - 1;
|
||||
}
|
||||
|
||||
|
||||
Graph.prototype.DeleteEdge = function(edgeObject)
|
||||
{
|
||||
var index = this.edges.indexOf(edgeObject);
|
||||
if (index > -1)
|
||||
{
|
||||
var edgeRevert = this.FindEdge(edgeObject.vertex2, edgeObject.vertex1);
|
||||
if (edgeRevert != null && edgeRevert.isDirect)
|
||||
{
|
||||
edgeRevert.isPair = false;
|
||||
}
|
||||
this.edges.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Graph.prototype.DeleteVertex = function(vertexObject)
|
||||
{
|
||||
var index = this.vertices.indexOf(vertexObject);
|
||||
if (index > -1)
|
||||
{
|
||||
for (var i = 0; i < this.edges.length; i++)
|
||||
{
|
||||
if (this.edges[i].vertex1 == vertexObject || this.edges[i].vertex2 == vertexObject)
|
||||
{
|
||||
this.DeleteEdge(this.edges[i]);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
this.vertices.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Graph.prototype.FindVertex = function(id)
|
||||
{
|
||||
var res = null;
|
||||
for (var i = 0; i < this.vertices.length; i++)
|
||||
{
|
||||
if (this.vertices[i].id == id)
|
||||
{
|
||||
res = this.vertices[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Graph.prototype.FindEdge = function(id1, id2)
|
||||
{
|
||||
var res = null;
|
||||
for (var i = 0; i < this.edges.length; i++)
|
||||
{
|
||||
if ((this.edges[i].vertex1.id == id1 && this.edges[i].vertex2.id == id2)
|
||||
|| (!this.edges[i].isDirect && this.edges[i].vertex1.id == id2 && this.edges[i].vertex2.id == id1))
|
||||
{
|
||||
res = this.edges[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Graph.prototype.GetAdjacencyMatrix = function ()
|
||||
{
|
||||
var matrix = "";
|
||||
for (var i = 0; i < this.vertices.length; i++)
|
||||
{
|
||||
for (var j = 0; j < this.vertices.length; j++)
|
||||
{
|
||||
var edge = this.FindEdge (this.vertices[i].id, this.vertices[j].id);
|
||||
if (edge != null)
|
||||
{
|
||||
matrix += edge.weight;
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix += "0";
|
||||
}
|
||||
|
||||
if (j != this.vertices.length)
|
||||
{
|
||||
matrix += ", ";
|
||||
}
|
||||
|
||||
}
|
||||
matrix = matrix + "\n";
|
||||
}
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
Graph.prototype.TestAdjacencyMatrix = function (matrix, rowsObj, colsObj, separator = ",")
|
||||
{
|
||||
var bGoodFormat = true;
|
||||
rowsObj.rows = [];
|
||||
rowsObj.rows = matrix.split ("\n");
|
||||
for (j = 0; j < rowsObj.rows.length; ++j)
|
||||
{
|
||||
//rowsObj.rows[j] = rowsObj.rows[j].replace(/ /g,'');
|
||||
if (rowsObj.rows[j] === "")
|
||||
{
|
||||
rowsObj.rows.splice(j--, 1);
|
||||
}
|
||||
}
|
||||
|
||||
colsObj.cols = [];
|
||||
for (var i = 0; i < rowsObj.rows.length; i++)
|
||||
{
|
||||
colsObj.cols[i] = this.SplitMatrixString(rowsObj.rows[i], separator);//rowsObj.rows[i].split (",");
|
||||
for (j = 0; j < colsObj.cols[i].length; ++j)
|
||||
{
|
||||
if (colsObj.cols[i][j] === "")
|
||||
{
|
||||
colsObj.cols[i].splice(j--, 1);
|
||||
}
|
||||
}
|
||||
if (colsObj.cols[i].length != rowsObj.rows.length)
|
||||
{
|
||||
bGoodFormat = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bGoodFormat;
|
||||
}
|
||||
|
||||
|
||||
Graph.prototype.IsVertexesHasSamePosition = function (position, vertexCount)
|
||||
{
|
||||
var res = false;
|
||||
|
||||
for (var j = 0; j < Math.min(this.vertices.length, vertexCount); j++)
|
||||
{
|
||||
if (position.distance(this.vertices[j].position) < this.vertices[j].model.diameter * 2)
|
||||
{
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Graph.prototype.GetRandomPositionOfVertex = function (matrix, vertexIndex, viewportSize)
|
||||
{
|
||||
var point = new Point(0, 0);
|
||||
|
||||
var relatedVertex = [];
|
||||
|
||||
for (var j = 0; j < matrix.length; j++)
|
||||
{
|
||||
if (j < this.vertices.length && (cols[vertexIndex][j] > 0 || cols[j][vertexIndex] > 0) && j != vertexIndex)
|
||||
{
|
||||
relatedVertex.push(this.vertices[j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var diameter = (new VertexModel()).diameter;
|
||||
|
||||
if (relatedVertex.length > 1)
|
||||
{
|
||||
for (var j = 0; j < relatedVertex.length; j++)
|
||||
{
|
||||
point = point.add(relatedVertex[j].position);
|
||||
}
|
||||
|
||||
point = point.multiply(1 / relatedVertex.length);
|
||||
|
||||
point.offset (Math.random() * diameter + (Math.random() ? -1 : 1) * 2 * diameter, Math.random() * diameter + (Math.random() ? -1 : 1) * 2 * diameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
point = new Point(Math.random() * viewportSize.x, Math.random() * viewportSize.y);
|
||||
}
|
||||
|
||||
if (this.IsVertexesHasSamePosition (point, matrix.length))
|
||||
{
|
||||
point.offset (Math.random() * diameter + + (Math.random() ? -1 : 1) * 4 * diameter,
|
||||
Math.random() * diameter + + (Math.random() ? -1 : 1) * 4 * diameter);
|
||||
}
|
||||
|
||||
// Clamp
|
||||
point.x = Math.min(Math.max(point.x, diameter), viewportSize.x);
|
||||
point.y = Math.min(Math.max(point.y, diameter), viewportSize.y);
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
Graph.prototype.VertexesReposition = function (viewportSize, newVertexes)
|
||||
{
|
||||
var maxGravityDistanceSqr = Math.max(viewportSize.x, viewportSize.y) / 5.0;
|
||||
maxGravityDistanceSqr = maxGravityDistanceSqr * maxGravityDistanceSqr;
|
||||
//Math.min(viewportSize.x, viewportSize.y) / 2.0;
|
||||
var velocityDamping = 0.85;
|
||||
var diameter = (new VertexModel()).diameter;
|
||||
var maxDistance = diameter * 3;
|
||||
var gravityDistanceSqr = 10 * (maxDistance * maxDistance);
|
||||
var edgeGravityKof = 10 / (maxDistance);
|
||||
var kCenterForce = 10 / (maxDistance * 10);
|
||||
var centerPoint = viewportSize.multiply(0.5);
|
||||
var velocityMax = maxDistance * 10;
|
||||
|
||||
var edgesMatrix = {};
|
||||
for (var i = 0; i < this.edges.length; i++)
|
||||
{
|
||||
edgesMatrix[this.edges[i].vertex1.id + this.edges[i].vertex2.id * 1000] = 1;
|
||||
edgesMatrix[this.edges[i].vertex2.id + this.edges[i].vertex1.id * 1000] = 1;
|
||||
}
|
||||
|
||||
var startAngel = Math.random() * 180.0;
|
||||
for(i = 0; i < newVertexes.length; i++) // loop through vertices
|
||||
{
|
||||
newVertexes[i].position.orbit(new Point(viewportSize.x / 2, viewportSize.y / 2), (viewportSize.x - diameter * 2) / 2,
|
||||
(viewportSize.y - diameter * 2) / 2, 360 * i / newVertexes.length + startAngel);
|
||||
}
|
||||
|
||||
var k = 0;
|
||||
var bChanged = true;
|
||||
while (k < 1000 && bChanged)
|
||||
{
|
||||
var vertexData = [];
|
||||
for(i = 0; i < newVertexes.length; i++) // loop through vertices
|
||||
{
|
||||
// Has no in newVertexes.
|
||||
var currentVertex = {};
|
||||
currentVertex.object = newVertexes[i];
|
||||
currentVertex.net_force = new Point (0, 0);
|
||||
currentVertex.velocity = new Point (0, 0);
|
||||
vertexData.push(currentVertex);
|
||||
|
||||
for(j = 0; j < this.vertices.length; j++) // loop through other vertices
|
||||
{
|
||||
otherVertex = this.vertices[j];
|
||||
|
||||
if (otherVertex == currentVertex.object) continue;
|
||||
|
||||
// squared distance between "u" and "v" in 2D space
|
||||
var rsq = currentVertex.object.position.distanceSqr(otherVertex.position);
|
||||
|
||||
|
||||
{
|
||||
// counting the repulsion between two vertices
|
||||
var force = (currentVertex.object.position.subtract(otherVertex.position)).normalize(gravityDistanceSqr / rsq);
|
||||
currentVertex.net_force = currentVertex.net_force.add(force);
|
||||
}
|
||||
}
|
||||
|
||||
for(j = 0; j < this.vertices.length; j++) // loop through edges
|
||||
{
|
||||
otherVertex = this.vertices[j];
|
||||
if (edgesMatrix.hasOwnProperty(currentVertex.object.id + 1000 * otherVertex.id))
|
||||
{
|
||||
var distance = currentVertex.object.position.distance(otherVertex.position);
|
||||
|
||||
if (distance > maxDistance)
|
||||
{
|
||||
// countin the attraction
|
||||
var force = (otherVertex.position.subtract(currentVertex.object.position)).normalize(edgeGravityKof * (distance - maxDistance));
|
||||
currentVertex.net_force = currentVertex.net_force.add(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate force to center of world.
|
||||
var distanceToCenter = centerPoint.distance(currentVertex.object.position);
|
||||
var force = centerPoint.subtract(currentVertex.object.position).normalize(distanceToCenter * kCenterForce);
|
||||
currentVertex.net_force = currentVertex.net_force.add(force);
|
||||
|
||||
// counting the velocity (with damping 0.85)
|
||||
currentVertex.velocity = currentVertex.velocity.add(currentVertex.net_force);
|
||||
}
|
||||
|
||||
bChanged = false;
|
||||
|
||||
for(i = 0; i < vertexData.length; i++) // set new positions
|
||||
{
|
||||
var v = vertexData[i];
|
||||
var velocity = v.velocity;
|
||||
if (velocity.length() > velocityMax)
|
||||
{
|
||||
velocity = velocity.normalize(velocityMax);
|
||||
}
|
||||
v.object.position = v.object.position.add(velocity);
|
||||
if (velocity.length() >= 1)
|
||||
{
|
||||
bChanged = true;
|
||||
}
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
|
||||
// Looks like somthing going wrong and will use circle algorithm for reposition.
|
||||
var bbox = this.getGraphBBox();
|
||||
if (bbox.size().length() > viewportSize.length() * 1000)
|
||||
{
|
||||
for(i = 0; i < newVertexes.length; i++) // loop through vertices
|
||||
{
|
||||
newVertexes[i].position.orbit(new Point(viewportSize.x / 2, viewportSize.y / 2), (viewportSize.x - diameter * 2) / 2,
|
||||
(viewportSize.y - diameter * 2) / 2, 360 * i / newVertexes.length + startAngel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to rotate graph to fill small area.
|
||||
var count = 10;
|
||||
var agnle = 360.0 / count;
|
||||
var viewportAspect = viewportSize.x / viewportSize.y;
|
||||
var bestIndex = 0;
|
||||
var graphSize = bbox.size();
|
||||
var bestAspect = graphSize.x / graphSize.y;
|
||||
var center = bbox.center();
|
||||
|
||||
for (var i = 1; i < count; i++)
|
||||
{
|
||||
for(j = 0; j < newVertexes.length; j++) // loop through vertices
|
||||
{
|
||||
newVertexes[j].position.rotate(center, agnle);
|
||||
}
|
||||
|
||||
var newBBox = this.getGraphBBox();
|
||||
var newAspect = newBBox.size().x / newBBox.size().y;
|
||||
if (Math.abs(newAspect - viewportAspect) < Math.abs(bestAspect - viewportAspect))
|
||||
{
|
||||
bestAspect = newAspect;
|
||||
bestIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Rotate to best aspect.
|
||||
for(j = 0; j < newVertexes.length; j++) // loop through vertices
|
||||
{
|
||||
newVertexes[j].position.rotate(center, - agnle * (count - bestIndex - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Graph.prototype.SetAdjacencyMatrix = function (matrix, viewportSize, currentEnumVertesType, separator = ",")
|
||||
{
|
||||
var rowsObj = {};
|
||||
var colsObj = {};
|
||||
|
||||
//ViewportSize = viewportSize.subtract(new Point((new VertexModel()).diameter * 2, (new VertexModel()).diameter * 2));
|
||||
|
||||
if (this.TestAdjacencyMatrix(matrix, rowsObj, colsObj, separator))
|
||||
{
|
||||
rows = rowsObj.rows;
|
||||
cols = colsObj.cols;
|
||||
for (var i = 0; i < this.edges.length; i++)
|
||||
{
|
||||
this.DeleteEdge (this.edges[i]);
|
||||
}
|
||||
|
||||
var newVertexes = [];
|
||||
var bWeightGraph = false;
|
||||
|
||||
for (var i = 0; i < rows.length; i++)
|
||||
{
|
||||
for (var j = 0; j < rows.length; j++)
|
||||
{
|
||||
if (j >= this.vertices.length)
|
||||
{
|
||||
var newPos = this.GetRandomPositionOfVertex (matrix, j, viewportSize);
|
||||
newVertexes.push(new BaseVertex(newPos.x, newPos.y, currentEnumVertesType));
|
||||
this.AddNewVertex(newVertexes[newVertexes.length - 1]);
|
||||
}
|
||||
|
||||
if (cols[i][j] > 0)
|
||||
{
|
||||
var nEdgeIndex = this.AddNewEdgeSafe(this.vertices[i], this.vertices[j], cols[i][j] != cols[j][i], cols[i][j]);
|
||||
if (nEdgeIndex >= 0)
|
||||
{
|
||||
bWeightGraph = bWeightGraph || this.edges[nEdgeIndex].weight != 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set use weight false, because we have unwieghts graph.
|
||||
if (!bWeightGraph)
|
||||
{
|
||||
this.edges.forEach(function(part, index, theArray) {
|
||||
theArray[index].useWeight = false;
|
||||
});
|
||||
}
|
||||
|
||||
for (var i = rows.length; i < Math.max(this.vertices.length, rows.length); i++)
|
||||
{
|
||||
this.DeleteVertex(this.vertices[i]);
|
||||
i--;
|
||||
}
|
||||
|
||||
this.VertexesReposition(viewportSize, newVertexes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Graph.prototype.TestIncidenceMatrix = function (matrix, rowsObj, colsObj, separator = ",")
|
||||
{
|
||||
var bGoodFormat = true;
|
||||
rowsObj.rows = [];
|
||||
rowsObj.rows = matrix.split ("\n");
|
||||
for (j = 0; j < rowsObj.rows.length; ++j)
|
||||
{
|
||||
if (rowsObj.rows[j] === "")
|
||||
{
|
||||
rowsObj.rows.splice(j--, 1);
|
||||
}
|
||||
}
|
||||
colsObj.cols = [];
|
||||
var columnCount = 0;
|
||||
for (var i = 0; i < rowsObj.rows.length; i++)
|
||||
{
|
||||
colsObj.cols[i] = this.SplitMatrixString(rowsObj.rows[i], separator);//rowsObj.rows[i].split (",");
|
||||
for (j = 0; j < colsObj.cols[i].length; ++j)
|
||||
{
|
||||
if (colsObj.cols[i][j] === "")
|
||||
{
|
||||
colsObj.cols[i].splice(j--, 1);
|
||||
}
|
||||
}
|
||||
if (i == 0)
|
||||
{
|
||||
columnCount = colsObj.cols[i].length;
|
||||
}
|
||||
if (colsObj.cols[i].length != columnCount)
|
||||
{
|
||||
bGoodFormat = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (bGoodFormat)
|
||||
{
|
||||
for (var i = 0; i < colsObj.cols[0].length; i++)
|
||||
{
|
||||
var values = [];
|
||||
for (j = 0; j < colsObj.cols.length; ++j)
|
||||
{
|
||||
if (colsObj.cols[j][i] != 0)
|
||||
{
|
||||
values.push(colsObj.cols[j][i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(values.length <= 1 || (values.length == 2 && (values[0] == values[1] || values[0] == -values[1]))))
|
||||
{
|
||||
bGoodFormat = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bGoodFormat;
|
||||
}
|
||||
|
||||
Graph.prototype.SetIncidenceMatrix = function (matrix, viewportSize, currentEnumVertesType)
|
||||
{
|
||||
var rowsObj = {};
|
||||
var colsObj = {};
|
||||
|
||||
//ViewportSize = viewportSize.subtract(new Point((new VertexModel()).diameter * 2, (new VertexModel()).diameter * 2));
|
||||
|
||||
if (this.TestIncidenceMatrix(matrix, rowsObj, colsObj))
|
||||
{
|
||||
rows = rowsObj.rows;
|
||||
cols = colsObj.cols;
|
||||
for (var i = 0; i < this.edges.length; i++)
|
||||
{
|
||||
this.DeleteEdge (this.edges[i]);
|
||||
}
|
||||
var newVertexes = [];
|
||||
var bWeightGraph = false;
|
||||
for (var i = 0; i < cols[0].length; i++)
|
||||
{
|
||||
var edgeValue = [];
|
||||
var edgeIndex = [];
|
||||
for (var j = 0; j < cols.length; j++)
|
||||
{
|
||||
if (j >= this.vertices.length)
|
||||
{
|
||||
|
||||
var newPos = new Point(0, 0);//this.GetRandomPositionOfVertex (matrix, j, viewportSize);
|
||||
newVertexes.push(new BaseVertex(newPos.x, newPos.y, currentEnumVertesType));
|
||||
this.AddNewVertex(newVertexes[newVertexes.length - 1]);
|
||||
}
|
||||
|
||||
if (cols[j][i] != 0)
|
||||
{
|
||||
edgeValue.push(cols[j][i]);
|
||||
edgeIndex.push(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (edgeIndex.length == 1)
|
||||
{
|
||||
edgeValue.push(edgeValue[0]);
|
||||
edgeIndex.push(edgeIndex[0]);
|
||||
}
|
||||
|
||||
if (edgeIndex.length == 2)
|
||||
{
|
||||
if (edgeValue[0] != edgeValue[1])
|
||||
{
|
||||
if (edgeValue[1] > 0)
|
||||
{
|
||||
edgeValue = edgeValue.swap(0, 1);
|
||||
edgeIndex = edgeIndex.swap(0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
var nEdgeIndex = this.AddNewEdgeSafe(this.vertices[edgeIndex[0]], this.vertices[edgeIndex[1]],
|
||||
edgeValue[0] != edgeValue[1], Math.abs(edgeValue[1]));
|
||||
if (nEdgeIndex >= 0)
|
||||
{
|
||||
bWeightGraph = bWeightGraph || this.edges[nEdgeIndex].weight != 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set use weight false, because we have unwieghts graph.
|
||||
if (!bWeightGraph)
|
||||
{
|
||||
this.edges.forEach(function(part, index, theArray) {
|
||||
theArray[index].useWeight = false;
|
||||
});
|
||||
}
|
||||
|
||||
for (var i = cols.length; i < Math.max(this.vertices.length, cols.length); i++)
|
||||
{
|
||||
this.DeleteVertex(this.vertices[i]);
|
||||
i--;
|
||||
}
|
||||
|
||||
this.VertexesReposition(viewportSize, newVertexes);
|
||||
}
|
||||
}
|
||||
|
||||
Graph.prototype.GetIncidenceMatrix = function ()
|
||||
{
|
||||
var matrix = "";
|
||||
for (var i = 0; i < this.vertices.length; i++)
|
||||
{
|
||||
for (var j = 0; j < this.edges.length; j++)
|
||||
{
|
||||
if (this.edges[j].vertex1 == this.vertices[i])
|
||||
{
|
||||
matrix += this.edges[j].weight;
|
||||
}
|
||||
else if (this.edges[j].vertex2 == this.vertices[i] && !this.edges[j].isDirect)
|
||||
{
|
||||
matrix += this.edges[j].weight;
|
||||
}
|
||||
else if (this.edges[j].vertex2 == this.vertices[i] && this.edges[j].isDirect)
|
||||
{
|
||||
matrix += -this.edges[j].weight;
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix += "0";
|
||||
}
|
||||
|
||||
if (j != this.edges.length - 1)
|
||||
{
|
||||
matrix += ", ";
|
||||
}
|
||||
|
||||
}
|
||||
matrix = matrix + "\n";
|
||||
}
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
Graph.prototype.SplitMatrixString = function (line, separator = ",")
|
||||
{
|
||||
var res = [];
|
||||
var i = 0;
|
||||
|
||||
// For case: 00110101101
|
||||
var isZeroOneLine = true;
|
||||
|
||||
for (i = 0; i < line.length; i++)
|
||||
{
|
||||
if (line.charAt(i) != '0' && line.charAt(i) != '1')
|
||||
{
|
||||
isZeroOneLine = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isZeroOneLine)
|
||||
{
|
||||
if (separator != ",")
|
||||
{
|
||||
line = line.replace(/,/g, ".");
|
||||
}
|
||||
for (i = 0; i < line.length; i++)
|
||||
{
|
||||
// add , if we use space as separator
|
||||
if (("0123456789.-e").indexOf(line.charAt(i)) < 0 )
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
res.push(line.substr(0, i));
|
||||
}
|
||||
if (i == 0)
|
||||
{
|
||||
i = 1;
|
||||
}
|
||||
line = line.substr(i, line.length - i);
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
if (line.length > 0)
|
||||
{
|
||||
res.push(line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < line.length; i++)
|
||||
{
|
||||
res.push(line.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
console.log(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Graph.prototype.SaveToXML = function ()
|
||||
{
|
||||
var mainHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><graphml>";
|
||||
var header = "<graph id=\"Graph\" uidGraph=\"" + this.uidGraph + "\"" + " uidEdge=\"" + this.uidEdge + "\">";
|
||||
|
||||
var xmlBoby = "<nodes>";
|
||||
|
||||
for (var i = 0; i < this.vertices.length; i++)
|
||||
{
|
||||
xmlBoby = xmlBoby + this.vertices[i].SaveToXML();
|
||||
}
|
||||
|
||||
xmlBoby = xmlBoby + "</nodes><edges>";
|
||||
|
||||
for (var i = 0; i < this.edges.length; i++)
|
||||
{
|
||||
xmlBoby = xmlBoby + this.edges[i].SaveToXML();
|
||||
}
|
||||
|
||||
xmlBoby = xmlBoby + "</edges>";
|
||||
|
||||
return mainHeader + header + xmlBoby + "</graph></graphml>";
|
||||
}
|
||||
|
||||
Graph.prototype.LoadFromXML = function (xmlText)
|
||||
{
|
||||
xmlDoc = $.parseXML( xmlText );
|
||||
var $xml = $( xmlDoc );
|
||||
|
||||
$graphs = $xml.find( "graph" );
|
||||
|
||||
var loadedGraphId = 0;
|
||||
var loadedEdgeId = 0;
|
||||
|
||||
$graphs.each(function(){
|
||||
loadedGraphId = parseInt($(this).attr('uidGraph'));
|
||||
loadedEdgeId = parseInt($(this).attr('uidEdge'));
|
||||
});
|
||||
|
||||
// Back comportebility.
|
||||
if (isNaN(loadedEdgeId))
|
||||
{
|
||||
loadedEdgeId = 10000;
|
||||
}
|
||||
|
||||
this.uidGraph = loadedGraphId;
|
||||
this.uidEdge = loadedEdgeId;
|
||||
|
||||
$nodes = $xml.find( "node" );
|
||||
|
||||
var vertexs = [];
|
||||
|
||||
$nodes.each(function(){
|
||||
var vertex = new BaseVertex();
|
||||
vertex.LoadFromXML($(this));
|
||||
vertexs.push(vertex);
|
||||
});
|
||||
this.vertices = vertexs;
|
||||
|
||||
$edges = $xml.find( "edge" );
|
||||
|
||||
var edges = [];
|
||||
var graph = this;
|
||||
$edges.each(function(){
|
||||
var edge = new BaseEdge();
|
||||
edge.LoadFromXML($(this), graph);
|
||||
edges.push(edge);
|
||||
});
|
||||
|
||||
this.edges = edges;
|
||||
}
|
||||
|
||||
Graph.prototype.hasDirectEdge = function ()
|
||||
{
|
||||
var res = false;
|
||||
for (var i = 0; i < this.edges.length; i++)
|
||||
{
|
||||
if(this.edges[i].isDirect)
|
||||
{
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Graph.prototype.clampPositions = function (viewportSize)
|
||||
{
|
||||
var diameter = (new VertexModel()).diameter;
|
||||
|
||||
for(i = 0; i < this.vertices.length; i++) // set new positions
|
||||
{
|
||||
this.vertices[i].position.x = Math.min(Math.max(this.vertices[i].position.x, diameter), viewportSize.x - diameter);
|
||||
this.vertices[i].position.y = Math.min(Math.max(this.vertices[i].position.y, diameter), viewportSize.y - diameter);
|
||||
}
|
||||
}
|
||||
|
||||
// Use to setup scaling.
|
||||
Graph.prototype.getGraphBBox = function (viewportSize)
|
||||
{
|
||||
var pointMin = new Point(1e5, 1e5);
|
||||
var pointMax = new Point(-1e5, -1e5);
|
||||
var diameter = (new VertexModel()).diameter;
|
||||
|
||||
for(i = 0; i < this.vertices.length; i++)
|
||||
{
|
||||
var vertex = this.vertices[i];
|
||||
var deltaVector = new Point(vertex.diameterFactor() * diameter, diameter);
|
||||
pointMin = pointMin.min(vertex.position.subtract(deltaVector));
|
||||
pointMax = pointMax.max(vertex.position.add(deltaVector));
|
||||
}
|
||||
|
||||
return new Rect(pointMin, pointMax);
|
||||
}
|
||||
57
script/GraphMLCreater.js
Normal file
57
script/GraphMLCreater.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* This class creates GraphML xml.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
function GraphMLCreater(nodes, arcs)
|
||||
{
|
||||
this.nodes = nodes;
|
||||
this.arcs = arcs;
|
||||
}
|
||||
|
||||
|
||||
GraphMLCreater.prototype.GetXMLString = function()
|
||||
{
|
||||
var mainHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><graphml>";
|
||||
var directedHeader = "<graph id=\"Graph\" edgedefault=\"directed\">";
|
||||
var undirectedHeader = "<graph id=\"Graph\" edgedefault=\"undirected\">";
|
||||
|
||||
var defaultWeight = 1.0;
|
||||
var weightKeyId = "\"d0\"";
|
||||
var weightNode = "<key id="+ weightKeyId + " for=\"node\" attr.name=\"weight\" attr.type=\"double\">" +
|
||||
"<default>" + defaultWeight + "</default>" +
|
||||
"</key>";
|
||||
|
||||
var xmlBoby = "";
|
||||
|
||||
for (var i = 0; i < this.nodes.length; i++)
|
||||
{
|
||||
xmlBoby = xmlBoby + "<node id=\"" + this.nodes[i].id + "\"/>";
|
||||
}
|
||||
var hasDirected = false;
|
||||
for (var i = 0; i < this.arcs.length; i++)
|
||||
{
|
||||
if (this.arcs[i].isDirect)
|
||||
{
|
||||
hasDirected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < this.arcs.length; i++)
|
||||
{
|
||||
var weightData = "";
|
||||
if (this.arcs[i].weight != defaultWeight)
|
||||
{
|
||||
weightData = "<data key="+ weightKeyId + ">"+ this.arcs[i].weight + "</data>";
|
||||
}
|
||||
|
||||
xmlBoby = xmlBoby + "<edge source=\"" + this.arcs[i].vertex1.id + "\" target=\""
|
||||
+ this.arcs[i].vertex2.id + "\" "+
|
||||
(this.arcs[i].isDirect != hasDirected ? (hasDirected ? "directed=\"false\"" : "directed=\"true\"") : "");
|
||||
|
||||
xmlBoby = xmlBoby + ((weightData != "") ? ">" + weightData + "</edge>" : "/>")
|
||||
}
|
||||
xml = mainHeader + weightNode + (hasDirected ? directedHeader : undirectedHeader) + xmlBoby + "</graph></graphml>"
|
||||
return xml;
|
||||
}
|
||||
10
script/VertexModel.js
Normal file
10
script/VertexModel.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* This is graph model used for hit test and draw.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
function VertexModel()
|
||||
{
|
||||
this.diameter = 30;
|
||||
}
|
||||
15
script/createByMatrixMain.js
Normal file
15
script/createByMatrixMain.js
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
Main class for create by matrix page
|
||||
*/
|
||||
|
||||
|
||||
window.onload = function ()
|
||||
{
|
||||
if (document.getElementById('CreateByAdjacencyMatrix'))
|
||||
{
|
||||
document.getElementById('CreateByAdjacencyMatrix').onclick = function ()
|
||||
{
|
||||
window.location = "./?matrix=" + $( "#AdjacencyMatrixFieldPage" ).val();
|
||||
}
|
||||
}
|
||||
}
|
||||
4590
script/example.js
Normal file
4590
script/example.js
Normal file
File diff suppressed because it is too large
Load Diff
472
script/main.js
Normal file
472
script/main.js
Normal file
@@ -0,0 +1,472 @@
|
||||
var application = new Application(document, window);
|
||||
|
||||
var waitCounter = false;
|
||||
var userAction = function(str)
|
||||
{
|
||||
if (typeof window.yaCounter25827098 !== "undefined")
|
||||
{
|
||||
console.log(str);
|
||||
window.yaCounter25827098.hit("http://" + window.location.hostname + "/UserAction#" + str);
|
||||
}
|
||||
else if (!waitCounter)
|
||||
{
|
||||
waitCounter = true;
|
||||
setTimeout(function()
|
||||
{
|
||||
userAction(str);
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
var isIe = (navigator.userAgent.toLowerCase().indexOf("msie") != -1
|
||||
|| navigator.userAgent.toLowerCase().indexOf("trident") != -1);
|
||||
|
||||
var buttonsList = ['AddGraph', 'ConnectGraphs', 'DeleteObject', 'Default'];
|
||||
|
||||
function restButtons (me)
|
||||
{
|
||||
var needSetDefault = false;
|
||||
for (var i = 0; i < buttonsList.length; i ++)
|
||||
{
|
||||
if (buttonsList[i] != me)
|
||||
{
|
||||
document.getElementById(buttonsList[i]).className = "btn btn-default btn-sm";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (document.getElementById(buttonsList[i]).className != "btn btn-default btn-sm")
|
||||
{
|
||||
needSetDefault = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needSetDefault)
|
||||
{
|
||||
document.getElementById(buttonsList[i]).className = "btn btn-primary btn-sm";
|
||||
}
|
||||
else
|
||||
{
|
||||
document.getElementById(me).className = "btn btn-primary btn-sm";
|
||||
}
|
||||
}
|
||||
|
||||
var single = 0;
|
||||
|
||||
function resizeCanvas()
|
||||
{
|
||||
var adv = document.getElementById('adv');
|
||||
var canvas = document.getElementById('canvas');
|
||||
canvas.width = document.getElementById('canvasSection').offsetWidth;
|
||||
|
||||
//canvas.height = document.getElementById('footer').offsetTop - document.getElementById('canvasSection').offsetTop - (adv && $("#adv").css("display") === 'block' ? document.getElementById('adv').offsetHeight : 0);
|
||||
canvas.height = $(window).height() - document.getElementById('canvas').offsetTop - (adv && $("#adv").css("display") === 'block' ? document.getElementById('adv').offsetHeight : 0) - ($("#footer").css("display") === 'block' ? document.getElementById('footer').offsetHeight : 0) - (document.documentElement.clientWidth < 650 ? 20 : 0);
|
||||
|
||||
application.redrawGraph();
|
||||
}
|
||||
|
||||
function touchHandler(event)
|
||||
{
|
||||
var touches = event.changedTouches,
|
||||
first = touches[0],
|
||||
type = "";
|
||||
switch(event.type)
|
||||
{
|
||||
case "touchstart": type = "mousedown"; break;
|
||||
case "touchmove": type="mousemove"; break;
|
||||
case "touchend": type="mouseup"; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
var simulatedEvent = document.createEvent("MouseEvent");
|
||||
simulatedEvent.initMouseEvent(type, true, true, window, 1,
|
||||
first.screenX, first.screenY,
|
||||
first.clientX, first.clientY, false,
|
||||
false, false, false, 0/*left*/, null);
|
||||
|
||||
first.target.dispatchEvent(simulatedEvent);
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
function preLoadPage()
|
||||
{
|
||||
loadTexts();
|
||||
application.onLoad();
|
||||
}
|
||||
|
||||
function createAlgorithmMenu()
|
||||
{
|
||||
var algorihtmsBaseId = "Algo";
|
||||
var algorithms = application.getAlgorithmNames();
|
||||
var index = 0;
|
||||
|
||||
for (var i = 0; i < algorithms.length; i++)
|
||||
{
|
||||
algorithm = algorithms[i];
|
||||
|
||||
var list = document.getElementById("algorithmList");
|
||||
var item = list.lastElementChild;
|
||||
var clone = item.cloneNode(true);
|
||||
var button = clone.getElementsByTagName("button")[0];
|
||||
var textSpan = button.getElementsByTagName("span")[1];
|
||||
button.id = algorithm.id;
|
||||
textSpan.innerHTML = algorithm.name;
|
||||
clone.style.display = "block";
|
||||
|
||||
buttonsList.push(algorithm.id);
|
||||
|
||||
button.onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
restButtons (this.id);
|
||||
application.SetHandlerMode(this.id);
|
||||
}
|
||||
|
||||
list.appendChild(clone);
|
||||
index++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function postLoadPage()
|
||||
{
|
||||
application.userAction = userAction;
|
||||
|
||||
application.canvas.onmousemove = function (e)
|
||||
{
|
||||
return application.CanvasOnMouseMove(e);
|
||||
};
|
||||
|
||||
application.canvas.onmousedown = function (e)
|
||||
{
|
||||
return application.CanvasOnMouseDown(e);
|
||||
};
|
||||
|
||||
application.canvas.onmouseup = function (e)
|
||||
{
|
||||
return application.CanvasOnMouseUp(e);
|
||||
}
|
||||
|
||||
application.canvas.onmousewheel = function (e)
|
||||
{
|
||||
var e = window.event || e; // old IE support
|
||||
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
|
||||
if (delta > 0)
|
||||
{
|
||||
application.multCanvasScale(1.3);
|
||||
}
|
||||
else
|
||||
{
|
||||
application.multCanvasScale(1.0 / 1.3);
|
||||
}
|
||||
}
|
||||
|
||||
document.onkeypress = function (e)
|
||||
{
|
||||
if (event.defaultPrevented
|
||||
|| ($('#addVertex').hasClass('ui-dialog-content') && $('#addVertex').dialog('isOpen'))
|
||||
|| ($('#adjacencyMatrix').hasClass('ui-dialog-content') && $('#adjacencyMatrix').dialog('isOpen'))
|
||||
|| ($('#addEdge').hasClass('ui-dialog-content') && $('#addEdge').dialog('isOpen'))
|
||||
|| ($('#incidenceMatrix').hasClass('ui-dialog-content') && $('#incidenceMatrix').dialog('isOpen'))
|
||||
|| ($('#saveDialog').hasClass('ui-dialog-content') && $('#saveDialog').dialog('isOpen'))
|
||||
|| ($('#saveImageDialog').hasClass('ui-dialog-content') && $('#saveImageDialog').dialog('isOpen'))
|
||||
|| ($('#GroupRenameDialog').hasClass('ui-dialog-content') && $('#GroupRenameDialog').dialog('isOpen'))
|
||||
|| $('#developerTools').css("display") != "none")
|
||||
{
|
||||
console.log("prevent");
|
||||
return; // Should do nothing if the default action has been cancelled
|
||||
}
|
||||
|
||||
|
||||
var key = 0;
|
||||
|
||||
if(window.event)
|
||||
{
|
||||
key = event.keyCode;
|
||||
}
|
||||
else if(event.which)
|
||||
{
|
||||
key = event.which;
|
||||
}
|
||||
console.log(key);
|
||||
|
||||
var moveValue = 10;
|
||||
if (key == 61 || key == 43) // +
|
||||
{
|
||||
application.multCanvasScale(1.5);
|
||||
}
|
||||
else if (key == 45) // -
|
||||
{
|
||||
application.multCanvasScale(1 / 1.5);
|
||||
}
|
||||
else if (key == 119 || key == 1094) // up
|
||||
{
|
||||
application.onCanvasMove(new Point(0, moveValue));
|
||||
}
|
||||
else if (key == 115 || key == 1099) // down
|
||||
{
|
||||
application.onCanvasMove(new Point(0, -moveValue));
|
||||
}
|
||||
else if (key == 97 || key == 1092) // left
|
||||
{
|
||||
application.onCanvasMove(new Point(moveValue, 0));
|
||||
}
|
||||
else if (key == 100 || key == 1074) // right
|
||||
{
|
||||
application.onCanvasMove(new Point(-moveValue, 0));
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('ShowAdjacencyMatrix').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.SetHandlerMode("showAdjacencyMatrix");
|
||||
}
|
||||
document.getElementById('ShowIncidenceMatrix').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.SetHandlerMode("showIncidenceMatrix");
|
||||
}
|
||||
|
||||
document.getElementById('GroupRename').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.SetHandlerMode("GroupRename");
|
||||
}
|
||||
document.getElementById('groupRenameButton').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.SetHandlerMode("GroupRename");
|
||||
}
|
||||
|
||||
|
||||
document.getElementById('Default').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
restButtons ('Default');
|
||||
application.SetHandlerMode("default");
|
||||
document.getElementById('Default').className = "btn btn-primary btn-sm";
|
||||
}
|
||||
|
||||
document.getElementById('AddGraph').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
restButtons ('AddGraph');
|
||||
application.SetHandlerMode(document.getElementById('AddGraph').className != "" ? "addGraph" : "default");
|
||||
}
|
||||
|
||||
document.getElementById('ConnectGraphs').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
restButtons ('ConnectGraphs');
|
||||
application.SetHandlerMode(document.getElementById('ConnectGraphs').className != "" ? "addArc" : "default");
|
||||
}
|
||||
|
||||
document.getElementById('DeleteObject').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
restButtons ('DeleteObject');
|
||||
application.SetHandlerMode(document.getElementById('DeleteObject').className != "" ? "delete" : "default");
|
||||
}
|
||||
|
||||
document.getElementById('DeleteAll').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.SetHandlerMode("deleteAll");
|
||||
}
|
||||
|
||||
|
||||
document.getElementById('SaveGraph').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.SetHandlerMode("saveDialog");
|
||||
}
|
||||
|
||||
document.getElementById('NewGraph').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.SetHandlerMode("deleteAll");
|
||||
application.SetDefaultTransformations();
|
||||
}
|
||||
|
||||
document.getElementById('SaveGraphImage').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.SetHandlerMode("saveDialogImage");
|
||||
}
|
||||
|
||||
document.getElementById('Zoom100').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.setCanvasScale(1.0);
|
||||
}
|
||||
|
||||
document.getElementById('Zoom50').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.setCanvasScale(50 / 100);
|
||||
}
|
||||
|
||||
document.getElementById('Zoom25').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.setCanvasScale(25 / 100);
|
||||
}
|
||||
|
||||
document.getElementById('ZoomFit').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.OnAutoAdjustViewport();
|
||||
}
|
||||
|
||||
document.getElementById('ZoomIn').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.multCanvasScale(1.5);
|
||||
}
|
||||
|
||||
document.getElementById('ZoomOut').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
application.multCanvasScale(1.0 / 1.5);
|
||||
}
|
||||
|
||||
document.getElementById('MoveWorspace').onclick = function ()
|
||||
{
|
||||
userAction(this.id);
|
||||
restButtons ('Default');
|
||||
application.SetHandlerMode("default");
|
||||
document.getElementById('Default').className = "btn btn-primary btn-sm";
|
||||
}
|
||||
|
||||
document.getElementById('runUserScript').onclick = function ()
|
||||
{
|
||||
var el = document.getElementById('userScript');
|
||||
|
||||
var oldScript = document.getElementById("userScriptSource");
|
||||
if (oldScript)
|
||||
{
|
||||
document.head.removeChild(oldScript);
|
||||
}
|
||||
|
||||
var script = document.createElement('script');
|
||||
script.type = "text/javascript";
|
||||
script.innerHTML = el.value;
|
||||
script.id = "userScriptSource";
|
||||
document.head.appendChild(script);
|
||||
|
||||
application.SetHandlerMode("user.algorithm");
|
||||
}
|
||||
|
||||
document.getElementById('submitUserScript').onclick = function ()
|
||||
{
|
||||
var script = document.getElementById('userScript');
|
||||
var data = "message=" + script.value + "&";
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/feedback",
|
||||
data: data
|
||||
});
|
||||
|
||||
$( "#sentAlgorithm" ).dialog({
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 400,
|
||||
modal: true,
|
||||
dialogClass: 'EdgeDialog'
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('devToolsZoom').onclick = function ()
|
||||
{
|
||||
var devTools = document.getElementById('developerTools');
|
||||
if (devTools.hasOwnProperty("isMin") && !devTools["isMin"])
|
||||
{
|
||||
devTools["isMin"] = true;
|
||||
devTools.style.width = "30%";
|
||||
}
|
||||
else
|
||||
{
|
||||
devTools["isMin"] = false;
|
||||
devTools.style.width = "100%";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Get algorithms list and load it.
|
||||
$.get( "/cgi-bin/getPluginsList.php",
|
||||
function( data )
|
||||
{
|
||||
var scriptList = JSON.parse(data);
|
||||
|
||||
var loadOneScript = function()
|
||||
{
|
||||
if (scriptList.length == 0)
|
||||
{
|
||||
createAlgorithmMenu();
|
||||
}
|
||||
else
|
||||
{
|
||||
var script = document.createElement('script');
|
||||
script.src = scriptList[0];
|
||||
scriptList.shift();
|
||||
script.onload = loadOneScript;
|
||||
script.onerror = loadOneScript;
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
}
|
||||
|
||||
loadOneScript();
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
var devTools = document.getElementById('developerTools');
|
||||
devTools.style.left = 0;
|
||||
resizeCanvas();
|
||||
application.onPostLoadEvent();
|
||||
}
|
||||
|
||||
//window.onload = function ()
|
||||
$(document).ready(function ()
|
||||
{
|
||||
|
||||
window.onresize = function(event)
|
||||
{
|
||||
resizeCanvas();
|
||||
}
|
||||
|
||||
|
||||
document.getElementById('canvas').addEventListener("touchstart", touchHandler, true);
|
||||
document.getElementById('canvas').addEventListener("touchmove", touchHandler, true);
|
||||
document.getElementById('canvas').addEventListener("touchend", touchHandler, true);
|
||||
document.getElementById('canvas').addEventListener("touchcancel", touchHandler, true);
|
||||
|
||||
/*
|
||||
$(document).ready(function(){
|
||||
//set up some basic options for the feedback_me plugin
|
||||
fm_options = {
|
||||
position: "left-bottom",
|
||||
message_placeholder: g_what_do_you_think,
|
||||
message_required: true,
|
||||
name_label: g_name,
|
||||
message_label: g_feedback,
|
||||
trigger_label: g_feedback,
|
||||
submit_label: g_send,
|
||||
title_label: g_write_to_us,
|
||||
feedback_url: "/feedback",
|
||||
};
|
||||
//init feedback_me plugin
|
||||
fm.init(fm_options);
|
||||
});
|
||||
*/
|
||||
});
|
||||
|
||||
Array.prototype.swap = function (x,y) {
|
||||
var b = this[x];
|
||||
this[x] = this[y];
|
||||
this[y] = b;
|
||||
return this;
|
||||
}
|
||||
32
script/merge.php
Normal file
32
script/merge.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
$outputFilename = 'example.js';
|
||||
|
||||
unlink($outputFilename);
|
||||
|
||||
file_put_contents($outputFilename, file_get_contents("texts.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("point.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("EdgeModel.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("VertexModel.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("BaseVertex.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("BaseEdge.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("BaseVertexDrawer.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("BaseEdgeDrawer.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("Algorithms.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("EventHandlers.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("GraphMLCreater.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("Graph.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("EnumVertices.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("Appilcation.js"), FILE_APPEND);
|
||||
file_put_contents($outputFilename, file_get_contents("main.js"), FILE_APPEND);
|
||||
|
||||
|
||||
if (file_exists($outputFilename))
|
||||
{
|
||||
echo ("File exists");
|
||||
}
|
||||
else
|
||||
{
|
||||
echo ("File not exists");
|
||||
}
|
||||
|
||||
?>
|
||||
104
script/plugins/ConnectedComponent.js
Normal file
104
script/plugins/ConnectedComponent.js
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Default handler.
|
||||
* Select using mouse, drag.
|
||||
*
|
||||
*/
|
||||
function FindConnectedComponentNew(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
this.connectedComponentNumber = 0;
|
||||
this.component = {};
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindConnectedComponentNew.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
|
||||
FindConnectedComponentNew.prototype.getName = function(local)
|
||||
{
|
||||
return local == "ru" ? "Найти компоненты связности" : "Find connected components";
|
||||
}
|
||||
|
||||
FindConnectedComponentNew.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.ConnectedComponent";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindConnectedComponentNew.prototype.getMessage = function(local)
|
||||
{
|
||||
return (this.graph.hasDirectEdge() ? g_sickConnectedComponent : g_connectedComponent) + this.connectedComponentNumber;
|
||||
}
|
||||
|
||||
FindConnectedComponentNew.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.connectedComponentNumber = 0;
|
||||
this.component = {};
|
||||
var tempVertexes = this.graph.vertices.slice();
|
||||
connectedVertex = getVertexToVertexArray(this.graph, true);
|
||||
var connectedComponentNumber = 0;
|
||||
|
||||
while (tempVertexes.length > 0)
|
||||
{
|
||||
connectedComponentNumber++;
|
||||
|
||||
var stack = [];
|
||||
stack.push(tempVertexes[0]);
|
||||
|
||||
tempVertexes.splice(0, 1);
|
||||
|
||||
indexInStack = 0;
|
||||
|
||||
for (i = 0; i < stack.length; i++)
|
||||
{
|
||||
var stackElement = stack[i];
|
||||
this.component[stackElement.id] = connectedComponentNumber;
|
||||
stackElement.upText = connectedComponentNumber;
|
||||
|
||||
if (connectedVertex.hasOwnProperty(stackElement.id))
|
||||
{
|
||||
for (j = 0; j < connectedVertex[stackElement.id].length; j++)
|
||||
{
|
||||
var nextVertex = connectedVertex[stackElement.id][j];
|
||||
var connectedEdge = this.graph.FindEdge(stackElement.id, nextVertex.id);
|
||||
if (stack.indexOf(nextVertex) < 0)
|
||||
{
|
||||
stack.push(nextVertex);
|
||||
tempVertexes.splice(tempVertexes.indexOf(nextVertex), 1);
|
||||
if (connectedEdge)
|
||||
{
|
||||
this.component[connectedEdge.id] = connectedComponentNumber;
|
||||
}
|
||||
}
|
||||
else if (connectedEdge && !(connectedEdge.id in this.component))
|
||||
{
|
||||
this.component[connectedEdge.id] = connectedComponentNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.connectedComponentNumber = connectedComponentNumber;
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
this.selectedObjects = this.component;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
FindConnectedComponentNew.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
|
||||
}
|
||||
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateConnectedComponetsNew(graph, app)
|
||||
{
|
||||
return new FindConnectedComponentNew(graph)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateConnectedComponetsNew);
|
||||
87
script/plugins/EulerianLoop.js
Normal file
87
script/plugins/EulerianLoop.js
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Find Eulerian Loop.
|
||||
*
|
||||
*/
|
||||
function FindEulerianLoop(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.message = g_processing;
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindEulerianLoop.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
|
||||
|
||||
FindEulerianLoop.prototype.getName = function(local)
|
||||
{
|
||||
return local == "ru" ? "Найти Эйлеров цикл" : "Find Eulerian cycle";
|
||||
}
|
||||
|
||||
FindEulerianLoop.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.FindEulerianCycle";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindEulerianLoop.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
FindEulerianLoop.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
this.CalculateAlgorithm("elloop=cgiInput&report=xml", function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FindEulerianLoop.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
result = results.length > 0 && results[0].value > 0 && results[0].type == 1;
|
||||
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
|
||||
this.message = result > 0 ? g_hasEulerianLoop : g_hasNotEulerianLoop;
|
||||
if (result > 0)
|
||||
{
|
||||
var nodesPath = this.GetNodesPath(results, 1, results.length - 1);
|
||||
outputResult["paths"] = [];
|
||||
outputResult["paths"].push(nodesPath);
|
||||
this.selectedObjects = [];
|
||||
|
||||
for (var i = 0; i < pathObjects.length; i++)
|
||||
{
|
||||
this.selectedObjects[pathObjects[i].id] = 1;
|
||||
}
|
||||
|
||||
this.message = this.message + ": ";
|
||||
for (var i = 0; i < nodesPath.length; i++)
|
||||
{
|
||||
this.message = this.message + this.graph.FindVertex(nodesPath[i]).mainText + ((i < nodesPath.length - 1) ? "⇒" : "");
|
||||
}
|
||||
}
|
||||
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
FindEulerianLoop.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
|
||||
}
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateFindEulerianLoop(graph, app)
|
||||
{
|
||||
return new FindEulerianLoop(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateFindEulerianLoop);
|
||||
152
script/plugins/MinimumSpanningTree.js
Normal file
152
script/plugins/MinimumSpanningTree.js
Normal file
@@ -0,0 +1,152 @@
|
||||
|
||||
function MinimumSpanningTree(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
this.isNotConneted = false;
|
||||
this.MST = 0;
|
||||
this.edges = [];
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
MinimumSpanningTree.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
|
||||
MinimumSpanningTree.prototype.getName = function(local)
|
||||
{
|
||||
return local == "ru" ? "Поиск минимального остовного дерева" : "Search of minimum spanning tree";
|
||||
}
|
||||
|
||||
MinimumSpanningTree.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.minimalSpanningTree";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
MinimumSpanningTree.prototype.getMessage = function(local)
|
||||
{
|
||||
if (!this.isNotConneted )
|
||||
{
|
||||
return local == "ru" ? "Вес минимального оставного дерева равнен " + this.MST : "Weight of minimum spanning tree is " + this.MST;
|
||||
}
|
||||
else
|
||||
{
|
||||
return local == "ru" ? "Граф не является связным" : "Graph is disconnected";
|
||||
}
|
||||
}
|
||||
|
||||
MinimumSpanningTree.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.MST = 0;
|
||||
this.edges = [];
|
||||
this.isNotConneted = true;
|
||||
var tempVertexes = this.graph.vertices.slice();
|
||||
connectedVertex = getVertexToVertexArray(this.graph, false);
|
||||
|
||||
if (!this.graph.hasDirectEdge())
|
||||
{
|
||||
res = this.resultStartedFrom(tempVertexes[0], connectedVertex);
|
||||
this.isNotConneted = res.isNotConneted;
|
||||
if (!this.isNotConneted)
|
||||
{
|
||||
this.MST = res.MST;
|
||||
this.edges = res.edges;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < tempVertexes.length; i++)
|
||||
{
|
||||
res = this.resultStartedFrom(tempVertexes[i], connectedVertex);
|
||||
if (!res.isNotConneted)
|
||||
{
|
||||
this.isNotConneted = res.isNotConneted;
|
||||
if (this.MST == 0 || res.MST < this.MST)
|
||||
{
|
||||
console.log(res);
|
||||
this.MST = res.MST;
|
||||
this.edges = res.edges;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MinimumSpanningTree.prototype.resultStartedFrom = function(vertex, connectedVertex)
|
||||
{
|
||||
var res = {};
|
||||
res.MST = 0;
|
||||
res.edges = [];
|
||||
res.isNotConneted = false;
|
||||
|
||||
var inTree = [];
|
||||
inTree.push(vertex);
|
||||
var vertecesInTree = 0;
|
||||
|
||||
// Will break in end of loop
|
||||
while (true)
|
||||
{
|
||||
vertecesInTree++;
|
||||
var minVert = null;
|
||||
var minEdge = null;
|
||||
|
||||
for (i = 0; i < inTree.length; i++)
|
||||
{
|
||||
var element = inTree[i];
|
||||
|
||||
if (connectedVertex.hasOwnProperty(element.id))
|
||||
{
|
||||
for (j = 0; j < connectedVertex[element.id].length; j++)
|
||||
{
|
||||
var connectedElement = connectedVertex[element.id][j];
|
||||
var connectedEdge = this.graph.FindEdge(element.id, connectedElement.id);
|
||||
if (inTree.indexOf(connectedElement) < 0)
|
||||
{
|
||||
if (minEdge == null || minEdge.weight > connectedEdge.weight)
|
||||
{
|
||||
minEdge = connectedEdge;
|
||||
minVert = connectedElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minVert == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.MST = res.MST + Number(minEdge.weight);
|
||||
inTree.push(minVert);
|
||||
res.edges.push(minEdge);
|
||||
}
|
||||
}
|
||||
|
||||
res.isNotConneted = (inTree.length < this.graph.vertices.length);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
MinimumSpanningTree.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return this.isNotConneted ? 0 :
|
||||
(object instanceof BaseVertex || this.edges.indexOf(object) >= 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
// Factory for algorithm.
|
||||
function CreateMinimumSpanningTree(graph, app)
|
||||
{
|
||||
return new MinimumSpanningTree(graph)
|
||||
}
|
||||
|
||||
// Register connected component.
|
||||
RegisterAlgorithm (CreateMinimumSpanningTree);
|
||||
|
||||
212
script/plugins/ShortestPath.js
Normal file
212
script/plugins/ShortestPath.js
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* Find short path.
|
||||
*
|
||||
*/
|
||||
function FindShortPathNew(graph, app)
|
||||
{
|
||||
BaseAlgorithmEx.apply(this, arguments);
|
||||
this.message = g_selectStartVertexForShortPath;
|
||||
this.selectedObjects = {};
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
FindShortPathNew.prototype = Object.create(BaseAlgorithmEx.prototype);
|
||||
// First selected.
|
||||
FindShortPathNew.prototype.firstObject = null;
|
||||
// Second selected.
|
||||
FindShortPathNew.prototype.secondObject = null;
|
||||
// Path
|
||||
FindShortPathNew.prototype.pathObjects = null;
|
||||
|
||||
|
||||
FindShortPathNew.prototype.getName = function(local)
|
||||
{
|
||||
return local == "ru" ? "Найти кратчайший путь" : "Find shortest path";
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.FindShortestPath";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
FindShortPathNew.prototype.getMessage = function(local)
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.result = function(resultCallback)
|
||||
{
|
||||
if (this.firstObject && this.secondObject)
|
||||
{
|
||||
this.outResultCallback = function (result ) { resultCallback(result); };
|
||||
self = this;
|
||||
this.CalculateAlgorithm("dsp=cgiInput&start=" + this.firstObject.id + "&finish=" + this.secondObject.id + "&report=xml", function (pathObjects, properties, results)
|
||||
{
|
||||
self.resultCallback(pathObjects, properties, results);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.resultCallback = function(pathObjects, properties, results)
|
||||
{
|
||||
var outputResult = {};
|
||||
outputResult["version"] = 1;
|
||||
|
||||
this.pathObjects = pathObjects;
|
||||
this.properties = properties;
|
||||
|
||||
var bFound = results.length > 0 && results[0].value < 1E5 && (results[0].type == 1 || results[0].type == 2);
|
||||
|
||||
if (bFound)
|
||||
{
|
||||
this.selectedObjects = {};
|
||||
|
||||
for (var i = 0; i < pathObjects.length; i++)
|
||||
{
|
||||
this.selectedObjects[pathObjects[i].id] = 1;
|
||||
}
|
||||
|
||||
this.message = g_shortestPathResult.replace("%d", (results[0].value * 1).toString());
|
||||
|
||||
var nodesPath = this.GetNodesPath(results, 1, results.length - 1);
|
||||
outputResult["paths"] = [];
|
||||
outputResult["paths"].push(nodesPath);
|
||||
|
||||
this.message = this.message + ": ";
|
||||
for (var i = 0; i < nodesPath.length; i++)
|
||||
{
|
||||
this.message = this.message + this.graph.FindVertex(nodesPath[i]).mainText + ((i < nodesPath.length - 1) ? "⇒" : "");
|
||||
}
|
||||
|
||||
this.message = this.message + " <select style=\"float:right\" id=\"enumReport\"></select>";
|
||||
|
||||
this.updateUpText();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.message = g_pathNotExists;
|
||||
}
|
||||
this.secondObject = null;
|
||||
this.firstObject = null;
|
||||
|
||||
this.outResultCallback(outputResult);
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.selectVertex = function(vertex)
|
||||
{
|
||||
this.pathObjects = null;
|
||||
this.shortDist = null;
|
||||
|
||||
if (this.firstObject)
|
||||
{
|
||||
this.message = g_processing;
|
||||
this.secondObject = vertex;
|
||||
this.selectedObjects = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.firstObject = vertex;
|
||||
this.secondObject = null;
|
||||
this.selectedObjects = {};
|
||||
this.message = g_selectFinishVertexForShortPath;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.deselectAll = function()
|
||||
{
|
||||
this.firstObject = null;
|
||||
this.secondObject = null;
|
||||
this.selectedObjects = {};
|
||||
this.message = g_selectStartVertexForShortPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.instance = function()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : ((object == this.firstObject || object == object.secondObject) ? 1 : 0);
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.messageWasChanged = function()
|
||||
{
|
||||
var enumReport = document.getElementById("enumReport");
|
||||
if (enumReport)
|
||||
{
|
||||
var optionFull = document.createElement('option');
|
||||
optionFull.text = g_fullReport;
|
||||
optionFull.value = 0;
|
||||
|
||||
var optionShort = document.createElement('option');
|
||||
optionShort.text = g_shortReport;
|
||||
optionShort.value = 1;
|
||||
|
||||
enumReport.add(optionFull, 0);
|
||||
enumReport.add(optionShort, 1);
|
||||
|
||||
enumReport.selectedIndex = this.app.GetCurrentValue("findShortPathReportType", 1);
|
||||
|
||||
var self = this;
|
||||
enumReport.onchange = function () {
|
||||
self.changedType();
|
||||
self.app.redrawGraph();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FindShortPathNew.prototype.changedType = function()
|
||||
{
|
||||
var enumReport = document.getElementById("enumReport");
|
||||
|
||||
this.app.SetCurrentValue("findShortPathReportType", enumReport.options[enumReport.selectedIndex].value);
|
||||
this.updateUpText();
|
||||
}
|
||||
|
||||
FindShortPathNew.prototype.updateUpText = function()
|
||||
{
|
||||
var reportType = this.app.GetCurrentValue("findShortPathReportType", 1);
|
||||
|
||||
if (reportType == 0)
|
||||
{
|
||||
for (var i = 0; i < this.graph.vertices.length; i++)
|
||||
{
|
||||
var object = this.graph.vertices[i];
|
||||
if (this.properties.hasOwnProperty(object.id))
|
||||
{
|
||||
var propertie = this.properties[object.id];
|
||||
if (propertie.hasOwnProperty('lowestDistance'))
|
||||
{
|
||||
object.upText = g_shortestDistance + (propertie.lowestDistance > 1E5 ? "\u221E" : (propertie.lowestDistance * 1).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < this.graph.vertices.length; i++)
|
||||
{
|
||||
this.graph.vertices[i].upText = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateFindShortPathNew(graph, app)
|
||||
{
|
||||
return new FindShortPathNew(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateFindShortPathNew);
|
||||
73
script/plugins/VerticesDegree.js
Normal file
73
script/plugins/VerticesDegree.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Algorithm samble.
|
||||
*
|
||||
*/
|
||||
function VerticesDegree(graph, app)
|
||||
{
|
||||
BaseAlgorithm.apply(this, arguments);
|
||||
this.degree = {};
|
||||
this.maxDegree = 0;
|
||||
}
|
||||
|
||||
|
||||
// inheritance.
|
||||
VerticesDegree.prototype = Object.create(BaseAlgorithm.prototype);
|
||||
|
||||
|
||||
VerticesDegree.prototype.getName = function(local)
|
||||
{
|
||||
return local == "ru" ? "Рассчитать степень вершин" : "Calculate vertices degree";
|
||||
}
|
||||
|
||||
VerticesDegree.prototype.getId = function()
|
||||
{
|
||||
return "OlegSh.VertexDegree";
|
||||
}
|
||||
|
||||
// @return message for user.
|
||||
VerticesDegree.prototype.getMessage = function(local)
|
||||
{
|
||||
return (local == "ru" ? "Максимальная степень вершин графа равна " : "The maximum degree of a graph is ") + this.maxDegree;
|
||||
}
|
||||
|
||||
VerticesDegree.prototype.result = function(resultCallback)
|
||||
{
|
||||
this.degree = {};
|
||||
this.maxDegree = 0;
|
||||
|
||||
var result = {};
|
||||
result["version"] = 1;
|
||||
this.degree = getVertexToVertexArray(this.graph, false);
|
||||
var graph = this.graph;
|
||||
|
||||
for (var i = 0; i < graph.vertices.length; i++)
|
||||
{
|
||||
var vertex = graph.vertices[i];
|
||||
var currentDegree = 0;
|
||||
|
||||
if (this.degree.hasOwnProperty(vertex.id))
|
||||
{
|
||||
currentDegree = this.degree[vertex.id].length;
|
||||
this.maxDegree = Math.max(this.maxDegree, currentDegree);
|
||||
}
|
||||
|
||||
vertex.upText = currentDegree;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VerticesDegree.prototype.getObjectSelectedGroup = function(object)
|
||||
{
|
||||
return (this.degree.hasOwnProperty(object.id)) ? this.degree[object.id].length: 0;
|
||||
}
|
||||
|
||||
|
||||
// Factory for connected components.
|
||||
function CreateAlgorithmVerticesDegree(graph, app)
|
||||
{
|
||||
return new VerticesDegree(graph, app)
|
||||
}
|
||||
|
||||
// Gerister connected component.
|
||||
RegisterAlgorithm (CreateAlgorithmVerticesDegree);
|
||||
132
script/point.js
Normal file
132
script/point.js
Normal file
@@ -0,0 +1,132 @@
|
||||
function Point(x, y){
|
||||
this.x = x || 0;
|
||||
this.y = y || 0;
|
||||
};
|
||||
Point.prototype.x = null;
|
||||
Point.prototype.y = null;
|
||||
Point.prototype.add = function(v){
|
||||
return new Point(this.x + v.x, this.y + v.y);
|
||||
};
|
||||
Point.prototype.addValue = function(v){
|
||||
return new Point(this.x + v, this.y + v);
|
||||
};
|
||||
Point.prototype.clone = function(){
|
||||
return new Point(this.x, this.y);
|
||||
};
|
||||
Point.prototype.degreesTo = function(v){
|
||||
var dx = this.x - v.x;
|
||||
var dy = this.y - v.y;
|
||||
var angle = Math.atan2(dy, dx); // radians
|
||||
return angle * (180 / Math.PI); // degrees
|
||||
};
|
||||
Point.prototype.distance = function(v){
|
||||
return Math.sqrt(this.distanceSqr(v));
|
||||
};
|
||||
Point.prototype.distanceSqr = function(v){
|
||||
var x = this.x - v.x;
|
||||
var y = this.y - v.y;
|
||||
return x * x + y * y;
|
||||
};
|
||||
Point.prototype.equals = function(toCompare){
|
||||
return this.x == toCompare.x && this.y == toCompare.y;
|
||||
};
|
||||
Point.prototype.interpolate = function(v, f){
|
||||
return new Point((this.x + v.x) * f, (this.y + v.y) * f);
|
||||
};
|
||||
Point.prototype.length = function(){
|
||||
return Math.sqrt(this.x * this.x + this.y * this.y);
|
||||
};
|
||||
Point.prototype.normalize = function(thickness){
|
||||
var l = this.length();
|
||||
this.x = this.x / l * thickness;
|
||||
this.y = this.y / l * thickness;
|
||||
return new Point(this.x, this.y);
|
||||
};
|
||||
Point.prototype.normalizeCopy = function(thickness){
|
||||
var l = this.length();
|
||||
return new Point(this.x / l * thickness, this.y / l * thickness);
|
||||
};
|
||||
Point.prototype.orbit = function(origin, arcWidth, arcHeight, degrees){
|
||||
var radians = degrees * (Math.PI / 180);
|
||||
this.x = origin.x + arcWidth * Math.cos(radians);
|
||||
this.y = origin.y + arcHeight * Math.sin(radians);
|
||||
};
|
||||
Point.prototype.rotate = function(center, degrees){
|
||||
var radians = degrees * (Math.PI / 180);
|
||||
offset = this.subtract(center);
|
||||
this.x = offset.x * Math.cos(radians) - offset.y * Math.sin(radians);
|
||||
this.y = offset.x * Math.sin(radians) + offset.y * Math.cos(radians);
|
||||
this.x = this.x + center.x;
|
||||
this.y = this.y + center.y;
|
||||
};
|
||||
|
||||
Point.prototype.offset = function(dx, dy){
|
||||
this.x += dx;
|
||||
this.y += dy;
|
||||
};
|
||||
Point.prototype.subtract = function(v){
|
||||
return new Point(this.x - v.x, this.y - v.y);
|
||||
};
|
||||
Point.prototype.subtractValue = function(value){
|
||||
return new Point(this.x - value, this.y - value);
|
||||
};
|
||||
Point.prototype.multiply = function(value){
|
||||
return new Point(this.x * value, this.y * value);
|
||||
};
|
||||
Point.prototype.toString = function(){
|
||||
return "(x=" + this.x + ", y=" + this.y + ")";
|
||||
};
|
||||
|
||||
Point.prototype.normal = function(){
|
||||
return new Point(-this.y, this.x);
|
||||
};
|
||||
|
||||
Point.prototype.min = function(point)
|
||||
{
|
||||
return new Point(Math.min(this.x, point.x), Math.min(this.y, point.y));
|
||||
};
|
||||
|
||||
Point.prototype.max = function(point)
|
||||
{
|
||||
return new Point(Math.max(this.x, point.x), Math.max(this.y, point.y));
|
||||
};
|
||||
|
||||
Point.prototype.inverse = function()
|
||||
{
|
||||
return new Point(-this.x, -this.y);
|
||||
};
|
||||
|
||||
Point.interpolate = function(pt1, pt2, f){
|
||||
return new Point(pt1.x * (1.0 - f) + pt2.x * f, pt1.y * (1.0 - f) + pt2.y * f);
|
||||
};
|
||||
Point.polar = function(len, angle){
|
||||
return new Point(len * Math.cos(angle), len * Math.sin(angle));
|
||||
};
|
||||
Point.distance = function(pt1, pt2){
|
||||
var x = pt1.x - pt2.x;
|
||||
var y = pt1.y - pt2.y;
|
||||
return Math.sqrt(x * x + y * y);
|
||||
};
|
||||
|
||||
Point.center = function(pt1, pt2){
|
||||
return new Point((pt1.x + pt2.x) / 2.0, (pt1.y + pt2.y) / 2.0);
|
||||
};
|
||||
|
||||
Point.toString = function(){
|
||||
return x + " " + y;
|
||||
}
|
||||
|
||||
function Rect(minPoint, maxPoint){
|
||||
this.minPoint = minPoint;
|
||||
this.maxPoint = maxPoint;
|
||||
};
|
||||
|
||||
Rect.prototype.center = function()
|
||||
{
|
||||
return Point.center(this.minPoint, this.maxPoint);
|
||||
};
|
||||
|
||||
Rect.prototype.size = function()
|
||||
{
|
||||
return this.maxPoint.subtract(this.minPoint);
|
||||
};
|
||||
136
script/texts.js
Normal file
136
script/texts.js
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Place here all tests constans.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
var g_textsSelectAndMove = "Drag objects";
|
||||
var g_moveCursorForMoving = "Move cursor";
|
||||
var g_clickToAddVertex = "Click to add vertex";
|
||||
var g_selectFisrtVertexToConnect = "Select first vertex to connect";
|
||||
var g_selectSecondVertexToConnect = "Select second vertex to connect";
|
||||
var g_selectStartVertexForShortPath = "Select start vertex for shortest path";
|
||||
var g_selectFinishVertexForShortPath = "Select finish vertex for shortest path";
|
||||
var g_shortestPathResult = "Shortest path is %d";
|
||||
var g_pathNotExists = "Path does not exists";
|
||||
var g_selectObjectToDelete = "Select object to delete";
|
||||
|
||||
|
||||
var g_addEdge = "Add edge";
|
||||
var g_orintEdge = "Orient";
|
||||
var g_notOrintEdge = "not Orient";
|
||||
|
||||
var g_adjacencyMatrixText = "Adjacency Matrix";
|
||||
var g_save = "Save";
|
||||
var g_cancel = "Cancel";
|
||||
|
||||
var g_shortestDistance = "lowest-distance is ";
|
||||
var g_incidenceMatrixText = "Incidence Matrix";
|
||||
|
||||
var g_save_dialog = "Save dialog";
|
||||
var g_close = "close";
|
||||
var g_sickConnectedComponent = "Sick connected component is ";
|
||||
var g_connectedComponent = "Connected component is ";
|
||||
|
||||
|
||||
var g_what_do_you_think = "What do you think about site?";
|
||||
var g_name = "Name";
|
||||
var g_feedback = "Feedback";
|
||||
var g_send = "Send";
|
||||
var g_write_to_us = "Write to us";
|
||||
|
||||
var g_fixMatrix = "Fix matrix";
|
||||
var g_readMatrixHelp = "Matrix format help";
|
||||
var g_matrixWrongFormat = "Matrix is wrong";
|
||||
|
||||
var g_save_image_dialog = "Save graph image";
|
||||
|
||||
var g_fullReport = "Full report";
|
||||
|
||||
var g_shortReport = "Short report";
|
||||
|
||||
var g_hasEulerianLoop = "Graph has Eulerian Loop";
|
||||
var g_hasNotEulerianLoop = "Graph has not Eulerian Loop";
|
||||
|
||||
var g_processing = "Processing...";
|
||||
|
||||
var g_customEnumVertex = "Custom";
|
||||
var g_addVertex = "Add vertex";
|
||||
|
||||
var g_renameVertex = "Rename vertex";
|
||||
var g_rename = "Rename";
|
||||
|
||||
var g_language = "en";
|
||||
|
||||
var g_editWeight = "Edit weight";
|
||||
|
||||
var g_noWeight = "No weight";
|
||||
var g_groupRename = "Group rename";
|
||||
|
||||
function loadTexts()
|
||||
{
|
||||
g_textsSelectAndMove = document.getElementById("SelectAndMoveObject").innerHTML;
|
||||
g_moveCursorForMoving = document.getElementById("MoveCursorForMoving").innerHTML;
|
||||
g_clickToAddVertex = document.getElementById("clickToAddVertex").innerHTML;
|
||||
g_selectFisrtVertexToConnect = document.getElementById("selectFisrtVertextToConnect").innerHTML;
|
||||
g_selectSecondVertexToConnect = document.getElementById("selectSecondVertextToConnect").innerHTML;
|
||||
g_selectStartVertexForShortPath = document.getElementById("selectStartShortPathVertex").innerHTML;
|
||||
g_selectFinishVertexForShortPath = document.getElementById("selectFinishShortPathVertex").innerHTML;
|
||||
g_shortestPathResult = document.getElementById("shortPathResult").innerHTML;
|
||||
g_pathNotExists = document.getElementById("pathNotExists").innerHTML;
|
||||
g_selectObjectToDelete = document.getElementById("selectObjectToDelete").innerHTML;
|
||||
|
||||
g_addEdge = document.getElementById("AddEdge").innerHTML;
|
||||
g_orintEdge = document.getElementById("OrintEdge").innerHTML;
|
||||
g_notOrintEdge = document.getElementById("NotOrintdge").innerHTML;
|
||||
|
||||
g_adjacencyMatrixText = document.getElementById("AdjacencyMatrixText").innerHTML;
|
||||
g_save = document.getElementById("Save").innerHTML;
|
||||
g_cancel = document.getElementById("Cancel").innerHTML;
|
||||
|
||||
g_shortestDistance = document.getElementById("shortestDist").innerHTML;
|
||||
|
||||
g_incidenceMatrixText = document.getElementById("IncidenceMatrixText").innerHTML;
|
||||
|
||||
g_save_dialog = document.getElementById("saveDialogTitle").innerHTML;
|
||||
g_close = document.getElementById("closeButton").innerHTML;
|
||||
|
||||
g_sickConnectedComponent = document.getElementById("sickConnectedComponentResult").innerHTML;
|
||||
g_connectedComponent = document.getElementById("connectedComponentResult").innerHTML;
|
||||
|
||||
g_what_do_you_think = document.getElementById("whatDoYouThink").innerHTML;
|
||||
g_name = document.getElementById("name").innerHTML;
|
||||
g_feedback = document.getElementById("feedback").innerHTML;
|
||||
g_send = document.getElementById("send").innerHTML;
|
||||
g_write_to_us = document.getElementById("writeToUs").innerHTML;
|
||||
|
||||
|
||||
g_fixMatrix = document.getElementById("fixMatrixButton").innerHTML;
|
||||
g_readMatrixHelp = document.getElementById("matrixHelp").innerHTML;
|
||||
g_matrixWrongFormat = document.getElementById("wronMatrixTitle").innerHTML;
|
||||
|
||||
g_save_image_dialog = document.getElementById("saveImageDialogTitle").innerHTML;
|
||||
|
||||
g_fullReport = document.getElementById("fullReport").innerHTML;
|
||||
g_shortReport = document.getElementById("shortReport").innerHTML;
|
||||
|
||||
|
||||
g_hasEulerianLoop = document.getElementById("hasEulerianLoop").innerHTML;
|
||||
g_hasNotEulerianLoop = document.getElementById("hasNotEulerianLoop").innerHTML;
|
||||
|
||||
g_processing = document.getElementById("processing").innerHTML;
|
||||
|
||||
g_customEnumVertex = document.getElementById("customEnumVertex").innerHTML;
|
||||
|
||||
g_addVertex = document.getElementById("addVertexText").innerHTML;
|
||||
|
||||
g_renameVertex = document.getElementById("renameVertex").innerHTML;
|
||||
g_rename = document.getElementById("renameText").innerHTML;
|
||||
|
||||
g_language = document.getElementById("currentLanguage").innerHTML;
|
||||
|
||||
g_editWeight = document.getElementById("editWeight").innerHTML;
|
||||
|
||||
g_noWeight = document.getElementById("noWeight").innerHTML;
|
||||
g_groupRename = document.getElementById("groupeRenameText").innerHTML;
|
||||
}
|
||||
Reference in New Issue
Block a user