Change script location.

Split js code.
Added cache and changed loading mechanism for js sources.
This commit is contained in:
Oleg Sh
2023-11-06 19:16:50 +02:00
parent c29ad15e3c
commit 43a4b44a22
86 changed files with 7738 additions and 3383 deletions

View File

@@ -0,0 +1,59 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Add Graph handler.
*
*/
function AddGraphHandler(app)
{
this.removeStack = true;
BaseHandler.apply(this, arguments);
this.message = g_clickToAddVertex;
this.addContextMenu();
}
// inheritance.
AddGraphHandler.prototype = Object.create(BaseHandler.prototype);
AddGraphHandler.prototype.MouseDown = function(pos)
{
this.app.PushToStack("Add");
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.GetEnumVerticesList();
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.SetEnumVerticesType(enumVertexsText.options[enumVertexsText.selectedIndex].value);
}

View File

@@ -0,0 +1,131 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Algorithm Graph handler.
*
*/
function AlgorithmGraphHandler(app, algorithm)
{
BaseHandler.apply(this, arguments);
this.algorithm = algorithm;
this.SaveUpText();
this.UpdateResultAndMessage();
}
// 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.UpdateResultAndMessage();
}
else if (selectedObject && (selectedObject instanceof BaseEdge))
{
if (this.algorithm.selectEdge(selectedObject))
{
this.needRedraw = true;
}
this.UpdateResultAndMessage();
}
else
{
if (this.algorithm.deselectAll())
{
this.needRedraw = true;
this.UpdateResultAndMessage();
}
}
}
}
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();
}
if (this.algorithm.wantRestore())
{
this.algorithm.restore();
}
}
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.UpdateResultAndMessage = 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();
}
AlgorithmGraphHandler.prototype.GetMessage = function()
{
return this.algorithm.getMessage(g_language);
}

View File

@@ -0,0 +1,35 @@
{
let modulDir = "features/algorithms/";
doInclude ([
include ("model/Algorithms.js", modulDir),
include ("model/BaseTraversal.js", modulDir)
])
function loadAsyncAlgorithms(onFinish) {
let pluginsList = ["BFS.js",
"Coloring.js",
"ConnectedComponent.js",
"DFS.js",
"EulerianLoop.js",
"EulerianPath.js",
"FindAllPatches.js",
"FindLongestPath.js",
"FindShortPatchsFromOne.js",
"Floid.js",
"GraphReorder.js",
"HamiltonianLoop.js",
"HamiltonianPath.js",
"IsomorphismCheck.js",
"MaxClique.js",
"MaxFlow.js",
"MinimumSpanningTree.js",
"ModernGraphStyle.js",
"RadiusAndDiameter.js",
"ShortestPath.js",
"VerticesDegree.js"];
doIncludeAsync (pluginsList.map((plugin) => include ("model/plugins/" + plugin, modulDir)), onFinish);
}
}

View File

