mirror of
https://github.com/UnickSoft/graphonline.git
synced 2026-04-09 17:26:24 +00:00
Change script location.
Split js code. Added cache and changed loading mechanism for js sources.
This commit is contained in:
59
script/features/add_vertices_handler/index.js
Normal file
59
script/features/add_vertices_handler/index.js
Normal 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);
|
||||
}
|
||||
131
script/features/algorithm_handler/index.js
Normal file
131
script/features/algorithm_handler/index.js
Normal 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);
|
||||
}
|
||||
35
script/features/algorithms/api/index.js
Normal file
35
script/features/algorithms/api/index.js
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
305
script/features/algorithms/model/Algorithms.js
Normal file
305
script/features/algorithms/model/Algorithms.js
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
56
script/features/algorithms/model/BaseTraversal.js
Normal file
56
script/features/algorithms/model/BaseTraversal.js
Normal 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;
|
||||
}
|
||||
125
script/features/algorithms/model/plugins/BFS.js
Normal file
125
script/features/algorithms/model/plugins/BFS.js
Normal 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);
|
||||
386
script/features/algorithms/model/plugins/Coloring.js
Normal file
386
script/features/algorithms/model/plugins/Coloring.js
Normal 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);
|
||||
130
script/features/algorithms/model/plugins/ConnectedComponent.js
Normal file
130
script/features/algorithms/model/plugins/ConnectedComponent.js
Normal 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);
|
||||
124
script/features/algorithms/model/plugins/DFS.js
Normal file
124
script/features/algorithms/model/plugins/DFS.js
Normal 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);
|
||||
97
script/features/algorithms/model/plugins/EulerianLoop.js
Normal file
97
script/features/algorithms/model/plugins/EulerianLoop.js
Normal 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) ? "⇒" : "");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
97
script/features/algorithms/model/plugins/EulerianPath.js
Normal file
97
script/features/algorithms/model/plugins/EulerianPath.js
Normal 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) ? "⇒" : "");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
232
script/features/algorithms/model/plugins/FindAllPatches.js
Normal file
232
script/features/algorithms/model/plugins/FindAllPatches.js
Normal 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);
|
||||
229
script/features/algorithms/model/plugins/FindLongestPath.js
Normal file
229
script/features/algorithms/model/plugins/FindLongestPath.js
Normal 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);
|
||||
@@ -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);
|
||||
235
script/features/algorithms/model/plugins/Floid.js
Normal file
235
script/features/algorithms/model/plugins/Floid.js
Normal 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" ? "Алгоритм Флойда — Уоршелла" : "Floyd–Warshall 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);
|
||||
175
script/features/algorithms/model/plugins/GraphReorder.js
Normal file
175
script/features/algorithms/model/plugins/GraphReorder.js
Normal 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);
|
||||
114
script/features/algorithms/model/plugins/HamiltonianLoop.js
Normal file
114
script/features/algorithms/model/plugins/HamiltonianLoop.js
Normal 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) ? "⇒" : "");
|
||||
}
|
||||
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);
|
||||
112
script/features/algorithms/model/plugins/HamiltonianPath.js
Normal file
112
script/features/algorithms/model/plugins/HamiltonianPath.js
Normal 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) ? "⇒" : "");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
299
script/features/algorithms/model/plugins/IsomorphismCheck.js
Normal file
299
script/features/algorithms/model/plugins/IsomorphismCheck.js
Normal 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 + " </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 + " </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 + " </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 + " </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);
|
||||
100
script/features/algorithms/model/plugins/MaxClique.js
Normal file
100
script/features/algorithms/model/plugins/MaxClique.js
Normal 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);
|
||||
227
script/features/algorithms/model/plugins/MaxFlow.js
Normal file
227
script/features/algorithms/model/plugins/MaxFlow.js
Normal 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);
|
||||
167
script/features/algorithms/model/plugins/MinimumSpanningTree.js
Normal file
167
script/features/algorithms/model/plugins/MinimumSpanningTree.js
Normal 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);
|
||||
|
||||
198
script/features/algorithms/model/plugins/ModernGraphStyle.js
Normal file
198
script/features/algorithms/model/plugins/ModernGraphStyle.js
Normal 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);
|
||||
231
script/features/algorithms/model/plugins/RadiusAndDiameter.js
Normal file
231
script/features/algorithms/model/plugins/RadiusAndDiameter.js
Normal 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) ? "⇒" : "");
|
||||
}
|
||||
}
|
||||
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) ? "⇒" : "");
|
||||
}
|
||||
}
|
||||
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);
|
||||
232
script/features/algorithms/model/plugins/ShortestPath.js
Normal file
232
script/features/algorithms/model/plugins/ShortestPath.js
Normal 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) ? "⇒" : "");
|
||||
}
|
||||
|
||||
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);
|
||||
102
script/features/algorithms/model/plugins/VerticesDegree.js
Normal file
102
script/features/algorithms/model/plugins/VerticesDegree.js
Normal 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);
|
||||
@@ -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);
|
||||
457
script/features/base_handler/index.js
Normal file
457
script/features/base_handler/index.js
Normal 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") + " → " + 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;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
226
script/features/connect_vertices_handler/index.js
Normal file
226
script/features/connect_vertices_handler/index.js
Normal 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());
|
||||
}
|
||||
431
script/features/default_handler/index.js
Normal file
431
script/features/default_handler/index.js
Normal 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> "
|
||||
+ "<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>    "
|
||||
+ "<button type=\"button\" id=\"RemoveSelected\" class=\"btn btn-default btn-xs\">"
|
||||
+ g_removeGroupeButton + "</button>"
|
||||
|
||||
this.message = this.message
|
||||
+ "     <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);
|
||||
}
|
||||
}
|
||||
52
script/features/delete_objects_handler/index.js
Normal file
52
script/features/delete_objects_handler/index.js
Normal 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;
|
||||
}
|
||||
10
script/features/draw_graph/api/index.js
Normal file
10
script/features/draw_graph/api/index.js
Normal 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)
|
||||
])
|
||||
|
||||
}
|
||||
89
script/features/draw_graph/model/BaseBackgroundDrawer.js
Normal file
89
script/features/draw_graph/model/BaseBackgroundDrawer.js
Normal 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)
|
||||
}
|
||||
564
script/features/draw_graph/model/BaseEdgeDrawer.js
Normal file
564
script/features/draw_graph/model/BaseEdgeDrawer.js
Normal 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);
|
||||
}
|
||||
428
script/features/draw_graph/model/BaseVertexDrawer.js
Normal file
428
script/features/draw_graph/model/BaseVertexDrawer.js
Normal 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);
|
||||
}
|
||||
|
||||
201
script/features/enum_vertices/EnumVertices.js
Normal file
201
script/features/enum_vertices/EnumVertices.js
Normal 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();
|
||||
}
|
||||
});
|
||||
}
|
||||
1
script/features/graphoffline/Graphoffline.Emscripten.js
Normal file
1
script/features/graphoffline/Graphoffline.Emscripten.js
Normal file
File diff suppressed because one or more lines are too long
BIN
script/features/graphoffline/Graphoffline.Emscripten.wasm
Normal file
BIN
script/features/graphoffline/Graphoffline.Emscripten.wasm
Normal file
Binary file not shown.
61
script/features/group_rename_handler/index.js
Normal file
61
script/features/group_rename_handler/index.js
Normal 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'
|
||||
});
|
||||
}
|
||||
52
script/features/saved_graph_handler/index.js
Normal file
52
script/features/saved_graph_handler/index.js
Normal 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'
|
||||
});
|
||||
|
||||
}
|
||||
94
script/features/saved_graph_image_handler/index.js
Normal file
94
script/features/saved_graph_image_handler/index.js
Normal 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);
|
||||
}
|
||||
8
script/features/serialization/api/index.js
Normal file
8
script/features/serialization/api/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
let modulDir = "features/serialization/";
|
||||
|
||||
doInclude ([
|
||||
include ("model/GraphMLCreator.js", modulDir)
|
||||
])
|
||||
|
||||
}
|
||||
62
script/features/serialization/model/GraphMLCreator.js
Normal file
62
script/features/serialization/model/GraphMLCreator.js
Normal 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;
|
||||
}
|
||||
167
script/features/setup_background_style/index.js
Normal file
167
script/features/setup_background_style/index.js
Normal 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);
|
||||
}
|
||||
295
script/features/setup_edge_style/index.js
Normal file
295
script/features/setup_edge_style/index.js
Normal 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);
|
||||
}
|
||||
299
script/features/setup_vertex_style/index.js
Normal file
299
script/features/setup_vertex_style/index.js
Normal 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);
|
||||
}
|
||||
66
script/features/show_adjacency_matrix/index.js
Normal file
66
script/features/show_adjacency_matrix/index.js
Normal 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'
|
||||
});
|
||||
}
|
||||
77
script/features/show_distance_matrix/index.js
Normal file
77
script/features/show_distance_matrix/index.js
Normal 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'
|
||||
});
|
||||
}
|
||||
61
script/features/show_incidence_matrix/index.js
Normal file
61
script/features/show_incidence_matrix/index.js
Normal 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'
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user