@@ -0,0 +1,305 @@
/**
* File for algorithms.
*
*/
// Return list of 'vertex = [connected vertices]'
function getVertexToVertexArray(graph, ignoreDirection)
{
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 || ignoreDirection)
{
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 algorithm.
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 algorithm. For now we supports only 2 locals: "ru" and "en"
BaseAlgorithm.prototype.getName = function(local)
{
return "unknown_name_" + local;
}
// @return id of algorithm. 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 true, if you change restore graph after use.
BaseAlgorithm.prototype.wantRestore = function()
{
return false;
}
// calls this method if wantRestore return true.
BaseAlgorithm.prototype.restore = function()
{
}
// @return 0, if object is not selected, in other case return groupe of selection.
BaseAlgorithm.prototype.getObjectSelectedGroup = function(object)
{
return 0;
}
// This method is called, when messages was updated on html page.
BaseAlgorithm.prototype.messageWasChanged = function() {}
// Algorithm priority in menu
BaseAlgorithm.prototype.getPriority = function()
{
return 0;
}
// Algorithm support multi graph
BaseAlgorithm.prototype.IsSupportMultiGraph = function()
{
return false;
}
BaseAlgorithm.prototype.getCategory = function()
{
return 0;
}
/**
* 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(algorithmName, otherParams, resultCallback, ignoreSeparateNodes = false)
{
if (location.hostname === "localhost" || location.hostname === "127.0.0.1")
console.log(algorithmName + " " + otherParams);
var graph = this.graph;
var ignoreNodes = {};
if (ignoreSeparateNodes)
for (var i = 0; i < graph.vertices.length; i++)
if (!graph.HasConnectedNodes(graph.vertices[i]))
ignoreNodes[graph.vertices[i].id] = 1;
var creator = new GraphMLCreator(graph.vertices, graph.edges, ignoreNodes);
var pathObjects = [];
var properties = {};
var result = [];
var xml = creator.GetXMLString();
console.log(xml);
var processResult = 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');
var edge = graph.FindEdge(source, target);
if (typeof $(this).attr('id') !== 'undefined')
{
edge = graph.FindEdgeById($(this).attr('id'));
}
pathObjects.push(edge);
$data = $(this).find("data");
$data.each(function(){
if (!properties[edge.id])
{
properties[edge.id] = {};
}
properties[edge.id][$(this).attr('key')] = $(this).text();
});
});
console.log(result);
resultCallback(pathObjects, properties, result);
};
if (this.app.isSupportEmscripten()) {
console.log("Use Emscripten");
var delimiter = "<s\\emscript_split\\s>";
var processData = algorithmName + delimiter + xml +
delimiter + "report" + delimiter + "xml";
otherParams.forEach ( (param) => processData += delimiter + param.name + delimiter + param.value);
var res = this.app.processEmscripten(processData);
processResult(res);
} else {
console.log("Use new CGI");
var queryString = algorithmName + "=cgiInput&report=xml";
otherParams.forEach ( (param) => queryString += "&" + param.name + "=" + param.value);
$.ajax({
type: "POST",
url: "/" + SiteDir + "cgi-bin/GraphCGI.exe?" + queryString,
data: xml,
dataType: "text",
})
.done(function( msg )
{
processResult(msg);
});
}
return true;
}
BaseAlgorithmEx.prototype.GetNodesPath = function(array, start, count)
{
var res = [];
for (var index = start; index < start + count; index++)
{
if (array[index].type == 4)
{
res.push(array[index].value);
}
}
return res;
}
BaseAlgorithmEx.prototype.GetNodesEdgesPath = function(array, start, count)
{
var res = [];
for (var index = start; index < start + count; index++)
{
if (array[index].type == 4 || array[index].type == 5)
{
res.push(array[index].value);
}
}
return res;
}

View File

@@ -0,0 +1,56 @@
/**
* Find short path.
*
*/
function BaseTraversal(graph, app)
{
BaseAlgorithmEx.apply(this, arguments);
this.visited = [];
this.edges = [];
this.timer = null;
}
// inheritance.
BaseTraversal.prototype = Object.create(BaseAlgorithmEx.prototype);
// timer interval
BaseTraversal.prototype.timerInterval = 500;
BaseTraversal.prototype.result = function(resultCallback)
{
var result = {};
result["version"] = 1;
return result;
}
BaseTraversal.prototype.selectVertex = function(vertex)
{
this.visited = [];
this.edges = [];
if (this.timer)
clearTimeout(this.timer);
this.timer = null;
this.visited.push(vertex);
var context = this;
this.timer = setInterval(function()
{
context.step();
}, this.timerInterval);
this.message = this.getMainMessage();
return true;
}
BaseTraversal.prototype.getObjectSelectedGroup = function(object)
{
return (this.visited.includes(object) ? 1 : (this.edges.includes(object) ? 1 : 0));
}
BaseTraversal.prototype.instance = function()
{
return false;
}

View File

@@ -0,0 +1,125 @@
/**
* Find short path.
*
*/
function BFSAlgorithm(graph, app)
{
BaseTraversal.apply(this, arguments);
this.message = g_startTraversal;
}
// inheritance.
BFSAlgorithm.prototype = Object.create(BaseTraversal.prototype);
// timer interval
BFSAlgorithm.prototype.timerInterval = 500;
BFSAlgorithm.prototype.getName = function(local)
{
return g_BFSName;// local == "ru" ? "Поиск в ширину" : "Breadth-first search";
}
BFSAlgorithm.prototype.getId = function()
{
return "OlegSh.BFSAlgorithm";
}
// @return message for user.
BFSAlgorithm.prototype.getMessage = function(local)
{
return this.message;
}
BFSAlgorithm.prototype.getCategory = function()
{
return 1;
}
BFSAlgorithm.prototype.result = function(resultCallback)
{
var result = {};
result["version"] = 1;
return result;
}
BFSAlgorithm.prototype.getMainMessage = function()
{
var message = g_traversalOrder;
// calculate.
var tempVisited = this.visited.slice();
var tempEdge = [];
var oldLength = 0;
while (oldLength < tempVisited.length)
{
oldLength = tempVisited.length;
for (var i = 0; i < tempVisited.length; i++)
{
if (this.bfs(tempVisited[i], tempVisited, tempEdge))
break;
}
}
// Format message
for (var i = 0; i < tempVisited.length; i ++)
{
tempVisited[i].upText = (i + 1) + "";
message = message + tempVisited[i].mainText + " ";
}
return message;
}
BFSAlgorithm.prototype.getPriority = function()
{
return -9.5;
}
BFSAlgorithm.prototype.step = function()
{
for (var i = 0; i < this.visited.length; i++)
{
if (this.bfs(this.visited[i], this.visited, this.edges))
{
this.app.redrawGraph();
return;
}
}
clearTimeout(this.timer);
this.timer = null;
return;
}
BFSAlgorithm.prototype.bfs = function(vertex, vertexArray, edgeArray)
{
for (var i = 0; i < this.graph.vertices.length; i ++)
{
var nextVertex = this.graph.vertices[i];
var edge = this.graph.FindEdgeAny(vertex.id, nextVertex.id);
if (edge && !vertexArray.includes(nextVertex))
{
edgeArray.push(edge);
vertexArray.push(nextVertex);
return true;
}
}
return false;
}
// Algorithm support multi graph
BFSAlgorithm.prototype.IsSupportMultiGraph = function()
{
return true;
}
// Factory for connected components.
function CreateBFSAlgorithm(graph, app)
{
return new BFSAlgorithm(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateBFSAlgorithm);

View File

@@ -0,0 +1,386 @@
/**
* Default handler.
* Select using mouse, drag.
*
*/
function Coloring(graph, app)
{
BaseAlgorithm.apply(this, arguments);
this.connectedComponentNumber = 0;
this.component = {};
this.selectedObjects = [];
this.MaxColor = 1000;
}
// inheritance.
Coloring.prototype = Object.create(BaseAlgorithm.prototype);
Coloring.prototype.getName = function(local)
{
return g_ColoringName; //local == "ru" ? "Раскраска графа" : "Graph coloring";
}
Coloring.prototype.getId = function()
{
return "OlegSh.GraphColoring";
}
// @return message for user.
Coloring.prototype.getMessage = function(local)
{
return g_colorNumber + " " + this.connectedComponentNumber;
}
Coloring.prototype.result = function(resultCallback)
{
this.calculate(true);
var result = {};
result["version"] = 1;
this.selectedObjects = this.component;
return result;
}
Coloring.prototype.calculate = function(fillUpText = false)
{
this.connectedComponentNumber = 0;
this.component = {};
connectedVertex = getVertexToVertexArray(this.graph, true);
var listOfOrders = [];
this.addSimpleAndRandomOrders(listOfOrders);
this.addBasedOnDegree(listOfOrders, connectedVertex);
this.addForTree(listOfOrders, connectedVertex);
this.connectedComponentNumber = this.MaxColor;
// Find minimal variant.
for (var i = 0; i < listOfOrders.length; i++)
{
var coloringComponent = this.makeColoring(listOfOrders[i], connectedVertex);
if (coloringComponent["max"] < this.connectedComponentNumber)
{
this.component = coloringComponent;
this.connectedComponentNumber = coloringComponent["max"];
}
}
// Fill Up text
for (var i = 0; i < this.graph.vertices.length; i++)
{
this.graph.vertices[i].upText = this.component[this.graph.vertices[i].id];
}
//var result = {};
//result["version"] = 1;
//this.selectedObjects = this.component;
return this.connectedComponentNumber;
}
Coloring.prototype.makeColoring = function(vertexOrder, connectedVertex)
{
var res = {};
var maxColor = 0;
for (var i = 0; i < vertexOrder.length; i++)
{
var id = this.graph.vertices[vertexOrder[i]].id;
var hasColor = {};
if (id in connectedVertex)
{
// find color of neighbors.
for (var j = 0; j < connectedVertex[id].length; j++)
{
nearId = connectedVertex[id][j].id;
if (nearId in res)
{
hasColor[res[nearId]] = 1;
}
}
}
// find color for current vertex;
var color = 0;
for (var j = 1; j < this.MaxColor; j++)
{
if (!(j in hasColor))
{
color = j;
break;
}
}
res[id] = color;
maxColor = Math.max(maxColor, color);
}
res["max"] = maxColor;
return res;
}
Coloring.prototype.addSimpleAndRandomOrders = function(listOfOrders)
{
var vertexOrder = [];
for (var i = 0; i < this.graph.vertices.length; i++)
{
vertexOrder.push(i);
}
// As in graph
listOfOrders.push(vertexOrder);
// Push some randoms
for (var i = 0; i < Math.floor(Math.sqrt(this.graph.vertices.length)); i++)
{
listOfOrders.push(this.shuffleArray(vertexOrder));
}
}
Coloring.prototype.addBasedOnDegree = function(listOfOrders, connectedVertex)
{
var vertexDegree = [];
for (var i = 0; i < this.graph.vertices.length; i++)
{
var degree = 0;
var id = this.graph.vertices[i].id;
if (id in connectedVertex)
{
degree = connectedVertex[id].length;
}
vertexDegree.push({index : i, degree : degree});
}
// sort
vertexDegree.sort(
function(a, b) {
return (a.degree > b.degree) ? -1 :
((b.degree > a.degree) ? 1 : 0);
});
var vertexOrder = [];
for (var i = 0; i < vertexDegree.length; i++)
{
vertexOrder.push(vertexDegree[i].index);
}
//console.log(vertexDegree);
// Sorted by degree.
listOfOrders.push(vertexOrder);
var shuffleLitle = vertexOrder.slice();
for (var i = 0; i < shuffleLitle.length - 1; i +=2)
{
var t = shuffleLitle[i];
shuffleLitle[i] = shuffleLitle[i + 1];
shuffleLitle[i + 1] = t;
}
// Swap near.
listOfOrders.push(shuffleLitle);
// shufl by half
if (vertexDegree.length > 1)
{
var pivotElement = Math.round(vertexOrder.length / 2);
var randomByPart = this.shuffleArray(vertexOrder.slice(0, pivotElement)).concat(this.shuffleArray(vertexOrder.slice(pivotElement)));
listOfOrders.push(randomByPart);
// add with random pivots
for (var i = 0; i < Math.floor(Math.sqrt(this.graph.vertices.length)); i++)
{
var pivot = Math.floor(Math.random() * (vertexOrder.length - 2)) + 1;
var randomByPart = this.shuffleArray(vertexOrder.slice(0, pivot)).concat(this.shuffleArray(vertexOrder.slice(pivot)));
listOfOrders.push(randomByPart);
//console.log(randomByPart);
}
}
}
Coloring.prototype.addForTree = function(listOfOrders, connectedVertex)
{
var vertexDegree = [];
var idToIndex = {};
var idToDegree = {};
for (var i = 0; i < this.graph.vertices.length; i++)
{
var degree = 0;
var id = this.graph.vertices[i].id;
if (id in connectedVertex)
{
degree = connectedVertex[id].length;
}
vertexDegree.push({index : i, degree : degree});
idToIndex[id] = i;
idToDegree[id] = degree;
}
// sort
vertexDegree.sort(
function(a, b) {
return (a.degree > b.degree) ? -1 :
((b.degree > a.degree) ? 1 : 0);
});
var vertexDegreeOrder = [];
for (var i = 0; i < vertexDegree.length; i++)
{
vertexDegreeOrder.push(vertexDegree[i].index);
}
{
var wasAdded = {};
var resSimple = [];
//------ simple near ------
for (var i = 0; i < vertexDegreeOrder.length; i++)
{
var vertex = this.graph.vertices[vertexDegreeOrder[i]].id;
if (!(vertex in wasAdded))
{
wasAdded[vertex] = 1;
resSimple.push(idToIndex[vertex]);
var queue = [];
queue.push(vertex);
while (true)
{
var needBreak = true;
for (var j = 0; j < queue.length; j++)
{
var vertexId = queue[j];
if (vertexId in connectedVertex)
{
for (var k = 0; k < connectedVertex[vertexId].length; k++)
{
if (!(connectedVertex[vertexId][k].id in wasAdded))
{
var id = connectedVertex[vertexId][k].id;
wasAdded[id] = 1;
queue.push(id);
resSimple.push(idToIndex[id]);
needBreak = false;
}
}
}
}
if (needBreak)
{
break;
}
}
}
}
listOfOrders.push(resSimple);
}
//-------------------------------
//------ simple near with max degree
{
var wasAdded = {};
var resMaxDegree = [];
for (var i = 0; i < vertexDegreeOrder.length; i++)
{
var vertex = this.graph.vertices[vertexDegreeOrder[i]].id;
if (!(vertex in wasAdded))
{
wasAdded[vertex] = 1;
resMaxDegree.push(idToIndex[vertex]);
var queue = [];
queue.push(vertex);
while (true)
{
var needBreak = true;
for (var j = 0; j < queue.length; j++)
{
var vertexId = queue[j];
if (vertexId in connectedVertex)
{
var maxDegree = -1;
var vertexMaxId = -1;
for (var k = 0; k < connectedVertex[vertexId].length; k++)
{
if (!(connectedVertex[vertexId][k].id in wasAdded))
{
var id = connectedVertex[vertexId][k].id;
if (idToDegree[id] > maxDegree)
{
maxDegree = idToDegree[id];
vertexMaxId = id;
}
}
}
if (vertexMaxId >= 0)
{
wasAdded[vertexMaxId] = 1;
queue.push(vertexMaxId);
resMaxDegree.push(idToIndex[vertexMaxId]);
needBreak = false;
}
}
}
if (needBreak)
{
break;
}
}
}
}
listOfOrders.push(resMaxDegree);
}
//-------------------------------
}
Coloring.prototype.shuffleArray = function(a)
{
var j, x, i;
for (i = a.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
x = a[i];
a[i] = a[j];
a[j] = x;
}
return a;
}
Coloring.prototype.getObjectSelectedGroup = function(object)
{
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
}
Coloring.prototype.getPriority = function()
{
return -9.0;
}
// Algorithm support multi graph
Coloring.prototype.IsSupportMultiGraph = function()
{
return true;
}
// Factory for connected components.
function CreateColoring(graph, app)
{
return new Coloring(graph)
}
// Gerister connected component.
RegisterAlgorithm (CreateColoring);

View File

@@ -0,0 +1,130 @@
/**
* 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 g_findConnectedComponent; //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.calculate(true);
var result = {};
result["version"] = 1;
this.selectedObjects = this.component;
return result;
}
FindConnectedComponentNew.prototype.calculate = function(fillUpText = false)
{
this.connectedComponentNumber = 0;
this.component = {};
var tempVertices = this.graph.vertices.slice();
connectedVertex = getVertexToVertexArray(this.graph, true);
var connectedComponentNumber = 0;
while (tempVertices.length > 0)
{
connectedComponentNumber++;
var stack = [];
stack.push(tempVertices[0]);
tempVertices.splice(0, 1);
indexInStack = 0;
for (i = 0; i < stack.length; i++)
{
var stackElement = stack[i];
this.component[stackElement.id] = connectedComponentNumber;
if (fillUpText)
{
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.FindEdgeAny(stackElement.id, nextVertex.id);
if (stack.indexOf(nextVertex) < 0)
{
stack.push(nextVertex);
tempVertices.splice(tempVertices.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 this.connectedComponentNumber;
}
FindConnectedComponentNew.prototype.getObjectSelectedGroup = function(object)
{
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
}
FindConnectedComponentNew.prototype.getPriority = function()
{
return 0;
}
// Algorithm support multi graph
FindConnectedComponentNew.prototype.IsSupportMultiGraph = function()
{
return true;
}
// Factory for connected components.
function CreateConnectedComponetsNew(graph, app)
{
return new FindConnectedComponentNew(graph)
}
// Gerister connected component.
RegisterAlgorithm (CreateConnectedComponetsNew);

View File

@@ -0,0 +1,124 @@
/**
* Find short path.
*
*/
function DFSAlgorithm(graph, app)
{
BaseTraversal.apply(this, arguments);
this.message = g_startTraversal;
}
// inheritance.
DFSAlgorithm.prototype = Object.create(BaseTraversal.prototype);
// timer interval
DFSAlgorithm.prototype.timerInterval = 500;
DFSAlgorithm.prototype.getName = function(local)
{
return g_DFSName;// local == "ru" ? "Поиск в глубину" : "Depth-first search";
}
DFSAlgorithm.prototype.getId = function()
{
return "OlegSh.DFSAlgorithm";
}
// @return message for user.
DFSAlgorithm.prototype.getMessage = function(local)
{
return this.message;
}
DFSAlgorithm.prototype.result = function(resultCallback)
{
var result = {};
result["version"] = 1;
return result;
}
DFSAlgorithm.prototype.getMainMessage = function()
{
var message = g_traversalOrder;
// calculate.
var tempVisited = this.visited.slice();
var tempEdge = [];
var oldLength = 0;
while (oldLength < tempVisited.length)
{
oldLength = tempVisited.length;
for (var i = tempVisited.length - 1; i >= 0; i--)
{
if (this.dfs(tempVisited[i], tempVisited, tempEdge))
break;
}
}
// Format message
for (var i = 0; i < tempVisited.length; i ++)
{
tempVisited[i].upText = (i + 1) + "";
message = message + tempVisited[i].mainText + " ";
}
return message;
}
DFSAlgorithm.prototype.getPriority = function()
{
return -9.5;
}
DFSAlgorithm.prototype.getCategory = function()
{
return 1;
}
DFSAlgorithm.prototype.step = function()
{
for (var i = this.visited.length - 1; i >= 0; i--)
{
if (this.dfs(this.visited[i], this.visited, this.edges))
{
this.app.redrawGraph();
return;
}
}
clearTimeout(this.timer);
this.timer = null;
return;
}
DFSAlgorithm.prototype.dfs = function(vertex, vertexArray, edgeArray)
{
for (var i = 0; i < this.graph.vertices.length; i ++)
{
var nextVertex = this.graph.vertices[i];
var edge = this.graph.FindEdgeAny(vertex.id, nextVertex.id);
if (edge && !vertexArray.includes(nextVertex))
{
edgeArray.push(edge);
vertexArray.push(nextVertex);
return true;
}
}
return false;
}
// Algorithm support multi graph
DFSAlgorithm.prototype.IsSupportMultiGraph = function()
{
return true;
}
// Factory for connected components.
function CreateDFSAlgorithm(graph, app)
{
return new DFSAlgorithm(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateDFSAlgorithm);

View File

@@ -0,0 +1,97 @@
/**
* 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 g_EulerinLoopName;//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.getCategory = function()
{
return 1;
}
FindEulerianLoop.prototype.result = function(resultCallback)
{
this.outResultCallback = function (result ) { resultCallback(result); };
self = this;
this.CalculateAlgorithm("elloop", [], function (pathObjects, properties, results)
{
self.resultCallback(pathObjects, properties, results);
}, true);
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) ? "&rArr;" : "");
}
}
this.outResultCallback(outputResult);
}
FindEulerianLoop.prototype.getObjectSelectedGroup = function(object)
{
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
}
FindEulerianLoop.prototype.getPriority = function()
{
return -7.5;
}
// Factory for connected components.
function CreateFindEulerianLoop(graph, app)
{
return new FindEulerianLoop(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateFindEulerianLoop);

View File

@@ -0,0 +1,97 @@
/**
* Find Eulerian Path.
*
*/
function FindEulerianPath(graph, app)
{
BaseAlgorithmEx.apply(this, arguments);
this.message = g_processing;
this.selectedObjects = [];
}
// inheritance.
FindEulerianPath.prototype = Object.create(BaseAlgorithmEx.prototype);
FindEulerianPath.prototype.getName = function(local)
{
return g_EulerinPath;//local == "ru" ? "Найти Эйлерову цепь" : "Find Eulerian path";
}
FindEulerianPath.prototype.getId = function()
{
return "OlegSh.FindEulerianPath";
}
// @return message for user.
FindEulerianPath.prototype.getMessage = function(local)
{
return this.message;
}
FindEulerianPath.prototype.getCategory = function()
{
return 1;
}
FindEulerianPath.prototype.result = function(resultCallback)
{
this.outResultCallback = function (result ) { resultCallback(result); };
self = this;
this.CalculateAlgorithm("elpath", [], function (pathObjects, properties, results)
{
self.resultCallback(pathObjects, properties, results);
}, true);
return true;
}
FindEulerianPath.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_hasEulerianPath : g_hasNotEulerianPath;
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) ? "&rArr;" : "");
}
}
this.outResultCallback(outputResult);
}
FindEulerianPath.prototype.getObjectSelectedGroup = function(object)
{
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
}
FindEulerianPath.prototype.getPriority = function()
{
return -7.5;
}
// Factory for connected components.
function CreateFindEulerianPath(graph, app)
{
return new FindEulerianPath(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateFindEulerianPath);

View File

@@ -0,0 +1,232 @@
/**
* Find short path.
*
*/
function FindAllPathes(graph, app)
{
BaseAlgorithmEx.apply(this, arguments);
this.message = g_selectStartVertex;
this.selectedObjects = {};
this.foundSubGraphs = {};
this.nSubgraphIndex = 0;
this.nSubGraphCount = 0;
this.foundPaths = {};
}
// inheritance.
FindAllPathes.prototype = Object.create(BaseAlgorithmEx.prototype);
// First selected.
FindAllPathes.prototype.firstObject = null;
// Second selected.
FindAllPathes.prototype.secondObject = null;
// Path
FindAllPathes.prototype.pathObjects = null;
// Infinity
FindAllPathes.prototype.infinityValue = 1E9 - 1;
FindAllPathes.prototype.getName = function(local)
{
return g_findAllPathes;
}
FindAllPathes.prototype.getId = function()
{
return "Abin.FindAllPathes";
}
// @return message for user.
FindAllPathes.prototype.getMessage = function(local)
{
return this.message;
}
FindAllPathes.prototype.getCategory = function()
{
return 1;
}
FindAllPathes.prototype.result = function(resultCallback)
{
if (this.firstObject && this.secondObject)
{
this.outResultCallback = function (result ) { resultCallback(result); };
self = this;
this.CalculateAlgorithm("prnpaths", [
{name: "start", value: this.firstObject.id},
{name: "finish", value: this.secondObject.id}
],
function (pathObjects, properties, results)
{
self.resultCallback(pathObjects, properties, results);
});
}
return null;
}
FindAllPathes.prototype.setResultMessage = function()
{
if (this.nSubGraphCount > 0)
{
var currentPath = "";
var first = true;
this.foundPaths[this.nSubgraphIndex].forEach((nodeId) => {
currentPath += (first ? "" : "⇒") + this.graph.FindVertex(nodeId).mainText;
first = false;
});
this.message = g_numberOfPathesFrom + this.firstObject.mainText +
g_to + this.secondObject.mainText + g_are +
this.nSubGraphCount + ". " + g_pathN + (1 + parseInt(this.nSubgraphIndex)) + ": " + currentPath +
" <select style=\"float:right\" id=\"enumSubgraphs\"></select>";
}
else
{
this.message = g_pathNotExists;
}
}
FindAllPathes.prototype.resultCallback = function(pathObjects, properties, results)
{
var outputResult = {};
outputResult["version"] = 1;
outputResult["minPath"] = true;
this.pathObjects = pathObjects;
this.properties = properties;
var bFound = results.length > 0 && results[0].value < this.infinityValue && (results[0].type == 1 || results[0].type == 2);
if (bFound)
{
this.nSubGraphCount = results.length > 0 && results[0].type == 1 ? results[0].value : 0;
this.foundSubGraphs = {};
this.foundPaths = {};
for (var i = 0; i < this.nSubGraphCount; i++)
{
this.foundSubGraphs[i] = {};
this.foundPaths[i] = [];
}
var subGraphIndex = 0;
var prevNodeId = -1;
for (var i = 0; i < results.length; i++)
{
if (results[i].type == 6)
{
subGraphIndex++;
prevNodeId = -1;
}
if (results[i].type == 4)
{
var nodeId = parseInt(results[i].value);
var index = subGraphIndex;
var subgGraph = this.foundSubGraphs[index];
subgGraph[nodeId] = true;
this.foundPaths[index].push(nodeId);
if (prevNodeId >= 0)
{
var edgeObject = this.graph.FindEdgeMin(prevNodeId, nodeId);
subgGraph[edgeObject.id] = true;
}
prevNodeId = nodeId;
}
}
this.setResultMessage();
}
else
{
this.secondObject = null;
this.firstObject = null;
this.message = g_pathNotExists;
}
this.outResultCallback(outputResult);
}
FindAllPathes.prototype.messageWasChanged = function()
{
var self = this;
if ($('#enumSubgraphs'))
{
for (var i = 0; i < this.nSubGraphCount; i++)
{
$('#enumSubgraphs').append("<option value=\"" + i + "\"" + (self.nSubgraphIndex==i ? "selected": "") + ">" +
g_pathN + (i + 1) +
"</option>");
}
$('#enumSubgraphs').change(function () {
self.nSubgraphIndex = $('#enumSubgraphs').val();
self.setResultMessage();
self.app.redrawGraph();
self.app.updateMessage();
});
}
}
FindAllPathes.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_selectFinishVertex;
}
return true;
}
FindAllPathes.prototype.deselectAll = function()
{
this.firstObject = null;
this.secondObject = null;
this.selectedObjects = {};
this.foundSubGraphs = {};
this.nSubgraphIndex = 0;
this.nSubGraphCount = 0;
this.message = g_selectStartVertex;
return true;
}
FindAllPathes.prototype.instance = function()
{
return false;
}
FindAllPathes.prototype.getObjectSelectedGroup = function(object)
{
return (this.nSubgraphIndex in this.foundSubGraphs && object.id in this.foundSubGraphs[this.nSubgraphIndex]) ? 1 :
(object.id in this.selectedObjects) ? this.selectedObjects[object.id] : ((object == this.firstObject || object == object.secondObject) ? 1 : 0);
}
FindAllPathes.prototype.getPriority = function()
{
return -9.4;
}
// Factory for connected components.
function CreateFindAllPathes(graph, app)
{
return new FindAllPathes(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateFindAllPathes);

View File

@@ -0,0 +1,229 @@
/**
* Find short path.
*
*/
function FindLongestPath(graph, app)
{
BaseAlgorithmEx.apply(this, arguments);
this.message = g_selectStartVertex;
this.selectedObjects = {};
this.foundSubGraphs = {};
this.nSubgraphIndex = 0;
this.nSubGraphCount = 0;
this.foundPaths = {};
this.maxPathLength = 0;
}
// inheritance.
FindLongestPath.prototype = Object.create(BaseAlgorithmEx.prototype);
// First selected.
FindLongestPath.prototype.firstObject = null;
// Second selected.
FindLongestPath.prototype.secondObject = null;
// Path
FindLongestPath.prototype.pathObjects = null;
// Infinity
FindLongestPath.prototype.infinityValue = 1E9 - 1;
FindLongestPath.prototype.getName = function(local)
{
return g_findLongestPath;
}
FindLongestPath.prototype.getId = function()
{
return "OlegSh.FindLongestPath";
}
// @return message for user.
FindLongestPath.prototype.getMessage = function(local)
{
return this.message;
}
FindLongestPath.prototype.getCategory = function()
{
return 1;
}
FindLongestPath.prototype.result = function(resultCallback)
{
if (this.firstObject && this.secondObject)
{
this.outResultCallback = function (result ) { resultCallback(result); };
self = this;
this.CalculateAlgorithm("prnpaths", [
{name: "start", value: this.firstObject.id},
{name: "finish", value: this.secondObject.id}
],
function (pathObjects, properties, results)
{
self.resultCallback(pathObjects, properties, results);
});
}
return null;
}
FindLongestPath.prototype.setResultMessage = function()
{
if (this.nSubGraphCount > 0)
{
var currentPath = "";
var first = true;
this.foundPaths[this.nSubgraphIndex].forEach((nodeId) => {
currentPath += (first ? "" : "⇒") + this.graph.FindVertex(nodeId).mainText;
first = false;
});
this.message = g_LengthOfLongestPathFrom + this.firstObject.mainText +
g_to + this.secondObject.mainText + g_are +
this.maxPathLength + ": " + currentPath;
}
else
{
this.message = g_pathNotExists;
}
}
FindLongestPath.prototype.resultCallback = function(pathObjects, properties, results)
{
var outputResult = {};
outputResult["version"] = 1;
outputResult["minPath"] = true;
this.pathObjects = pathObjects;
this.properties = properties;
var bFound = results.length > 0 && results[0].value < this.infinityValue && (results[0].type == 1 || results[0].type == 2);
if (bFound)
{
this.nSubGraphCount = results.length > 0 && results[0].type == 1 ? results[0].value : 0;
this.foundSubGraphs = {};
this.foundPaths = {};
this.maxPathLength = 0;
var maxPathIndex = 0;
var currentLength = 0;
for (var i = 0; i < this.nSubGraphCount; i++)
{
this.foundSubGraphs[i] = {};
this.foundPaths[i] = [];
}
var subGraphIndex = 0;
var prevNodeId = -1;
for (var i = 0; i < results.length; i++)
{
if (results[i].type == 6)
{
if (currentLength > this.maxPathLength) {
this.maxPathLength = currentLength;
maxPathIndex = subGraphIndex;
}
currentLength = 0;
subGraphIndex++;
prevNodeId = -1;
}
if (results[i].type == 4)
{
var nodeId = parseInt(results[i].value);
var index = subGraphIndex;
var subgGraph = this.foundSubGraphs[index];
subgGraph[nodeId] = true;
this.foundPaths[index].push(nodeId);
if (prevNodeId >= 0)
{
var edgeObject = this.graph.FindEdgeMax(prevNodeId, nodeId);
subgGraph[edgeObject.id] = true;
currentLength += edgeObject.GetWeight();
}
prevNodeId = nodeId;
}
}
if (currentLength > this.maxPathLength) {
this.maxPathLength = currentLength;
maxPathIndex = subGraphIndex;
}
this.nSubgraphIndex = maxPathIndex;
this.setResultMessage();
this.firstObject = null;
this.secondObject = null;
}
else
{
this.secondObject = null;
this.firstObject = null;
this.message = g_pathNotExists;
}
this.outResultCallback(outputResult);
}
FindLongestPath.prototype.selectVertex = function(vertex)
{
this.pathObjects = null;
this.shortDist = null;
if (this.firstObject)
{
this.message = g_processing;
this.secondObject = vertex;
this.selectedObjects = [];
}
else
{
this.deselectAll();
this.firstObject = vertex;
this.secondObject = null;
this.selectedObjects = {};
this.message = g_selectFinishVertex;
}
return true;
}
FindLongestPath.prototype.deselectAll = function()
{
this.firstObject = null;
this.secondObject = null;
this.selectedObjects = {};
this.foundSubGraphs = {};
this.nSubgraphIndex = 0;
this.nSubGraphCount = 0;
this.message = g_selectStartVertex;
this.maxPathLength = 0;
return true;
}
FindLongestPath.prototype.instance = function()
{
return false;
}
FindLongestPath.prototype.getObjectSelectedGroup = function(object)
{
return (this.nSubgraphIndex in this.foundSubGraphs && object.id in this.foundSubGraphs[this.nSubgraphIndex]) ? 1 :
(object.id in this.selectedObjects) ? this.selectedObjects[object.id] : ((object == this.firstObject || object == object.secondObject) ? 1 : 0);
}
FindLongestPath.prototype.getPriority = function()
{
return -9.4;
}
// Factory for connected components.
function CreateFindLongestPath(graph, app)
{
return new FindLongestPath(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateFindLongestPath);

View File

@@ -0,0 +1,219 @@
/**
* Find short path.
*
*/
function FindShortPatchsFromOne(graph, app)
{
BaseAlgorithmEx.apply(this, arguments);
this.message = g_selectStartVertex;
this.selectedObjects = {};
this.foundSubGraphs = {};
this.nSubgraphIndex = 0;
this.nSubGraphCount = 0;
this.lastVertexInPath = [];
this.lengthOfPath = [];
}
// inheritance.
FindShortPatchsFromOne.prototype = Object.create(BaseAlgorithmEx.prototype);
// First selected.
FindShortPatchsFromOne.prototype.firstObject = null;
// Path
FindShortPatchsFromOne.prototype.pathObjects = null;
// Infinity
FindShortPatchsFromOne.prototype.infinityValue = 1E9 - 1;
FindShortPatchsFromOne.prototype.getName = function(local)
{
return g_findAllPathesFromVertex;
}
FindShortPatchsFromOne.prototype.getId = function()
{
return "Abin.FindShortPatchsFromOne";
}
// @return message for user.
FindShortPatchsFromOne.prototype.getMessage = function(local)
{
return this.message;
}
FindShortPatchsFromOne.prototype.getCategory = function()
{
return 1;
}
FindShortPatchsFromOne.prototype.result = function(resultCallback)
{
if (this.firstObject)
{
this.outResultCallback = function (result ) { resultCallback(result); };
self = this;
this.CalculateAlgorithm("blf", [
{name: "start", value : this.firstObject.id}
], function (pathObjects, properties, results)
{
self.resultCallback(pathObjects, properties, results);
});
}
return null;
}
FindShortPatchsFromOne.prototype.setResultMessage = function()
{
if (this.nSubGraphCount > 0)
{
this.message = g_distanceFrom + this.firstObject.mainText +
g_to + this.lastVertexInPath[this.nSubgraphIndex] + g_are +
this.lengthOfPath[this.nSubgraphIndex] + " <select style=\"float:right\" id=\"enumSubgraphs\"></select>";
}
else
{
this.message = g_pathNotExists;
}
}
FindShortPatchsFromOne.prototype.resultCallback = function(pathObjects, properties, results)
{
var outputResult = {};
outputResult["version"] = 1;
outputResult["minPath"] = true;
this.pathObjects = pathObjects;
this.properties = properties;
var bFound = results.length > 0 && results[0].value < this.infinityValue && (results[0].type == 1 || results[0].type == 2);
if (bFound)
{
this.nSubGraphCount = results.length > 0 && results[0].type == 1 ? results[0].value : 0;
this.foundSubGraphs = {};
for (var i = 0; i < this.nSubGraphCount; i++)
{
this.foundSubGraphs[i] = {};
this.lengthOfPath.push(0);
this.lastVertexInPath.push(0);
}
var subGraphIndex = 0;
var prevNodeId = -1;
for (var i = 0; i < results.length; i++)
{
if (results[i].type == 6)
{
subGraphIndex++;
prevNodeId = -1;
}
if (results[i].type == 4)
{
var nodeId = parseInt(results[i].value);
var index = subGraphIndex;
var subgGraph = this.foundSubGraphs[index];
subgGraph[nodeId] = true;
var vertex = this.graph.FindVertex(nodeId);
this.lastVertexInPath[index] = vertex != null ? vertex.mainText : "";
if (prevNodeId >= 0)
{
var edgeObject = this.graph.FindEdgeMin(prevNodeId, nodeId);
subgGraph[edgeObject.id] = true;
this.lengthOfPath[index] += edgeObject.GetWeight();
}
prevNodeId = nodeId;
}
}
this.setResultMessage();
}
else
{
this.firstObject = null;
this.message = g_pathNotExists;
}
this.outResultCallback(outputResult);
}
FindShortPatchsFromOne.prototype.messageWasChanged = function()
{
var self = this;
if ($('#enumSubgraphs'))
{
for (var i = 0; i < this.nSubGraphCount; i++)
{
$('#enumSubgraphs').append("<option value=\"" + i + "\"" + (self.nSubgraphIndex==i ? "selected": "") + ">" +
g_pathTo + this.lastVertexInPath[i] +
"</option>");
}
$('#enumSubgraphs').change(function () {
self.nSubgraphIndex = $('#enumSubgraphs').val();
self.app.redrawGraph();
self.setResultMessage();
});
}
}
FindShortPatchsFromOne.prototype.selectVertex = function(vertex)
{
this.pathObjects = null;
this.shortDist = null;
this.deselectAll();
this.firstObject = vertex;
this.selectedObjects = {};
this.message = "Processing...";
return true;
}
FindShortPatchsFromOne.prototype.deselectAll = function()
{
this.firstObject = null;
this.selectedObjects = {};
this.foundSubGraphs = {};
this.nSubgraphIndex = 0;
this.nSubGraphCount = 0;
this.message = g_selectStartVertex;
this.lastVertexInPath = [];
this.lengthOfPath = [];
return true;
}
FindShortPatchsFromOne.prototype.instance = function()
{
return false;
}
FindShortPatchsFromOne.prototype.getObjectSelectedGroup = function(object)
{
return (this.nSubgraphIndex in this.foundSubGraphs && object.id in this.foundSubGraphs[this.nSubgraphIndex]) ? 1 :
(object.id in this.selectedObjects) ? this.selectedObjects[object.id] : ((object == this.firstObject || object == object.secondObject) ? 1 : 0);
}
FindShortPatchsFromOne.prototype.getPriority = function()
{
return -9.4;
}
// Algorithm support multi graph
FindShortPatchsFromOne.prototype.IsSupportMultiGraph = function()
{
return true;
}
// Factory for connected components.
function CreateFindShortPatchsFromOne(graph, app)
{
return new FindShortPatchsFromOne(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateFindShortPatchsFromOne);

View File

@@ -0,0 +1,235 @@
/**
* Find short path.
*
*/
function FloidAlgorithm(graph, app)
{
BaseAlgorithmEx.apply(this, arguments);
this.selectedObjects = {};
this.matrix = [];
this.updateMessage(false);
this.edgesCopy = [];
}
// inheritance.
FloidAlgorithm.prototype = Object.create(BaseAlgorithmEx.prototype);
// First selected.
FloidAlgorithm.prototype.firstObject = null;
// Second selected.
FloidAlgorithm.prototype.secondObject = null;
// Path
FloidAlgorithm.prototype.pathObjects = null;
// infinity
FloidAlgorithm.prototype.infinity = 1E8;
FloidAlgorithm.prototype.getName = function(local)
{
return g_FloidName; //local == "ru" ? "Алгоритм Флойда — Уоршелла" : "FloydWarshall algorithm";
}
FloidAlgorithm.prototype.getId = function()
{
return "OlegSh.FloidAlgorithm";
}
// @return message for user.
FloidAlgorithm.prototype.getMessage = function(local)
{
return this.message;
}
FloidAlgorithm.prototype.getCategory = function()
{
return 1;
}
FloidAlgorithm.prototype.result = function(resultCallback)
{
var result = {};
result["version"] = 1;
this.matrix = [];
this.resultMatrix();
//console.log(this.matrix);
// Remove all edges.
this.egdesCopy = this.graph.edges.slice();
this.removeAllEdges();
this.isGraphMulti = this.graph.isMulti();
this.graph.hasDirect = false;
// Added new edges
for (var i = 0; i < this.graph.vertices.length; i ++)
{
for (var j = 0; j < this.graph.vertices.length; j ++)
{
if (i != j)
{
var directed = (this.matrix[i][j] != this.matrix[j][i]);
if (this.matrix[i][j] < this.infinity && (directed || i < j))
{
this.graph.AddNewEdgeSafe(this.graph.vertices[i], this.graph.vertices[j], directed, this.matrix[i][j]);
}
}
}
}
this.app.redrawGraph();
return result;
}
FloidAlgorithm.prototype.resultMatrix = function()
{
this.matrix = [];
for (var i = 0; i < this.graph.vertices.length; i ++)
{
this.matrix.push([]);
var v1 = this.graph.vertices[i];
var str = "";
for (var j = 0; j < this.graph.vertices.length; j ++)
{
var v2 = this.graph.vertices[j];
var edge = this.graph.FindEdgeMin(v1.id, v2.id);
if (edge != null)
{
this.matrix[i][j] = edge.GetWeight();
}
else
{
this.matrix[i][j] = this.infinity;
}
}
}
for (var k = 0; k < this.graph.vertices.length; k ++)
for (var i = 0; i < this.graph.vertices.length; i ++)
for (var j = 0; j < this.graph.vertices.length; j ++)
{
if (this.matrix[i][j] > this.matrix[i][k] + this.matrix[k][j])
{
this.matrix[i][j] = this.matrix[i][k] + this.matrix[k][j];
}
}
return this.matrix;
}
FloidAlgorithm.prototype.getObjectSelectedGroup = function(object)
{
return 0;
}
FloidAlgorithm.prototype.messageWasChanged = function()
{
var self = this;
var matrixButton = document.getElementById("showFloidMatrix");
if (matrixButton)
{
matrixButton.onclick = function () {
var dialogButtons = {};
dialogButtons[g_close] = function() {
$( this ).dialog( "close" );
};
$( "#FloidMatrixField" ).val(self.GetFloidMatrix());
$( "#floidMatrix" ).dialog({
resizable: false,
height: "auto",
width: "auto",
modal: true,
title: g_minDistMatrixText,
buttons: dialogButtons,
dialogClass: 'EdgeDialog'
});
};
}
$('#saveFloidGraph').change(function() {
self.updateMessage(this.checked);
});
}
FloidAlgorithm.prototype.GetFloidMatrix = function()
{
return this.graph.GetAdjacencyMatrixStr();
}
FloidAlgorithm.prototype.changedType = function()
{
var enumReport = document.getElementById("enumReport");
this.app.SetCurrentValue("findShortPathReportType", enumReport.options[enumReport.selectedIndex].value);
this.updateUpText();
}
FloidAlgorithm.prototype.getPriority = function()
{
return 0;
}
FloidAlgorithm.prototype.removeAllEdges = function()
{
while (this.graph.edges.length > 0)
{
this.graph.DeleteEdge(this.graph.edges[0]);
}
}
FloidAlgorithm.prototype.wantRestore = function()
{
console.log($("#saveFloidGraph").is(':checked'));
return !$("#saveFloidGraph").is(':checked');
}
FloidAlgorithm.prototype.restore = function()
{
this.removeAllEdges();
this.graph.hasDirect = false;
console.log(this.egdesCopy);
for (var i = 0; i < this.egdesCopy.length; i ++)
{
var edgeIndex = this.graph.AddNewEdgeSafe(this.egdesCopy[i].vertex1,
this.egdesCopy[i].vertex2,
this.egdesCopy[i].isDirect,
this.egdesCopy[i].weight,
this.isGraphMulti);
var edge = this.graph.edges[edgeIndex];
edge.model.type = this.egdesCopy[i].model.type;
edge.model.curveValue = this.egdesCopy[i].model.curveValue;
//edge.model = this.egdesCopy[i].model;
}
}
FloidAlgorithm.prototype.updateMessage = function(save)
{
this.message = g_graphOfMinDist + " <label style=\"margin-bottom: 0px\">" + g_checkToSave + " <input id=\"saveFloidGraph\" type=\"checkbox\"" + (save ? "checked" : "") + "></label>" +
"<button type=\"button\" class=\"btn btn-default btn-xs\" id=\"showFloidMatrix\" style=\"float:right\">" + g_showDistMatrix + "</button>"
}
// Algorithm support multi graph
FloidAlgorithm.prototype.IsSupportMultiGraph = function ()
{
return true;
}
// Factory for connected components.
function CreateFloidAlgorithm(graph, app)
{
return new FloidAlgorithm(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateFloidAlgorithm);

View File

@@ -0,0 +1,175 @@
/**
* Algorithm for reorder graph.
*
*/
function GraphReorder(graph, app)
{
BaseAlgorithm.apply(this, arguments);
if (graph != null)
{
this.edges = graph.edges;
this.vertices = graph.vertices;
}
}
// inheritance.
GraphReorder.prototype = Object.create(BaseAlgorithm.prototype);
GraphReorder.prototype.getName = function(local)
{
return g_GraphReorder; //local == "ru" ? "Упорядочить граф" : "Arrange the graph";
}
GraphReorder.prototype.getId = function()
{
return "OlegSh.GraphReorder";
}
// @return message for user.
GraphReorder.prototype.getMessage = function(local)
{
return g_done;
}
GraphReorder.prototype.result = function(resultCallback)
{
var result = {};
result["version"] = 1;
if (this.vertices.length == 0)
{
return result;
}
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 centerPoint = new Point();
for(i = 0; i < this.vertices.length; i++) // loop through vertices
{
centerPoint.add(this.vertices[i].position);
}
centerPoint.multiply(1.0 / this.vertices.length);
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 k = 0;
var bChanged = true;
while (k < 1000 && bChanged)
{
var vertexData = [];
for(i = 0; i < this.vertices.length; i++) // loop through vertices
{
// Has no in newVertices.
var currentVertex = {};
currentVertex.object = this.vertices[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++;
}
this.app.OnAutoAdjustViewport();
this.app.SetHandlerMode("default");
// Looks like somthing going wrong and will use circle algorithm for reposition.
//var bbox = this.getGraphBBox();
return result;
}
GraphReorder.prototype.getObjectSelectedGroup = function(object)
{
return 0;
}
GraphReorder.prototype.getPriority = function()
{
return -8.5;
}
// Algorithm support multi graph
GraphReorder.prototype.IsSupportMultiGraph = function()
{
return true;
}
// Factory for connected components.
function CreateAlgorithmGraphReorder(graph, app)
{
return new GraphReorder(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateAlgorithmGraphReorder);

View File

@@ -0,0 +1,114 @@
/**
* Find Eulerian Loop.
*
*/
function FindHamiltonianLoop(graph, app)
{
BaseAlgorithmEx.apply(this, arguments);
this.message = g_processing;
this.selectedObjects = [];
}
// inheritance.
FindHamiltonianLoop.prototype = Object.create(BaseAlgorithmEx.prototype);
FindHamiltonianLoop.prototype.getName = function(local)
{
return g_HamiltoianCycleName; //local == "ru" ? "Найти Гамильтонов цикл" : "Find Hamiltonian cycle";
}
FindHamiltonianLoop.prototype.getId = function()
{
return "OlegSh.FindHamiltonianLoop";
}
// @return message for user.
FindHamiltonianLoop.prototype.getMessage = function(local)
{
return this.message;
}
FindHamiltonianLoop.prototype.getCategory = function()
{
return 1;
}
FindHamiltonianLoop.prototype.result = function(resultCallback)
{
this.outResultCallback = function (result ) { resultCallback(result); };
self = this;
this.CalculateAlgorithm("hamloop", [], function (pathObjects, properties, results)
{
self.resultCallback(pathObjects, properties, results);
});
return true;
}
FindHamiltonianLoop.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_hasHamiltonianLoop : g_hasNotHamiltonianLoop;
if (result > 0)
{
var nodesEdgesPath = this.GetNodesEdgesPath(results, 1, results.length - 1);
var nodesPath = this.GetNodesPath(results, 1, results.length - 1);
this.message = this.message + ": ";
if (this.graph.isMulti())
{
outputResult["pathsWithEdges"] = [];
outputResult["pathsWithEdges"].push(nodesEdgesPath);
}
else
{
outputResult["paths"] = [];
outputResult["paths"].push(nodesEdgesPath);
}
for (var i = 0; i < nodesPath.length; i++)
{
this.message = this.message + this.graph.FindVertex(nodesPath[i]).mainText + ((i < nodesPath.length - 1) ? "&rArr;" : "");
}
this.selectedObjects = [];
for (var i = 0; i < pathObjects.length; i++)
{
this.selectedObjects[pathObjects[i].id] = 1;
}
}
this.outResultCallback(outputResult);
}
FindHamiltonianLoop.prototype.getObjectSelectedGroup = function(object)
{
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
}
FindHamiltonianLoop.prototype.getPriority = function()
{
return -5;
}
// Algorithm support multi graph
FindHamiltonianLoop.prototype.IsSupportMultiGraph = function()
{
return true;
}
// Factory for connected components.
function CreateFindHamiltonianLoop(graph, app)
{
return new FindHamiltonianLoop(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateFindHamiltonianLoop);

View File

@@ -0,0 +1,112 @@
/**
* Find Eulerian Loop.
*
*/
function FindHamiltonianPath(graph, app)
{
BaseAlgorithmEx.apply(this, arguments);
this.message = g_processing;
this.selectedObjects = [];
}
// inheritance.
FindHamiltonianPath.prototype = Object.create(BaseAlgorithmEx.prototype);
FindHamiltonianPath.prototype.getName = function(local)
{
return g_HamiltonianPath;//local == "ru" ? "Найти Гамильтонову цепь" : "Find Hamiltonian path";
}
FindHamiltonianPath.prototype.getId = function()
{
return "OlegSh.FindHamiltonianPath";
}
// @return message for user.
FindHamiltonianPath.prototype.getMessage = function(local)
{
return this.message;
}
FindHamiltonianPath.prototype.getCategory = function()
{
return 1;
}
FindHamiltonianPath.prototype.result = function(resultCallback)
{
this.outResultCallback = function (result ) { resultCallback(result); };
self = this;
this.CalculateAlgorithm("hampath", [], function (pathObjects, properties, results)
{
self.resultCallback(pathObjects, properties, results);
});
return true;
}
FindHamiltonianPath.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_hasHamiltonianPath : g_hasNotHamiltonianPath;
if (result > 0)
{
var nodesEdgesPath = this.GetNodesEdgesPath(results, 1, results.length - 1);
var nodesPath = this.GetNodesPath(results, 1, results.length - 1);
if (this.graph.isMulti())
{
outputResult["pathsWithEdges"] = [];
outputResult["pathsWithEdges"].push(nodesEdgesPath);
}
else
{
outputResult["paths"] = [];
outputResult["paths"].push(nodesEdgesPath);
}
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) ? "&rArr;" : "");
}
}
this.outResultCallback(outputResult);
}
FindHamiltonianPath.prototype.getObjectSelectedGroup = function(object)
{
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
}
FindHamiltonianPath.prototype.getPriority = function()
{
return -5;
}
FindHamiltonianPath.prototype.IsSupportMultiGraph = function()
{
return true;
}
// Factory for connected components.
function CreateFindHamiltonianPath(graph, app)
{
return new FindHamiltonianPath(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateFindHamiltonianPath);

View File

@@ -0,0 +1,299 @@
/**
* Find short path.
*
*/
function IsomorphismCheck(graph, app)
{
BaseAlgorithmEx.apply(this, arguments);
if (graph && app)
{
this.connectedComponent = new FindConnectedComponentNew(graph, app);
this.connectedComponent.calculate();
}
this.setFirstMessage();
this.prevCalculated = false;
this.searchSubGraphs = false;
this.foundSubGraphs = {};
this.nSubgraphIndex = 0;
this.nSubGraphCount = 0;
this.bIsomorph = false;
}
// inheritance.
IsomorphismCheck.prototype = Object.create(BaseAlgorithmEx.prototype);
// First selected.
IsomorphismCheck.prototype.firstGraph = null;
// Second selected.
IsomorphismCheck.prototype.secondGraph = null;
IsomorphismCheck.prototype.getName = function(local)
{
return g_IsomorphismCheck;
}
IsomorphismCheck.prototype.getId = function()
{
return "OlegSh.IsomorphismCheck";
}
// @return message for user.
IsomorphismCheck.prototype.getMessage = function(local)
{
return this.message;
}
IsomorphismCheck.prototype.result = function(resultCallback)
{
if (this.firstGraph && this.secondGraph)
{
this.outResultCallback = function (result ) { resultCallback(result); };
self = this;
var params = [
{name : "graph1", value: this.getGraphEdges(this.firstGraph)},
{name : "graph2", value: this.getGraphEdges(this.secondGraph)},
];
if (this.searchSubGraphs) {
params.push({name: "searchSubgraphs", value: true});
}
this.CalculateAlgorithm("isocheck", params, function (pathObjects, properties, results)
{
self.resultCallback(pathObjects, properties, results);
});
}
return null;
}
IsomorphismCheck.prototype.getGraphEdges = function(nodesAndEdges)
{
var res = ""
for (var key in nodesAndEdges)
{
var edgeObject = this.graph.FindEdgeById(key);
if (edgeObject)
{
if (res != "")
res = res + ","
res = res + edgeObject.vertex1.id + "-" + edgeObject.vertex2.id;
}
}
return res;
}
IsomorphismCheck.prototype.resultCallback = function(pathObjects, properties, results)
{
var outputResult = {};
outputResult["version"] = 1;
if (!this.searchSubGraphs)
{
this.bIsomorph = results.length > 0 && results[0].type == 1 && results[0].value == 1;
this.setResultMessage();
}
else
{
this.nSubGraphCount = results.length > 0 && results[0].type == 1 ? results[0].value : 0;
this.setResultMessage();
this.foundSubGraphs = {};
for (var i = 0; i < this.nSubGraphCount; i++)
{
this.foundSubGraphs[i] = {};
}
var subGraphIndex = 0;
for (var i = 0; i < results.length; i++)
{
if (results[i].type == 6)
{
subGraphIndex++;
}
if (results[i].type == 5)
{
var edgeId = parseInt(results[i].value);
var index = subGraphIndex;
var subgGraph = this.foundSubGraphs[index];
subgGraph[edgeId] = true;
var edgeObject = this.graph.FindEdgeById(edgeId);
subgGraph[edgeObject.vertex1.id] = true;
subgGraph[edgeObject.vertex2.id] = true;
}
}
}
this.prevCalculated = true;
this.outResultCallback(outputResult);
}
IsomorphismCheck.prototype.selectVertex = function(vertex)
{
if (this.connectedComponent && this.connectedComponent.connectedComponentNumber <= 1)
return true;
if (this.firstGraph && !this.prevCalculated && (!this.firstGraph || !(vertex.id in this.firstGraph)))
{
this.message = g_processing;
this.secondGraph = this.getGraphWithNode(vertex);
}
else
{
this.deselectAll();
this.firstGraph = this.getGraphWithNode(vertex);
this.secondGraph = null;
this.setSecondMessage();
this.app.updateMessage();
}
return true;
}
IsomorphismCheck.prototype.deselectAll = function()
{
this.firstGraph = null;
this.secondGraph = null;
this.prevCalculated = false;
this.setFirstMessage();
this.restore();
this.foundSubGraphs = {};
this.nSubgraphIndex = 0;
this.nSubGraphCount = 0;
this.bIsomorph = false;
this.app.updateMessage();
return true;
}
IsomorphismCheck.prototype.instance = function()
{
return false;
}
IsomorphismCheck.prototype.getObjectSelectedGroup = function(object)
{
return (this.nSubgraphIndex in this.foundSubGraphs && object.id in this.foundSubGraphs[this.nSubgraphIndex]) ? 3 :
(this.firstGraph && object.id in this.firstGraph) ? 1 : ((this.secondGraph && object.id in this.secondGraph) ? 2 : 0);
}
IsomorphismCheck.prototype.getPriority = function()
{
return -8.0;
}
IsomorphismCheck.prototype.getGraphWithNode = function(node)
{
var res = {}
if (node.id in this.connectedComponent.component)
{
var componentNumber = this.connectedComponent.component[node.id];
for (var key in this.connectedComponent.component)
{
if (this.connectedComponent.component[key] == componentNumber)
{
res[key] = true;
}
}
}
return res;
}
IsomorphismCheck.prototype.setFirstMessage = function()
{
if (this.connectedComponent && this.connectedComponent.connectedComponentNumber <= 1)
{
this.message = g_graphHasNoAtleast2Graphs;
return;
}
if (!this.searchSubGraphs)
this.message = g_selectFirstGraphIsomorphismCheck + "<input id=\"searchSubGraph\" type=\"checkbox\" " + (this.searchSubGraphs ? "checked": "")+ " style=\"float:right\">" + "<label style=\"margin-bottom: 0px;float:right\">" + g_searchIsomorphSubgraph + "&nbsp; </label>";
else
this.message = g_selectFirstGraphPatternCheck + "<input id=\"searchSubGraph\" type=\"checkbox\" " + (this.searchSubGraphs ? "checked": "")+ " style=\"float:right\">" + "<label style=\"margin-bottom: 0px;float:right\">" + g_searchIsomorphSubgraph + "&nbsp; </label>";
}
IsomorphismCheck.prototype.setSecondMessage = function()
{
if (!this.searchSubGraphs)
this.message = g_selectSecondGraphIsomorphismCheck + "<input id=\"searchSubGraph\" type=\"checkbox\" " + (this.searchSubGraphs ? "checked": "")+ " style=\"float:right\">" + "<label style=\"margin-bottom: 0px;float:right\">" + g_searchIsomorphSubgraph + "&nbsp; </label>";
else
this.message = g_selectSecondGraphForSearchSubgraph + "<input id=\"searchSubGraph\" type=\"checkbox\" " + (this.searchSubGraphs ? "checked": "")+ " style=\"float:right\">" + "<label style=\"margin-bottom: 0px;float:right\">" + g_searchIsomorphSubgraph + "&nbsp; </label>";
}
IsomorphismCheck.prototype.setResultMessage = function()
{
if (!this.searchSubGraphs)
{
if (this.bIsomorph)
{
this.message = g_graphsIsomorph;
}
else
{
this.message = g_graphsNotIsomorph;
}
}
else
{
if (this.nSubGraphCount > 0)
{
this.message = g_numberOfIsomorphSubgraphIs + this.nSubGraphCount + " <select style=\"float:right\" id=\"enumSubgraphs\"></select>";
}
else
{
this.message = g_graphHasNoIsomorphSubgraph;
}
}
}
IsomorphismCheck.prototype.messageWasChanged = function()
{
var self = this;
if ($('#searchSubGraph'))
{
$('#searchSubGraph').change(function() {
self.searchSubGraphs = this.checked;
if (self.firstGraph && !self.prevCalculated)
self.setSecondMessage();
else
self.setFirstMessage();
self.app.updateMessage();
});
}
if ($('#enumSubgraphs'))
{
for (var i = 0; i < this.nSubGraphCount; i++)
{
$('#enumSubgraphs').append("<option value=\"" + i + "\"" + (self.nSubgraphIndex==i ? "selected": "") + ">" +
g_subgraphNo + (i + 1) +
"</option>");
}
$('#enumSubgraphs').change(function () {
self.nSubgraphIndex = $('#enumSubgraphs').val();
self.app.redrawGraph();
self.setResultMessage();
});
}
}
// Factory for connected components.
function CreateIsomorphismCheck(graph, app)
{
return new IsomorphismCheck(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateIsomorphismCheck);

View File

@@ -0,0 +1,100 @@
/**
* Find Eulerian Loop.
*
*/
function MaxClique(graph, app)
{
BaseAlgorithmEx.apply(this, arguments);
this.message = g_processing;
this.selectedObjects = [];
}
// inheritance.
MaxClique.prototype = Object.create(BaseAlgorithmEx.prototype);
MaxClique.prototype.getName = function(local)
{
return g_MaxClique;
}
MaxClique.prototype.getId = function()
{
return "OlegSh.MaxClique";
}
// @return message for user.
MaxClique.prototype.getMessage = function(local)
{
return this.message;
}
MaxClique.prototype.result = function(resultCallback)
{
this.outResultCallback = function (result ) { resultCallback(result); };
self = this;
this.CalculateAlgorithm("mc", [], function (pathObjects, properties, results)
{
self.resultCallback(pathObjects, properties, results);
});
return true;
}
MaxClique.prototype.resultCallback = function(pathObjects, properties, results)
{
result = results.length > 0 && results[0].value > 0 && results[0].type == 1;
var outputResult = {};
outputResult["version"] = 1;
console.log("properties");
console.log(properties);
console.log("results");
console.log(results);
console.log("pathObjects");
console.log(pathObjects);
this.message = result > 0 ? "" : g_MaxCliqueNotFound;
if (result > 0)
{
let size = results[0].value;
this.message = g_MaxCliqueSizeIs + size;
this.selectedObjects = [];
this.message = this.message + g_MaxCliqueContains;
var vertexIndex = 0;
for (var i = 0; i < pathObjects.length; i++)
{
let object = pathObjects[i];
if (object instanceof BaseVertex) {
this.message = this.message + object.mainText + ((vertexIndex < size - 1) ? ", " : ".");
vertexIndex++;
}
this.selectedObjects[object.id] = 1;
}
}
this.outResultCallback(outputResult);
}
MaxClique.prototype.getObjectSelectedGroup = function(object)
{
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : 0;
}
MaxClique.prototype.getPriority = function()
{
return -5;
}
function CreateMaxClique(graph, app)
{
return new MaxClique(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateMaxClique);

View File

@@ -0,0 +1,227 @@
/**
* Find short path.
*
*/
function FindMaxFlow(graph, app)
{
BaseAlgorithmEx.apply(this, arguments);
this.message = g_selectStartVertexForMaxFlow;
this.selectedObjects = {};
this.selectedEdges = [];
this.resetUpText = [];
this.minEdgeSize = 2;
this.maxEdgeSize = 12;
}
// inheritance.
FindMaxFlow.prototype = Object.create(BaseAlgorithmEx.prototype);
// First selected.
FindMaxFlow.prototype.firstObject = null;
// Second selected.
FindMaxFlow.prototype.secondObject = null;
// Path
FindMaxFlow.prototype.selectedEdges = null;
FindMaxFlow.prototype.getName = function(local)
{
return g_MaxFlowName; //local == "ru" ? "Поиск максимального потока" : "Find Maximum flow";
}
FindMaxFlow.prototype.getId = function()
{
return "OlegSh.FindMaxFlow";
}
// @return message for user.
FindMaxFlow.prototype.getMessage = function(local)
{
return this.message;
}
FindMaxFlow.prototype.result = function(resultCallback)
{
if (this.firstObject && this.secondObject)
{
this.outResultCallback = function (result ) { resultCallback(result); };
self = this;
this.CalculateAlgorithm("mfpr",
[
{name: "source", value: this.firstObject.id},
{name: "drain", value: this.secondObject.id}
],
function (pathObjects, properties, results)
{
self.resultCallback(pathObjects, properties, results);
});
}
return null;
}
FindMaxFlow.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) && results[0].value * 1 > 0.0;
var maxFlow = results[0].value * 1;
if (bFound)
{
this.selectedObjects = {};
var defaultDiameter = (new EdgeModel()).width;
var avgFlow = 0;
var countEdges = 0;
for (var i = 0; i < pathObjects.length; i++)
{
if (pathObjects[i] instanceof BaseEdge)
{
avgFlow += properties[pathObjects[i].id]["flowValue"] * 1;
countEdges += 1;
}
}
avgFlow = avgFlow / countEdges;
for (var i = 0; i < pathObjects.length; i++)
{
if (pathObjects[i] instanceof BaseEdge)
{
this.selectedObjects[pathObjects[i].id] = 1;
var flow = properties[pathObjects[i].id]["flowValue"] * 1;
if (pathObjects[i].useWeight || flow != pathObjects[i].GetWeight())
{
pathObjects[i].text = flow + " / " + pathObjects[i].GetWeight();
}
if (!pathObjects[i].isDirect)
{
if (parseInt(properties[pathObjects[i].id]["backToFront"]) > 0)
{
pathObjects[i].arrayStyleStart = "arrow";
}
else
{
pathObjects[i].arrayStyleFinish = "arrow";
}
}
pathObjects[i].model.width = Math.max(Math.min((flow / avgFlow) * defaultDiameter, this.maxEdgeSize), this.minEdgeSize);
}
}
this.selectedEdges = pathObjects;
this.message = g_maxFlowResult.replace("%1", (maxFlow).toString()).replace("%2", this.firstObject.mainText).replace("%3", this.secondObject.mainText);
this.selectedObjects[this.secondObject.id] = 3;
this.selectedObjects[this.firstObject.id] = 1;
this.secondObject.upText = g_sinkVertex;
this.resetUpText.push(this.secondObject);
}
else
{
this.message = g_flowNotExists.toString().replace("%1", this.firstObject.mainText).replace("%2", this.secondObject.mainText);
}
this.secondObject = null;
this.firstObject = null;
this.outResultCallback(outputResult);
}
FindMaxFlow.prototype.selectVertex = function(vertex)
{
this.pathObjects = null;
this.shortDist = null;
if (this.firstObject)
{
this.message = g_processing;
this.secondObject = vertex;
this.selectedObjects = [];
}
else
{
this.restore();
this.firstObject = vertex;
this.secondObject = null;
this.selectedObjects = {};
this.message = g_selectFinishVertexForMaxFlow;
this.firstObject.upText = g_sourceVertex;
this.resetUpText.push(this.firstObject);
}
return true;
}
FindMaxFlow.prototype.deselectAll = function()
{
this.firstObject = null;
this.secondObject = null;
this.selectedObjects = {};
this.message = g_selectStartVertexForMaxFlow;
this.restore();
return true;
}
FindMaxFlow.prototype.instance = function()
{
return false;
}
FindMaxFlow.prototype.getObjectSelectedGroup = function(object)
{
return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : ((object == this.firstObject || object == object.secondObject) ? 1 : 0);
}
FindMaxFlow.prototype.getPriority = function()
{
return -8.0;
}
// @return true, if you change resotry graph after use.
BaseAlgorithm.prototype.wantRestore = function()
{
return true;
}
// calls this method if wantRestore return true.
BaseAlgorithm.prototype.restore = function()
{
if (this.selectedEdges != null)
{
for (var i = 0; i < this.selectedEdges.length; i++)
{
if (this.selectedEdges[i] instanceof BaseEdge)
{
this.selectedEdges[i].text = "";
this.selectedEdges[i].arrayStyleStart = "";
this.selectedEdges[i].arrayStyleFinish = "";
this.selectedEdges[i].model.width = (new EdgeModel()).width;
}
}
for (var i = 0; i < this.resetUpText.length; i++)
{
this.resetUpText[i].upText = "";
}
}
}
// Factory for connected components.
function CreateFindMaxFlow(graph, app)
{
return new FindMaxFlow(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateFindMaxFlow);

View File

@@ -0,0 +1,167 @@
function MinimumSpanningTree(graph, app)
{
BaseAlgorithm.apply(this, arguments);
this.isNotConnected = false;
this.MST = 0;
this.edges = [];
}
// inheritance.
MinimumSpanningTree.prototype = Object.create(BaseAlgorithm.prototype);
MinimumSpanningTree.prototype.getName = function(local)
{
return g_minimumSpanningTree; //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.isNotConnected )
{
return g_SpanningTreeResult + this.MST + ". " +
(this.graph.hasDirectEdge() ? g_SpanningTreeIgnoreDir : "");
}
else
{
return g_SpanningTreeNotConnected;
}
}
MinimumSpanningTree.prototype.result = function(resultCallback)
{
this.MST = 0;
this.edges = [];
this.isNotConnected = true;
var tempVertices = this.graph.vertices.slice();
connectedVertex = getVertexToVertexArray(this.graph, true);
// We ignore orientation for this algorithm.
//if (!this.graph.hasDirectEdge())
{
res = this.resultStartedFrom(tempVertices[0], connectedVertex);
this.isNotConnected = res.isNotConnected;
if (!this.isNotConnected)
{
this.MST = res.MST;
this.edges = res.edges;
}
}
/*else
{
for (var i = 0; i < tempVertices.length; i++)
{
res = this.resultStartedFrom(tempVertices[i], connectedVertex);
if (!res.isNotConnected)
{
this.isNotConnected = res.isNotConnected;
if (this.MST == 0 || res.MST < this.MST)
{
console.log(res);
this.MST = res.MST;
this.edges = res.edges;
}
}
}
}*/
var result = {};
result["version"] = 1;
result["minPath"] = true;
return result;
}
MinimumSpanningTree.prototype.resultStartedFrom = function(vertex, connectedVertex)
{
var res = {};
res.MST = 0;
res.edges = [];
res.isNotConnected = 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.FindEdgeMinIgnoreDirection(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.isNotConnected = (inTree.length < this.graph.vertices.length);
return res;
}
MinimumSpanningTree.prototype.getObjectSelectedGroup = function(object)
{
return this.isNotConnected ? 0 :
(object instanceof BaseVertex || this.edges.indexOf(object) >= 0) ? 1 : 0;
}
MinimumSpanningTree.prototype.getPriority = function()
{
return -9.3;
}
// Algorithm support multi graph
MinimumSpanningTree.prototype.IsSupportMultiGraph = function ()
{
return true;
}
// Factory for algorithm.
function CreateMinimumSpanningTree(graph, app)
{
return new MinimumSpanningTree(graph)
}
// Register connected component.
RegisterAlgorithm (CreateMinimumSpanningTree);

View File

@@ -0,0 +1,198 @@
/**
* Algorithm for modern style of graph.
*
*/
function ModernGraphStyle(graph, app)
{
BaseAlgorithm.apply(this, arguments);
this.minVertexSize = 20;
this.maxVertexSize = 100;
this.minEdgeSize = 2;
this.maxEdgeSize = 12;
}
// inheritance.
ModernGraphStyle.prototype = Object.create(BaseAlgorithm.prototype);
ModernGraphStyle.prototype.getName = function(local)
{
return g_modernGraphStyleName;// local == "ru" ? "Визуализация на основе весов" : "Visualisation based on weight";
}
ModernGraphStyle.prototype.getId = function()
{
return "OlegSh.ModernGraphStyle";
}
// @return message for user.
ModernGraphStyle.prototype.getMessage = function(local)
{
return g_done;
}
ModernGraphStyle.prototype.result = function(resultCallback)
{
var result = {};
result["version"] = 1;
this.vertexVisualization2();
this.edgeVisualization();
return result;
}
ModernGraphStyle.prototype.vertexVisualization = function()
{
var degree = getVertexToVertexArray(this.graph, false);
var graph = this.graph;
var maxDegree = 0;
var sumDegree = 0;
var sumOfDiameters = graph.vertices.length * (new VertexModel()).diameter;
// Search max vertex degree.
for (var i = 0; i < graph.vertices.length; i++)
{
var vertex = graph.vertices[i];
if (degree.hasOwnProperty(vertex.id))
{
var currentDegree = degree[vertex.id].length;
maxDegree = Math.max(maxDegree, currentDegree);
sumDegree = sumDegree + currentDegree;
}
}
for (var i = 0; i < graph.vertices.length; i++)
{
var vertex = graph.vertices[i];
if (degree.hasOwnProperty(vertex.id))
{
var currentDegree = degree[vertex.id].length;
//vertex.model.diameter = (currentDegree / maxDegree) * (this.maxVertexSize - this.minVertexSize) + this.minVertexSize;
vertex.model.diameter = Math.max(Math.min((currentDegree / sumDegree) * sumOfDiameters, this.maxVertexSize), this.minVertexSize);
//sumOfDiameters
}
else
{
vertex.model.diameter = this.minVertexSize;
}
}
}
ModernGraphStyle.prototype.vertexVisualization2 = function()
{
var degree = {};
var graph = this.graph;
var sumDegree = 0;
var sumOfDiameters = graph.vertices.length * (new VertexModel()).diameter;
// Search max vertex degree.
for (var i = 0; i < graph.edges.length; i++)
{
var edge = graph.edges[i];
if (!degree.hasOwnProperty(edge.vertex1.id))
{
degree[edge.vertex1.id] = 0;
}
if (!degree.hasOwnProperty(edge.vertex2.id))
{
degree[edge.vertex2.id] = 0;
}
var currentWeight = 0;
if (edge.isDirect)
{
currentWeight = edge.GetWeight() / 2;
}
else
{
currentWeight = edge.GetWeight();
}
sumDegree = sumDegree + 2 * currentWeight;
degree[edge.vertex1.id] += currentWeight;
degree[edge.vertex2.id] += currentWeight;
}
console.log("sumDegree = " + sumDegree);
for (var i = 0; i < graph.vertices.length; i++)
{
var vertex = graph.vertices[i];
if (degree.hasOwnProperty(vertex.id))
{
var currentDegree = degree[vertex.id];
console.log(currentDegree / sumDegree);
vertex.model.diameter = Math.max(Math.min((currentDegree / sumDegree) * sumOfDiameters, this.maxVertexSize), this.minVertexSize);
//sumOfDiameters
}
else
{
vertex.model.diameter = this.minVertexSize;
}
}
}
ModernGraphStyle.prototype.edgeVisualization = function()
{
var graph = this.graph;
var maxEdgeWeight = 0;
var sumWeight = 0;
var sumOfDiameters = graph.edges.length * (new EdgeModel()).width;
// Search max edge weight.
for (var i = 0; i < graph.edges.length; i++)
{
var edge = graph.edges[i];
if (edge.useWeight)
{
maxEdgeWeight = Math.max(maxEdgeWeight, edge.weight);
sumWeight = sumWeight + edge.weight;
}
}
// Search max edge weight.
if (maxEdgeWeight != 0)
{
for (var i = 0; i < graph.edges.length; i++)
{
var edge = graph.edges[i];
if (edge.useWeight)
{
//edge.model.width = (edge.weight / maxEdgeWeight) * (this.maxEdgeSize - this.minEdgeSize) + this.minEdgeSize;
edge.model.width = Math.max(Math.min((edge.weight / sumWeight) * sumOfDiameters, this.maxEdgeSize), this.minEdgeSize);
}
else
{
edge.model.width = this.minEdgeSize;
}
}
}
}
ModernGraphStyle.prototype.getObjectSelectedGroup = function(object)
{
return 0;
}
// Algorithm support multi graph
ModernGraphStyle.prototype.IsSupportMultiGraph = function()
{
return true;
}
// Factory for connected components.
function CreateAlgorithmModernGraphStyle(graph, app)
{
return new ModernGraphStyle(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateAlgorithmModernGraphStyle);

View File

@@ -0,0 +1,231 @@
/**
* Algorithm for reorder graph.
*
*/
function RadiusAndDiameter(graph, app)
{
BaseAlgorithm.apply(this, arguments);
this.diameter = 0;
this.radius = 0;
this.diameterSelectedObjects = [];
this.radiusSelectedObjects = [];
this.centerVertices = [];
this.peripheralVertices = [];
this.isNotConnected = false;
this.isOneVertex = false;
}
// inheritance.
RadiusAndDiameter.prototype = Object.create(BaseAlgorithm.prototype);
RadiusAndDiameter.prototype.getName = function(local)
{
return g_RadiusAndDiameter;
}
RadiusAndDiameter.prototype.getId = function()
{
return "OlegSh.RadiusAndDiameter";
}
// @return message for user.
RadiusAndDiameter.prototype.getMessage = function(local)
{
if (this.isNotConnected)
{
return g_graphIsDisconnected;
}
if (this.isOneVertex)
{
return g_graphIsTrivial;
}
var text = g_graphRadius + ": " + this.radius;
text = text + " (";
for (i = 0; i < this.radiusSelectedObjects.length; i++)
{
if (this.radiusSelectedObjects[i] instanceof BaseVertex)
{
text = text + this.radiusSelectedObjects[i].mainText + ((i < this.radiusSelectedObjects.length - 1) ? "&rArr;" : "");
}
}
text = text + ").";
text = text + " " + g_graphDiameter + ": " + this.diameter;
text = text + " (";
for (i = 0; i < this.diameterSelectedObjects.length; i++)
{
if (this.diameterSelectedObjects[i] instanceof BaseVertex)
{
text = text + this.diameterSelectedObjects[i].mainText + ((i < this.diameterSelectedObjects.length - 1) ? "&rArr;" : "");
}
}
text = text + ").";
return text;
}
RadiusAndDiameter.prototype.result = function(resultCallback)
{
var result = {};
result["version"] = 1;
if (this.graph.vertices.length == 1)
{
this.isOneVertex = true;
return;
}
var connectedComponents = new FindConnectedComponentNew(this.graph, this.app);
var connectedComponentNumber = connectedComponents.calculate();
if (connectedComponentNumber == 1)
{
var floid = new FloidAlgorithm(this.graph, this.app);
var matrix = floid.resultMatrix();
this.diameter = -1;
var diameterStart = 0;
var diameterFinish = 0;
this.radius = 1E10;
var radiusStart = 0;
var radiusFinish = 0;
var eccentricity = [];
for (var i = 0; i < matrix.length; i++)
{
var vertex = -1;//(i == 0 ? 1 : 0);
var vertexEccentricity = -1;//matrix[i][vertex];
for (var j = 0; j < matrix[i].length; j++)
{
if (vertexEccentricity < matrix[i][j] && i != j && matrix[i][j] != floid.infinity)
{
vertexEccentricity = matrix[i][j];
vertex = j;
}
}
var res = {value: vertexEccentricity, vertex: vertex};
eccentricity.push(res);
}
for (var i = 0; i < eccentricity.length; i++)
{
var vertexEccentricity = eccentricity[i].value;
if (vertexEccentricity < 0)
{
continue;
}
if (this.radius > vertexEccentricity)
{
this.radius = vertexEccentricity;
radiusStart = i;
radiusFinish = eccentricity[i].vertex;
}
if (this.diameter < vertexEccentricity)
{
this.diameter = vertexEccentricity;
diameterStart = i;
diameterFinish = eccentricity[i].vertex;
}
}
for (var i = 0; i < eccentricity.length; i++)
{
var vertexEccentricity = eccentricity[i].value;
if (vertexEccentricity < 0)
{
continue;
}
if (eccentricity[i].value == this.radius)
{
this.centerVertices.push(this.graph.vertices[i].id);
this.graph.vertices[i].upText = g_vertexCentral;
}
if (eccentricity[i].value == this.diameter)
{
this.peripheralVertices.push(this.graph.vertices[i].id);
this.graph.vertices[i].upText = g_vertexPeripheral;
}
}
this.diameterSelectedObjects = this.getPathByMatrix(this.graph.GetAdjacencyMatrix(), matrix, diameterStart, diameterFinish, this.diameter);
this.radiusSelectedObjects = this.getPathByMatrix(this.graph.GetAdjacencyMatrix(), matrix, radiusStart, radiusFinish, this.radius);
}
else
{
this.isNotConnected = true;
}
return result;
}
RadiusAndDiameter.prototype.getPathByMatrix = function(adjacencyMatrix, minPathMatrix, startNode, finishNode, length)
{
var res = [];
vertices = this.graph.vertices;
while (length != adjacencyMatrix[startNode][finishNode])
{
for (var i = 0; i < adjacencyMatrix.length; i ++)
{
if (minPathMatrix[i][finishNode] == length - adjacencyMatrix[startNode][i] && i != startNode)
{
res.push(vertices[startNode]);
res.push(this.graph.FindEdgeMin(vertices[startNode].id, vertices[i].id));
length -= adjacencyMatrix[startNode][i];
startNode = i;
break;
}
}
}
res.push(vertices[startNode]);
res.push(this.graph.FindEdgeMin(vertices[startNode].id, vertices[finishNode].id));
res.push(vertices[finishNode]);
return res;
}
RadiusAndDiameter.prototype.getObjectSelectedGroup = function(object)
{
var res = (this.diameterSelectedObjects.includes(object)) ? 1 : 0;
res = (this.radiusSelectedObjects.includes(object)) ? 2 : res;
//res = (this.centerVertices.includes(object.id)) ? 3 : res;
//res = (this.peripheralVertices.includes(object.id)) ? 4 : res;
return res;
}
RadiusAndDiameter.prototype.getPriority = function()
{
return 0;
}
// Algorithm support multi graph
RadiusAndDiameter.prototype.IsSupportMultiGraph = function ()
{
return true;
}
// Factory for connected components.
function CreateAlgorithmRadiusAndDiameter(graph, app)
{
return new RadiusAndDiameter(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateAlgorithmRadiusAndDiameter);

View File

@@ -0,0 +1,232 @@
/**
* 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;
// Infinity
FindShortPathNew.prototype.infinityValue = 1E9 - 1;
FindShortPathNew.prototype.getName = function(local)
{
return g_findShortPathName; //local == "ru" ? "Поиск кратчайший путь алгоритмом Дейкстры" : "Find shortest path using Dijkstra's algorithm";
}
FindShortPathNew.prototype.getId = function()
{
return "OlegSh.FindShortestPath";
}
// @return message for user.
FindShortPathNew.prototype.getMessage = function(local)
{
return this.message;
}
FindShortPathNew.prototype.getCategory = function()
{
return 1;
}
FindShortPathNew.prototype.result = function(resultCallback)
{
if (this.firstObject && this.secondObject)
{
this.outResultCallback = function (result ) { resultCallback(result); };
self = this;
this.CalculateAlgorithm("dsp",
[
{name: "start", value: this.firstObject.id},
{name: "finish", value: this.secondObject.id}
], function (pathObjects, properties, results)
{
self.resultCallback(pathObjects, properties, results);
});
}
return null;
}
FindShortPathNew.prototype.resultCallback = function(pathObjects, properties, results)
{
var outputResult = {};
outputResult["version"] = 1;
outputResult["minPath"] = true;
this.pathObjects = pathObjects;
this.properties = properties;
var bFound = results.length > 0 && results[0].value < this.infinityValue && (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) ? "&rArr;" : "");
}
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 > this.infinityValue ? "\u221E" : (propertie.lowestDistance * 1).toString());
}
}
}
}
else
{
for (var i = 0; i < this.graph.vertices.length; i++)
{
this.graph.vertices[i].upText = "";
}
}
}
FindShortPathNew.prototype.getPriority = function()
{
return -10;
}
// Algorithm support multi graph
FindShortPathNew.prototype.IsSupportMultiGraph = function ()
{
return true;
}
// Factory for connected components.
function CreateFindShortPathNew(graph, app)
{
return new FindShortPathNew(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateFindShortPathNew);

View File

@@ -0,0 +1,102 @@
/**
* 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 g_VerticesDegreeName; //local == "ru" ? "Рассчитать степень вершин" : "Calculate vertices degree";
}
VerticesDegree.prototype.getId = function()
{
return "OlegSh.VertexDegree";
}
// @return message for user.
VerticesDegree.prototype.getMessage = function(local)
{
return g_maximumDegreeOfGraph + " " + this.maxDegree;
}
VerticesDegree.prototype.result = function(resultCallback)
{
this.degree = {};
this.maxDegree = 0;
var result = {};
result["version"] = 1;
var graph = this.graph;
var thisObj = this;
var addDegreeToVertex = function (id)
{
if (thisObj.degree.hasOwnProperty(id))
{
thisObj.degree[id] ++;
currentDegree = thisObj.degree[id];
thisObj.maxDegree = Math.max(thisObj.maxDegree, currentDegree);
}
else
{
thisObj.degree[id] = 1;
}
}
for (var i = 0; i < graph.edges.length; i++)
{
var edge = graph.edges[i];
var currentDegree = 0;
addDegreeToVertex(edge.vertex1.id);
if (!edge.isDirect)
{
addDegreeToVertex(edge.vertex2.id);
}
}
for (var i = 0; i < graph.vertices.length; i++)
{
var vertex = graph.vertices[i];
if (!this.degree.hasOwnProperty(vertex.id))
{
this.degree[vertex.id] = 0;
}
vertex.upText = this.degree[vertex.id];
}
return result;
}
VerticesDegree.prototype.getObjectSelectedGroup = function(object)
{
return (this.degree.hasOwnProperty(object.id)) ? this.degree[object.id]: 0;
}
// Algorithm support multi graph
VerticesDegree.prototype.IsSupportMultiGraph = function ()
{
return true;
}
// Factory for connected components.
function CreateAlgorithmVerticesDegree(graph, app)
{
return new VerticesDegree(graph, app)
}
// Gerister connected component.
RegisterAlgorithm (CreateAlgorithmVerticesDegree);

View File

@@ -0,0 +1,117 @@
/**
* Default handler.
* Select using mouse, drag.
*
*/
function NeedAlgorithm(graph, app)
{
BaseAlgorithm.apply(this, arguments);
}
// inheritance.
NeedAlgorithm.prototype = Object.create(BaseAlgorithm.prototype);
NeedAlgorithm.prototype.getName = function(local)
{
return local == "ru" ? "Не нашли нужный алгоритм?" : "Didn't you find the algorithm you need?";
}
NeedAlgorithm.prototype.getId = function()
{
return "OlegSh.NeedAlgorithm";
}
// @return message for user.
NeedAlgorithm.prototype.getMessage = function(local)
{
return local == "ru" ? "Спасибо" : "Thank you";
}
NeedAlgorithm.prototype.result = function(resultCallback)
{
/*
var dialogButtons = {};
dialogButtons[g_send] = function() {
console.log("Message" + $( "#NeedAlgorithmMessage" ).val());
$.ajax({
type: "GET",
url: "/cgi-bin/sendEmail.php?text=" + $( "#NeedAlgorithmMessage" ).val(),
dataType: "text"
});
$( this ).dialog( "close" );
};
dialogButtons[g_close] = function() {
$( this ).dialog( "close" );
};
$( "#NeedAlgorithm" ).dialog({
resizable: false,
title: g_recommendAlgorithm,
width: 400,
modal: true,
dialogClass: 'EdgeDialog',
buttons: dialogButtons,
});
*/
var dialogButtons = {};
for (var i = 0; i < 6 && document.getElementById('vote' + i) !== null; i++)
{
document.getElementById('vote' + i)["voteIndex"] = i;
document.getElementById('vote' + i).onclick = function ()
{
console.log("Vote" + this["voteIndex"]);
$.ajax({
type: "GET",
url: "/" + SiteDir + "cgi-bin/vote.php?index=" + this["voteIndex"],
dataType: "text"
});
$("#voteDialog").dialog('close');
$("#VoteButton").hide();
}
}
dialogButtons[g_close] = function() {
$( this ).dialog( "close" );
};
$( "#voteDialog" ).dialog({
resizable: false,
title: g_vote,
width: 400,
modal: true,
dialogClass: 'EdgeDialog',
buttons: dialogButtons,
});
var result = {};
result["version"] = 1;
return result;
}
NeedAlgorithm.prototype.getObjectSelectedGroup = function(object)
{
return 0;
}
NeedAlgorithm.prototype.getPriority = function()
{
return 100;
}
// Factory for connected components.
function CreateNeedAlgorithm(graph, app)
{
return new NeedAlgorithm(graph)
}
// Gerister connected component.
RegisterAlgorithm (CreateNeedAlgorithm);

View File

@@ -0,0 +1,457 @@
/**
* Base Handler.
*
*/
function BaseHandler(app)
{
this.app = app;
this.app.setRenderPath([]);
if (this.removeStack) {
this.removeContextMenu();
}
this.contextMenuObject = null;
this.contextMenuPoint = null;
//this.app.ClearUndoStack();
}
// 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.
var res = null;
for (var i = 0; i < this.app.graph.vertices.length; i ++)
{
if (this.app.graph.vertices[i].HitTest(pos))
{
// Select last of them.
res = this.app.graph.vertices[i];
}
}
return res;
}
BaseHandler.prototype.GetSelectedArc = function(pos)
{
// Selected Arc.
for (var i = 0; i < this.app.graph.edges.length; i ++)
{
var edge = this.app.graph.edges[i];
if (edge.HitTest(new Point(pos.x, pos.y)))
return edge;
}
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()
{
var vertex1Text = document.getElementById("Vertex1");
if (vertex1Text)
{
var handler = this;
vertex1Text.onchange = function () {
for (var i = 0; i < handler.app.graph.vertices.length; i++)
{
if (handler.app.graph.vertices[i].mainText == vertex1Text.value)
{
handler.SelectFirstVertexMenu(vertex1Text, handler.app.graph.vertices[i]);
userAction("selectVertex1_menu");
break;
}
}
};
this.UpdateFirstVertexMenu(vertex1Text);
}
var vertex2Text = document.getElementById("Vertex2");
if (vertex2Text)
{
var handler = this;
vertex2Text.onchange = function () {
for (var i = 0; i < handler.app.graph.vertices.length; i++)
{
if (handler.app.graph.vertices[i].mainText == vertex2Text.value)
{
handler.SelectSecondVertexMenu(vertex2Text, handler.app.graph.vertices[i]);
userAction("selectVertex2_menu");
break;
}
}
};
this.UpdateSecondVertexMenu(vertex2Text);
}
}
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()
{
}
BaseHandler.prototype.GetSelectVertexMenu = function(menuName)
{
var res = "<input list=\"vertexList" + menuName + "\" id=\"" + menuName + "\" class=\"SelectVertexInput\"/>" +
"<datalist id=\"vertexList" + menuName + "\">";
for (var i = 0; i < this.app.graph.vertices.length; i++)
{
res = res + "<option value=\"" + this.app.graph.vertices[i].mainText + "\"/>";
}
return res + "</datalist>";
}
BaseHandler.prototype.GetSelect2VertexMenu = function()
{
return "<span style=\"float:right\">" +
this.GetSelectVertexMenu("Vertex1") + " &rarr; " + this.GetSelectVertexMenu("Vertex2") + "</span>";
}
BaseHandler.prototype.SelectFirstVertexMenu = function(vertex1Text, vertex)
{}
BaseHandler.prototype.UpdateFirstVertexMenu = function()
{}
BaseHandler.prototype.SelectSecondVertexMenu = function(vertex2Text, vertex)
{}
BaseHandler.prototype.UpdateSecondVertexMenu = function()
{}
BaseHandler.prototype.GetSelectedVertex = function()
{
return null;
}
BaseHandler.prototype.addContextMenu = function()
{
var $contextMenu = $("#contextMenu");
var handler = this;
$("#Context_Delete").click(function() {
if (handler.contextMenuObject != null) {
handler.app.PushToStack("DeleteObject");
handler.app.DeleteObject(handler.contextMenuObject);
handler.app.redrawGraph();
userAction("DeleteObject_contextMenu");
}
});
$("#Context_Rename").click(function() {
if (handler.contextMenuObject != null) {
var callback = function (enumType) {
handler.RenameVertex(enumType.GetVertexText(0), handler.contextMenuObject);
userAction("RenameVertex_contextMenu");
};
var customEnum = new TextEnumVerticesCustom(handler.app);
customEnum.ShowDialog(callback, g_rename, g_renameVertex, handler.contextMenuObject.mainText);
}
});
$("#Context_Connect").click(function() {
if (handler.contextMenuObject != null && handler.GetSelectedVertex() != null) {
var addFunc = function(firstVertex, secondVertex, direct) {
handler.app.CreateNewArc(firstVertex, secondVertex, direct,
document.getElementById('EdgeWeight').value,
$("#RadiosReplaceEdge").prop("checked"),
document.getElementById('EdgeLable').value);
handler.app.redrawGraph();
}
handler.ShowCreateEdgeDialog(handler.GetSelectedVertex(), handler.contextMenuObject, addFunc);
}
});
$("#Context_Delete_Edge").click(function() {
if (handler.contextMenuObject != null) {
handler.app.PushToStack("DeleteObject");
handler.app.DeleteObject(handler.contextMenuObject);
handler.app.redrawGraph();
userAction("DeleteObject_contextMenu");
}
});
$("#Context_Edit_Edge").click(function() {
if (handler.contextMenuObject != null) {
handler.ShowEditEdgeDialog(handler.contextMenuObject);
}
});
$("#Context_Add_Vertex").click(function() {
handler.app.PushToStack("Add");
handler.app.CreateNewGraph(handler.contextMenuPoint.x, handler.contextMenuPoint.y);
handler.app.redrawGraph();
});
$("#Context_Back_Color").click(function() {
var setupBackgroundStyle = new SetupBackgroundStyle(handler.app);
setupBackgroundStyle.show();
});
$("body").on("contextmenu", "canvas", function(e) {
handler.contextMenuPoint = handler.app.getMousePos(handler.app.canvas, e);
handler.contextMenuObject = handler.GetSelectedObject(handler.contextMenuPoint);
if (handler.contextMenuObject instanceof BaseVertex) {
$("#edgeContextMenu").hide();
$("#backgroundContextMenu").hide();
$("#vertexContextMenu").show();
if (handler.GetSelectedVertex() == null) {
$("#Context_Connect").hide();
} else {
$("#Context_Connect").show();
}
} else if (handler.contextMenuObject instanceof BaseEdge) {
$("#vertexContextMenu").hide();
$("#backgroundContextMenu").hide();
$("#edgeContextMenu").show();
} else {
$("#vertexContextMenu").hide();
$("#edgeContextMenu").hide();
$("#backgroundContextMenu").show();
}
$contextMenu.css({
display: "block",
left: e.offsetX,
top: e.offsetY
});
return false;
});
$("body").click(function() {
$contextMenu.hide();
});
}
BaseHandler.prototype.removeContextMenu = function()
{
$("body").off("contextmenu");
$("#Context_Delete").off("click");
$("#Context_Rename").off("click");
$("#Context_Connect").off("click");
$("#Context_Delete_Edge").off("click");
$("#Context_Edit_Edge").off("click");
$("#Context_Add_Vertex").off("click");
$("#Context_Back_Color").off("click");
}
BaseHandler.prototype.RenameVertex = function(text, object)
{
if (object != null && (object instanceof BaseVertex))
{
this.app.PushToStack("RenameVertex");
object.mainText = text;
this.app.redrawGraph();
}
}
BaseHandler.prototype.ShowCreateEdgeDialog = function(firstVertex, secondVertex, addEdgeCallBack) {
if (!this.app.graph.isMulti())
{
var hasEdge = this.app.graph.FindEdgeAny(firstVertex.id, secondVertex.id);
var hasReverseEdge = this.app.graph.FindEdgeAny(secondVertex.id, firstVertex.id);
if (hasEdge == null && hasReverseEdge == null)
{
$("#RadiosReplaceEdge").prop("checked", true);
$("#NewEdgeAction" ).hide();
}
else {
$( "#NewEdgeAction" ).show();
}
}
else
{
$("#RadiosAddEdge").prop("checked", true);
$("#NewEdgeAction" ).hide();
}
var dialogButtons = {};
var handler = this;
$("#CheckSaveDefaultEdge").prop("checked", false);
$("#defaultEdgeDialogBlock").show();
dialogButtons[g_orintEdge] = function() {
handler.app.PushToStack("Connect");
addEdgeCallBack(firstVertex, secondVertex, true);
//handler.AddNewEdge(selectedObject, true);
$( this ).dialog( "close" );
};
dialogButtons[g_notOrintEdge] = function() {
handler.app.PushToStack("Connect");
addEdgeCallBack(firstVertex, secondVertex, false);
//handler.AddNewEdge(selectedObject, false);
$( this ).dialog( "close" );
};
var edgePresets = this.app.GetEdgePresets();
var presetsStr = "<span onClick=\"document.getElementById('EdgeWeight').value='" + g_DefaultWeightPreset
+ "'; document.getElementById('EdgeWeightSlider').value='" + g_DefaultWeightPreset
+ "';\" style=\"cursor: pointer\" class=\"defaultWeigth\">" + g_DefaultWeightPreset + "</span>";
for(var i = 0; i < edgePresets.length; i ++)
{
var edgePreset = edgePresets[i];
presetsStr += "<span onClick=\"document.getElementById('EdgeWeight').value='" + edgePreset
+ "'; document.getElementById('EdgeWeightSlider').value=" + edgePreset
+ ";\" style=\"cursor: pointer\" class=\"defaultWeigth\">" + edgePreset + "</span>";
}
document.getElementById("EdgesPresets").innerHTML = presetsStr;
document.getElementById('EdgeLable').value = "";
$( "#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;
});
// Focues weight
setTimeout(function(){
const weightInput = document.getElementById('EdgeWeight');
if(weightInput)
{
weightInput.focus();
weightInput.select();
}
},0);
}
});
}
BaseHandler.prototype.ShowEditEdgeDialog = function(edgeObject) {
var dialogButtons = {};
var handler = this;
dialogButtons[g_save] = function() {
handler.app.PushToStack("ChangeEdge");
edgeObject.SetWeight(document.getElementById('EdgeWeight').value);
edgeObject.SetUpText(document.getElementById('EdgeLable').value);
handler.needRedraw = true;
handler.app.redrawGraph();
userAction("ChangeWeight");
$( this ).dialog( "close" );
};
document.getElementById('EdgeWeight').value = edgeObject.useWeight ? edgeObject.weight : g_noWeight;
document.getElementById('EdgeWeightSlider').value = edgeObject.useWeight ? edgeObject.weight : 0;
var edgePresets = handler.app.GetEdgePresets();
var presetsStr = "<span onClick=\"document.getElementById('EdgeWeight').value='" + g_DefaultWeightPreset + "'; document.getElementById('EdgeWeightSlider').value='" +
g_DefaultWeightPreset + "';\" style=\"cursor: pointer\" class=\"defaultWeigth\">" + g_DefaultWeightPreset + "</span>";
for(var i = 0; i < edgePresets.length; i ++)
{
var edgePreset = edgePresets[i];
presetsStr += "<span onClick=\"document.getElementById('EdgeWeight').value='" + edgePreset + "'; document.getElementById('EdgeWeightSlider').value=" +
edgePreset + ";\" style=\"cursor: pointer\" class=\"defaultWeigth\">" + edgePreset + "</span>";
}
document.getElementById("EdgesPresets").innerHTML = presetsStr;
document.getElementById('EdgeLable').value = edgeObject.upText;
$("#CheckSaveDefaultEdge").prop("checked", false);
$("#defaultEdgeDialogBlock").hide();
$( "#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;
});
}
});
}

View File

@@ -0,0 +1,226 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Connection Graph handler.
*
*/
function ConnectionGraphHandler(app)
{
this.removeStack = true;
BaseHandler.apply(this, arguments);
this.SelectFirst();
this.addContextMenu();
}
// inheritance.
ConnectionGraphHandler.prototype = Object.create(BaseHandler.prototype);
// First selected.
ConnectionGraphHandler.prototype.firstObject = null;
ConnectionGraphHandler.prototype.GetSelectedVertex = function()
{
return (this.firstObject instanceof BaseVertex) ? this.firstObject : null;
}
ConnectionGraphHandler.prototype.AddNewEdge = function(selectedObject, isDirect)
{
let newEdge = this.app.CreateNewArc(this.firstObject, selectedObject, isDirect,
document.getElementById('EdgeWeight').value,
$("#RadiosReplaceEdge").prop("checked"),
document.getElementById('EdgeLable').value);
if ($("#CheckSaveDefaultEdge").prop("checked")) {
let defaultEdge = new BaseEdge();
defaultEdge.copyFrom(this.app.graph.edges[newEdge]);
this.app.setDefaultEdge(defaultEdge);
}
this.SelectFirst();
this.app.NeedRedraw();
}
ConnectionGraphHandler.prototype.AddDefaultEdge = function(selectedObject)
{
let defaultEdge = this.app.getDefaultEdge();
let newEdge = this.app.CreateNewArc(this.firstObject, selectedObject, defaultEdge.isDirect,
defaultEdge.weight,
false,
defaultEdge.upText);
this.app.graph.edges[newEdge].useWeight = defaultEdge.useWeight;
this.SelectFirst();
this.app.NeedRedraw();
userAction("CreateDefaultEdge");
}
ConnectionGraphHandler.prototype.SelectVertex = function(selectedObject)
{
if (this.firstObject)
{
var direct = false;
var handler = this;
if (!this.app.hasDefaultEdge() || !document.getElementById('useDefaultEdge').checked) {
this.ShowCreateEdgeDialog(this.firstObject, selectedObject, function (firstVertex, secondVertex, direct) {
handler.AddNewEdge(secondVertex, direct);
});
} else {
handler.AddDefaultEdge(selectedObject);
}
}
else
{
this.SelectSecond(selectedObject);
}
this.needRedraw = true;
}
ConnectionGraphHandler.prototype.MouseDown = function(pos)
{
$('#message').unbind();
var selectedObject = this.GetSelectedGraph(pos);
if (selectedObject && (selectedObject instanceof BaseVertex))
{
this.SelectVertex(selectedObject);
}
else
{
this.SelectFirst();
this.needRedraw = true;
}
}
ConnectionGraphHandler.prototype.GetSelectedGroup = function(object)
{
return (object == this.firstObject) ? 1 : 0;
}
ConnectionGraphHandler.prototype.SelectFirst = function()
{
this.firstObject = null;
this.message = g_selectFirstVertexToConnect + this.GetUseDefaultEdgeCheckBox() +
this.GetSelect2VertexMenu();
this.message = this.AppendSpecialSctionsButton(this.message);
}
ConnectionGraphHandler.prototype.SelectSecond = function(selectedObject)
{
this.firstObject = selectedObject;
this.message = g_selectSecondVertexToConnect + this.GetUseDefaultEdgeCheckBox() +
this.GetSelect2VertexMenu();
this.message = this.AppendSpecialSctionsButton(this.message);
}
ConnectionGraphHandler.prototype.SelectFirstVertexMenu = function(vertex1Text, vertex)
{
this.firstObject = null;
this.SelectVertex(vertex);
}
ConnectionGraphHandler.prototype.UpdateFirstVertexMenu = function(vertex1Text)
{
if (this.firstObject)
{
vertex1Text.value = this.firstObject.mainText;
}
}
ConnectionGraphHandler.prototype.SelectSecondVertexMenu = function(vertex2Text, vertex)
{
this.SelectVertex(vertex);
}
ConnectionGraphHandler.prototype.UpdateSecondVertexMenu = function(vertex2Text)
{
if (this.secondObject)
{
vertex2Text.value = this.secondObject.mainText;
}
}
ConnectionGraphHandler.prototype.AppendSpecialSctionsButton = function(baseMessage)
{
let hasEdges = this.app.graph.hasEdges();
if (!hasEdges) return baseMessage;
let hasDirectedEdges = this.app.graph.hasDirectEdge();
let hasUndirectedEdges = this.app.graph.hasUndirectEdge();
let handler = this;
$('#message').on('click', '#reverseAll', function() {
handler.app.PushToStack("ReverseAllEdges");
handler.app.graph.reverseAllEdges();
handler.app.redrawGraph();
userAction("ReverseAllEdges");
});
$('#message').on('click', '#makeAllUndirected', function(){
handler.app.PushToStack("makeAllEdgesUndirected");
handler.app.graph.makeAllEdgesUndirected();
handler.app.redrawGraph();
userAction("makeAllEdgesUndirected");
});
$('#message').on('click', '#makeAllDirected', function(){
handler.app.PushToStack("makeAllEdgesDirected");
handler.app.graph.makeAllEdgesDirected();
handler.app.redrawGraph();
userAction("makeAllEdgesDirected");
});
return "<div class=\"btn-group\" style=\"float:right; position: relative; margin-left: 8px\">"
+ "<button type=\"button\" class=\"btn btn-default btn-sm dropdown-toggle\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">"
+ g_additionalActions + " <span class=\"caret\"></span>"
+ " </button> "
+ "<ul class=\"dropdown-menu dropdown-menu-right\" style=\"z-index:15; position: absolute;\">"
+ (hasDirectedEdges ? " <li><a href=\"#\" id=\"reverseAll\">" + g_reverseAllEdges + "</a></li>" : "")
+ (hasDirectedEdges ? " <li><a href=\"#\" id=\"makeAllUndirected\">" + g_makeAllUndirected + "</a></li>" : "")
+ (hasUndirectedEdges ? " <li><a href=\"#\" id=\"makeAllDirected\">" + g_makeAllDirected + "</a></li>" : "")
+ "</ul>"
+ "</div> " + baseMessage;
}
ConnectionGraphHandler.checkUseDefaultEdge = function (elem, app)
{
app.setUseDefaultEdge(elem.checked);
app.updateMessage();
};
ConnectionGraphHandler.prototype.GetUseDefaultEdgeCheckBox = function() {
if (!this.app.hasDefaultEdge()) {
return "";
}
return " <div class=\"messageSwitcher\" style=\"display:inline\">" +
"<span id=\"switcher\"><input type=\"checkbox\" id=\"useDefaultEdge\" >" +
"<label for=\"useDefaultEdge\" class=\"Switcher\"></label></span> <label for=\"useDefaultEdge\" class=\"switcherText\">" + g_reuseSavedEdge + "</label>" +
"</div>";
}
ConnectionGraphHandler.prototype.InitControls = function() {
BaseHandler.prototype.InitControls.call(this)
if (!this.app.hasDefaultEdge()) {
return;
}
let app = this.app;
$('#useDefaultEdge').unbind();
$('#useDefaultEdge').change(function() {
app.setUseDefaultEdge(this.checked);
});
$("#useDefaultEdge").prop("checked", this.app.getUseDefaultEdge());
}

View File

@@ -0,0 +1,431 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Default handler.
* Select using mouse, drag.
*
*/
function DefaultHandler(app)
{
this.removeStack = true;
BaseHandler.apply(this, arguments);
this.message = g_textsSelectAndMove + " <span class=\"hidden-phone\">" + g_selectGroupText + "</span>" + " <span class=\"hidden-phone\">" + g_useContextMenuText + "</span>";
this.selectedObjects = [];
this.dragObject = null;
this.selectedObject = null;
this.prevPosition = null;
this.groupingSelect = false;
this.selectedLogRect = false;
this.selectedLogCtrl = false;
this.saveUndo = false;
this.addContextMenu();
}
// inheritance.
DefaultHandler.prototype = Object.create(BaseHandler.prototype);
// Is pressed
DefaultHandler.prototype.pressed = false;
// Curve change value.
DefaultHandler.prototype.curveValue = 0.1;
DefaultHandler.prototype.GetSelectedVertex = function()
{
return (this.selectedObject instanceof BaseVertex) ? this.selectedObject : null;
}
DefaultHandler.prototype.MouseMove = function(pos)
{
if (this.dragObject)
{
if (!this.saveUndo)
{
this.app.PushToStack("Move");
this.saveUndo = true;
}
this.dragObject.position.x = pos.x;
this.dragObject.position.y = pos.y;
this.needRedraw = true;
}
else if (this.selectedObjects.length > 0 && this.pressed && !this.groupingSelect)
{
if (!this.saveUndo)
{
this.app.PushToStack("Move");
this.saveUndo = true;
}
var offset = (new Point(pos.x, pos.y)).subtract(this.prevPosition);
for (var i = 0; i < this.selectedObjects.length; i ++)
{
var object = this.selectedObjects[i];
if (object instanceof BaseVertex)
{
object.position = object.position.add(offset);
}
}
this.prevPosition = pos;
this.needRedraw = true;
}
else if (this.pressed)
{
if (this.groupingSelect)
{
// Rect select.
var newPos = new Point(pos.x, pos.y);
this.app.SetSelectionRect(new Rect(newPos.min(this.prevPosition), newPos.max(this.prevPosition)));
this.SelectObjectInRect(this.app.GetSelectionRect());
this.needRedraw = true;
if (!this.selectedLogRect)
{
userAction("GroupSelected.SelectRect");
this.selectedLogRect = true;
}
}
else
{
// Move work space
this.app.onCanvasMove((new Point(pos.x, pos.y)).subtract(this.prevPosition).multiply(this.app.canvasScale));
this.needRedraw = true;
}
}
}
DefaultHandler.prototype.MouseDown = function(pos)
{
this.dragObject = null;
var selectedObject = this.GetSelectedObject(pos);
var severalSelect = g_ctrlPressed;
if (selectedObject == null || (!severalSelect && !this.selectedObjects.includes(selectedObject)))
{
this.selectedObject = null;
this.selectedObjects = [];
this.groupingSelect = g_ctrlPressed;
}
if ((severalSelect || this.selectedObjects.includes(selectedObject)) && (this.selectedObjects.length > 0 || this.selectedObject != null) && selectedObject != null)
{
if (this.selectedObjects.length == 0)
{
this.selectedObjects.push(this.selectedObject);
this.selectedObject = null;
this.selectedObjects.push(selectedObject);
}
else if (!this.selectedObjects.includes(selectedObject))
{
this.selectedObjects.push(selectedObject);
}
else if (severalSelect && this.selectedObjects.includes(selectedObject))
{
var index = this.selectedObjects.indexOf(selectedObject);
this.selectedObjects.splice(index, 1);
}
if (!this.selectedLogCtrl)
{
userAction("GroupSelected.SelectCtrl");
this.selectedLogCtrl = true;
}
}
else
{
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.MouseUp = function(pos)
{
this.saveUndo = false;
this.message = g_textsSelectAndMove + " <span class=\"hidden-phone\">" + g_selectGroupText + "</span>" + " <span class=\"hidden-phone\">" + g_useContextMenuText + "</span>";
this.dragObject = null;
this.pressed = false;
this.app.canvas.style.cursor = "auto";
this.app.SetSelectionRect(null);
this.groupingSelect = false;
if (this.selectedObject != null && (this.selectedObject instanceof BaseVertex))
{
this.message = g_textsSelectAndMove
+ "<div class=\"btn-group\" style=\"float:right;position: relative;\">"
+ "<button type=\"button\" class=\"btn btn-default btn-sm dropdown-toggle\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">"
+ " " + g_action + " <span class=\"caret\"></span>"
+ " </button>"
+ "<ul class=\"dropdown-menu dropdown-menu-right\" style=\"z-index:15; position: absolute;\">"
+ " <li><a href=\"#\" id=\"renameButton\">" + g_renameVertex + "</a></li>"
+ " <li><a href=\"#\" id=\"changeCommonStyle\">" + g_commonVertexStyle + "</a></li>"
+ " <li><a href=\"#\" id=\"changeSelectedStyle\">" + g_selectedVertexStyle + "</a></li>"
+ "</ul>"
+ "</div>";
var handler = this;
var callback = function (enumType) {
handler.RenameVertex(enumType.GetVertexText(0), handler.selectedObject);
userAction("RenameVertex");
};
$('#message').unbind();
$('#message').on('click', '#renameButton', function(){
var customEnum = new TextEnumVerticesCustom(handler.app);
customEnum.ShowDialog(callback, g_rename, g_renameVertex, handler.selectedObject.mainText);
});
$('#message').on('click', '#changeCommonStyle', function(){
var selectedVertices = handler.app.GetSelectedVertices();
var setupVertexStyle = new SetupVertexStyle(handler.app);
setupVertexStyle.show(0, selectedVertices);
});
$('#message').on('click', '#changeSelectedStyle', function(){
var selectedVertices = handler.app.GetSelectedVertices();
var setupVertexStyle = new SetupVertexStyle(handler.app);
setupVertexStyle.show(1, selectedVertices);
});
}
else if (this.selectedObject != null && (this.selectedObject instanceof BaseEdge))
{
this.message = g_textsSelectAndMove
+ "<span style=\"float:right;\"><button type=\"button\" id=\"incCurvel\" class=\"btn btn-default btn-xs\"> + </button>"
+ " " + g_curveEdge + " "
+ "<button type=\"button\" id=\"decCurvel\" class=\"btn btn-default btn-xs\"> - </button> &nbsp; "
+ "<div class=\"btn-group\" style=\"float:right;position: relative;\">"
+ "<button type=\"button\" class=\"btn btn-default btn-sm dropdown-toggle\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">"
+ " " + g_action + " <span class=\"caret\"></span>"
+ " </button>"
+ "<ul class=\"dropdown-menu dropdown-menu-right\" style=\"z-index:15; position: absolute;\">"
+ " <li><a href=\"#\" id=\"editEdge\">" + g_editWeight + "</a></li>"
+ " <li><a href=\"#\" id=\"changeCommonStyle\">" + g_commonEdgeStyle + "</a></li>"
+ " <li><a href=\"#\" id=\"changeSelectedStyle\">" + g_selectedEdgeStyle + "</a></li>"
+ "</ul>"
+ "</div>";
var handler = this;
$('#message').unbind();
$('#message').on('click', '#editEdge', function(){
handler.ShowEditEdgeDialog(handler.selectedObject);
});
$('#message').on('click', '#incCurvel', function(){
handler.app.PushToStack("ChangeCurvelEdge");
handler.selectedObject.model.ChangeCurveValue(DefaultHandler.prototype.curveValue);
handler.needRedraw = true;
handler.app.redrawGraph();
userAction("Edge.Bend");
});
$('#message').on('click', '#decCurvel', function(){
handler.app.PushToStack("ChangeCurvelEdge");
handler.selectedObject.model.ChangeCurveValue(-DefaultHandler.prototype.curveValue);
handler.needRedraw = true;
handler.app.redrawGraph();
userAction("Edge.Bend");
});
$('#message').on('click', '#changeCommonStyle', function(){
var selectedEdges = handler.app.GetSelectedEdges();
var setupVertexStyle = new SetupEdgeStyle(handler.app);
setupVertexStyle.show(0, selectedEdges);
});
$('#message').on('click', '#changeSelectedStyle', function(){
var selectedEdges = handler.app.GetSelectedEdges();
var setupVertexStyle = new SetupEdgeStyle(handler.app);
setupVertexStyle.show(1, selectedEdges);
});
}
else if (this.selectedObjects.length > 0)
{
this.message = g_dragGroupText + " <span class=\"hidden-phone\">" + g_selectGroupText + "</span>";
var hasVertices = false;
var hasEdges = false;
for(var i = 0; i < this.selectedObjects.length; i ++)
{
var object = this.selectedObjects[i];
if (object instanceof BaseVertex)
{
hasVertices = true;
}
else if (object instanceof BaseEdge)
{
hasEdges = true;
}
}
this.message = this.message + "<span style=\"float:right;position: relative;\">";
this.message = this.message
+ "<button type=\"button\" id=\"DublicateSelected\" class=\"btn btn-default btn-xs\">"
+ g_copyGroupeButton + "</button> &nbsp &nbsp"
+ "<button type=\"button\" id=\"RemoveSelected\" class=\"btn btn-default btn-xs\">"
+ g_removeGroupeButton + "</button>"
this.message = this.message
+ " &nbsp &nbsp <button type=\"button\" class=\"btn btn-default btn-xs dropdown-toggle\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">"
+ " " + g_action + " <span class=\"caret\"></span>"
+ " </button>"
+ "<ul class=\"dropdown-menu dropdown-menu-right\" style=\"z-index:15; position: absolute;\">";
if (hasEdges) {
this.message = this.message + " <li><a href=\"#\" id=\"changeCommonStyleEdge\">" + g_commonEdgeStyle + "</a></li>";
this.message = this.message + " <li><a href=\"#\" id=\"changeSelectedStyleEdge\">" + g_selectedEdgeStyle + "</a></li>";
}
if (hasVertices) {
this.message = this.message + " <li><a href=\"#\" id=\"changeCommonStyleVertex\">" + g_commonVertexStyle + "</a></li>";
this.message = this.message + " <li><a href=\"#\" id=\"changeSelectedStyleVertex\">" + g_selectedVertexStyle + "</a></li>";
}
this.message = this.message
+ "</ul>"
+ "</span>";
var handler = this;
$('#message').unbind();
$('#message').on('click', '#DublicateSelected', function(){
handler.app.PushToStack("DublicateSelection");
userAction("GroupSelected.Dublicate");
var newSelected = [];
var copyVertex = {};
// Copy vertex
for(var i = 0; i < handler.selectedObjects.length; i ++)
{
var object = handler.selectedObjects[i];
if (object instanceof BaseVertex)
{
var newObject = new BaseVertex()
newObject.copyFrom(object);
newObject.vertexEnumType = null;
handler.app.AddNewVertex(newObject);
var vertex = newObject;
var diameter = (new VertexModel()).diameter;
vertex.position.offset(diameter, diameter);
newSelected.push(vertex);
copyVertex[object.id] = vertex;
}
}
// Copy edge
for (var i = 0; i < handler.selectedObjects.length; i ++)
{
var object = handler.selectedObjects[i];
if (object instanceof BaseEdge)
{
var newObject = new BaseEdge()
newObject.copyFrom(object);
var toNewVertex = false;
if (newObject.vertex1.id in copyVertex)
{
newObject.vertex1 = copyVertex[newObject.vertex1.id];
toNewVertex = true;
}
if (newObject.vertex2.id in copyVertex)
{
newObject.vertex2 = copyVertex[newObject.vertex2.id];
toNewVertex = true;
}
handler.app.AddNewEdge(newObject);
if (!toNewVertex)
{
var neighborEdges = handler.app.graph.getNeighborEdges(newObject);
if (neighborEdges.length >= 1)
{
var curve = handler.app.GetAvailableCurveValue(neighborEdges, newObject);
newObject.model.SetCurveValue(curve);
}
}
newSelected.push(newObject);
}
}
handler.selectedObjects = newSelected;
handler.needRedraw = true;
handler.app.redrawGraph();
});
$('#message').on('click', '#RemoveSelected', function(){
handler.app.PushToStack("RemoveSelection");
userAction("GroupSelected.Remove");
for(var i = 0; i < handler.selectedObjects.length; i ++)
handler.app.DeleteObject(handler.selectedObjects[i]);
handler.selectedObjects = [];
handler.needRedraw = true;
handler.app.redrawGraph();
handler.message = g_textsSelectAndMove + " <span class=\"hidden-phone\">" + g_selectGroupText + "</span>";
});
if (hasEdges) {
$('#message').on('click', '#changeCommonStyleEdge', function(){
var selectedEdges = handler.app.GetSelectedEdges();
var setupVertexStyle = new SetupEdgeStyle(handler.app);
setupVertexStyle.show(0, selectedEdges);
});
$('#message').on('click', '#changeSelectedStyleEdge', function(){
var selectedEdges = handler.app.GetSelectedEdges();
var setupVertexStyle = new SetupEdgeStyle(handler.app);
setupVertexStyle.show(1, selectedEdges);
});
}
if (hasVertices) {
$('#message').on('click', '#changeCommonStyleVertex', function(){
var selectedVertices = handler.app.GetSelectedVertices();
var setupVertexStyle = new SetupVertexStyle(handler.app);
setupVertexStyle.show(0, selectedVertices);
});
$('#message').on('click', '#changeSelectedStyleVertex', function(){
var selectedVertices = handler.app.GetSelectedVertices();
var setupVertexStyle = new SetupVertexStyle(handler.app);
setupVertexStyle.show(1, selectedVertices);
});
}
}
this.needRedraw = true;
}
DefaultHandler.prototype.GetSelectedGroup = function(object)
{
return (object == this.dragObject) || (object == this.selectedObject) ? 1 : 0 || this.selectedObjects.includes(object);
}
DefaultHandler.prototype.SelectObjectInRect = function (rect)
{
this.selectedObjects = [];
var vertices = this.app.graph.vertices;
for (var i = 0; i < vertices.length; i ++)
{
if (rect.isIn(vertices[i].position) && !this.selectedObjects.includes(vertices[i]))
this.selectedObjects.push(vertices[i]);
}
// Selected Arc.
var edges = this.app.graph.edges;
for (var i = 0; i < edges.length; i ++)
{
var edge = edges[i];
if (rect.isIn(edge.vertex1.position) && rect.isIn(edge.vertex2.position) && !this.selectedObjects.includes(edge))
this.selectedObjects.push(edge);
}
}

View File

@@ -0,0 +1,52 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Delete Graph handler.
*
*/
function DeleteGraphHandler(app)
{
this.removeStack = true;
BaseHandler.apply(this, arguments);
this.message = g_selectObjectToDelete;
this.addContextMenu();
}
// inheritance.
DeleteGraphHandler.prototype = Object.create(BaseHandler.prototype);
DeleteGraphHandler.prototype.MouseDown = function(pos)
{
var selectedObject = this.GetSelectedObject(pos);
if (!this.app.IsCorrectObject(selectedObject))
return;
this.app.PushToStack("Delete");
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()
{
this.app.PushToStack("DeleteAll");
// Selected Graph.
this.app.graph = new Graph();
this.app.savedGraphName = "";
this.needRedraw = true;
}

View File

@@ -0,0 +1,10 @@
{
let modulDir = "features/draw_graph/";
doInclude ([
include ("model/BaseBackgroundDrawer.js", modulDir),
include ("model/BaseEdgeDrawer.js", modulDir),
include ("model/BaseVertexDrawer.js", modulDir)
])
}

View File

@@ -0,0 +1,89 @@
/**
* Graph drawer.
*/
function CommonBackgroundStyle()
{
this.commonColor = '#ffffff';
this.commonOpacity = 1.0;
this.image = null;
}
CommonBackgroundStyle.prototype.Clear = function ()
{
delete this.commonColor;
delete this.commonOpacity;
delete this.image;
}
CommonBackgroundStyle.prototype.ShouldLoad = function (field)
{
return true;
}
CommonBackgroundStyle.prototype.saveToJson = function (field)
{
return JSON.stringify({commonColor: this.commonColor, commonOpacity: this.commonOpacity, image: this.image != null ? this.image.src : null});
}
CommonBackgroundStyle.prototype.loadFromJson = function (json, callbackOnLoaded)
{
this.commonColor = json["commonColor"];
this.commonOpacity = json["commonOpacity"];
this.image = null;
if (typeof json["image"] === 'string') {
this.image = new Image();
this.image.onload = function() {
callbackOnLoaded();
}
this.image.src = json["image"];
}
}
PrintBackgroundStyle.prototype = Object.create(CommonBackgroundStyle.prototype);
function PrintBackgroundStyle()
{
CommonBackgroundStyle.apply(this, arguments);
this.commonColor = '#ffffff';
this.commonOpacity = 1.0;
this.image = null;
}
function BaseBackgroundDrawer(context)
{
this.context = context;
}
BaseBackgroundDrawer.prototype.Draw = function(style, width, height, position, scale)
{
var context = this.context;
var rect = new Rect(position, position.add(new Point(width / scale, height / scale)));
context.clearRect(-rect.minPoint.x, -rect.minPoint.y, rect.size().x + 1, rect.size().y + 1);
var oldOpacity = context.globalAlpha;
if (style.commonOpacity > 0.0)
{
context.globalAlpha = style.commonOpacity;
context.fillStyle = style.commonColor;
context.fillRect(-rect.minPoint.x, -rect.minPoint.y, rect.size().x + 1, rect.size().y + 1);
this.DrawImage(style, width, height, position, scale);
}
context.globalAlpha = oldOpacity;
}
BaseBackgroundDrawer.prototype.DrawImage = function(style, width, height, position, scale)
{
if (style.image == null) {
return;
}
var context = this.context;
context.clearRect(0, 0, style.image.width, style.image.height);
context.drawImage(style.image, 0, 0)
}

View File

@@ -0,0 +1,564 @@
/**
* Graph drawer.
*/
const lineDashTypes = [
[],
[4, 4],
[12, 12],
[16, 4, 4, 4],
];
// Common text position
const WeightTextCenter = 0,
WeightTextUp = 1;
function BaseEdgeStyle()
{
this.baseStyles = [];
}
BaseEdgeStyle.prototype.GetStyle = function (baseStyle, object)
{
this.baseStyles.forEach(function(element) {
var styleObject = globalApplication.GetStyle("edge", element, object);
baseStyle = styleObject.GetStyle(baseStyle, object);
});
if (this.hasOwnProperty('weightText'))
baseStyle.weightText = this.weightText;
if (this.hasOwnProperty('strokeStyle'))
baseStyle.strokeStyle = this.strokeStyle;
if (this.hasOwnProperty('fillStyle'))
baseStyle.fillStyle = this.fillStyle;
if (this.hasOwnProperty('textPadding'))
baseStyle.textPadding = this.textPadding;
if (this.hasOwnProperty('textStrokeWidth'))
baseStyle.textStrokeWidth = this.textStrokeWidth;
if (this.hasOwnProperty('lineDash'))
baseStyle.lineDash = this.lineDash;
if (this.hasOwnProperty('additionalTextColor'))
baseStyle.additionalTextColor = this.additionalTextColor;
if (this.hasOwnProperty('weightPosition'))
baseStyle.weightPosition = this.weightPosition;
return this.FixNewFields(baseStyle);
}
BaseEdgeStyle.prototype.FixNewFields = function (style)
{
if (!style.hasOwnProperty('lineDash'))
style.lineDash = 0;
if (!style.hasOwnProperty('weightPosition'))
style.weightPosition = WeightTextCenter;
return style;
}
BaseEdgeStyle.prototype.Clear = function ()
{
delete this.weightText;
delete this.strokeStyle;
delete this.fillStyle;
delete this.textPadding;
delete this.textStrokeWidth;
delete this.lineDash;
delete this.additionalTextColor;
delete this.weightPosition;
}
BaseEdgeStyle.prototype.ShouldLoad = function (field)
{
return field != "baseStyles";
}
function CommonEdgeStyle()
{
BaseEdgeStyle.apply(this, arguments);
this.strokeStyle = '#c7b7c7';
this.weightText = '#f0d543';
this.fillStyle = '#68aeba';
this.textPadding = 4;
this.textStrokeWidth = 2;
this.lineDash = 0;
this.additionalTextColor = '#c7b7c7';
this.weightPosition = WeightTextCenter;
}
CommonEdgeStyle.prototype = Object.create(BaseEdgeStyle.prototype);
function CommonPrintEdgeStyle()
{
BaseEdgeStyle.apply(this, arguments);
this.strokeStyle = '#000000';
this.weightText = '#000000';
this.fillStyle = '#FFFFFF';
this.textPadding = 4;
this.textStrokeWidth = 2;
this.baseStyles.push("common");
}
CommonPrintEdgeStyle.prototype = Object.create(BaseEdgeStyle.prototype);
function SelectedEdgeStyle0()
{
BaseEdgeStyle.apply(this, arguments);
this.strokeStyle = '#f0d543';
this.weightText = '#f0d543';
this.fillStyle = '#c7627a';
this.baseStyles.push("common");
}
SelectedEdgeStyle0.prototype = Object.create(BaseEdgeStyle.prototype);
function SelectedEdgeStyle1()
{
BaseEdgeStyle.apply(this, arguments);
this.strokeStyle = '#8FBF83';
this.weightText = '#8FBF83';
this.fillStyle = '#F9F9D5';
this.baseStyles.push("selected");
}
SelectedEdgeStyle1.prototype = Object.create(BaseEdgeStyle.prototype);
function SelectedEdgeStyle2()
{
BaseEdgeStyle.apply(this, arguments);
this.strokeStyle = '#8C4C86';
this.weightText = '#8C4C86';
this.fillStyle = '#253267';
this.baseStyles.push("selected");
}
SelectedEdgeStyle2.prototype = Object.create(BaseEdgeStyle.prototype);
function SelectedEdgeStyle3()
{
BaseEdgeStyle.apply(this, arguments);
this.strokeStyle = '#6188FF';
this.weightText = '#6188FF';
this.fillStyle = '#E97CF9';
this.baseStyles.push("selected");
}
SelectedEdgeStyle3.prototype = Object.create(BaseEdgeStyle.prototype);
function SelectedEdgeStyle4()
{
BaseEdgeStyle.apply(this, arguments);
this.strokeStyle = '#C6B484';
this.weightText = '#C6B484';
this.fillStyle = '#E0DEE1';
this.baseStyles.push("selected");
}
SelectedEdgeStyle4.prototype = Object.create(BaseEdgeStyle.prototype);
function SelectedEdgePrintStyle()
{
BaseEdgeStyle.apply(this, arguments);
this.strokeStyle = '#AAAAAA';
this.weightText = '#000000';
this.fillStyle = '#AAAAAA';
this.baseStyles.push("printed");
}
SelectedEdgePrintStyle.prototype = Object.create(BaseEdgeStyle.prototype);
var DefaultSelectedEdgeStyles = [new SelectedEdgeStyle0(), new SelectedEdgeStyle1(),
new SelectedEdgeStyle2(), new SelectedEdgeStyle3(), new SelectedEdgeStyle4()];
var DefaultPrintSelectedEdgeStyles = [new SelectedEdgePrintStyle()];
function BaseEdgeDrawer(context, drawObjects)
{
if (drawObjects === undefined)
{
drawObjects = null;
}
this.context = context;
this.drawObject = null;
this.drawArc = null;
this.startArrowDirection = null;
this.finishArrowDirection = null;
this.textCenterObject = null;
this.getPointOnArc = null;
if (drawObjects)
{
if (drawObjects.hasOwnProperty("drawObject"))
this.drawObject = drawObjects.drawObject;
if (drawObjects.hasOwnProperty("drawArc"))
this.drawArc = drawObjects.drawArc;
if (drawObjects.hasOwnProperty("startArrowDirection"))
this.startArrowDirection = drawObjects.startArrowDirection;
if (drawObjects.hasOwnProperty("finishArrowDirection"))
this.finishArrowDirection = drawObjects.finishArrowDirection;
if (drawObjects.hasOwnProperty("textCenterObject"))
this.textCenterObject = drawObjects.textCenterObject;
if (drawObjects.hasOwnProperty("getPointOnArc"))
this.getPointOnArc = drawObjects.getPointOnArc;
}
}
BaseEdgeDrawer.prototype.Draw = function(baseEdge, arcStyle)
{
if (this.drawObject && this.drawObject != this)
{
this.drawObject.Draw(baseEdge, arcStyle);
return;
}
this.SetupStyle(baseEdge, arcStyle);
var lengthArrow = Math.max(baseEdge.model.width * 4, 8);
var widthArrow = Math.max(baseEdge.model.width * 2, 4);
var position1 = baseEdge.vertex1.position;
var position2 = baseEdge.vertex2.position;
var direction = position1.subtract(position2);
direction.normalize(1.0);
var positions = baseEdge.GetEdgePositionsShift();
var hasStartStyle = !position1.equals(position2) && baseEdge.GetStartEdgeStyle() != "";
var hasFinishStyle = !position1.equals(position2) && baseEdge.GetFinishEdgeStyle() != "";
var arcPos1 = positions[0];
var arcPos2 = positions[1];
if (hasStartStyle)
{
var dirArrow = this.GetStartArrowDirection(positions[0], positions[1], lengthArrow);
arcPos1 = arcPos1.add(dirArrow.multiply(lengthArrow / 2));
}
if (hasFinishStyle)
{
var dirArrow = this.GetFinishArrowDirection(positions[0], positions[1], lengthArrow);
arcPos2 = arcPos2.add(dirArrow.multiply(-lengthArrow / 2));
}
this.DrawArc (arcPos1, arcPos2, arcStyle);
this.context.fillStyle = this.context.strokeStyle;
this.context.lineWidth = 0;
if (hasStartStyle)
{
this.DrawArrow(positions[0], this.GetStartArrowDirection(positions[0], positions[1], lengthArrow), lengthArrow, widthArrow);
}
if (hasFinishStyle)
{
this.DrawArrow(positions[1], this.GetFinishArrowDirection(positions[0], positions[1], lengthArrow), lengthArrow, widthArrow);
}
this.SetupStyle(baseEdge, arcStyle);
if (arcStyle.weightPosition == WeightTextCenter)
{
if (baseEdge.GetText().length > 0)
{
this.DrawWeight(positions[0], positions[1], baseEdge.GetText(), arcStyle, false);
}
if (baseEdge.GetUpText().length > 0)
{
this.DrawUpText(positions[0], positions[1], baseEdge.GetUpText(), arcStyle, false, arcStyle.additionalTextColor, baseEdge.model.width / 2 + 20, null);
}
}
else if (arcStyle.weightPosition == WeightTextUp)
{
if (baseEdge.GetText().length > 0)
{
this.DrawUpText(positions[0], positions[1], baseEdge.GetText(), arcStyle, false, arcStyle.weightText, baseEdge.model.width / 2 + 10, "16px");
}
if (baseEdge.GetUpText().length > 0)
{
this.DrawUpText(positions[0], positions[1], baseEdge.GetUpText(), arcStyle, false, arcStyle.additionalTextColor, - baseEdge.model.width / 2 - 15, null);
}
}
}
BaseEdgeDrawer.prototype.SetupStyle = function(baseEdge, arcStyle)
{
this.context.lineWidth = baseEdge.model.width;
this.context.strokeStyle = arcStyle.strokeStyle;
this.context.fillStyle = arcStyle.fillStyle;
this.model = baseEdge.model;
this.style = arcStyle;
}
BaseEdgeDrawer.prototype.DrawArc = function(position1, position2, arcStyle)
{
if (this.drawArc && this.drawArc != this)
{
this.drawArc.DrawArc(position1, position2, arcStyle);
return;
}
this.context.setLineDash(lineDashTypes[arcStyle.lineDash]);
if (position1.equals(position2))
{
this.context.beginPath();
this.context.arc(position1.x - Math.cos(this.model.GetLoopShiftAngel()) * this.model.GetLoopSize(),
position1.y - Math.sin(this.model.GetLoopShiftAngel()) * this.model.GetLoopSize(), this.model.GetLoopSize(), 0, 2 * Math.PI);
this.context.stroke();
}
else
{
this.context.beginPath();
this.context.moveTo(position1.x, position1.y);
this.context.lineTo(position2.x, position2.y);
this.context.stroke();
}
this.context.setLineDash([]);
}
BaseEdgeDrawer.prototype.DrawWeight = function(position1, position2, text, arcStyle, hasPair)
{
var centerPoint = this.GetTextCenterPoint(position1, position2, hasPair, arcStyle);
this.context.font = "bold 16px sans-serif";
this.context.textBaseline = "middle";
this.context.lineWidth = arcStyle.textStrokeWidth;
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.DrawUpText = function(position1, position2, text, arcStyle, hasPair, color, offset, fontSize)
{
var centerPoint = this.GetTextCenterPoint(position1, position2, hasPair, arcStyle);
this.context.font = fontSize == null ? "bold 12px sans-serif" : "bold " + fontSize + " sans-serif";
this.context.textBaseline = "middle";
var widthText = this.context.measureText(text).width;
this.context.fillStyle = color;
var vectorEdge = new Point(position2.x - position1.x, position2.y - position1.y);
var angleRadians = Math.atan2(vectorEdge.y, vectorEdge.x);
if (angleRadians > Math.PI / 2 || angleRadians < -Math.PI / 2)
{
vectorEdge = new Point(position1.x - position2.x, position1.y - position2.y);
angleRadians = Math.atan2(vectorEdge.y, vectorEdge.x);
}
var normalize = vectorEdge.normal().normalizeCopy(offset);
this.context.save();
this.context.translate(centerPoint.x - normalize.x, centerPoint.y - normalize.y);
this.context.rotate(angleRadians);
this.context.textAlign = "center";
this.context.fillText(text, 0, 0);
this.context.restore();
}
BaseEdgeDrawer.prototype.DrawArrow = function(position, direction, length, width)
{
var normal = direction.normal();
var pointOnLine = position.subtract(direction.multiply(length));
var point1 = pointOnLine.add(normal.multiply(width));
var point2 = pointOnLine.add(normal.multiply(-width));
this.context.beginPath();
this.context.moveTo(position.x, position.y);
this.context.lineTo(point1.x, point1.y);
this.context.lineTo(point2.x, point2.y);
this.context.lineTo(position.x, position.y);
this.context.closePath();
this.context.fill();
}
BaseEdgeDrawer.prototype.GetStartArrowDirection = function(position1, position2, lengthArrow)
{
if (this.startArrowDirection && this.startArrowDirection != this)
{
return this.startArrowDirection.GetStartArrowDirection(position1, position2, lengthArrow);
}
var direction = position1.subtract(position2);
direction.normalize(1.0);
return direction;
}
BaseEdgeDrawer.prototype.GetFinishArrowDirection = function(position1, position2, lengthArrow)
{
if (this.finishArrowDirection && this.finishArrowDirection != this)
{
return this.finishArrowDirection.GetFinishArrowDirection(position1, position2, lengthArrow);
}
var direction = position2.subtract(position1);
direction.normalize(1.0);
return direction;
}
BaseEdgeDrawer.prototype.GetTextCenterPoint = function (position1, position2, hasPair, arcStyle)
{
if (this.textCenterObject && this.textCenterObject != this)
{
return this.textCenterObject.GetTextCenterPoint(position1, position2, hasPair, arcStyle);
}
var textShift = Math.min(12 / position1.subtract(position2).length(), 0.4);
var centerPoint = Point.interpolate(position1, position2, 0.5);
if (position1.equals(position2))
{
let sinVal = Math.sin(this.model.GetLoopShiftAngel());
let cosVal = Math.cos(this.model.GetLoopShiftAngel());
centerPoint.x = centerPoint.x - cosVal * this.model.GetLoopSize();
centerPoint.y = centerPoint.y - (sinVal + Math.sign(sinVal) * 1.0) * this.model.GetLoopSize();
}
return centerPoint;
}
BaseEdgeDrawer.prototype.GetPointOnArc = function (position1, position2, percent)
{
if (this.getPointOnArc && this.getPointOnArc != this)
{
return this.getPointOnArc.GetPointOnArc(position1, position2, percent);
}
return Point.interpolate(position1, position2, percent);
}
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.context.lineWidth = 10;
var positions = baseEdge.GetEdgePositionsShift();
var progressSize = 10;
if (positions[0].equals(positions[1]))
{
var sizeInRadian = progressSize / (2 * Math.PI * this.baseDrawer.model.GetLoopSize()) * 6;
this.context.beginPath();
this.context.arc(positions[0].x - Math.cos(this.baseDrawer.model.GetLoopShiftAngel()) * this.baseDrawer.model.GetLoopSize(),
positions[0].y - Math.sin(this.baseDrawer.model.GetLoopShiftAngel()) * this.baseDrawer.model.GetLoopSize(), this.baseDrawer.model.GetLoopSize(), this.progress * 2 * Math.PI, this.progress * 2 * Math.PI + sizeInRadian);
this.context.stroke();
}
else
{
var startPosition = this.baseDrawer.GetPointOnArc(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.stroke();
}
}
function CurvedArcDrawer(context, model)
{
this.context = context;
this.model = model;
}
CurvedArcDrawer.prototype = Object.create(BaseEdgeDrawer.prototype);
CurvedArcDrawer.prototype.DrawArc = function(position1, position2, arcStyle)
{
this.context.setLineDash(lineDashTypes[arcStyle.lineDash]);
if (position1.equals(position2))
{
this.context.beginPath();
this.context.arc(position1.x - Math.cos(this.model.GetLoopShiftAngel()) * this.model.GetLoopSize(),
position1.y - Math.sin(this.model.GetLoopShiftAngel()) * this.model.GetLoopSize(), this.model.GetLoopSize(), 0, 2 * Math.PI);
this.context.closePath();
this.context.stroke();
}
else
{
var points = this.model.GetBezierPoints(position1, position2);
var firstBezierPoint = points[0];
var secondBezierPoint = points[1];
this.context.beginPath();
this.context.moveTo(position1.x, position1.y);
this.context.bezierCurveTo(firstBezierPoint.x, firstBezierPoint.y, secondBezierPoint.x, secondBezierPoint.y, position2.x, position2.y);
this.context.stroke();
}
this.context.setLineDash([]);
}
CurvedArcDrawer.prototype.GetStartArrowDirection = function(position1, position2, lengthArrow)
{
var dist = position1.distance(position2);
var direction = position1.subtract(this.model.GetCurvePoint(position1, position2, lengthArrow / dist));
direction.normalize(1.0);
return direction;
}
CurvedArcDrawer.prototype.GetFinishArrowDirection = function(position1, position2, lengthArrow)
{
var dist = position1.distance(position2);
var direction = position2.subtract(this.model.GetCurvePoint(position1, position2, 1.0 - lengthArrow / dist));
direction.normalize(1.0);
return direction;
}
CurvedArcDrawer.prototype.GetTextCenterPoint = function (position1, position2, hasPair, arcStyle)
{
var centerPoint = this.model.GetCurvePoint(position1, position2, 0.5)
if (position1.equals(position2))
{
let sinVal = Math.sin(this.model.GetLoopShiftAngel());
let cosVal = Math.cos(this.model.GetLoopShiftAngel());
centerPoint.x = centerPoint.x - cosVal * this.model.GetLoopSize();
centerPoint.y = centerPoint.y - (sinVal + Math.sign(sinVal) * 1.0) * this.model.GetLoopSize();
}
return centerPoint;
}
CurvedArcDrawer.prototype.GetPointOnArc = function (position1, position2, percent)
{
return this.model.GetCurvePoint(position1, position2, percent);
}

View File

@@ -0,0 +1,428 @@
/**
* Graph drawer.
*/
// Test graph: http://localhost:8080/?graph=oimDPgsdgiAjWGBHZZcst
// Vertex shape
const VertexCircleShape = 0,
VertexSquareShape = 1,
VertexTriangleShape = 2,
VertexPentagonShape = 3,
VertexHomeShape = 4,
VertexTextboxShape = 5;
VertexSnowflakeShape = 6;
// Common text position
const CommonTextCenter = 0,
CommonTextUp = 1;
// Fonts
const DefaultFont = "px sans-serif",
MainTextFontSize = 16,
TopTextFontSize = 12.0;
function GetSquarePoints(diameter)
{
var res = [];
var a = diameter;
res.push(new Point(-a / 2, - a / 2));
res.push(new Point(a / 2, -a / 2));
res.push(new Point(a / 2, a / 2));
res.push(new Point(-a / 2, a / 2));
return res;
}
function GetTrianglePoints(diameter)
{
var res = [];
var effectiveDiameter = diameter * 1.5;
var upOffset = effectiveDiameter / 2;
var downOffset = effectiveDiameter / 4;
var lrOffset = effectiveDiameter * 3 / (Math.sqrt(3) * 4);
res.push(new Point(0, - upOffset));
res.push(new Point(lrOffset, downOffset));
res.push(new Point(- lrOffset, downOffset));
return res;
}
function GetPentagonPoints(diameter)
{
var res = [];
var baseValue = diameter / 2 * 1.2;
res.push(new Point(0, - baseValue));
res.push((new Point(0, - baseValue)).rotate(new Point(0, 0), 72));
res.push((new Point(0, - baseValue)).rotate(new Point(0, 0), 72 * 2));
res.push((new Point(0, - baseValue)).rotate(new Point(0, 0), 72 * 3));
res.push((new Point(0, - baseValue)).rotate(new Point(0, 0), 72 * 4));
res.push((new Point(0, - baseValue)).rotate(new Point(0, 0), 72 * 5));
return res;
}
function GetTextboxPoints(diameter, text)
{
var res = [];
var width = diameter;
var height = diameter;
if (text)
{
var tempContext = document.createElement('canvas').getContext('2d');
tempContext.font = "bold " + MainTextFontSize + DefaultFont;
width = tempContext.measureText(text).width + diameter / 2;
}
res.push(new Point(-width / 2, -height / 2));
res.push(new Point(width / 2, -height / 2));
res.push(new Point(width / 2, height / 2));
res.push(new Point(-width / 2, height / 2));
return res;
}
function GetShowflakePoints(diameter)
{
var res = [];
var superSmallRadius = diameter * 0.8 / 2;
var smallRadius = diameter * 0.95 / 2;
var bigRadius = diameter * 1.5 / 2;
let angel = 8;
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), - angel));
res.push(new Point(smallRadius, 0));
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), angel));
res.push(new Point(bigRadius, 0).rotate(new Point(0, 0), 30));
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 - angel));
res.push(new Point(smallRadius, 0).rotate(new Point(0, 0), 60));
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + angel));
res.push(new Point(bigRadius, 0).rotate(new Point(0, 0), 30 + 60));
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 - angel));
res.push(new Point(smallRadius, 0).rotate(new Point(0, 0), 60 + 60));
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + angel));
res.push(new Point(bigRadius, 0).rotate(new Point(0, 0), 30 + 60 + 60));
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 - angel));
res.push(new Point(smallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60));
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + angel));
res.push(new Point(bigRadius, 0).rotate(new Point(0, 0), 30 + 60 + 60 + 60));
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + 60 - angel));
res.push(new Point(smallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + 60));
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + 60 + angel));
res.push(new Point(bigRadius, 0).rotate(new Point(0, 0), 30 + 60 + 60 + 60 + 60));
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + 60 + 60 - angel));
res.push(new Point(smallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + 60 + 60));
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + 60 + 60 + angel));
res.push(new Point(bigRadius, 0).rotate(new Point(0, 0), 30 + 60 + 60 + 60 + 60 + 60));
return res;
}
function GetPointsForShape(shape, diameter, text=null)
{
switch (parseInt(shape))
{
case VertexSquareShape: return GetSquarePoints(diameter); break;
case VertexTriangleShape: return GetTrianglePoints(diameter); break;
case VertexPentagonShape: return GetPentagonPoints(diameter); break;
case VertexTextboxShape: return GetTextboxPoints(diameter, text); break;
case VertexSnowflakeShape: return GetShowflakePoints(diameter); break;
default: return null; break;
}
}
function GetSizeForShape(shape, diameter)
{
switch (parseInt(shape))
{
case VertexSquareShape: return diameter; break;
case VertexTriangleShape: return diameter * 1.5; break;
case VertexPentagonShape: return diameter * 1.2; break;
case VertexTextboxShape: return diameter; break;
case VertexSnowflakeShape: return diameter * 1.5; break;
default: return diameter; break;
}
}
function BaseVertexStyle()
{
this.baseStyles = [];
}
BaseVertexStyle.prototype.GetStyle = function (baseStyle, object)
{
this.baseStyles.forEach(function(element) {
var styleObject = globalApplication.GetStyle("vertex", element, object);
baseStyle = styleObject.GetStyle(baseStyle, object);
});
if (this.hasOwnProperty('lineWidth'))
baseStyle.lineWidth = this.lineWidth;
if (this.hasOwnProperty('strokeStyle'))
baseStyle.strokeStyle = this.strokeStyle;
if (this.hasOwnProperty('fillStyle'))
baseStyle.fillStyle = this.fillStyle;
if (this.hasOwnProperty('mainTextColor'))
baseStyle.mainTextColor = this.mainTextColor;
if (this.hasOwnProperty('shape'))
baseStyle.shape = this.shape;
if (this.hasOwnProperty('upTextColor'))
baseStyle.upTextColor = this.upTextColor;
if (this.hasOwnProperty('commonTextPosition'))
baseStyle.commonTextPosition = this.commonTextPosition;
baseStyle.lineWidth = parseInt(baseStyle.lineWidth);
return this.FixNewFields(baseStyle);
}
BaseVertexStyle.prototype.FixNewFields = function (style)
{
if (!style.hasOwnProperty('shape'))
style.shape = VertexCircleShape;
if (!style.hasOwnProperty('commonTextPosition'))
style.commonTextPosition = CommonTextCenter;
return style;
}
BaseVertexStyle.prototype.Clear = function ()
{
delete this.lineWidth;
delete this.strokeStyle;
delete this.fillStyle;
delete this.mainTextColor;
delete this.shape;
delete this.upTextColor;
delete this.commonTextPosition;
delete this.lineWidth;
}
BaseVertexStyle.prototype.ShouldLoad = function (field)
{
return field != "baseStyles";
}
// Common style of Graphs.
function CommonVertexStyle()
{
BaseVertexStyle.apply(this, arguments);
this.lineWidth = 2;
this.strokeStyle = '#c7b7c7';
this.fillStyle = '#68aeba';
this.mainTextColor = '#f0d543';
this.shape = VertexCircleShape;
this.upTextColor = '#68aeba';
this.commonTextPosition = CommonTextCenter;
this.baseStyles = [];
}
CommonVertexStyle.prototype = Object.create(BaseVertexStyle.prototype);
function CommonPrintVertexStyle()
{
BaseVertexStyle.apply(this, arguments);
this.strokeStyle = '#000000';
this.fillStyle = '#FFFFFF';
this.mainTextColor = '#000000';
this.baseStyles.push("common");
}
CommonPrintVertexStyle.prototype = Object.create(BaseVertexStyle.prototype);
// Selected style of Graphs.
function SelectedVertexStyle0()
{
BaseVertexStyle.apply(this, arguments);
this.strokeStyle = '#f0d543';
this.mainTextColor = '#f0d543';
this.fillStyle = '#c7627a';
this.baseStyles.push("common");
}
SelectedVertexStyle0.prototype = Object.create(BaseVertexStyle.prototype);
function SelectedVertexStyle1()
{
BaseVertexStyle.apply(this, arguments);
this.strokeStyle = '#7a9ba0';
this.mainTextColor = '#c3d2d5';
this.fillStyle = '#534641';
this.baseStyles.push("selected");
}
SelectedVertexStyle1.prototype = Object.create(BaseVertexStyle.prototype);
function SelectedVertexStyle2()
{
BaseVertexStyle.apply(this, arguments);
this.strokeStyle = '#8C4C86';
this.mainTextColor = '#dbbdd8';
this.fillStyle = '#253267';
this.baseStyles.push("selected");
}
SelectedVertexStyle2.prototype = Object.create(BaseVertexStyle.prototype);
function SelectedVertexStyle3()
{
BaseVertexStyle.apply(this, arguments);
this.strokeStyle = '#6188FF';
this.mainTextColor = '#6188FF';
this.fillStyle = '#E97CF9';
this.baseStyles.push("selected");
}
SelectedVertexStyle3.prototype = Object.create(BaseVertexStyle.prototype);
function SelectedVertexStyle4()
{
BaseVertexStyle.apply(this, arguments);
this.strokeStyle = '#C6B484';
this.mainTextColor = '#C6B484';
this.fillStyle = '#E0DEE1';
this.baseStyles.push("selected");
}
SelectedVertexStyle4.prototype = Object.create(BaseVertexStyle.prototype);
function SelectedPrintVertexStyle()
{
BaseVertexStyle.apply(this, arguments);
this.strokeStyle = '#000000';
this.mainTextColor = '#000000';
this.fillStyle = '#AAAAAA';
this.baseStyles.push("printed");
}
SelectedPrintVertexStyle.prototype = Object.create(BaseVertexStyle.prototype);
var DefaultSelectedGraphStyles = [new SelectedVertexStyle0(), new SelectedVertexStyle1(),
new SelectedVertexStyle2(), new SelectedVertexStyle3(), new SelectedVertexStyle4()];
var DefaultPrintSelectedGraphStyles = [new SelectedPrintVertexStyle()];
function BaseVertexDrawer(context)
{
this.context = context;
}
BaseVertexDrawer.prototype.Draw = function(baseGraph, graphStyle)
{
this.SetupStyle(graphStyle);
this.DrawShape(baseGraph);
if (this.currentStyle.lineWidth != 0)
this.context.stroke();
this.context.fill();
var shapeSize = GetSizeForShape(graphStyle.shape, baseGraph.model.diameter + graphStyle.lineWidth);
if (graphStyle.commonTextPosition == CommonTextCenter)
{
this.DrawCenterText(baseGraph.position, baseGraph.mainText, graphStyle.mainTextColor,
graphStyle.fillStyle, true, true, MainTextFontSize);
// Top text
this.DrawCenterText(baseGraph.position.add(new Point(0, - shapeSize / 2.0 - 9.0)), baseGraph.upText,
graphStyle.upTextColor, graphStyle.strokeStyle, false, false, TopTextFontSize);
}
else if (graphStyle.commonTextPosition == CommonTextUp)
{
this.DrawCenterText(baseGraph.position.add(new Point(0, - shapeSize / 2.0 - 7.0)), baseGraph.mainText,
graphStyle.mainTextColor, graphStyle.fillStyle, true, false, MainTextFontSize);
// Top text
this.DrawCenterText(baseGraph.position.add(new Point(0, shapeSize / 2.0 + 9.0)), baseGraph.upText,
graphStyle.upTextColor, graphStyle.strokeStyle, false, false, TopTextFontSize);
}
/*
// 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.currentStyle = style;
this.context.lineWidth = style.lineWidth;
this.context.strokeStyle = style.strokeStyle;
this.context.fillStyle = style.fillStyle;
}
BaseVertexDrawer.prototype.DrawShape = function(baseGraph)
{
this.context.beginPath();
if (this.currentStyle.shape == VertexCircleShape)
{
this.context.arc(baseGraph.position.x, baseGraph.position.y, baseGraph.model.diameter / 2.0, 0, 2 * Math.PI);
}
else
{
var points = GetPointsForShape(this.currentStyle.shape, baseGraph.model.diameter, baseGraph.mainText);
this.context.moveTo(baseGraph.position.x + points[points.length - 1].x, baseGraph.position.y + points[points.length - 1].y);
var context = this.context;
points.forEach(function(point) {
context.lineTo(baseGraph.position.x + point.x, baseGraph.position.y + point.y);
});
}
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 + DefaultFont;
var textWidth = this.context.measureText(text).width;
this.DrawText(new Point(position.x - textWidth / 2, position.y), text, color, outlineColor, outline, this.context.font);
}

View File

@@ -0,0 +1,201 @@
/*
Classes for creating text for vertices.
*/
/**
* Base Enum Vertices.
*
*/
function BaseEnumVertices(app, startNumber)
{
this.app = app;
this.startNumber = startNumber;
}
BaseEnumVertices.prototype.GetVertexText = function(id)
{
return this.startNumber + id;
}
BaseEnumVertices.prototype.GetVertexTextAsync = function(callback)
{
callback (this);
}
BaseEnumVertices.prototype.GetText = function()
{
return this.startNumber + ", " + (this.startNumber + 1) + ", " + (this.startNumber + 2) + "...";
}
BaseEnumVertices.prototype.GetValue = function()
{
return "Numbers" + this.startNumber;
}
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 TextEnumVertices(app)
{
BaseEnumVertices.apply(this, arguments);
this.pattern = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
}
// inheritance.
TextEnumVertices.prototype = Object.create(BaseEnumVertices.prototype);
TextEnumVertices.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;
}
TextEnumVertices.prototype.GetText = function()
{
return "A, B, ... Z";
}
TextEnumVertices.prototype.GetValue = function()
{
return "Latin";
}
/**
* Text Enum
*
*/
function TextEnumVerticesCyr(app)
{
TextEnumVertices.apply(this, arguments);
this.pattern = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
}
// inheritance.
TextEnumVerticesCyr.prototype = Object.create(TextEnumVertices.prototype);
TextEnumVerticesCyr.prototype.GetText = function()
{
return "А, Б, ... Я";
}
TextEnumVerticesCyr.prototype.GetValue = function()
{
return "Cyrillic";
}
/**
* Text Enum
*
*/
function TextEnumVerticesGreek(app)
{
TextEnumVertices.apply(this, arguments);
this.pattern = "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ";
}
// inheritance.
TextEnumVerticesGreek.prototype = Object.create(TextEnumVertices.prototype);
TextEnumVerticesGreek.prototype.GetText = function()
{
return "Α, Β, ... Ω";
}
TextEnumVerticesGreek.prototype.GetValue = function()
{
return "Greek";
}
/**
* Text Enum
*
*/
function TextEnumVerticesCustom(app)
{
BaseEnumVertices.apply(this, arguments);
this.pattern = "";
}
// inheritance.
TextEnumVerticesCustom.prototype = Object.create(BaseEnumVertices.prototype);
TextEnumVerticesCustom.prototype.GetText = function()
{
return g_customEnumVertex;
}
TextEnumVerticesCustom.prototype.GetValue = function()
{
return "Custom";
}
TextEnumVerticesCustom.prototype.GetVertexTextAsync = function(callback)
{
this.ShowDialog(callback, g_addVertex, g_addVertex, "A");
}
TextEnumVerticesCustom.prototype.ShowDialog = function(callback, buttonText, titleTitle, title)
{
var dialogButtons = {};
app = this.app;
dialogButtons[buttonText] = function() {
app.PushToStack("RenameVertex");
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();
}
});
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,61 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* 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() {
app.PushToStack("Rename");
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'
});
}

View File

@@ -0,0 +1,52 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* 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'
});
}

View File

@@ -0,0 +1,94 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Save dialog Graph handler.
*
*/
function SavedDialogGraphImageHandler(app)
{
BaseHandler.apply(this, arguments);
this.message = "";
this.imageName = "";
}
// 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.showDialogCallback = function (imageExtension)
{
var dialogButtons = {};
dialogButtons[g_close] = function() {
$( this ).dialog( "close" );
};
var fileLocation = "tmp/saved/" + this.imageName.substr(0, 2) + "/"+ this.imageName + "." + imageExtension
document.getElementById("showSavedImageGraph").src = "/" + fileLocation;
document.getElementById("showSavedImageGraphRef").href = "/" + fileLocation;
//document.getElementById("showSavedImageGraph").src = document.getElementById("showSavedImageGraph").src.replace(/tmp\/saved\/([A-Za-z]*)\/([A-Za-z]*).png/g, fileLocation);
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'
});
}
SavedDialogGraphImageHandler.prototype.showWorkspace = function()
{
var object = this;
var callback = function() {
object.showDialogCallback("png");
};
this.imageName = this.app.SaveGraphImageOnDisk(callback);
}
SavedDialogGraphImageHandler.prototype.showFullgraph = function()
{
var object = this;
var callback = function() {
object.showDialogCallback("png");
};
this.imageName = this.app.SaveFullGraphImageOnDisk(callback, false);
}
SavedDialogGraphImageHandler.prototype.showPrint = function()
{
var object = this;
var callback = function() {
object.showDialogCallback("png");
};
this.imageName = this.app.SaveFullGraphImageOnDisk(callback, true);
}
SavedDialogGraphImageHandler.prototype.showSvg = function()
{
var object = this;
var callback = function() {
object.showDialogCallback("svg");
};
this.imageName = this.app.SaveSVGGraphOnDisk(callback);
}

View File

@@ -0,0 +1,8 @@
{
let modulDir = "features/serialization/";
doInclude ([
include ("model/GraphMLCreator.js", modulDir)
])
}

View File

@@ -0,0 +1,62 @@
/**
* This class creates GraphML xml.
*
*/
function GraphMLCreator(nodes, arcs, ignoreNodes = {})
{
this.nodes = nodes;
this.arcs = arcs;
this.ignoreNodes = ignoreNodes;
}
GraphMLCreator.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 xmlBody = "";
for (var i = 0; i < this.nodes.length; i++)
{
if (!this.ignoreNodes.hasOwnProperty(this.nodes[i].id))
xmlBody = xmlBody + "<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 = "";
var arc = this.arcs[i];
if (this.arcs[i].weight != defaultWeight)
{
weightData = "<data key=" + weightKeyId + ">" + arc.weight + "</data>";
}
xmlBody = xmlBody + "<edge source=\"" + arc.vertex1.id + "\" target=\""
+ arc.vertex2.id + "\" " +
(arc.isDirect != hasDirected ? (hasDirected ? "directed=\"false\"" : "directed=\"true\"") : "") +
" id=\"" + arc.id + "\"";
xmlBody = xmlBody + ((weightData != "") ? ">" + weightData + "</edge>" : "/>")
}
xml = mainHeader + weightNode + (hasDirected ? directedHeader : undirectedHeader) + xmlBody + "</graph></graphml>"
return xml;
}

View File

@@ -0,0 +1,167 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Setup Background Style rename vertices.
*
*/
function SetupBackgroundStyle(app)
{
BaseHandler.apply(this, arguments);
this.message = "";
this.maxImageSize = 2048;
}
// inheritance.
SetupBackgroundStyle.prototype = Object.create(BaseHandler.prototype);
SetupBackgroundStyle.prototype.handleImportBackgroundFile = function(files, updateBackgroundCallback) {
var graphFileToLoad = files[0];
var re = /(?:\.([^.]+))?$/;
var imageExtension = re.exec(graphFileToLoad.name)[1].toLowerCase();
if (!(imageExtension == "png" || imageExtension == "jpg" || imageExtension == "jpeg")) {
$("#UploadBackgroundImageError").html(g_wrongImageFormatPNGAndJPEG);
$("#UploadBackgroundImageError").show();
return;
}
let self = this;
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent){
var textFromFileLoaded = fileLoadedEvent.target.result;
var image = new Image();
image.onload = function() {
console.log(this.width + 'x' + this.height);
if (this.width > self.maxImageSize || this.height > self.maxImageSize) {
$("#UploadBackgroundImageError").html(formatString(g_wrongImageSizeP1, [self.maxImageSize]));
$("#UploadBackgroundImageError").show();
return;
}
updateBackgroundCallback(image);
}
image.src = 'data:image/' + imageExtension + ';base64' + textFromFileLoaded;
ImportBackgroundImage.value = "";
};
fileReader.readAsDataURL(graphFileToLoad);
}
SetupBackgroundStyle.prototype.show = function()
{
var handler = this;
var dialogButtons = {};
var graph = this.app.graph;
var app = this.app;
var style = FullObjectCopy(app.backgroundCommonStyle);
var fillFields = function()
{
$( "#backgroundColor" ).val(style.commonColor);
$( "#backgroundTransporent" ).val(style.commonOpacity);
}
var redrawVertex = function()
{
style.commonColor = $( "#backgroundColor" ).val();
style.commonOpacity = $( "#backgroundTransporent" ).val();
var canvas = document.getElementById( "BackgroundPreview" );
var context = canvas.getContext('2d');
context.save();
let bestScale = 1.0;
if (style.image != null) {
let wScale = canvas.width / style.image.width;
let hScale = canvas.height / style.image.height;
bestScale = Math.min(wScale, hScale);
context.scale(bestScale, bestScale);
}
var backgroundDrawer = new BaseBackgroundDrawer(context);
backgroundDrawer.Draw(style, canvas.width, canvas.height, new Point(0, 0), bestScale);
context.restore();
if (style.image != null) {
$( "#RemoveBackgroundFile" ).show();
} else {
$( "#RemoveBackgroundFile" ).hide();
}
}
var loadFile = function() {
userAction("background_loadFromFile");
if (ImportBackgroundImage) {
ImportBackgroundImage.click();
}
}
var updateBackgroundImage = function(image) {
style.image = image;
$("#UploadBackgroundImageError").hide();
redrawVertex();
}
var clearBackgroundImage = function() {
style.image = null;
$("#UploadBackgroundImageError").hide();
redrawVertex();
}
dialogButtons[g_default] =
{
text : g_default,
class : "MarginLeft",
click : function() {
app.PushToStack("ChangeBackground");
app.ResetBackgroundStyle();
app.redrawGraph();
$( this ).dialog( "close" );
}
};
dialogButtons[g_save] = function() {
app.PushToStack("ChangeBackground");
app.SetBackgroundStyle(style);
app.redrawGraph();
$( this ).dialog( "close" );
};
dialogButtons[g_cancel] = function() {
$( this ).dialog( "close" );
};
fillFields();
$( "#SetupBackgroundStyleDialog" ).dialog({
resizable: false,
height: "auto",
width: "auto",
modal: true,
title: g_backgroundStyle,
buttons: dialogButtons,
dialogClass: 'EdgeDialog'
});
try {
redrawVertex();
} catch (error) {
console.error(error);
}
$( "#backgroundColor" ).unbind();
$( "#backgroundTransporent" ).unbind();
$( "#LoadBackgroundFile" ).unbind();
$( "#ImportBackgroundImage" ).unbind();
$( "#RemoveBackgroundFile" ).unbind();
$( "#backgroundColor" ).change(redrawVertex);
$( "#backgroundTransporent" ).change(redrawVertex);
$( "#LoadBackgroundFile" ).click(loadFile);
$( "#ImportBackgroundImage" ).change( function () {handler.handleImportBackgroundFile(this.files, updateBackgroundImage);});
$( "#RemoveBackgroundFile" ).click(clearBackgroundImage);
}

View File

@@ -0,0 +1,295 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Setup Vertex Style rename vertices.
*
*/
function SetupEdgeStyle(app)
{
BaseHandler.apply(this, arguments);
this.message = "";
}
// inheritance.
SetupEdgeStyle.prototype = Object.create(BaseHandler.prototype);
SetupEdgeStyle.prototype.show = function(index, selectedEdges)
{
var handler = this;
var dialogButtons = {};
var graph = this.app.graph;
var app = this.app;
this.forAll = selectedEdges == null;
var forAll = this.forAll;
var self = this;
var applyIndex = function(index)
{
self.index = index;
var originStyle = (self.index == 0 ? app.edgeCommonStyle : app.edgeSelectedStyles[self.index - 1]);
if (!forAll)
{
originStyle = selectedEdges[0].getStyleFor(self.index);
}
self.style = FullObjectCopy(originStyle);
}
applyIndex(index);
var fillFields = function()
{
var fullStyle = self.style.GetStyle({}, forAll ? undefined : selectedEdges[0]);
$( "#edgeFillColor" ).val(fullStyle.fillStyle);
$( "#edgeStrokeColor" ).val(fullStyle.strokeStyle);
$( "#edgeTextColor" ).val(fullStyle.weightText);
$( "#edgeStyle" ).val(fullStyle.lineDash);
$( "#edgeWidth" ).val(forAll ? app.GetDefaultEdgeWidth() : selectedEdges[0].model.width);
$( "#weightEdgeTextColor" ).val(fullStyle.additionalTextColor);
$( "#weightTextPosition" ).val(fullStyle.weightPosition);
if (self.index > 0 || self.index == "all")
{
$( "#EdgeSelectedIndexForm" ).show();
$( "#edgeSelectedIndex" ).val(self.index);
}
else
{
$( "#EdgeSelectedIndexForm" ).hide();
}
// Fill color presets.
var stylesArray = [];
stylesArray.push(app.edgeCommonStyle);
for (i = 0; i < app.edgeSelectedStyles.length; i ++)
stylesArray.push(app.edgeSelectedStyles[i]);
var colorSet = {};
for (i = 0; i < stylesArray.length; i ++)
{
var style = stylesArray[i];
if (style.hasOwnProperty('strokeStyle'))
colorSet[style.strokeStyle] = 1;
if (style.hasOwnProperty('fillStyle'))
colorSet[style.fillStyle] = 1;
if (style.hasOwnProperty('additionalTextColor'))
colorSet[style.additionalTextColor] = 1;
}
$("#edgeFillColorPreset").find('option').remove();
$("#weightEdgeTextColorPreset").find('option').remove();
$("#edgeTextColorPreset").find('option').remove();
$("#edgeStrokeColorPreset").find('option').remove();
for (const property in colorSet)
{
$("#edgeFillColorPreset").append(new Option(property));
$("#weightEdgeTextColorPreset").append(new Option(property));
$("#edgeTextColorPreset").append(new Option(property));
$("#edgeStrokeColorPreset").append(new Option(property));
}
}
var redrawVertex = function()
{
var fullStyle = self.style.GetStyle({}, forAll ? undefined : selectedEdges[0]);
if (fullStyle.fillStyle != $( "#edgeFillColor" ).val())
self.style.fillStyle = $( "#edgeFillColor" ).val();
if (fullStyle.strokeStyle != $( "#edgeStrokeColor" ).val())
self.style.strokeStyle = $( "#edgeStrokeColor" ).val();
if (fullStyle.weightText != $( "#edgeTextColor" ).val())
self.style.weightText = $( "#edgeTextColor" ).val();
if (fullStyle.lineDash != $( "#edgeStyle" ).val())
self.style.lineDash = $( "#edgeStyle" ).val();
if (fullStyle.additionalTextColor != $( "#weightEdgeTextColor" ).val())
self.style.additionalTextColor = $( "#weightEdgeTextColor" ).val();
if (fullStyle.weightPosition != $( "#weightTextPosition" ).val())
self.style.weightPosition = $( "#weightTextPosition" ).val();
var edgeWidth = parseInt($( "#edgeWidth" ).val());
var canvas = document.getElementById( "EdgePreview" );
var context = canvas.getContext('2d');
context.save();
var backgroundDrawer = new BaseBackgroundDrawer(context);
backgroundDrawer.Draw(app.backgroundCommonStyle, canvas.width, canvas.height, new Point(0, 0), 1.0);
var graphDrawer = new BaseEdgeDrawer(context);
var baseVertex1 = new BaseVertex(0, canvas.height / 2, new BaseEnumVertices(this));
var baseVertex2 = new BaseVertex(canvas.width, canvas.height / 2, new BaseEnumVertices(this));
baseVertex1.currentStyle = baseVertex1.getStyleFor(0);
baseVertex2.currentStyle = baseVertex2.getStyleFor(0);
var baseEdge = new BaseEdge(baseVertex1, baseVertex2, true, 10, "Text");
if (!forAll)
baseEdge.ownStyles = selectedEdges[0].ownStyles;
baseEdge.model.width = edgeWidth;
graphDrawer.Draw(baseEdge, self.style.GetStyle({}, baseEdge));
context.restore();
}
var changeIndex = function()
{
var val = $( "#edgeSelectedIndex" ).val();
if (val == "all")
{
applyIndex(1);
self.index = "all";
fillFields();
}
else
{
var index = parseInt(val);
self.index = index;
applyIndex(index);
fillFields();
}
redrawVertex();
}
var applyWidth = function(width)
{
if (forAll)
{
app.SetDefaultEdgeWidth(width);
}
else
{
selectedEdges.forEach(function(edge) {
edge.model.width = width;
});
}
};
dialogButtons[g_default] =
{
text : g_default,
class : "MarginLeft",
click : function() {
app.PushToStack("ChangeStyle");
applyWidth(forAll ? (new EdgeModel()).width : app.GetDefaultEdgeWidth());
var indexes = [];
if (self.index == "all")
{
for (i = 0; i < app.edgeSelectedStyles.length; i ++)
indexes.push(i + 1);
}
else
indexes.push(self.index);
if (forAll)
{
indexes.forEach(function(index) {
app.ResetEdgeStyle(index);
});
}
else
{
selectedEdges.forEach(function(edge) {
indexes.forEach(function(index) {
edge.resetOwnStyle(index);
});
});
}
app.redrawGraph();
$( this ).dialog( "close" );
}
};
dialogButtons[g_save] = function() {
app.PushToStack("ChangeStyle");
applyWidth(parseInt($( "#edgeWidth" ).val()));
var indexes = [];
if (self.index == "all")
{
indexes.push({index : 1, style : self.style});
for (i = 1; i < app.edgeSelectedStyles.length; i ++)
{
var style = (new BaseEdgeStyle());
style.baseStyles.push("selected");
indexes.push({index : i + 1, style : style});
}
self.style.baseStyles = [];
self.style.baseStyles = self.style.baseStyles.concat((new SelectedEdgeStyle0()).baseStyles);
}
else
indexes.push({index : self.index, style : self.style});
if (forAll)
{
indexes.forEach(function(index) {
app.SetEdgeStyle(index.index, index.style);
});
}
else
{
selectedEdges.forEach(function(edge) {
indexes.forEach(function(index) {
edge.setOwnStyle(index.index, index.style);
});
});
}
app.redrawGraph();
$( this ).dialog( "close" );
};
dialogButtons[g_cancel] = function() {
$( this ).dialog( "close" );
};
fillFields();
$( "#SetupEdgeStyleDialog" ).dialog({
resizable: false,
height: "auto",
width: "auto",
modal: true,
title: g_edgeDraw,
buttons: dialogButtons,
dialogClass: 'EdgeDialog'
});
redrawVertex();
$( "#edgeFillColor" ).unbind();
$( "#edgeStrokeColor" ).unbind();
$( "#edgeTextColor" ).unbind();
$( "#edgeStyle" ).unbind();
$( "#edgeWidth" ).unbind();
$( "#weightEdgeTextColor" ).unbind();
$( "#weightTextPosition" ).unbind();
$( "#edgeSelectedIndex" ).unbind();
$( "#edgeFillColor" ).change(redrawVertex);
$( "#edgeStrokeColor" ).change(redrawVertex);
$( "#edgeTextColor" ).change(redrawVertex);
$( "#edgeStyle" ).change(redrawVertex);
$( "#edgeWidth" ).change(redrawVertex);
$( "#weightEdgeTextColor" ).change(redrawVertex);
$( "#weightTextPosition" ).change(redrawVertex);
$( "#edgeSelectedIndex" ).change(changeIndex);
}

View File

@@ -0,0 +1,299 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Setup Vertex Style rename vertices.
*
*/
function SetupVertexStyle(app)
{
BaseHandler.apply(this, arguments);
this.message = "";
}
// inheritance.
SetupVertexStyle.prototype = Object.create(BaseHandler.prototype);
SetupVertexStyle.prototype.show = function(index, selectedVertices)
{
var handler = this;
var dialogButtons = {};
var graph = this.app.graph;
var app = this.app;
this.forAll = selectedVertices == null;
var forAll = this.forAll;
var self = this;
var applyIndex = function(index)
{
self.index = index;
self.originStyle = (self.index == 0 ? app.vertexCommonStyle : app.vertexSelectedVertexStyles[self.index - 1]);
if (!forAll)
{
self.originStyle = selectedVertices[0].getStyleFor(self.index);
}
self.style = FullObjectCopy(self.originStyle);
}
applyIndex(index);
var fillFields = function()
{
var fullStyle = self.style.GetStyle({}, forAll ? undefined : selectedVertices[0]);
$( "#vertexFillColor" ).val(fullStyle.fillStyle);
$( "#vertexStrokeColor" ).val(fullStyle.strokeStyle);
$( "#vertexTextColor" ).val(fullStyle.mainTextColor);
$( "#upVertexTextColor" ).val(fullStyle.upTextColor);
$( "#vertexStrokeSize" ).val(fullStyle.lineWidth);
$( "#vertexShape" ).val(fullStyle.shape);
$( "#vertexSize" ).val(forAll ? app.GetDefaultVertexSize() : selectedVertices[0].model.diameter);
$( "#commonTextPosition" ).val(fullStyle.commonTextPosition);
if (self.index > 0 || self.index == "all")
{
$( "#VertexSelectedIndexForm" ).show();
$( "#vertexSelectedIndex" ).val(self.index);
}
else
{
$( "#VertexSelectedIndexForm" ).hide();
}
// Fill color presets.
var stylesArray = [];
stylesArray.push(app.vertexCommonStyle);
for (i = 0; i < app.vertexSelectedVertexStyles.length; i ++)
stylesArray.push(app.vertexSelectedVertexStyles[i]);
var colorSet = {};
for (i = 0; i < stylesArray.length; i ++)
{
var style = stylesArray[i];
if (style.hasOwnProperty('strokeStyle'))
colorSet[style.strokeStyle] = 1;
if (style.hasOwnProperty('fillStyle'))
colorSet[style.fillStyle] = 1;
if (style.hasOwnProperty('mainTextColor'))
colorSet[style.mainTextColor] = 1;
if (style.hasOwnProperty('upTextColor'))
colorSet[style.upTextColor] = 1;
}
$("#vertexFillColorPreset").find('option').remove();
$("#upVertexTextColorPreset").find('option').remove();
$("#vertexTextColorPreset").find('option').remove();
$("#vertexStrokeColorPreset").find('option').remove();
for (const property in colorSet)
{
$("#vertexFillColorPreset").append(new Option(property));
$("#upVertexTextColorPreset").append(new Option(property));
$("#vertexTextColorPreset").append(new Option(property));
$("#vertexStrokeColorPreset").append(new Option(property));
}
}
var redrawVertex = function()
{
var fullStyle = self.style.GetStyle({}, forAll ? undefined : selectedVertices[0]);
if (fullStyle.fillStyle != $( "#vertexFillColor" ).val())
self.style.fillStyle = $( "#vertexFillColor" ).val();
if (fullStyle.strokeStyle != $( "#vertexStrokeColor" ).val())
self.style.strokeStyle = $( "#vertexStrokeColor" ).val();
if (fullStyle.mainTextColor != $( "#vertexTextColor" ).val())
self.style.mainTextColor = $( "#vertexTextColor" ).val();
if (fullStyle.lineWidth != $( "#vertexStrokeSize" ).val())
self.style.lineWidth = parseInt($( "#vertexStrokeSize" ).val());
if (fullStyle.shape != $( "#vertexShape" ).val())
self.style.shape = parseInt($( "#vertexShape" ).val());
if (fullStyle.upTextColor != $( "#upVertexTextColor" ).val())
self.style.upTextColor = $( "#upVertexTextColor" ).val();
if (fullStyle.commonTextPosition != $( "#commonTextPosition" ).val())
self.style.commonTextPosition = $( "#commonTextPosition" ).val();
var diameter = parseInt($( "#vertexSize" ).val());
var canvas = document.getElementById( "VertexPreview" );
var context = canvas.getContext('2d');
context.save();
var backgroundDrawer = new BaseBackgroundDrawer(context);
backgroundDrawer.Draw(app.backgroundCommonStyle, canvas.width, canvas.height, new Point(0, 0), 1.0);
var graphDrawer = new BaseVertexDrawer(context);
var baseVertex = new BaseVertex(canvas.width / 2, canvas.height / 2, new BaseEnumVertices(this));
baseVertex.mainText = "1";
baseVertex.upText = "Up Text";
baseVertex.model.diameter = diameter;
if (!forAll)
baseVertex.ownStyles = selectedVertices[0].ownStyles;
graphDrawer.Draw(baseVertex, self.style.GetStyle({}, baseVertex));
context.restore();
}
var changeIndex = function()
{
var val = $( "#vertexSelectedIndex" ).val();
if (val == "all")
{
applyIndex(1);
self.index = "all";
fillFields();
}
else
{
var index = parseInt(val);
self.index = index;
applyIndex(index);
fillFields();
}
redrawVertex();
}
var applyDiameter = function(diameter)
{
if (forAll)
{
app.SetDefaultVertexSize(diameter);
}
else
{
selectedVertices.forEach(function(vertex) {
vertex.model.diameter = diameter;
});
}
};
dialogButtons[g_default] =
{
text : g_default,
class : "MarginLeft",
click : function() {
app.PushToStack("ChangeStyle");
applyDiameter(forAll ? (new VertexModel()).diameter : app.GetDefaultVertexSize());
var indexes = [];
if (self.index == "all")
{
for (i = 0; i < app.vertexSelectedVertexStyles.length; i ++)
indexes.push(i + 1);
}
else
indexes.push(self.index);
if (forAll)
{
indexes.forEach(function(index) {
app.ResetVertexStyle(index);
});
}
else
{
selectedVertices.forEach(function(vertex) {
indexes.forEach(function(index) {
vertex.resetOwnStyle(index);
});
});
}
app.redrawGraph();
$( this ).dialog( "close" );
}
};
dialogButtons[g_save] = function() {
app.PushToStack("ChangeStyle");
applyDiameter(parseInt($( "#vertexSize" ).val()));
var indexes = [];
if (self.index == "all")
{
indexes.push({index : 1, style : self.style});
for (i = 1; i < app.vertexSelectedVertexStyles.length; i ++)
{
var style = (new BaseVertexStyle());
style.baseStyles.push("selected");
indexes.push({index : i + 1, style : style});
}
self.style.baseStyles = [];
self.style.baseStyles = self.style.baseStyles.concat((new SelectedVertexStyle0()).baseStyles);
}
else
indexes.push({index : self.index, style : self.style});
if (forAll)
{
indexes.forEach(function(index) {
app.SetVertexStyle(index.index, index.style);
});
}
else
{
if (JSON.stringify(self.originStyle) !== JSON.stringify(self.style))
{
selectedVertices.forEach(function(vertex) {
indexes.forEach(function(index) {
vertex.setOwnStyle(index.index, index.style);
});
});
}
}
app.redrawGraph();
$( this ).dialog( "close" );
};
dialogButtons[g_cancel] = function() {
$( this ).dialog( "close" );
};
fillFields();
$( "#SetupVertexStyleDialog" ).dialog({
resizable: false,
height: "auto",
width: "auto",
modal: true,
title: g_vertexDraw,
buttons: dialogButtons,
dialogClass: 'EdgeDialog'
});
redrawVertex();
$( "#vertexFillColor" ).unbind();
$( "#vertexStrokeColor" ).unbind();
$( "#vertexTextColor" ).unbind();
$( "#upVertexTextColor" ).unbind();
$( "#vertexStrokeSize" ).unbind();
$( "#vertexShape" ).unbind();
$( "#vertexSize" ).unbind();
$( "#commonTextPosition" ).unbind();
$( "#vertexSelectedIndex" ).unbind();
$( "#vertexFillColor" ).change(redrawVertex);
$( "#vertexStrokeColor" ).change(redrawVertex);
$( "#vertexTextColor" ).change(redrawVertex);
$( "#vertexStrokeSize" ).change(redrawVertex);
$( "#vertexShape" ).change(redrawVertex);
$( "#vertexSize" ).change(redrawVertex);
$( "#upVertexTextColor" ).change(redrawVertex);
$( "#commonTextPosition" ).change(redrawVertex);
$( "#vertexSelectedIndex" ).change(changeIndex);
}

View File

@@ -0,0 +1,66 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* 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').unbind();
$( "#AdjacencyMatrixField" ).on('keyup change', function (eventObject)
{
if (!handler.app.TestAdjacencyMatrix($( "#AdjacencyMatrixField" ).val(), [], []))
{
$( "#BadMatrixFormatMessage" ).show();
}
else
{
$( "#BadMatrixFormatMessage" ).hide();
}
});
dialogButtons[g_save] = function() {
handler.app.PushToStack("ChangeAdjacencyMatrix");
handler.app.SetAdjacencyMatrixSmart($( "#AdjacencyMatrixField" ).val());
$( this ).dialog( "close" );
};
dialogButtons[g_cancel] = function() {
$( this ).dialog( "close" );
};
$( "#AdjacencyMatrixField" ).val(this.app.GetAdjacencyMatrix());
$( "#BadMatrixFormatMessage" ).hide();
if (this.app.graph.isMulti())
$( "#AdjacencyMatrixMultiGraphDesc").show();
else
$( "#AdjacencyMatrixMultiGraphDesc").hide();
$( "#adjacencyMatrix" ).dialog({
resizable: false,
height: "auto",
width: "auto",
modal: true,
title: g_adjacencyMatrixText,
buttons: dialogButtons,
dialogClass: 'EdgeDialog'
});
}

View File

@@ -0,0 +1,77 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Show distance matrix.
*
*/
function ShowDistanceMatrix(app)
{
BaseHandler.apply(this, arguments);
this.app = app;
this.message = "";
}
// inheritance.
ShowDistanceMatrix.prototype = Object.create(BaseHandler.prototype);
// First selected.
ShowDistanceMatrix.prototype.firstObject = null;
// Path
ShowDistanceMatrix.prototype.pathObjects = null;
ShowDistanceMatrix.prototype.GetIncidenceMatrix = function (rawMatrix)
{
var matrix = "";
for (var i = 0; i < rawMatrix.length; i++)
{
for (var j = 0; j < rawMatrix[i].length; j++)
{
if (i == j)
{
matrix += "0";
}
else if ((new Graph()).infinity == rawMatrix[i][j])
{
matrix += '\u221E';
}
else
{
matrix += rawMatrix[i][j];
}
if (j != rawMatrix[i].length - 1)
{
matrix += ", ";
}
}
matrix = matrix + "\n";
}
return matrix;
}
ShowDistanceMatrix.prototype.show = function()
{
var handler = this;
var dialogButtons = {};
dialogButtons[g_close] = function() {
$( this ).dialog( "close" );
};
var handler = g_Algorithms[g_AlgorithmIds.indexOf("OlegSh.FloidAlgorithm")](this.app.graph, this.app);
$( "#FloidMatrixField" ).val(this.GetIncidenceMatrix(handler.resultMatrix()));
$( "#floidMatrix" ).dialog({
resizable: false,
height: "auto",
width: "auto",
modal: true,
title: g_minDistMatrixText,
buttons: dialogButtons,
dialogClass: 'EdgeDialog'
});
}

View File

@@ -0,0 +1,61 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* 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').unbind();
$( "#IncidenceMatrixField" ).on('keyup change', function (eventObject)
{
if (!handler.app.TestIncidenceMatrix($( "#IncidenceMatrixField" ).val(), [], []))
{
$( "#BadIncidenceMatrixFormatMessage" ).show();
}
else
{
$( "#BadIncidenceMatrixFormatMessage" ).hide();
}
});
dialogButtons[g_save] = function() {
handler.app.PushToStack("IncidenceMatrixChanged");
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'
});
}