Change script location.

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

No files matched your search

+8 -4
View File
@@ -173,11 +173,15 @@
return SITE_ROOT . "{$dir}{$uri}"; return SITE_ROOT . "{$dir}{$uri}";
} }
function RootCacheJS($uri = '', $version = '') { function RootCacheJS($uri = '') {
global $g_config; global $g_config;
return Root(($g_config['use_js_cache'] ? $uri . ".cache" : $cacheFilePath = Root($uri . ".cache");
$uri) . "?v=" . $version); $filePath = Root($uri);
$cacheExists = file_exists("." . $cacheFilePath);
$finalFileName = $cacheExists && $g_config['use_js_cache'] ? $cacheFilePath : $filePath;
return $finalFileName . "?v=" . $g_config['engine_version'];
} }
/** /**
+2
View File
@@ -145,6 +145,8 @@
$g_lang["opensource_message"] = "Our project is now open source. More details..."; $g_lang["opensource_message"] = "Our project is now open source. More details...";
$g_lang["we_are_improving"] = "We are improving Graphonline, if you faced with any problem please let us know: admin@graphonline.ru";
$g_lang["settings"] = "Settings"; $g_lang["settings"] = "Settings";
$g_lang["common_vertex_settings"] = "Common vertices"; $g_lang["common_vertex_settings"] = "Common vertices";
$g_lang["selected_vertex_settings"] = "Selected vertices"; $g_lang["selected_vertex_settings"] = "Selected vertices";
+2
View File
@@ -148,6 +148,8 @@
$g_lang["opensource_message"] = "Наш проект стал проектом с открытым исходным кодом. Подробнее..."; $g_lang["opensource_message"] = "Наш проект стал проектом с открытым исходным кодом. Подробнее...";
$g_lang["we_are_improving"] = "Мы улучшаем Graphonline, если вы столкнулись с проблемами напишете нам: admin@graphonline.ru";
$g_lang["settings"] = "Настройки"; $g_lang["settings"] = "Настройки";
$g_lang["common_vertex_settings"] = "Обычных вершин"; $g_lang["common_vertex_settings"] = "Обычных вершин";
$g_lang["selected_vertex_settings"] = "Выделенных вершин"; $g_lang["selected_vertex_settings"] = "Выделенных вершин";
File diff suppressed because it is too large. Load diff
+9
View File
@@ -0,0 +1,9 @@
{
let modulDir = "entities/edge/";
doInclude ([
include ("model/BaseEdge.js", modulDir),
include ("model/EdgeModel.js", modulDir)
])
}
View File
File renamed without changes.
+1 -1
View File
@@ -31,7 +31,7 @@ EdgeModel.prototype.SaveToXML = function ()
{ {
return "model_width=\"" + this.width + "\" " + return "model_width=\"" + this.width + "\" " +
"model_type=\"" + this.type + "\" " + "model_type=\"" + this.type + "\" " +
"model_curveValue=\"" + this.curveValue + "\" " "model_curveValue=\"" + this.curveValue + "\" " +
"model_default=\"" + this.default + "\" "; "model_default=\"" + this.default + "\" ";
} }
+11
View File
@@ -0,0 +1,11 @@
{
let modulDir = "entities/graph/";
doInclude ([
include ("shared/point.js"),
include ("entities/edge/api/index.js"),
include ("entities/vertex/api/index.js"),
include ("model/Graph.js", modulDir)
])
}
File renamed without changes.
+8
View File
@@ -0,0 +1,8 @@
{
let modulDir = "entities/vertex/";
doInclude ([
include ("model/BaseVertex.js", modulDir),
include ("model/VertexModel.js", modulDir)
])
}
View File
File renamed without changes.
+1 -1
View File
@@ -3,7 +3,7 @@
* *
*/ */
const defaultVertexDiameter = 30; const defaultVertexDiameter = 30;
function VertexModel() function VertexModel()
{ {
@@ -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
View File
@@ -0,0 +1,131 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Algorithm Graph handler.
*
*/
function AlgorithmGraphHandler(app, algorithm)
{
BaseHandler.apply(this, arguments);
this.algorithm = algorithm;
this.SaveUpText();
this.UpdateResultAndMessage();
}
// inheritance.
AlgorithmGraphHandler.prototype = Object.create(BaseHandler.prototype);
// Rest this handler.
AlgorithmGraphHandler.prototype.MouseMove = function(pos) {}
AlgorithmGraphHandler.prototype.MouseDown = function(pos)
{
this.app.setRenderPath([]);
if (this.algorithm.instance())
{
this.app.SetDefaultHandler();
}
else
{
var selectedObject = this.GetSelectedGraph(pos);
if (selectedObject && (selectedObject instanceof BaseVertex))
{
if (this.algorithm.selectVertex(selectedObject))
{
this.needRedraw = true;
}
this.UpdateResultAndMessage();
}
else if (selectedObject && (selectedObject instanceof BaseEdge))
{
if (this.algorithm.selectEdge(selectedObject))
{
this.needRedraw = true;
}
this.UpdateResultAndMessage();
}
else
{
if (this.algorithm.deselectAll())
{
this.needRedraw = true;
this.UpdateResultAndMessage();
}
}
}
}
AlgorithmGraphHandler.prototype.MouseUp = function(pos) {}
AlgorithmGraphHandler.prototype.GetSelectedGroup = function(object)
{
return this.algorithm.getObjectSelectedGroup(object);
}
AlgorithmGraphHandler.prototype.RestoreAll = function()
{
this.app.setRenderPath([]);
if (this.algorithm.needRestoreUpText())
{
this.RestoreUpText();
}
if (this.algorithm.wantRestore())
{
this.algorithm.restore();
}
}
AlgorithmGraphHandler.prototype.SaveUpText = function()
{
this.vertexUpText = {};
var graph = this.app.graph;
for (i = 0; i < graph.vertices.length; i ++)
{
this.vertexUpText[graph.vertices[i].id] = graph.vertices[i].upText;
}
}
AlgorithmGraphHandler.prototype.RestoreUpText = function()
{
var graph = this.app.graph;
for (i = 0; i < graph.vertices.length; i ++)
{
if (graph.vertices[i].id in this.vertexUpText)
{
graph.vertices[i].upText = this.vertexUpText[graph.vertices[i].id];
}
}
}
AlgorithmGraphHandler.prototype.UpdateResultAndMessage = function()
{
var self = this;
result = this.algorithm.result(function (result)
{
self.message = self.algorithm.getMessage(g_language);
self.app.resultCallback(result);
});
this.app.resultCallback(result);
this.message = this.algorithm.getMessage(g_language);
}
AlgorithmGraphHandler.prototype.InitControls = function()
{
this.algorithm.messageWasChanged();
}
AlgorithmGraphHandler.prototype.GetMessage = function()
{
return this.algorithm.getMessage(g_language);
}
+35
View File
@@ -0,0 +1,35 @@
{
let modulDir = "features/algorithms/";
doInclude ([
include ("model/Algorithms.js", modulDir),
include ("model/BaseTraversal.js", modulDir)
])
function loadAsyncAlgorithms(onFinish) {
let pluginsList = ["BFS.js",
"Coloring.js",
"ConnectedComponent.js",
"DFS.js",
"EulerianLoop.js",
"EulerianPath.js",
"FindAllPatches.js",
"FindLongestPath.js",
"FindShortPatchsFromOne.js",
"Floid.js",
"GraphReorder.js",
"HamiltonianLoop.js",
"HamiltonianPath.js",
"IsomorphismCheck.js",
"MaxClique.js",
"MaxFlow.js",
"MinimumSpanningTree.js",
"ModernGraphStyle.js",
"RadiusAndDiameter.js",
"ShortestPath.js",
"VerticesDegree.js"];
doIncludeAsync (pluginsList.map((plugin) => include ("model/plugins/" + plugin, modulDir)), onFinish);
}
}
@@ -1,305 +1,305 @@
/** /**
* File for algorithms. * File for algorithms.
* *
*/ */
// Return list of 'vertex = [connected vertices]' // Return list of 'vertex = [connected vertices]'
function getVertexToVertexArray(graph, ignoreDirection) function getVertexToVertexArray(graph, ignoreDirection)
{ {
res = {}; res = {};
for (var i = 0; i < graph.edges.length; i ++) for (var i = 0; i < graph.edges.length; i ++)
{ {
edge = graph.edges[i]; edge = graph.edges[i];
if (!res.hasOwnProperty(edge.vertex1.id)) if (!res.hasOwnProperty(edge.vertex1.id))
{ {
res[edge.vertex1.id] = []; res[edge.vertex1.id] = [];
} }
res[edge.vertex1.id].push(edge.vertex2); res[edge.vertex1.id].push(edge.vertex2);
if (!edge.isDirect || ignoreDirection) if (!edge.isDirect || ignoreDirection)
{ {
if (!res.hasOwnProperty(edge.vertex2.id)) if (!res.hasOwnProperty(edge.vertex2.id))
{ {
res[edge.vertex2.id] = []; res[edge.vertex2.id] = [];
} }
res[edge.vertex2.id].push(edge.vertex1); res[edge.vertex2.id].push(edge.vertex1);
} }
} }
return res; return res;
} }
// Global array of all algorithms. // Global array of all algorithms.
var g_Algorithms = []; var g_Algorithms = [];
var g_AlgorithmIds = []; var g_AlgorithmIds = [];
// Call this function to register your factory algorithm. // Call this function to register your factory algorithm.
function RegisterAlgorithm (factory) function RegisterAlgorithm (factory)
{ {
g_Algorithms.push(factory); g_Algorithms.push(factory);
g_AlgorithmIds.push(factory(null).getId()); g_AlgorithmIds.push(factory(null).getId());
} }
// Base algorithm class. // Base algorithm class.
function BaseAlgorithm (graph, app) function BaseAlgorithm (graph, app)
{ {
this.graph = graph; this.graph = graph;
this.app = app; this.app = app;
} }
// @return name of algorithm. For now we supports only 2 locals: "ru" and "en" // @return name of algorithm. For now we supports only 2 locals: "ru" and "en"
BaseAlgorithm.prototype.getName = function(local) BaseAlgorithm.prototype.getName = function(local)
{ {
return "unknown_name_" + local; return "unknown_name_" + local;
} }
// @return id of algorithm. Please use format: "your id"."algorithm id". Ex. "OlegSh.ConnectedComponent" // @return id of algorithm. Please use format: "your id"."algorithm id". Ex. "OlegSh.ConnectedComponent"
BaseAlgorithm.prototype.getId = function() BaseAlgorithm.prototype.getId = function()
{ {
return "unknown.unknown"; return "unknown.unknown";
} }
// @return message for user. // @return message for user.
BaseAlgorithm.prototype.getMessage = function(local) BaseAlgorithm.prototype.getMessage = function(local)
{ {
return "unknown_message_" + local; return "unknown_message_" + local;
} }
// calls when user select vertex. // calls when user select vertex.
// @return true if you allow to select this object or false. // @return true if you allow to select this object or false.
BaseAlgorithm.prototype.selectVertex = function(vertex) BaseAlgorithm.prototype.selectVertex = function(vertex)
{ {
return false; return false;
} }
// calls when user select edge. // calls when user select edge.
// @return true if you allow to select this object or false. // @return true if you allow to select this object or false.
BaseAlgorithm.prototype.selectEdge = function(edge) BaseAlgorithm.prototype.selectEdge = function(edge)
{ {
return false; return false;
} }
// user click to workspace. // user click to workspace.
// @return true if you allow to deselect all // @return true if you allow to deselect all
BaseAlgorithm.prototype.deselectAll = function() BaseAlgorithm.prototype.deselectAll = function()
{ {
return true; return true;
} }
// get result of algorithm. // get result of algorithm.
// If result if not ready, please return null. // If result if not ready, please return null.
// It will be called after each user action. // It will be called after each user action.
// Please return true, if you done. // Please return true, if you done.
BaseAlgorithm.prototype.result = function(resultCallback) BaseAlgorithm.prototype.result = function(resultCallback)
{ {
return null; return null;
} }
// If you no need to get feedback from user, return true. // If you no need to get feedback from user, return true.
// In this case result will calls once. // In this case result will calls once.
BaseAlgorithm.prototype.instance = function() BaseAlgorithm.prototype.instance = function()
{ {
return true; return true;
} }
// @return false, if you change up text and do not want to restore it back. // @return false, if you change up text and do not want to restore it back.
BaseAlgorithm.prototype.needRestoreUpText = function() BaseAlgorithm.prototype.needRestoreUpText = function()
{ {
return true; return true;
} }
// @return true, if you change restore graph after use. // @return true, if you change restore graph after use.
BaseAlgorithm.prototype.wantRestore = function() BaseAlgorithm.prototype.wantRestore = function()
{ {
return false; return false;
} }
// calls this method if wantRestore return true. // calls this method if wantRestore return true.
BaseAlgorithm.prototype.restore = function() BaseAlgorithm.prototype.restore = function()
{ {
} }
// @return 0, if object is not selected, in other case return groupe of selection. // @return 0, if object is not selected, in other case return groupe of selection.
BaseAlgorithm.prototype.getObjectSelectedGroup = function(object) BaseAlgorithm.prototype.getObjectSelectedGroup = function(object)
{ {
return 0; return 0;
} }
// This method is called, when messages was updated on html page. // This method is called, when messages was updated on html page.
BaseAlgorithm.prototype.messageWasChanged = function() {} BaseAlgorithm.prototype.messageWasChanged = function() {}
// Algorithm priority in menu // Algorithm priority in menu
BaseAlgorithm.prototype.getPriority = function() BaseAlgorithm.prototype.getPriority = function()
{ {
return 0; return 0;
} }
// Algorithm support multi graph // Algorithm support multi graph
BaseAlgorithm.prototype.IsSupportMultiGraph = function() BaseAlgorithm.prototype.IsSupportMultiGraph = function()
{ {
return false; return false;
} }
BaseAlgorithm.prototype.getCategory = function() BaseAlgorithm.prototype.getCategory = function()
{ {
return 0; return 0;
} }
/** /**
* Default handler. * Default handler.
* Select using mouse, drag. * Select using mouse, drag.
* *
*/ */
function BaseAlgorithmEx(graph, app) function BaseAlgorithmEx(graph, app)
{ {
BaseAlgorithm.apply(this, arguments); BaseAlgorithm.apply(this, arguments);
} }
// inheritance. // inheritance.
BaseAlgorithmEx.prototype = Object.create(BaseAlgorithm.prototype); BaseAlgorithmEx.prototype = Object.create(BaseAlgorithm.prototype);
BaseAlgorithmEx.prototype.CalculateAlgorithm = function(algorithmName, otherParams, resultCallback, ignoreSeparateNodes = false) BaseAlgorithmEx.prototype.CalculateAlgorithm = function(algorithmName, otherParams, resultCallback, ignoreSeparateNodes = false)
{ {
if (location.hostname === "localhost" || location.hostname === "127.0.0.1") if (location.hostname === "localhost" || location.hostname === "127.0.0.1")
console.log(algorithmName + " " + otherParams); console.log(algorithmName + " " + otherParams);
var graph = this.graph; var graph = this.graph;
var ignoreNodes = {}; var ignoreNodes = {};
if (ignoreSeparateNodes) if (ignoreSeparateNodes)
for (var i = 0; i < graph.vertices.length; i++) for (var i = 0; i < graph.vertices.length; i++)
if (!graph.HasConnectedNodes(graph.vertices[i])) if (!graph.HasConnectedNodes(graph.vertices[i]))
ignoreNodes[graph.vertices[i].id] = 1; ignoreNodes[graph.vertices[i].id] = 1;
var creator = new GraphMLCreator(graph.vertices, graph.edges, ignoreNodes); var creator = new GraphMLCreator(graph.vertices, graph.edges, ignoreNodes);
var pathObjects = []; var pathObjects = [];
var properties = {}; var properties = {};
var result = []; var result = [];
var xml = creator.GetXMLString(); var xml = creator.GetXMLString();
console.log(xml); console.log(xml);
var processResult = function (msg) { var processResult = function (msg) {
console.log(msg); console.log(msg);
$('#debug').text(msg); $('#debug').text(msg);
xmlDoc = $.parseXML( msg ); xmlDoc = $.parseXML( msg );
var $xml = $( xmlDoc ); var $xml = $( xmlDoc );
$results = $xml.find( "result" ); $results = $xml.find( "result" );
$results.each(function(){ $results.each(function(){
$values = $(this).find( "value" ); $values = $(this).find( "value" );
$values.each(function(){ $values.each(function(){
var type = $(this).attr('type'); var type = $(this).attr('type');
var value = $(this).text(); var value = $(this).text();
var res = {}; var res = {};
res.type = type; res.type = type;
res.value = value; res.value = value;
result.push(res); result.push(res);
}); });
}); });
$nodes = $xml.find( "node" ); $nodes = $xml.find( "node" );
$nodes.each(function(){ $nodes.each(function(){
var id = $(this).attr('id'); var id = $(this).attr('id');
$data = $(this).find("data"); $data = $(this).find("data");
$data.each(function(){ $data.each(function(){
if ("hightlightNode" == $(this).attr('key') && $(this).text() == "1") if ("hightlightNode" == $(this).attr('key') && $(this).text() == "1")
{ {
pathObjects.push(graph.FindVertex(id)); pathObjects.push(graph.FindVertex(id));
} }
else else
{ {
if (!properties[id]) if (!properties[id])
{ {
properties[id] = {}; properties[id] = {};
} }
properties[id][$(this).attr('key')] = $(this).text(); properties[id][$(this).attr('key')] = $(this).text();
} }
}); });
}); });
$edges = $xml.find( "edge" ); $edges = $xml.find( "edge" );
$edges.each(function(){ $edges.each(function(){
var source = $(this).attr('source'); var source = $(this).attr('source');
var target = $(this).attr('target'); var target = $(this).attr('target');
var edge = graph.FindEdge(source, target); var edge = graph.FindEdge(source, target);
if (typeof $(this).attr('id') !== 'undefined') if (typeof $(this).attr('id') !== 'undefined')
{ {
edge = graph.FindEdgeById($(this).attr('id')); edge = graph.FindEdgeById($(this).attr('id'));
} }
pathObjects.push(edge); pathObjects.push(edge);
$data = $(this).find("data"); $data = $(this).find("data");
$data.each(function(){ $data.each(function(){
if (!properties[edge.id]) if (!properties[edge.id])
{ {
properties[edge.id] = {}; properties[edge.id] = {};
} }
properties[edge.id][$(this).attr('key')] = $(this).text(); properties[edge.id][$(this).attr('key')] = $(this).text();
}); });
}); });
console.log(result); console.log(result);
resultCallback(pathObjects, properties, result); resultCallback(pathObjects, properties, result);
}; };
if (this.app.isSupportEmscripten()) { if (this.app.isSupportEmscripten()) {
console.log("Use Emscripten"); console.log("Use Emscripten");
var delimiter = "<s\\emscript_split\\s>"; var delimiter = "<s\\emscript_split\\s>";
var processData = algorithmName + delimiter + xml + var processData = algorithmName + delimiter + xml +
delimiter + "report" + delimiter + "xml"; delimiter + "report" + delimiter + "xml";
otherParams.forEach ( (param) => processData += delimiter + param.name + delimiter + param.value); otherParams.forEach ( (param) => processData += delimiter + param.name + delimiter + param.value);
var res = this.app.processEmscripten(processData); var res = this.app.processEmscripten(processData);
processResult(res); processResult(res);
} else { } else {
console.log("Use new CGI"); console.log("Use new CGI");
var queryString = algorithmName + "=cgiInput&report=xml"; var queryString = algorithmName + "=cgiInput&report=xml";
otherParams.forEach ( (param) => queryString += "&" + param.name + "=" + param.value); otherParams.forEach ( (param) => queryString += "&" + param.name + "=" + param.value);
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "/" + SiteDir + "cgi-bin/GraphCGI.exe?" + queryString, url: "/" + SiteDir + "cgi-bin/GraphCGI.exe?" + queryString,
data: xml, data: xml,
dataType: "text", dataType: "text",
}) })
.done(function( msg ) .done(function( msg )
{ {
processResult(msg); processResult(msg);
}); });
} }
return true; return true;
} }
BaseAlgorithmEx.prototype.GetNodesPath = function(array, start, count) BaseAlgorithmEx.prototype.GetNodesPath = function(array, start, count)
{ {
var res = []; var res = [];
for (var index = start; index < start + count; index++) for (var index = start; index < start + count; index++)
{ {
if (array[index].type == 4) if (array[index].type == 4)
{ {
res.push(array[index].value); res.push(array[index].value);
} }
} }
return res; return res;
} }
BaseAlgorithmEx.prototype.GetNodesEdgesPath = function(array, start, count) BaseAlgorithmEx.prototype.GetNodesEdgesPath = function(array, start, count)
{ {
var res = []; var res = [];
for (var index = start; index < start + count; index++) for (var index = start; index < start + count; index++)
{ {
if (array[index].type == 4 || array[index].type == 5) if (array[index].type == 4 || array[index].type == 5)
{ {
res.push(array[index].value); res.push(array[index].value);
} }
} }
return res; return res;
} }
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+457
View File
@@ -0,0 +1,457 @@
/**
* Base Handler.
*
*/
function BaseHandler(app)
{
this.app = app;
this.app.setRenderPath([]);
if (this.removeStack) {
this.removeContextMenu();
}
this.contextMenuObject = null;
this.contextMenuPoint = null;
//this.app.ClearUndoStack();
}
// Need redraw or nor.
BaseHandler.prototype.needRedraw = false;
BaseHandler.prototype.objects = [];
BaseHandler.prototype.message = "";
BaseHandler.prototype.IsNeedRedraw = function(object)
{
return this.needRedraw;
}
BaseHandler.prototype.RestRedraw = function(object)
{
this.needRedraw = false;
}
BaseHandler.prototype.SetObjects = function(objects)
{
this.objects = objects;
}
BaseHandler.prototype.GetSelectedGraph = function(pos)
{
// Selected Graph.
var res = null;
for (var i = 0; i < this.app.graph.vertices.length; i ++)
{
if (this.app.graph.vertices[i].HitTest(pos))
{
// Select last of them.
res = this.app.graph.vertices[i];
}
}
return res;
}
BaseHandler.prototype.GetSelectedArc = function(pos)
{
// Selected Arc.
for (var i = 0; i < this.app.graph.edges.length; i ++)
{
var edge = this.app.graph.edges[i];
if (edge.HitTest(new Point(pos.x, pos.y)))
return edge;
}
return null;
}
BaseHandler.prototype.GetSelectedObject = function(pos)
{
var graphObject = this.GetSelectedGraph(pos);
if (graphObject)
{
return graphObject;
}
var arcObject = this.GetSelectedArc(pos);
if (arcObject)
{
return arcObject;
}
return null;
}
BaseHandler.prototype.GetUpText = function(object)
{
return "";
}
BaseHandler.prototype.GetMessage = function()
{
return this.message;
}
BaseHandler.prototype.MouseMove = function(pos) {}
BaseHandler.prototype.MouseDown = function(pos) {}
BaseHandler.prototype.MouseUp = function(pos) {}
BaseHandler.prototype.GetSelectedGroup = function(object)
{
return 0;
}
BaseHandler.prototype.InitControls = function()
{
var vertex1Text = document.getElementById("Vertex1");
if (vertex1Text)
{
var handler = this;
vertex1Text.onchange = function () {
for (var i = 0; i < handler.app.graph.vertices.length; i++)
{
if (handler.app.graph.vertices[i].mainText == vertex1Text.value)
{
handler.SelectFirstVertexMenu(vertex1Text, handler.app.graph.vertices[i]);
userAction("selectVertex1_menu");
break;
}
}
};
this.UpdateFirstVertexMenu(vertex1Text);
}
var vertex2Text = document.getElementById("Vertex2");
if (vertex2Text)
{
var handler = this;
vertex2Text.onchange = function () {
for (var i = 0; i < handler.app.graph.vertices.length; i++)
{
if (handler.app.graph.vertices[i].mainText == vertex2Text.value)
{
handler.SelectSecondVertexMenu(vertex2Text, handler.app.graph.vertices[i]);
userAction("selectVertex2_menu");
break;
}
}
};
this.UpdateSecondVertexMenu(vertex2Text);
}
}
BaseHandler.prototype.GetNodesPath = function(array, start, count)
{
var res = [];
for (var index = start; index < start + count; index++)
{
res.push(this.app.graph.FindVertex(array[index].value));
}
return res;
}
BaseHandler.prototype.RestoreAll = function()
{
}
BaseHandler.prototype.GetSelectVertexMenu = function(menuName)
{
var res = "<input list=\"vertexList" + menuName + "\" id=\"" + menuName + "\" class=\"SelectVertexInput\"/>" +
"<datalist id=\"vertexList" + menuName + "\">";
for (var i = 0; i < this.app.graph.vertices.length; i++)
{
res = res + "<option value=\"" + this.app.graph.vertices[i].mainText + "\"/>";
}
return res + "</datalist>";
}
BaseHandler.prototype.GetSelect2VertexMenu = function()
{
return "<span style=\"float:right\">" +
this.GetSelectVertexMenu("Vertex1") + " &rarr; " + this.GetSelectVertexMenu("Vertex2") + "</span>";
}
BaseHandler.prototype.SelectFirstVertexMenu = function(vertex1Text, vertex)
{}
BaseHandler.prototype.UpdateFirstVertexMenu = function()
{}
BaseHandler.prototype.SelectSecondVertexMenu = function(vertex2Text, vertex)
{}
BaseHandler.prototype.UpdateSecondVertexMenu = function()
{}
BaseHandler.prototype.GetSelectedVertex = function()
{
return null;
}
BaseHandler.prototype.addContextMenu = function()
{
var $contextMenu = $("#contextMenu");
var handler = this;
$("#Context_Delete").click(function() {
if (handler.contextMenuObject != null) {
handler.app.PushToStack("DeleteObject");
handler.app.DeleteObject(handler.contextMenuObject);
handler.app.redrawGraph();
userAction("DeleteObject_contextMenu");
}
});
$("#Context_Rename").click(function() {
if (handler.contextMenuObject != null) {
var callback = function (enumType) {
handler.RenameVertex(enumType.GetVertexText(0), handler.contextMenuObject);
userAction("RenameVertex_contextMenu");
};
var customEnum = new TextEnumVerticesCustom(handler.app);
customEnum.ShowDialog(callback, g_rename, g_renameVertex, handler.contextMenuObject.mainText);
}
});
$("#Context_Connect").click(function() {
if (handler.contextMenuObject != null && handler.GetSelectedVertex() != null) {
var addFunc = function(firstVertex, secondVertex, direct) {
handler.app.CreateNewArc(firstVertex, secondVertex, direct,
document.getElementById('EdgeWeight').value,
$("#RadiosReplaceEdge").prop("checked"),
document.getElementById('EdgeLable').value);
handler.app.redrawGraph();
}
handler.ShowCreateEdgeDialog(handler.GetSelectedVertex(), handler.contextMenuObject, addFunc);
}
});
$("#Context_Delete_Edge").click(function() {
if (handler.contextMenuObject != null) {
handler.app.PushToStack("DeleteObject");
handler.app.DeleteObject(handler.contextMenuObject);
handler.app.redrawGraph();
userAction("DeleteObject_contextMenu");
}
});
$("#Context_Edit_Edge").click(function() {
if (handler.contextMenuObject != null) {
handler.ShowEditEdgeDialog(handler.contextMenuObject);
}
});
$("#Context_Add_Vertex").click(function() {
handler.app.PushToStack("Add");
handler.app.CreateNewGraph(handler.contextMenuPoint.x, handler.contextMenuPoint.y);
handler.app.redrawGraph();
});
$("#Context_Back_Color").click(function() {
var setupBackgroundStyle = new SetupBackgroundStyle(handler.app);
setupBackgroundStyle.show();
});
$("body").on("contextmenu", "canvas", function(e) {
handler.contextMenuPoint = handler.app.getMousePos(handler.app.canvas, e);
handler.contextMenuObject = handler.GetSelectedObject(handler.contextMenuPoint);
if (handler.contextMenuObject instanceof BaseVertex) {
$("#edgeContextMenu").hide();
$("#backgroundContextMenu").hide();
$("#vertexContextMenu").show();
if (handler.GetSelectedVertex() == null) {
$("#Context_Connect").hide();
} else {
$("#Context_Connect").show();
}
} else if (handler.contextMenuObject instanceof BaseEdge) {
$("#vertexContextMenu").hide();
$("#backgroundContextMenu").hide();
$("#edgeContextMenu").show();
} else {
$("#vertexContextMenu").hide();
$("#edgeContextMenu").hide();
$("#backgroundContextMenu").show();
}
$contextMenu.css({
display: "block",
left: e.offsetX,
top: e.offsetY
});
return false;
});
$("body").click(function() {
$contextMenu.hide();
});
}
BaseHandler.prototype.removeContextMenu = function()
{
$("body").off("contextmenu");
$("#Context_Delete").off("click");
$("#Context_Rename").off("click");
$("#Context_Connect").off("click");
$("#Context_Delete_Edge").off("click");
$("#Context_Edit_Edge").off("click");
$("#Context_Add_Vertex").off("click");
$("#Context_Back_Color").off("click");
}
BaseHandler.prototype.RenameVertex = function(text, object)
{
if (object != null && (object instanceof BaseVertex))
{
this.app.PushToStack("RenameVertex");
object.mainText = text;
this.app.redrawGraph();
}
}
BaseHandler.prototype.ShowCreateEdgeDialog = function(firstVertex, secondVertex, addEdgeCallBack) {
if (!this.app.graph.isMulti())
{
var hasEdge = this.app.graph.FindEdgeAny(firstVertex.id, secondVertex.id);
var hasReverseEdge = this.app.graph.FindEdgeAny(secondVertex.id, firstVertex.id);
if (hasEdge == null && hasReverseEdge == null)
{
$("#RadiosReplaceEdge").prop("checked", true);
$("#NewEdgeAction" ).hide();
}
else {
$( "#NewEdgeAction" ).show();
}
}
else
{
$("#RadiosAddEdge").prop("checked", true);
$("#NewEdgeAction" ).hide();
}
var dialogButtons = {};
var handler = this;
$("#CheckSaveDefaultEdge").prop("checked", false);
$("#defaultEdgeDialogBlock").show();
dialogButtons[g_orintEdge] = function() {
handler.app.PushToStack("Connect");
addEdgeCallBack(firstVertex, secondVertex, true);
//handler.AddNewEdge(selectedObject, true);
$( this ).dialog( "close" );
};
dialogButtons[g_notOrintEdge] = function() {
handler.app.PushToStack("Connect");
addEdgeCallBack(firstVertex, secondVertex, false);
//handler.AddNewEdge(selectedObject, false);
$( this ).dialog( "close" );
};
var edgePresets = this.app.GetEdgePresets();
var presetsStr = "<span onClick=\"document.getElementById('EdgeWeight').value='" + g_DefaultWeightPreset
+ "'; document.getElementById('EdgeWeightSlider').value='" + g_DefaultWeightPreset
+ "';\" style=\"cursor: pointer\" class=\"defaultWeigth\">" + g_DefaultWeightPreset + "</span>";
for(var i = 0; i < edgePresets.length; i ++)
{
var edgePreset = edgePresets[i];
presetsStr += "<span onClick=\"document.getElementById('EdgeWeight').value='" + edgePreset
+ "'; document.getElementById('EdgeWeightSlider').value=" + edgePreset
+ ";\" style=\"cursor: pointer\" class=\"defaultWeigth\">" + edgePreset + "</span>";
}
document.getElementById("EdgesPresets").innerHTML = presetsStr;
document.getElementById('EdgeLable').value = "";
$( "#addEdge" ).dialog({
resizable: false,
height: "auto",
width: "auto",
modal: true,
title: g_addEdge,
buttons: dialogButtons,
dialogClass: 'EdgeDialog',
open: function () {
$(this).off('submit').on('submit', function () {
return false;
});
// Focues weight
setTimeout(function(){
const weightInput = document.getElementById('EdgeWeight');
if(weightInput)
{
weightInput.focus();
weightInput.select();
}
},0);
}
});
}
BaseHandler.prototype.ShowEditEdgeDialog = function(edgeObject) {
var dialogButtons = {};
var handler = this;
dialogButtons[g_save] = function() {
handler.app.PushToStack("ChangeEdge");
edgeObject.SetWeight(document.getElementById('EdgeWeight').value);
edgeObject.SetUpText(document.getElementById('EdgeLable').value);
handler.needRedraw = true;
handler.app.redrawGraph();
userAction("ChangeWeight");
$( this ).dialog( "close" );
};
document.getElementById('EdgeWeight').value = edgeObject.useWeight ? edgeObject.weight : g_noWeight;
document.getElementById('EdgeWeightSlider').value = edgeObject.useWeight ? edgeObject.weight : 0;
var edgePresets = handler.app.GetEdgePresets();
var presetsStr = "<span onClick=\"document.getElementById('EdgeWeight').value='" + g_DefaultWeightPreset + "'; document.getElementById('EdgeWeightSlider').value='" +
g_DefaultWeightPreset + "';\" style=\"cursor: pointer\" class=\"defaultWeigth\">" + g_DefaultWeightPreset + "</span>";
for(var i = 0; i < edgePresets.length; i ++)
{
var edgePreset = edgePresets[i];
presetsStr += "<span onClick=\"document.getElementById('EdgeWeight').value='" + edgePreset + "'; document.getElementById('EdgeWeightSlider').value=" +
edgePreset + ";\" style=\"cursor: pointer\" class=\"defaultWeigth\">" + edgePreset + "</span>";
}
document.getElementById("EdgesPresets").innerHTML = presetsStr;
document.getElementById('EdgeLable').value = edgeObject.upText;
$("#CheckSaveDefaultEdge").prop("checked", false);
$("#defaultEdgeDialogBlock").hide();
$( "#addEdge" ).dialog({
resizable: false,
height: "auto",
width: "auto",
modal: true,
title: g_editWeight,
buttons: dialogButtons,
dialogClass: 'EdgeDialog',
open: function () {
$(handler).off('submit').on('submit', function () {
return false;
});
}
});
}
@@ -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
View File
@@ -0,0 +1,431 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Default handler.
* Select using mouse, drag.
*
*/
function DefaultHandler(app)
{
this.removeStack = true;
BaseHandler.apply(this, arguments);
this.message = g_textsSelectAndMove + " <span class=\"hidden-phone\">" + g_selectGroupText + "</span>" + " <span class=\"hidden-phone\">" + g_useContextMenuText + "</span>";
this.selectedObjects = [];
this.dragObject = null;
this.selectedObject = null;
this.prevPosition = null;
this.groupingSelect = false;
this.selectedLogRect = false;
this.selectedLogCtrl = false;
this.saveUndo = false;
this.addContextMenu();
}
// inheritance.
DefaultHandler.prototype = Object.create(BaseHandler.prototype);
// Is pressed
DefaultHandler.prototype.pressed = false;
// Curve change value.
DefaultHandler.prototype.curveValue = 0.1;
DefaultHandler.prototype.GetSelectedVertex = function()
{
return (this.selectedObject instanceof BaseVertex) ? this.selectedObject : null;
}
DefaultHandler.prototype.MouseMove = function(pos)
{
if (this.dragObject)
{
if (!this.saveUndo)
{
this.app.PushToStack("Move");
this.saveUndo = true;
}
this.dragObject.position.x = pos.x;
this.dragObject.position.y = pos.y;
this.needRedraw = true;
}
else if (this.selectedObjects.length > 0 && this.pressed && !this.groupingSelect)
{
if (!this.saveUndo)
{
this.app.PushToStack("Move");
this.saveUndo = true;
}
var offset = (new Point(pos.x, pos.y)).subtract(this.prevPosition);
for (var i = 0; i < this.selectedObjects.length; i ++)
{
var object = this.selectedObjects[i];
if (object instanceof BaseVertex)
{
object.position = object.position.add(offset);
}
}
this.prevPosition = pos;
this.needRedraw = true;
}
else if (this.pressed)
{
if (this.groupingSelect)
{
// Rect select.
var newPos = new Point(pos.x, pos.y);
this.app.SetSelectionRect(new Rect(newPos.min(this.prevPosition), newPos.max(this.prevPosition)));
this.SelectObjectInRect(this.app.GetSelectionRect());
this.needRedraw = true;
if (!this.selectedLogRect)
{
userAction("GroupSelected.SelectRect");
this.selectedLogRect = true;
}
}
else
{
// Move work space
this.app.onCanvasMove((new Point(pos.x, pos.y)).subtract(this.prevPosition).multiply(this.app.canvasScale));
this.needRedraw = true;
}
}
}
DefaultHandler.prototype.MouseDown = function(pos)
{
this.dragObject = null;
var selectedObject = this.GetSelectedObject(pos);
var severalSelect = g_ctrlPressed;
if (selectedObject == null || (!severalSelect && !this.selectedObjects.includes(selectedObject)))
{
this.selectedObject = null;
this.selectedObjects = [];
this.groupingSelect = g_ctrlPressed;
}
if ((severalSelect || this.selectedObjects.includes(selectedObject)) && (this.selectedObjects.length > 0 || this.selectedObject != null) && selectedObject != null)
{
if (this.selectedObjects.length == 0)
{
this.selectedObjects.push(this.selectedObject);
this.selectedObject = null;
this.selectedObjects.push(selectedObject);
}
else if (!this.selectedObjects.includes(selectedObject))
{
this.selectedObjects.push(selectedObject);
}
else if (severalSelect && this.selectedObjects.includes(selectedObject))
{
var index = this.selectedObjects.indexOf(selectedObject);
this.selectedObjects.splice(index, 1);
}
if (!this.selectedLogCtrl)
{
userAction("GroupSelected.SelectCtrl");
this.selectedLogCtrl = true;
}
}
else
{
if (selectedObject != null)
{
this.selectedObject = selectedObject;
}
if ((selectedObject instanceof BaseVertex) && selectedObject != null)
{
this.dragObject = selectedObject;
this.message = g_moveCursorForMoving;
}
}
this.needRedraw = true;
this.pressed = true;
this.prevPosition = pos;
this.app.canvas.style.cursor = "move";
}
DefaultHandler.prototype.MouseUp = function(pos)
{
this.saveUndo = false;
this.message = g_textsSelectAndMove + " <span class=\"hidden-phone\">" + g_selectGroupText + "</span>" + " <span class=\"hidden-phone\">" + g_useContextMenuText + "</span>";
this.dragObject = null;
this.pressed = false;
this.app.canvas.style.cursor = "auto";
this.app.SetSelectionRect(null);
this.groupingSelect = false;
if (this.selectedObject != null && (this.selectedObject instanceof BaseVertex))
{
this.message = g_textsSelectAndMove
+ "<div class=\"btn-group\" style=\"float:right;position: relative;\">"
+ "<button type=\"button\" class=\"btn btn-default btn-sm dropdown-toggle\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">"
+ " " + g_action + " <span class=\"caret\"></span>"
+ " </button>"
+ "<ul class=\"dropdown-menu dropdown-menu-right\" style=\"z-index:15; position: absolute;\">"
+ " <li><a href=\"#\" id=\"renameButton\">" + g_renameVertex + "</a></li>"
+ " <li><a href=\"#\" id=\"changeCommonStyle\">" + g_commonVertexStyle + "</a></li>"
+ " <li><a href=\"#\" id=\"changeSelectedStyle\">" + g_selectedVertexStyle + "</a></li>"
+ "</ul>"
+ "</div>";
var handler = this;
var callback = function (enumType) {
handler.RenameVertex(enumType.GetVertexText(0), handler.selectedObject);
userAction("RenameVertex");
};
$('#message').unbind();
$('#message').on('click', '#renameButton', function(){
var customEnum = new TextEnumVerticesCustom(handler.app);
customEnum.ShowDialog(callback, g_rename, g_renameVertex, handler.selectedObject.mainText);
});
$('#message').on('click', '#changeCommonStyle', function(){
var selectedVertices = handler.app.GetSelectedVertices();
var setupVertexStyle = new SetupVertexStyle(handler.app);
setupVertexStyle.show(0, selectedVertices);
});
$('#message').on('click', '#changeSelectedStyle', function(){
var selectedVertices = handler.app.GetSelectedVertices();
var setupVertexStyle = new SetupVertexStyle(handler.app);
setupVertexStyle.show(1, selectedVertices);
});
}
else if (this.selectedObject != null && (this.selectedObject instanceof BaseEdge))
{
this.message = g_textsSelectAndMove
+ "<span style=\"float:right;\"><button type=\"button\" id=\"incCurvel\" class=\"btn btn-default btn-xs\"> + </button>"
+ " " + g_curveEdge + " "
+ "<button type=\"button\" id=\"decCurvel\" class=\"btn btn-default btn-xs\"> - </button> &nbsp; "
+ "<div class=\"btn-group\" style=\"float:right;position: relative;\">"
+ "<button type=\"button\" class=\"btn btn-default btn-sm dropdown-toggle\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">"
+ " " + g_action + " <span class=\"caret\"></span>"
+ " </button>"
+ "<ul class=\"dropdown-menu dropdown-menu-right\" style=\"z-index:15; position: absolute;\">"
+ " <li><a href=\"#\" id=\"editEdge\">" + g_editWeight + "</a></li>"
+ " <li><a href=\"#\" id=\"changeCommonStyle\">" + g_commonEdgeStyle + "</a></li>"
+ " <li><a href=\"#\" id=\"changeSelectedStyle\">" + g_selectedEdgeStyle + "</a></li>"
+ "</ul>"
+ "</div>";
var handler = this;
$('#message').unbind();
$('#message').on('click', '#editEdge', function(){
handler.ShowEditEdgeDialog(handler.selectedObject);
});
$('#message').on('click', '#incCurvel', function(){
handler.app.PushToStack("ChangeCurvelEdge");
handler.selectedObject.model.ChangeCurveValue(DefaultHandler.prototype.curveValue);
handler.needRedraw = true;
handler.app.redrawGraph();
userAction("Edge.Bend");
});
$('#message').on('click', '#decCurvel', function(){
handler.app.PushToStack("ChangeCurvelEdge");
handler.selectedObject.model.ChangeCurveValue(-DefaultHandler.prototype.curveValue);
handler.needRedraw = true;
handler.app.redrawGraph();
userAction("Edge.Bend");
});
$('#message').on('click', '#changeCommonStyle', function(){
var selectedEdges = handler.app.GetSelectedEdges();
var setupVertexStyle = new SetupEdgeStyle(handler.app);
setupVertexStyle.show(0, selectedEdges);
});
$('#message').on('click', '#changeSelectedStyle', function(){
var selectedEdges = handler.app.GetSelectedEdges();
var setupVertexStyle = new SetupEdgeStyle(handler.app);
setupVertexStyle.show(1, selectedEdges);
});
}
else if (this.selectedObjects.length > 0)
{
this.message = g_dragGroupText + " <span class=\"hidden-phone\">" + g_selectGroupText + "</span>";
var hasVertices = false;
var hasEdges = false;
for(var i = 0; i < this.selectedObjects.length; i ++)
{
var object = this.selectedObjects[i];
if (object instanceof BaseVertex)
{
hasVertices = true;
}
else if (object instanceof BaseEdge)
{
hasEdges = true;
}
}
this.message = this.message + "<span style=\"float:right;position: relative;\">";
this.message = this.message
+ "<button type=\"button\" id=\"DublicateSelected\" class=\"btn btn-default btn-xs\">"
+ g_copyGroupeButton + "</button> &nbsp &nbsp"
+ "<button type=\"button\" id=\"RemoveSelected\" class=\"btn btn-default btn-xs\">"
+ g_removeGroupeButton + "</button>"
this.message = this.message
+ " &nbsp &nbsp <button type=\"button\" class=\"btn btn-default btn-xs dropdown-toggle\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">"
+ " " + g_action + " <span class=\"caret\"></span>"
+ " </button>"
+ "<ul class=\"dropdown-menu dropdown-menu-right\" style=\"z-index:15; position: absolute;\">";
if (hasEdges) {
this.message = this.message + " <li><a href=\"#\" id=\"changeCommonStyleEdge\">" + g_commonEdgeStyle + "</a></li>";
this.message = this.message + " <li><a href=\"#\" id=\"changeSelectedStyleEdge\">" + g_selectedEdgeStyle + "</a></li>";
}
if (hasVertices) {
this.message = this.message + " <li><a href=\"#\" id=\"changeCommonStyleVertex\">" + g_commonVertexStyle + "</a></li>";
this.message = this.message + " <li><a href=\"#\" id=\"changeSelectedStyleVertex\">" + g_selectedVertexStyle + "</a></li>";
}
this.message = this.message
+ "</ul>"
+ "</span>";
var handler = this;
$('#message').unbind();
$('#message').on('click', '#DublicateSelected', function(){
handler.app.PushToStack("DublicateSelection");
userAction("GroupSelected.Dublicate");
var newSelected = [];
var copyVertex = {};
// Copy vertex
for(var i = 0; i < handler.selectedObjects.length; i ++)
{
var object = handler.selectedObjects[i];
if (object instanceof BaseVertex)
{
var newObject = new BaseVertex()
newObject.copyFrom(object);
newObject.vertexEnumType = null;
handler.app.AddNewVertex(newObject);
var vertex = newObject;
var diameter = (new VertexModel()).diameter;
vertex.position.offset(diameter, diameter);
newSelected.push(vertex);
copyVertex[object.id] = vertex;
}
}
// Copy edge
for (var i = 0; i < handler.selectedObjects.length; i ++)
{
var object = handler.selectedObjects[i];
if (object instanceof BaseEdge)
{
var newObject = new BaseEdge()
newObject.copyFrom(object);
var toNewVertex = false;
if (newObject.vertex1.id in copyVertex)
{
newObject.vertex1 = copyVertex[newObject.vertex1.id];
toNewVertex = true;
}
if (newObject.vertex2.id in copyVertex)
{
newObject.vertex2 = copyVertex[newObject.vertex2.id];
toNewVertex = true;
}
handler.app.AddNewEdge(newObject);
if (!toNewVertex)
{
var neighborEdges = handler.app.graph.getNeighborEdges(newObject);
if (neighborEdges.length >= 1)
{
var curve = handler.app.GetAvailableCurveValue(neighborEdges, newObject);
newObject.model.SetCurveValue(curve);
}
}
newSelected.push(newObject);
}
}
handler.selectedObjects = newSelected;
handler.needRedraw = true;
handler.app.redrawGraph();
});
$('#message').on('click', '#RemoveSelected', function(){
handler.app.PushToStack("RemoveSelection");
userAction("GroupSelected.Remove");
for(var i = 0; i < handler.selectedObjects.length; i ++)
handler.app.DeleteObject(handler.selectedObjects[i]);
handler.selectedObjects = [];
handler.needRedraw = true;
handler.app.redrawGraph();
handler.message = g_textsSelectAndMove + " <span class=\"hidden-phone\">" + g_selectGroupText + "</span>";
});
if (hasEdges) {
$('#message').on('click', '#changeCommonStyleEdge', function(){
var selectedEdges = handler.app.GetSelectedEdges();
var setupVertexStyle = new SetupEdgeStyle(handler.app);
setupVertexStyle.show(0, selectedEdges);
});
$('#message').on('click', '#changeSelectedStyleEdge', function(){
var selectedEdges = handler.app.GetSelectedEdges();
var setupVertexStyle = new SetupEdgeStyle(handler.app);
setupVertexStyle.show(1, selectedEdges);
});
}
if (hasVertices) {
$('#message').on('click', '#changeCommonStyleVertex', function(){
var selectedVertices = handler.app.GetSelectedVertices();
var setupVertexStyle = new SetupVertexStyle(handler.app);
setupVertexStyle.show(0, selectedVertices);
});
$('#message').on('click', '#changeSelectedStyleVertex', function(){
var selectedVertices = handler.app.GetSelectedVertices();
var setupVertexStyle = new SetupVertexStyle(handler.app);
setupVertexStyle.show(1, selectedVertices);
});
}
}
this.needRedraw = true;
}
DefaultHandler.prototype.GetSelectedGroup = function(object)
{
return (object == this.dragObject) || (object == this.selectedObject) ? 1 : 0 || this.selectedObjects.includes(object);
}
DefaultHandler.prototype.SelectObjectInRect = function (rect)
{
this.selectedObjects = [];
var vertices = this.app.graph.vertices;
for (var i = 0; i < vertices.length; i ++)
{
if (rect.isIn(vertices[i].position) && !this.selectedObjects.includes(vertices[i]))
this.selectedObjects.push(vertices[i]);
}
// Selected Arc.
var edges = this.app.graph.edges;
for (var i = 0; i < edges.length; i ++)
{
var edge = edges[i];
if (rect.isIn(edge.vertex1.position) && rect.isIn(edge.vertex2.position) && !this.selectedObjects.includes(edge))
this.selectedObjects.push(edge);
}
}
@@ -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
View File
@@ -0,0 +1,10 @@
{
let modulDir = "features/draw_graph/";
doInclude ([
include ("model/BaseBackgroundDrawer.js", modulDir),
include ("model/BaseEdgeDrawer.js", modulDir),
include ("model/BaseVertexDrawer.js", modulDir)
])
}
File renamed without changes.
+201 -201
View File
@@ -1,201 +1,201 @@
/* /*
Classes for creating text for vertices. Classes for creating text for vertices.
*/ */
/** /**
* Base Enum Vertices. * Base Enum Vertices.
* *
*/ */
function BaseEnumVertices(app, startNumber) function BaseEnumVertices(app, startNumber)
{ {
this.app = app; this.app = app;
this.startNumber = startNumber; this.startNumber = startNumber;
} }
BaseEnumVertices.prototype.GetVertexText = function(id) BaseEnumVertices.prototype.GetVertexText = function(id)
{ {
return this.startNumber + id; return this.startNumber + id;
} }
BaseEnumVertices.prototype.GetVertexTextAsync = function(callback) BaseEnumVertices.prototype.GetVertexTextAsync = function(callback)
{ {
callback (this); callback (this);
} }
BaseEnumVertices.prototype.GetText = function() BaseEnumVertices.prototype.GetText = function()
{ {
return this.startNumber + ", " + (this.startNumber + 1) + ", " + (this.startNumber + 2) + "..."; return this.startNumber + ", " + (this.startNumber + 1) + ", " + (this.startNumber + 2) + "...";
} }
BaseEnumVertices.prototype.GetValue = function() BaseEnumVertices.prototype.GetValue = function()
{ {
return "Numbers" + this.startNumber; return "Numbers" + this.startNumber;
} }
function TextEnumTitle(app, title) function TextEnumTitle(app, title)
{ {
BaseEnumVertices.apply(this, arguments); BaseEnumVertices.apply(this, arguments);
this.pattern = ""; this.pattern = "";
this.title = title; this.title = title;
} }
// inheritance. // inheritance.
TextEnumTitle.prototype = Object.create(BaseEnumVertices.prototype); TextEnumTitle.prototype = Object.create(BaseEnumVertices.prototype);
TextEnumTitle.prototype.GetVertexText = function(id) TextEnumTitle.prototype.GetVertexText = function(id)
{ {
return this.title; return this.title;
} }
/** /**
* Text Enum * Text Enum
* *
*/ */
function TextEnumVertices(app) function TextEnumVertices(app)
{ {
BaseEnumVertices.apply(this, arguments); BaseEnumVertices.apply(this, arguments);
this.pattern = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; this.pattern = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
} }
// inheritance. // inheritance.
TextEnumVertices.prototype = Object.create(BaseEnumVertices.prototype); TextEnumVertices.prototype = Object.create(BaseEnumVertices.prototype);
TextEnumVertices.prototype.GetVertexText = function(id) TextEnumVertices.prototype.GetVertexText = function(id)
{ {
var res = ""; var res = "";
res = this.pattern[id % this.pattern.length] + res; res = this.pattern[id % this.pattern.length] + res;
while (id >= this.pattern.length) while (id >= this.pattern.length)
{ {
id = Math.floor(id / this.pattern.length) - 1; id = Math.floor(id / this.pattern.length) - 1;
res = this.pattern[id % this.pattern.length] + res; res = this.pattern[id % this.pattern.length] + res;
} }
return res; return res;
} }
TextEnumVertices.prototype.GetText = function() TextEnumVertices.prototype.GetText = function()
{ {
return "A, B, ... Z"; return "A, B, ... Z";
} }
TextEnumVertices.prototype.GetValue = function() TextEnumVertices.prototype.GetValue = function()
{ {
return "Latin"; return "Latin";
} }
/** /**
* Text Enum * Text Enum
* *
*/ */
function TextEnumVerticesCyr(app) function TextEnumVerticesCyr(app)
{ {
TextEnumVertices.apply(this, arguments); TextEnumVertices.apply(this, arguments);
this.pattern = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"; this.pattern = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
} }
// inheritance. // inheritance.
TextEnumVerticesCyr.prototype = Object.create(TextEnumVertices.prototype); TextEnumVerticesCyr.prototype = Object.create(TextEnumVertices.prototype);
TextEnumVerticesCyr.prototype.GetText = function() TextEnumVerticesCyr.prototype.GetText = function()
{ {
return "А, Б, ... Я"; return "А, Б, ... Я";
} }
TextEnumVerticesCyr.prototype.GetValue = function() TextEnumVerticesCyr.prototype.GetValue = function()
{ {
return "Cyrillic"; return "Cyrillic";
} }
/** /**
* Text Enum * Text Enum
* *
*/ */
function TextEnumVerticesGreek(app) function TextEnumVerticesGreek(app)
{ {
TextEnumVertices.apply(this, arguments); TextEnumVertices.apply(this, arguments);
this.pattern = "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ"; this.pattern = "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ";
} }
// inheritance. // inheritance.
TextEnumVerticesGreek.prototype = Object.create(TextEnumVertices.prototype); TextEnumVerticesGreek.prototype = Object.create(TextEnumVertices.prototype);
TextEnumVerticesGreek.prototype.GetText = function() TextEnumVerticesGreek.prototype.GetText = function()
{ {
return "Α, Β, ... Ω"; return "Α, Β, ... Ω";
} }
TextEnumVerticesGreek.prototype.GetValue = function() TextEnumVerticesGreek.prototype.GetValue = function()
{ {
return "Greek"; return "Greek";
} }
/** /**
* Text Enum * Text Enum
* *
*/ */
function TextEnumVerticesCustom(app) function TextEnumVerticesCustom(app)
{ {
BaseEnumVertices.apply(this, arguments); BaseEnumVertices.apply(this, arguments);
this.pattern = ""; this.pattern = "";
} }
// inheritance. // inheritance.
TextEnumVerticesCustom.prototype = Object.create(BaseEnumVertices.prototype); TextEnumVerticesCustom.prototype = Object.create(BaseEnumVertices.prototype);
TextEnumVerticesCustom.prototype.GetText = function() TextEnumVerticesCustom.prototype.GetText = function()
{ {
return g_customEnumVertex; return g_customEnumVertex;
} }
TextEnumVerticesCustom.prototype.GetValue = function() TextEnumVerticesCustom.prototype.GetValue = function()
{ {
return "Custom"; return "Custom";
} }
TextEnumVerticesCustom.prototype.GetVertexTextAsync = function(callback) TextEnumVerticesCustom.prototype.GetVertexTextAsync = function(callback)
{ {
this.ShowDialog(callback, g_addVertex, g_addVertex, "A"); this.ShowDialog(callback, g_addVertex, g_addVertex, "A");
} }
TextEnumVerticesCustom.prototype.ShowDialog = function(callback, buttonText, titleTitle, title) TextEnumVerticesCustom.prototype.ShowDialog = function(callback, buttonText, titleTitle, title)
{ {
var dialogButtons = {}; var dialogButtons = {};
app = this.app; app = this.app;
dialogButtons[buttonText] = function() { dialogButtons[buttonText] = function() {
app.PushToStack("RenameVertex"); app.PushToStack("RenameVertex");
callback(new TextEnumTitle(app, $("#VertexTitle").val())); callback(new TextEnumTitle(app, $("#VertexTitle").val()));
$( this ).dialog( "close" ); $( this ).dialog( "close" );
}; };
$( "#addVertex" ).dialog({ $( "#addVertex" ).dialog({
resizable: false, resizable: false,
height: "auto", height: "auto",
width: "auto", width: "auto",
modal: true, modal: true,
title: titleTitle, title: titleTitle,
buttons: dialogButtons, buttons: dialogButtons,
dialogClass: 'EdgeDialog', dialogClass: 'EdgeDialog',
open: function () { open: function () {
$(this).off('submit').on('submit', function () { $(this).off('submit').on('submit', function () {
return false; return false;
}); });
$("#VertexTitle").val(title); $("#VertexTitle").val(title);
$("#VertexTitle").focus(); $("#VertexTitle").focus();
} }
}); });
} }
@@ -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'
});
}
@@ -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'
});
}
@@ -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);
}
@@ -0,0 +1,8 @@
{
let modulDir = "features/serialization/";
doInclude ([
include ("model/GraphMLCreator.js", modulDir)
])
}
@@ -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
View File
@@ -0,0 +1,295 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Setup Vertex Style rename vertices.
*
*/
function SetupEdgeStyle(app)
{
BaseHandler.apply(this, arguments);
this.message = "";
}
// inheritance.
SetupEdgeStyle.prototype = Object.create(BaseHandler.prototype);
SetupEdgeStyle.prototype.show = function(index, selectedEdges)
{
var handler = this;
var dialogButtons = {};
var graph = this.app.graph;
var app = this.app;
this.forAll = selectedEdges == null;
var forAll = this.forAll;
var self = this;
var applyIndex = function(index)
{
self.index = index;
var originStyle = (self.index == 0 ? app.edgeCommonStyle : app.edgeSelectedStyles[self.index - 1]);
if (!forAll)
{
originStyle = selectedEdges[0].getStyleFor(self.index);
}
self.style = FullObjectCopy(originStyle);
}
applyIndex(index);
var fillFields = function()
{
var fullStyle = self.style.GetStyle({}, forAll ? undefined : selectedEdges[0]);
$( "#edgeFillColor" ).val(fullStyle.fillStyle);
$( "#edgeStrokeColor" ).val(fullStyle.strokeStyle);
$( "#edgeTextColor" ).val(fullStyle.weightText);
$( "#edgeStyle" ).val(fullStyle.lineDash);
$( "#edgeWidth" ).val(forAll ? app.GetDefaultEdgeWidth() : selectedEdges[0].model.width);
$( "#weightEdgeTextColor" ).val(fullStyle.additionalTextColor);
$( "#weightTextPosition" ).val(fullStyle.weightPosition);
if (self.index > 0 || self.index == "all")
{
$( "#EdgeSelectedIndexForm" ).show();
$( "#edgeSelectedIndex" ).val(self.index);
}
else
{
$( "#EdgeSelectedIndexForm" ).hide();
}
// Fill color presets.
var stylesArray = [];
stylesArray.push(app.edgeCommonStyle);
for (i = 0; i < app.edgeSelectedStyles.length; i ++)
stylesArray.push(app.edgeSelectedStyles[i]);
var colorSet = {};
for (i = 0; i < stylesArray.length; i ++)
{
var style = stylesArray[i];
if (style.hasOwnProperty('strokeStyle'))
colorSet[style.strokeStyle] = 1;
if (style.hasOwnProperty('fillStyle'))
colorSet[style.fillStyle] = 1;
if (style.hasOwnProperty('additionalTextColor'))
colorSet[style.additionalTextColor] = 1;
}
$("#edgeFillColorPreset").find('option').remove();
$("#weightEdgeTextColorPreset").find('option').remove();
$("#edgeTextColorPreset").find('option').remove();
$("#edgeStrokeColorPreset").find('option').remove();
for (const property in colorSet)
{
$("#edgeFillColorPreset").append(new Option(property));
$("#weightEdgeTextColorPreset").append(new Option(property));
$("#edgeTextColorPreset").append(new Option(property));
$("#edgeStrokeColorPreset").append(new Option(property));
}
}
var redrawVertex = function()
{
var fullStyle = self.style.GetStyle({}, forAll ? undefined : selectedEdges[0]);
if (fullStyle.fillStyle != $( "#edgeFillColor" ).val())
self.style.fillStyle = $( "#edgeFillColor" ).val();
if (fullStyle.strokeStyle != $( "#edgeStrokeColor" ).val())
self.style.strokeStyle = $( "#edgeStrokeColor" ).val();
if (fullStyle.weightText != $( "#edgeTextColor" ).val())
self.style.weightText = $( "#edgeTextColor" ).val();
if (fullStyle.lineDash != $( "#edgeStyle" ).val())
self.style.lineDash = $( "#edgeStyle" ).val();
if (fullStyle.additionalTextColor != $( "#weightEdgeTextColor" ).val())
self.style.additionalTextColor = $( "#weightEdgeTextColor" ).val();
if (fullStyle.weightPosition != $( "#weightTextPosition" ).val())
self.style.weightPosition = $( "#weightTextPosition" ).val();
var edgeWidth = parseInt($( "#edgeWidth" ).val());
var canvas = document.getElementById( "EdgePreview" );
var context = canvas.getContext('2d');
context.save();
var backgroundDrawer = new BaseBackgroundDrawer(context);
backgroundDrawer.Draw(app.backgroundCommonStyle, canvas.width, canvas.height, new Point(0, 0), 1.0);
var graphDrawer = new BaseEdgeDrawer(context);
var baseVertex1 = new BaseVertex(0, canvas.height / 2, new BaseEnumVertices(this));
var baseVertex2 = new BaseVertex(canvas.width, canvas.height / 2, new BaseEnumVertices(this));
baseVertex1.currentStyle = baseVertex1.getStyleFor(0);
baseVertex2.currentStyle = baseVertex2.getStyleFor(0);
var baseEdge = new BaseEdge(baseVertex1, baseVertex2, true, 10, "Text");
if (!forAll)
baseEdge.ownStyles = selectedEdges[0].ownStyles;
baseEdge.model.width = edgeWidth;
graphDrawer.Draw(baseEdge, self.style.GetStyle({}, baseEdge));
context.restore();
}
var changeIndex = function()
{
var val = $( "#edgeSelectedIndex" ).val();
if (val == "all")
{
applyIndex(1);
self.index = "all";
fillFields();
}
else
{
var index = parseInt(val);
self.index = index;
applyIndex(index);
fillFields();
}
redrawVertex();
}
var applyWidth = function(width)
{
if (forAll)
{
app.SetDefaultEdgeWidth(width);
}
else
{
selectedEdges.forEach(function(edge) {
edge.model.width = width;
});
}
};
dialogButtons[g_default] =
{
text : g_default,
class : "MarginLeft",
click : function() {
app.PushToStack("ChangeStyle");
applyWidth(forAll ? (new EdgeModel()).width : app.GetDefaultEdgeWidth());
var indexes = [];
if (self.index == "all")
{
for (i = 0; i < app.edgeSelectedStyles.length; i ++)
indexes.push(i + 1);
}
else
indexes.push(self.index);
if (forAll)
{
indexes.forEach(function(index) {
app.ResetEdgeStyle(index);
});
}
else
{
selectedEdges.forEach(function(edge) {
indexes.forEach(function(index) {
edge.resetOwnStyle(index);
});
});
}
app.redrawGraph();
$( this ).dialog( "close" );
}
};
dialogButtons[g_save] = function() {
app.PushToStack("ChangeStyle");
applyWidth(parseInt($( "#edgeWidth" ).val()));
var indexes = [];
if (self.index == "all")
{
indexes.push({index : 1, style : self.style});
for (i = 1; i < app.edgeSelectedStyles.length; i ++)
{
var style = (new BaseEdgeStyle());
style.baseStyles.push("selected");
indexes.push({index : i + 1, style : style});
}
self.style.baseStyles = [];
self.style.baseStyles = self.style.baseStyles.concat((new SelectedEdgeStyle0()).baseStyles);
}
else
indexes.push({index : self.index, style : self.style});
if (forAll)
{
indexes.forEach(function(index) {
app.SetEdgeStyle(index.index, index.style);
});
}
else
{
selectedEdges.forEach(function(edge) {
indexes.forEach(function(index) {
edge.setOwnStyle(index.index, index.style);
});
});
}
app.redrawGraph();
$( this ).dialog( "close" );
};
dialogButtons[g_cancel] = function() {
$( this ).dialog( "close" );
};
fillFields();
$( "#SetupEdgeStyleDialog" ).dialog({
resizable: false,
height: "auto",
width: "auto",
modal: true,
title: g_edgeDraw,
buttons: dialogButtons,
dialogClass: 'EdgeDialog'
});
redrawVertex();
$( "#edgeFillColor" ).unbind();
$( "#edgeStrokeColor" ).unbind();
$( "#edgeTextColor" ).unbind();
$( "#edgeStyle" ).unbind();
$( "#edgeWidth" ).unbind();
$( "#weightEdgeTextColor" ).unbind();
$( "#weightTextPosition" ).unbind();
$( "#edgeSelectedIndex" ).unbind();
$( "#edgeFillColor" ).change(redrawVertex);
$( "#edgeStrokeColor" ).change(redrawVertex);
$( "#edgeTextColor" ).change(redrawVertex);
$( "#edgeStyle" ).change(redrawVertex);
$( "#edgeWidth" ).change(redrawVertex);
$( "#weightEdgeTextColor" ).change(redrawVertex);
$( "#weightTextPosition" ).change(redrawVertex);
$( "#edgeSelectedIndex" ).change(changeIndex);
}
+299
View File
@@ -0,0 +1,299 @@
doInclude ([
include ("features/base_handler/index.js")
])
/**
* Setup Vertex Style rename vertices.
*
*/
function SetupVertexStyle(app)
{
BaseHandler.apply(this, arguments);
this.message = "";
}
// inheritance.
SetupVertexStyle.prototype = Object.create(BaseHandler.prototype);
SetupVertexStyle.prototype.show = function(index, selectedVertices)
{
var handler = this;
var dialogButtons = {};
var graph = this.app.graph;
var app = this.app;
this.forAll = selectedVertices == null;
var forAll = this.forAll;
var self = this;
var applyIndex = function(index)
{
self.index = index;
self.originStyle = (self.index == 0 ? app.vertexCommonStyle : app.vertexSelectedVertexStyles[self.index - 1]);
if (!forAll)
{
self.originStyle = selectedVertices[0].getStyleFor(self.index);
}
self.style = FullObjectCopy(self.originStyle);
}
applyIndex(index);
var fillFields = function()
{
var fullStyle = self.style.GetStyle({}, forAll ? undefined : selectedVertices[0]);
$( "#vertexFillColor" ).val(fullStyle.fillStyle);
$( "#vertexStrokeColor" ).val(fullStyle.strokeStyle);
$( "#vertexTextColor" ).val(fullStyle.mainTextColor);
$( "#upVertexTextColor" ).val(fullStyle.upTextColor);
$( "#vertexStrokeSize" ).val(fullStyle.lineWidth);
$( "#vertexShape" ).val(fullStyle.shape);
$( "#vertexSize" ).val(forAll ? app.GetDefaultVertexSize() : selectedVertices[0].model.diameter);
$( "#commonTextPosition" ).val(fullStyle.commonTextPosition);
if (self.index > 0 || self.index == "all")
{
$( "#VertexSelectedIndexForm" ).show();
$( "#vertexSelectedIndex" ).val(self.index);
}
else
{
$( "#VertexSelectedIndexForm" ).hide();
}
// Fill color presets.
var stylesArray = [];
stylesArray.push(app.vertexCommonStyle);
for (i = 0; i < app.vertexSelectedVertexStyles.length; i ++)
stylesArray.push(app.vertexSelectedVertexStyles[i]);
var colorSet = {};
for (i = 0; i < stylesArray.length; i ++)
{
var style = stylesArray[i];
if (style.hasOwnProperty('strokeStyle'))
colorSet[style.strokeStyle] = 1;
if (style.hasOwnProperty('fillStyle'))
colorSet[style.fillStyle] = 1;
if (style.hasOwnProperty('mainTextColor'))
colorSet[style.mainTextColor] = 1;
if (style.hasOwnProperty('upTextColor'))
colorSet[style.upTextColor] = 1;
}
$("#vertexFillColorPreset").find('option').remove();
$("#upVertexTextColorPreset").find('option').remove();
$("#vertexTextColorPreset").find('option').remove();
$("#vertexStrokeColorPreset").find('option').remove();
for (const property in colorSet)
{
$("#vertexFillColorPreset").append(new Option(property));
$("#upVertexTextColorPreset").append(new Option(property));
$("#vertexTextColorPreset").append(new Option(property));
$("#vertexStrokeColorPreset").append(new Option(property));
}
}
var redrawVertex = function()
{
var fullStyle = self.style.GetStyle({}, forAll ? undefined : selectedVertices[0]);
if (fullStyle.fillStyle != $( "#vertexFillColor" ).val())
self.style.fillStyle = $( "#vertexFillColor" ).val();
if (fullStyle.strokeStyle != $( "#vertexStrokeColor" ).val())
self.style.strokeStyle = $( "#vertexStrokeColor" ).val();
if (fullStyle.mainTextColor != $( "#vertexTextColor" ).val())
self.style.mainTextColor = $( "#vertexTextColor" ).val();
if (fullStyle.lineWidth != $( "#vertexStrokeSize" ).val())
self.style.lineWidth = parseInt($( "#vertexStrokeSize" ).val());
if (fullStyle.shape != $( "#vertexShape" ).val())
self.style.shape = parseInt($( "#vertexShape" ).val());
if (fullStyle.upTextColor != $( "#upVertexTextColor" ).val())
self.style.upTextColor = $( "#upVertexTextColor" ).val();
if (fullStyle.commonTextPosition != $( "#commonTextPosition" ).val())
self.style.commonTextPosition = $( "#commonTextPosition" ).val();
var diameter = parseInt($( "#vertexSize" ).val());
var canvas = document.getElementById( "VertexPreview" );
var context = canvas.getContext('2d');
context.save();
var backgroundDrawer = new BaseBackgroundDrawer(context);
backgroundDrawer.Draw(app.backgroundCommonStyle, canvas.width, canvas.height, new Point(0, 0), 1.0);
var graphDrawer = new BaseVertexDrawer(context);
var baseVertex = new BaseVertex(canvas.width / 2, canvas.height / 2, new BaseEnumVertices(this));
baseVertex.mainText = "1";
baseVertex.upText = "Up Text";
baseVertex.model.diameter = diameter;
if (!forAll)
baseVertex.ownStyles = selectedVertices[0].ownStyles;
graphDrawer.Draw(baseVertex, self.style.GetStyle({}, baseVertex));
context.restore();
}
var changeIndex = function()
{
var val = $( "#vertexSelectedIndex" ).val();
if (val == "all")
{
applyIndex(1);
self.index = "all";
fillFields();
}
else
{
var index = parseInt(val);
self.index = index;
applyIndex(index);
fillFields();
}
redrawVertex();
}
var applyDiameter = function(diameter)
{
if (forAll)
{
app.SetDefaultVertexSize(diameter);
}
else
{
selectedVertices.forEach(function(vertex) {
vertex.model.diameter = diameter;
});
}
};
dialogButtons[g_default] =
{
text : g_default,
class : "MarginLeft",
click : function() {
app.PushToStack("ChangeStyle");
applyDiameter(forAll ? (new VertexModel()).diameter : app.GetDefaultVertexSize());
var indexes = [];
if (self.index == "all")
{
for (i = 0; i < app.vertexSelectedVertexStyles.length; i ++)
indexes.push(i + 1);
}
else
indexes.push(self.index);
if (forAll)
{
indexes.forEach(function(index) {
app.ResetVertexStyle(index);
});
}
else
{
selectedVertices.forEach(function(vertex) {
indexes.forEach(function(index) {
vertex.resetOwnStyle(index);
});
});
}
app.redrawGraph();
$( this ).dialog( "close" );
}
};
dialogButtons[g_save] = function() {
app.PushToStack("ChangeStyle");
applyDiameter(parseInt($( "#vertexSize" ).val()));
var indexes = [];
if (self.index == "all")
{
indexes.push({index : 1, style : self.style});
for (i = 1; i < app.vertexSelectedVertexStyles.length; i ++)
{
var style = (new BaseVertexStyle());
style.baseStyles.push("selected");
indexes.push({index : i + 1, style : style});
}
self.style.baseStyles = [];
self.style.baseStyles = self.style.baseStyles.concat((new SelectedVertexStyle0()).baseStyles);
}
else
indexes.push({index : self.index, style : self.style});
if (forAll)
{
indexes.forEach(function(index) {
app.SetVertexStyle(index.index, index.style);
});
}
else
{
if (JSON.stringify(self.originStyle) !== JSON.stringify(self.style))
{
selectedVertices.forEach(function(vertex) {
indexes.forEach(function(index) {
vertex.setOwnStyle(index.index, index.style);
});
});
}
}
app.redrawGraph();
$( this ).dialog( "close" );
};
dialogButtons[g_cancel] = function() {
$( this ).dialog( "close" );
};
fillFields();
$( "#SetupVertexStyleDialog" ).dialog({
resizable: false,
height: "auto",
width: "auto",
modal: true,
title: g_vertexDraw,
buttons: dialogButtons,
dialogClass: 'EdgeDialog'
});
redrawVertex();
$( "#vertexFillColor" ).unbind();
$( "#vertexStrokeColor" ).unbind();
$( "#vertexTextColor" ).unbind();
$( "#upVertexTextColor" ).unbind();
$( "#vertexStrokeSize" ).unbind();
$( "#vertexShape" ).unbind();
$( "#vertexSize" ).unbind();
$( "#commonTextPosition" ).unbind();
$( "#vertexSelectedIndex" ).unbind();
$( "#vertexFillColor" ).change(redrawVertex);
$( "#vertexStrokeColor" ).change(redrawVertex);
$( "#vertexTextColor" ).change(redrawVertex);
$( "#vertexStrokeSize" ).change(redrawVertex);
$( "#vertexShape" ).change(redrawVertex);
$( "#vertexSize" ).change(redrawVertex);
$( "#upVertexTextColor" ).change(redrawVertex);
$( "#commonTextPosition" ).change(redrawVertex);
$( "#vertexSelectedIndex" ).change(changeIndex);
}
@@ -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'
});
}
@@ -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'
});
}
@@ -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'
});
}
+15 -31
View File
@@ -1,34 +1,18 @@
<h1>Update cache</h1>
<?php <?php
$outputFilename = 'example.js'; $cacheList = array(
"/script/pages/editor/api/index.js",
"/script/pages/create_graph_by_edge_list/api/index.js",
"/script/pages/create_graph_by_incidence_matrix/api/index.js",
"/script/pages/create_graph_by_matrix/api/index.js"
);
unlink($outputFilename); echo ("<ul>");
foreach ($cacheList as &$page) {
$date = date('d.m.Y H:i:s', filemtime("../$page.cache"));
echo ("<li><a href='pack.php?target=$page' target='_blank'>$page</a> $date</li>");
}
echo ("</ul>");
?>
file_put_contents($outputFilename, file_get_contents("utils.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("texts.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("point.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("EdgeModel.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("VertexModel.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("BaseVertex.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("BaseEdge.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("BaseVertexDrawer.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("BaseEdgeDrawer.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("BaseBackgroundDrawer.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("Algorithms.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("EventHandlers.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("GraphMLCreator.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("Graph.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("EnumVertices.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("Application.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("main.js"), FILE_APPEND);
file_put_contents($outputFilename, file_get_contents("BaseTraversal.js"), FILE_APPEND);
if (file_exists($outputFilename))
{
echo ("File exists");
}
else
{
echo ("File not exists");
}
?>
+104
View File
@@ -0,0 +1,104 @@
<?php if (!isset($_GET["cacheFiles"]) && isset($_GET["target"])): ?>
<head>
<script src="/script/shared/config.js" ></script>
<script src="/script/shared/loader.js" ></script>
<script src="<?= $_GET["target"] ?>" ></script>
<script>
setTimeout(
() => {
document.getElementById("state").innerHTML = "Saving files";
const xhr = new XMLHttpRequest();
xhr.open("GET", "<?= $_SERVER['PHP_SELF'] ?>?cacheFiles=" + moduleLoader.syncLoaded.toString() + "&target=" + "<?= $_GET["target"] ?>");
xhr.send();
xhr.onload = () => {
if (xhr.readyState == 4 && xhr.status == 200) {
document.getElementById("state").innerHTML = "Finished <br>" + xhr.response;
} else {
document.getElementById("state").innerHTML = "Error happends";
}
};
}, 3000);
</script>
</head>
<body>
<div>
<p>State:</p>
<p id="state">Loading</p>
</div>
</doby>
<?php endif; ?>
<?php
if (!isset($_GET["target"])) {
echo ("Error target is not set");
return;
}
?>
<!-- Create cache file -->
<?php
/**
* Return relative path between two sources
* @param $from
* @param $to
* @param string $separator
* @return string
*/
function relativePath($from, $to, $separator = DIRECTORY_SEPARATOR)
{
$from = str_replace(array('/', '\\'), $separator, $from);
$to = str_replace(array('/', '\\'), $separator, $to);
$arFrom = explode($separator, rtrim($from, $separator));
$arTo = explode($separator, rtrim($to, $separator));
while(count($arFrom) && count($arTo) && ($arFrom[0] == $arTo[0]))
{
array_shift($arFrom);
array_shift($arTo);
}
return str_pad("", count($arFrom) * 3, '..'.$separator).implode($separator, $arTo);
}
include (relativePath(dirname($_SERVER['PHP_SELF']), "/") . "lib/ExtraPacker/Lib/JSMin.php");
if (isset($_GET["cacheFiles"])) {
$cacheFilenameList = $_GET["cacheFiles"];
$files = explode(",", $cacheFilenameList);
//print_r($files);
$indexFilename = "../" . $_GET["target"];
$outputFilename = $indexFilename . '.cache';
unlink($outputFilename);
// Put files already loaded.
$cacheContent = "";
$cacheContent = $cacheContent . "\nmoduleLoader.beginCacheLoading([";
foreach ($files as &$file) {
$cacheContent = $cacheContent . "\"" . $file . "\"" . ",";
}
$cacheContent = $cacheContent . "]);\n";
// Put index file.
$processedFilesCount = 1;
$cacheContent = $cacheContent . file_get_contents($indexFilename);
// Put files
foreach ($files as &$file) {
$relativePath = strtok($file, '?');
$relativePath = relativePath(dirname($_SERVER['PHP_SELF']), $relativePath);
$cacheContent = $cacheContent . file_get_contents($relativePath);
$processedFilesCount ++;
}
// Put event about cache loaded.
$cacheContent = $cacheContent . "\nmoduleLoader.endCacheLoading();";
$minifiedCacheContent = JSMin::minify($cacheContent);
file_put_contents($outputFilename, $minifiedCacheContent, FILE_APPEND);
echo("Prcoessed files: " . $processedFilesCount);
}
?>
@@ -0,0 +1,9 @@
// Global version needs to force reload scripts from server.
globalVersion = 75;
{
let modulDir = "pages/create_graph_by_edge_list/";
doInclude ([
include ("entities/graph/api/index.js")]);
}
@@ -0,0 +1,594 @@
moduleLoader.beginCacheLoading(["/script/entities/graph/api/index.js?v=75","/script/shared/point.js?v=75","/script/entities/edge/api/index.js?v=75","/script/entities/edge/model/BaseEdge.js?v=75","/script/entities/edge/model/EdgeModel.js?v=75","/script/entities/vertex/api/index.js?v=75","/script/entities/vertex/model/BaseVertex.js?v=75","/script/entities/vertex/model/VertexModel.js?v=75","/script/entities/graph/model/Graph.js?v=75",]);globalVersion=75;{let modulDir="pages/create_graph_by_edge_list/";doInclude([include("entities/graph/api/index.js")]);}
{let modulDir="entities/graph/";doInclude([include("shared/point.js"),include("entities/edge/api/index.js"),include("entities/vertex/api/index.js"),include("model/Graph.js",modulDir)])}function Point(x,y){this.x=x||0;this.y=y||0;};Point.prototype.x=null;Point.prototype.y=null;Point.prototype.add=function(v){return new Point(this.x+v.x,this.y+v.y);};Point.prototype.addValue=function(v){return new Point(this.x+v,this.y+v);};Point.prototype.clone=function(){return new Point(this.x,this.y);};Point.prototype.degreesTo=function(v){var dx=this.x-v.x;var dy=this.y-v.y;var angle=Math.atan2(dy,dx);return angle*(180/Math.PI);};Point.prototype.distance=function(v){return Math.sqrt(this.distanceSqr(v));};Point.prototype.distanceSqr=function(v){var x=this.x-v.x;var y=this.y-v.y;return x*x+y*y;};Point.prototype.equals=function(toCompare){return this.x==toCompare.x&&this.y==toCompare.y;};Point.prototype.interpolate=function(v,f){return new Point((this.x+v.x)*f,(this.y+v.y)*f);};Point.prototype.length=function(){return Math.sqrt(this.x*this.x+this.y*this.y);};Point.prototype.normalize=function(thickness){var l=this.length();this.x=this.x/l*thickness;this.y=this.y/l*thickness;return new Point(this.x,this.y);};Point.prototype.normalizeCopy=function(thickness){var l=this.length();return new Point(this.x/l*thickness,this.y/l*thickness);};Point.prototype.orbit=function(origin,arcWidth,arcHeight,degrees){var radians=degrees*(Math.PI/180);this.x=origin.x+arcWidth*Math.cos(radians);this.y=origin.y+arcHeight*Math.sin(radians);};Point.prototype.rotate=function(center,degrees){var radians=degrees*(Math.PI/180);offset=this.subtract(center);this.x=offset.x*Math.cos(radians)-offset.y*Math.sin(radians);this.y=offset.x*Math.sin(radians)+offset.y*Math.cos(radians);this.x=this.x+center.x;this.y=this.y+center.y;return this;};Point.prototype.offset=function(dx,dy){this.x+=dx;this.y+=dy;};Point.prototype.subtract=function(v){return new Point(this.x-v.x,this.y-v.y);};Point.prototype.subtractValue=function(value){return new Point(this.x-value,this.y-value);};Point.prototype.multiply=function(value){return new Point(this.x*value,this.y*value);};Point.prototype.toString=function(){return"(x="+this.x+", y="+this.y+")";};Point.prototype.normal=function(){return new Point(-this.y,this.x);};Point.prototype.min=function(point)
{return new Point(Math.min(this.x,point.x),Math.min(this.y,point.y));};Point.prototype.max=function(point)
{return new Point(Math.max(this.x,point.x),Math.max(this.y,point.y));};Point.prototype.inverse=function()
{return new Point(-this.x,-this.y);};Point.prototype.cross=function(point)
{return this.x*point.y-this.y*point.x;};Point.interpolate=function(pt1,pt2,f){return new Point(pt1.x*(1.0-f)+pt2.x*f,pt1.y*(1.0-f)+pt2.y*f);};Point.polar=function(len,angle){return new Point(len*Math.cos(angle),len*Math.sin(angle));};Point.distance=function(pt1,pt2){var x=pt1.x-pt2.x;var y=pt1.y-pt2.y;return Math.sqrt(x*x+y*y);};Point.center=function(pt1,pt2){return new Point((pt1.x+pt2.x)/2.0,(pt1.y+pt2.y)/2.0);};Point.toString=function(){return x+" "+y;}
Point.projection=function(point,line1,line2)
{var x=line2.y-line1.y;var y=line1.x-line2.x;var l=(line1.cross(line2)+line1.cross(point)+line2.cross(point))/(x*(line2.y-line1.y)+y*(line1.x-line2.x));var res=new Point(point.x+x*l,point.y+y*l);return res;}
Point.hitTest=function(pt11,pt12,pt21,pt22)
{var res=null;var n=0.0;var x1=pt11.x;var y1=pt11.y;var x2=pt12.x;var y2=pt12.y;var x3=pt21.x;var y3=pt21.y;var x4=pt22.x;var y4=pt22.y;if(y2-y1!=0.0)
{var q=(x2-x1)/(y1-y2);var sn=(x3-x4)+(y3-y4)*q;if(sn==0.0)
{return res;}
var fn=(x3-x1)+(y3-y1)*q;n=fn/sn;}
else
{if((y3-y4)==0.0)
{return res;}
n=(y3-y1)/(y3-y4);}
res=new Point(x3+(x4-x3)*n,y3+(y4-y3)*n);var epsilon=1E-5;if(!(res.x>=Math.min(x1,x2)-epsilon&&res.x>=Math.min(x3,x4)-epsilon&&res.x<=Math.max(x1,x2)+epsilon&&res.x<=Math.max(x3,x4)+epsilon&&res.y>=Math.min(y1,y2)-epsilon&&res.y>=Math.min(y3,y4)-epsilon&&res.y<=Math.max(y1,y2)+epsilon&&res.y<=Math.max(y3,y4)+epsilon))
{res=null;}
return res;}
function Rect(minPoint,maxPoint){this.minPoint=minPoint;this.maxPoint=maxPoint;};Rect.prototype.center=function()
{return Point.center(this.minPoint,this.maxPoint);};Rect.prototype.size=function()
{return this.maxPoint.subtract(this.minPoint);};Rect.prototype.left=function()
{return this.minPoint.x;};Rect.prototype.top=function()
{return this.minPoint.y;};Rect.prototype.isIn=function(v)
{return this.minPoint.x<=v.x&&this.minPoint.y<=v.y&&this.maxPoint.x>v.x&&this.maxPoint.y>v.y;};{let modulDir="entities/edge/";doInclude([include("model/BaseEdge.js",modulDir),include("model/EdgeModel.js",modulDir)])}
function BaseEdge(vertex1,vertex2,isDirect,weight,upText)
{this.vertex1=vertex1;this.vertex2=vertex2;this.arrayStyleStart="";this.arrayStyleFinish="";this.isDirect=isDirect;this.weight=0;this.text="";this.useWeight=false;this.id=0;this.model=new EdgeModel();if(upText===undefined)
this.upText="";else
this.upText=upText;if(weight!==undefined)
this.SetWeight(weight);this.ownStyles={};}
BaseEdge.prototype.copyFrom=function(other)
{this.vertex1=other.vertex1;this.vertex2=other.vertex2;this.arrayStyleStart=other.arrayStyleStart;this.arrayStyleFinish=other.arrayStyleFinish;this.isDirect=other.isDirect;this.weight=other.weight;this.text=other.text;this.useWeight=other.useWeight;this.id=other.id;this.model=new EdgeModel();this.model.copyFrom(other.model);this.upText=other.upText;this.ownStyles=FullObjectCopy(other.ownStyles);}
BaseEdge.prototype.SaveToXML=function()
{return"<edge "+"source=\""+this.vertex1.id+"\" "+"target=\""+this.vertex2.id+"\" "+"isDirect=\""+this.isDirect+"\" "+"weight=\""+this.weight+"\" "+"useWeight=\""+this.useWeight+"\" "+"id=\""+this.id+"\" "+"text=\""+gEncodeToHTML(this.text)+"\" "+"upText=\""+gEncodeToHTML(this.upText)+"\" "+"arrayStyleStart=\""+this.arrayStyleStart+"\" "+"arrayStyleFinish=\""+this.arrayStyleFinish+"\" "+
((Object.keys(this.ownStyles).length>0)?"ownStyles = \""+gEncodeToHTML(JSON.stringify(this.ownStyles))+"\" ":"")+
this.model.SaveToXML()+"></edge>";}
BaseEdge.prototype.LoadFromXML=function(xml,graph)
{var attr=xml.attr('vertex1');if(typeof attr==='undefined')
{attr=xml.attr('source');}
this.vertex1=graph.FindVertex(typeof attr!=='undefined'?attr:xml.attr('graph1'));var attr=xml.attr('vertex2');if(typeof attr==='undefined')
{attr=xml.attr('target');}
this.vertex2=graph.FindVertex(typeof attr!=='undefined'?attr:xml.attr('graph2'));this.isDirect=xml.attr('isDirect')=="true";this.weight=parseFloat(xml.attr('weight'));if(isNaN(this.weight))
{this.weight=1;}
this.hasPair=xml.attr('hasPair')=="true";this.useWeight=xml.attr('useWeight')=="true";this.id=xml.attr('id');this.text=xml.attr("text")==null?"":gDecodeFromHTML(xml.attr("text"));this.arrayStyleStart=xml.attr("arrayStyleStart")==null?"":xml.attr("arrayStyleStart");this.arrayStyleFinish=xml.attr("arrayStyleFinish")==null?"":xml.attr("arrayStyleFinish");this.upText=xml.attr('upText');if(typeof this.upText==='undefined')
{this.upText="";}
else
{this.upText=gDecodeFromHTML(this.upText);}
var ownStyle=xml.attr('ownStyles');if(typeof ownStyle!=='undefined')
{var parsedSave=gDecodeFromHTML(JSON.parse(ownStyle));for(var indexField in parsedSave)
{var index=parseInt(indexField);this.ownStyles[index]=FullObjectCopy(this.getStyleFor(index));for(var field in parsedSave[indexField])
{if(this.ownStyles[index].ShouldLoad(field))
this.ownStyles[index][field]=parsedSave[indexField][field];}}}
this.model.LoadFromXML(xml);}
BaseEdge.prototype.GetPixelLength=function()
{if(this.vertex1==this.vertex2)
{return this.model.GetLoopSize()*2*Math.PI;}
else
{return Point.distance(this.vertex1.position,this.vertex2.position);}}
BaseEdge.prototype.GetWeight=function()
{return this.useWeight?this.weight:1;}
BaseEdge.prototype.GetText=function()
{return this.text.length>0?this.text:(this.useWeight?this.weight.toString():"");}
BaseEdge.prototype.GetUpText=function()
{return this.upText;}
BaseEdge.prototype.GetStartEdgeStyle=function()
{return this.arrayStyleStart;}
BaseEdge.prototype.GetFinishEdgeStyle=function()
{return(this.arrayStyleFinish!=""?this.arrayStyleFinish:(this.isDirect?"arrow":""));}
BaseEdge.prototype.HitTest=function(pos)
{var positions=this.GetEdgePositionsShift();return this.model.HitTest(positions[0],positions[1],pos);}
BaseEdge.prototype.GetEdgePositionsShift=function()
{return this.GetEdgePositions();}
BaseEdge.prototype.GetEdgePositions=function()
{var res=[];if(this.vertex1==this.vertex2)
{res.push(this.vertex1.position);res.push(this.vertex2.position);return res;}
var position1=this.vertex1.position;var position2=this.vertex2.position;var diameter1=this.vertex1.model.diameter+parseInt(this.vertex1.currentStyle.GetStyle({},this.vertex1).lineWidth);var diameter2=this.vertex2.model.diameter+parseInt(this.vertex2.currentStyle.GetStyle({},this.vertex2).lineWidth);var direction=position1.subtract(position2);var direction1=direction;var direction2=direction;var d1=diameter1;var d2=diameter2;if(this.model.type==EdgeModels.curve)
{var dist=position1.distance(position2);var point1=this.model.GetCurvePoint(position1,position2,10.0/dist);direction1=position1.subtract(point1);var point2=this.model.GetCurvePoint(position1,position2,1.0-10.0/dist);direction2=position2.subtract(point2);d2=diameter2;}
else
{direction2=direction2.multiply(-1);}
direction1.normalize(1.0);direction2.normalize(1.0);var vertices=[];vertices.push({vertex:this.vertex1,direction:direction1,position:position1,diameter:d1});vertices.push({vertex:this.vertex2,direction:direction2,position:position2,diameter:d2});vertices.forEach(function(data)
{var shape=data.vertex.currentStyle.GetStyle({},data.vertex).shape;if(shape==VertexCircleShape)
{var direction=data.direction.multiply(0.5);res.push(data.position.subtract(direction.multiply(data.diameter)));}
else
{var lineFinish1=data.direction.multiply(-1).multiply(1000.0);var pointsVertex1=GetPointsForShape(shape,data.diameter,data.vertex.mainText);pointsVertex1.push(pointsVertex1[0]);for(var i=0;i<pointsVertex1.length-1;i++)
{var hitText=Point.hitTest(new Point(0,0),lineFinish1,pointsVertex1[i],pointsVertex1[i+1]);if(hitText!=null)
{res.push(data.position.add(hitText));break;}}}});return res;}
BaseEdge.prototype.SetWeight=function(weight)
{var useWeight=false;if(!isNaN(parseInt(weight,10)))
{useWeight=true;}
weight=(!isNaN(parseInt(weight,10))&&weight>=0)?weight:1;this.weight=Number(weight);this.useWeight=useWeight;}
BaseEdge.prototype.SetUpText=function(text)
{this.upText=text;}
BaseEdge.prototype.resetOwnStyle=function(index)
{if(this.ownStyles.hasOwnProperty(index))
{delete this.ownStyles[index];}}
BaseEdge.prototype.setOwnStyle=function(index,style)
{this.ownStyles[index]=style;}
BaseEdge.prototype.getStyleFor=function(index)
{if(this.ownStyles.hasOwnProperty(index))
{return this.ownStyles[index];}
else
{var style=null;if(index==0)
style=globalApplication.GetStyle("edge","common");else
style=globalApplication.GetStyle("edge","selected",undefined,index-1);return style;}}
BaseEdge.prototype.hasOwnStyleFor=function(index)
{return this.ownStyles.hasOwnProperty(index);}
var EdgeModels={"line":0,"curve":1};const defaultEdgeWidth=4;function EdgeModel()
{this.width=globalApplication.GetDefaultEdgeWidth();this.type=EdgeModels.line;this.curveValue=EdgeModel.prototype.defaultCurve;this.default=true;this.sizeOfLoop=24;this.loopShiftAngel=Math.PI/6;}
EdgeModel.prototype.defaultCurve=0.1;EdgeModel.prototype.copyFrom=function(other)
{this.width=other.width;this.type=other.type;this.curveValue=other.curveValue;this.default=other.default;}
EdgeModel.prototype.SaveToXML=function()
{return"model_width=\""+this.width+"\" "+"model_type=\""+this.type+"\" "+"model_curveValue=\""+this.curveValue+"\" "+"model_default=\""+this.default+"\" ";}
EdgeModel.prototype.LoadFromXML=function(xml,graph)
{this.width=xml.attr('model_width')==null?this.width:parseFloat(xml.attr("model_width"));this.type=xml.attr('model_type')==null?this.type:xml.attr("model_type");this.curveValue=xml.attr('model_curveValue')==null?this.curveValue:parseFloat(xml.attr("model_curveValue"));this.default=xml.attr('model_default')==null?this.default:parseFloat(xml.attr("model_default"));}
EdgeModel.prototype.GetCurvePoint=function(position1,position2,t)
{var points=this.GetBezierPoints(position1,position2);var firstBezierPoint=points[0];var secondBezierPoint=points[1];var B0_t=Math.pow(1-t,3);var B1_t=3*t*Math.pow(1-t,2);var B2_t=3*t*t*(1-t)
var B3_t=t*t*t;var ax=position1.x;var ay=position1.y;var dx=position2.x;var dy=position2.y;var bx=firstBezierPoint.x;var by=firstBezierPoint.y;var cx=secondBezierPoint.x;var cy=secondBezierPoint.y;var px_t=(B0_t*ax)+(B1_t*bx)+(B2_t*cx)+(B3_t*dx);var py_t=(B0_t*ay)+(B1_t*by)+(B2_t*cy)+(B3_t*dy);return new Point(px_t,py_t);}
EdgeModel.prototype.GetBezierPoints=function(position1,position2)
{var direction=position2.subtract(position1);var delta=direction.length();direction.normalize(1.0);var normal=direction.normal();var deltaOffsetPixels=delta*this.curveValue;var yOffset=normal.multiply(deltaOffsetPixels);var firstBezierPointShift=(direction.multiply(delta*0.2)).add(yOffset);var secondBezierPointShift=(direction.multiply(-delta*0.2)).add(yOffset);var firstBezierPoint=position1.add(firstBezierPointShift);var secondBezierPoint=position2.add(secondBezierPointShift);return[firstBezierPoint,secondBezierPoint];}
EdgeModel.prototype.HitTest=function(position1,position2,mousePos)
{if(this.type==EdgeModels.line)
return this.HitTestLine(position1,position2,mousePos);else if(this.type==EdgeModels.curve)
return this.HitTestCurve(position1,position2,mousePos);return false;}
EdgeModel.prototype.HitTestLine=function(position1,position2,mousePos,factor)
{if(factor===undefined)
{factor=1.0;}
var pos1=position1;var pos2=position2;var pos0=mousePos;if(pos1.equals(pos2))
{var xCenter=pos1.x-Math.cos(this.GetLoopShiftAngel())*this.GetLoopSize();var yCenter=pos1.y-Math.sin(this.GetLoopShiftAngel())*this.GetLoopSize();return Math.abs((Point.distance(new Point(xCenter,yCenter),pos0))-this.GetLoopSize())<=this.width*1.5*factor;}
var r1=pos0.distance(pos1);var r2=pos0.distance(pos2);var r12=pos1.distance(pos2);if(r1>=(new Point(r2,r12)).length()||r2>=(new Point(r1,r12)).length())
{}
else
{var distance=((pos1.y-pos2.y)*pos0.x+(pos2.x-pos1.x)*pos0.y+(pos1.x*pos2.y-pos2.x*pos1.y))/r12;if(Math.abs(distance)<=this.width*1.5*factor)
{return true;}}
return false;}
EdgeModel.prototype.HitTestCurve=function(position1,position2,mousePos)
{var pos1=position1;var pos2=position2;var pos0=mousePos;if(pos1.equals(pos2))
{var xCenter=pos1.x-Math.cos(this.GetLoopShiftAngel())*this.GetLoopSize();var yCenter=pos1.y-Math.sin(this.GetLoopShiftAngel())*this.GetLoopSize();return Math.abs((Point.distance(new Point(xCenter,yCenter),pos0))-this.GetLoopSize())<=this.width*1.5;}
var interval_count=position1.distance(position2)/100*30;var start=position1;for(var i=0;i<interval_count;i++)
{var finish=this.GetCurvePoint(position1,position2,i/interval_count);if(this.HitTestLine(start,finish,mousePos,2.0))
return true;start=finish;}
return false;}
EdgeModel.prototype.ChangeCurveValue=function(delta)
{if(this.type==EdgeModels.line)
{this.type=EdgeModels.curve;this.curveValue=0.0;}
this.curveValue=this.curveValue+delta;if(Math.abs(this.curveValue)<=0.01)
this.type=EdgeModels.line;this.default=false;}
EdgeModel.prototype.SetCurveValue=function(value)
{if(this.type==EdgeModels.line)
{this.type=EdgeModels.curve;this.curveValue=0.0;}
this.curveValue=value;if(Math.abs(this.curveValue)<=0.01)
this.type=EdgeModels.line;this.default=false;}
EdgeModel.prototype.GetLoopSize=function()
{if(Math.abs(this.curveValue)<=0.01)
{return this.sizeOfLoop;}
else
{let normalCurve=this.curveValue;if(this.type==EdgeModels.line){normalCurve=this.defaultCurve;}
else if(normalCurve>=0.0){normalCurve+=this.defaultCurve}
return this.sizeOfLoop*Math.abs(normalCurve)*(1/this.defaultCurve);}}
EdgeModel.prototype.GetLoopShiftAngel=function()
{if(this.type==EdgeModels.line||this.curveValue>=0.0)
{return this.loopShiftAngel;}
else
{return this.loopShiftAngel+Math.PI;}}
{let modulDir="entities/vertex/";doInclude([include("model/BaseVertex.js",modulDir),include("model/VertexModel.js",modulDir)])}
function BaseVertex(x,y,vertexEnumType)
{this.position=new Point(x,y);this.id=0;this.mainText="";this.upText="";this.vertexEnumType=vertexEnumType;this.model=new VertexModel();this.hasUndefinedPosition=false;this.ownStyles={};};BaseVertex.prototype.position=new Point(0,0);BaseVertex.prototype.copyFrom=function(other)
{this.position=new Point(other.position.x,other.position.y);this.id=other.id;this.mainText=other.mainText;this.upText=other.upText;this.vertexEnumType=other.vertexEnumType;this.model=new VertexModel();this.hasUndefinedPosition=other.hasUndefinedPosition;this.ownStyles=FullObjectCopy(other.ownStyles);}
BaseVertex.prototype.SaveToXML=function()
{return"<node "+"positionX=\""+this.position.x+"\" "+"positionY=\""+this.position.y+"\" "+"id=\""+this.id+"\" "+"mainText=\""+gEncodeToHTML(this.mainText)+"\" "+"upText=\""+gEncodeToHTML(this.upText)+"\" "+
((Object.keys(this.ownStyles).length>0)?"ownStyles = \""+gEncodeToHTML(JSON.stringify(this.ownStyles))+"\" ":"")+"size=\""+this.model.diameter+"\" "+"></node>";}
BaseVertex.prototype.LoadFromXML=function(xml)
{var xmlX=xml.attr('positionX');var xmlY=xml.attr('positionY');this.hasUndefinedPosition=(typeof xmlX==='undefined')||(typeof xmlY==='undefined');this.position=new Point(parseFloat(xmlX),parseFloat(xmlY));this.id=xml.attr('id');this.mainText=xml.attr('mainText');this.upText=xml.attr('upText');if(typeof this.mainText==='undefined')
this.mainText=this.id;else
this.mainText=gDecodeFromHTML(this.mainText);if(typeof this.upText==='undefined')
this.upText="";else
this.upText=gDecodeFromHTML(this.upText);var ownStyle=xml.attr('ownStyles');if(typeof ownStyle!=='undefined')
{var parsedSave=gDecodeFromHTML(JSON.parse(ownStyle));for(var indexField in parsedSave)
{var index=parseInt(indexField);this.ownStyles[index]=FullObjectCopy(this.getStyleFor(index));for(var field in parsedSave[indexField])
{if(this.ownStyles[index].ShouldLoad(field))
this.ownStyles[index][field]=parsedSave[indexField][field];}}}
var size=xml.attr('size');if(typeof size!=='undefined')
this.model.diameter=parseInt(size);}
BaseVertex.prototype.SetId=function(id)
{this.id=id;if(this.vertexEnumType!=null)
this.mainText=this.vertexEnumType.GetVertexText(id);}
BaseVertex.prototype.diameterFactor=function()
{return new Point(1.0+(this.mainText.length?this.mainText.length/8.0:0),1.5);}
BaseVertex.prototype.IsUndefinedPosition=function()
{return this.hasUndefinedPosition;}
BaseVertex.prototype.HitTest=function(pos)
{var shape=this.hasOwnProperty('currentStyle')?this.currentStyle.GetStyle({},this).shape:VertexCircleShape;var width=this.hasOwnProperty('currentStyle')?this.currentStyle.GetStyle({},this).lineWidth:0;if(shape==VertexCircleShape)
{return this.position.distance(pos)<this.model.diameter/2.0+width;}
else
{var relativePos=(new Point(pos.x,pos.y)).subtract(this.position);var lineFinish1=relativePos.add(new Point(1000,0));var lineFinish2=relativePos.add(new Point(-1000,0));var pointsVertex1=GetPointsForShape(shape,this.model.diameter+width,this.mainText);pointsVertex1.push(pointsVertex1[0]);var hitNumber1=0;var hitNumber2=0;for(var i=0;i<pointsVertex1.length-1;i++)
{var hitTest=Point.hitTest(relativePos,lineFinish1,pointsVertex1[i],pointsVertex1[i+1]);if(hitTest!=null)
{hitNumber1++;}
hitTest=Point.hitTest(relativePos,lineFinish2,pointsVertex1[i],pointsVertex1[i+1]);if(hitTest!=null)
{hitNumber2++;}}
return hitNumber1==1&&hitNumber2==1;}
return false;}
BaseVertex.prototype.resetOwnStyle=function(index)
{if(this.ownStyles.hasOwnProperty(index))
{delete this.ownStyles[index];}}
BaseVertex.prototype.setOwnStyle=function(index,style)
{this.ownStyles[index]=FullObjectCopy(style);}
BaseVertex.prototype.getStyleFor=function(index)
{if(this.ownStyles.hasOwnProperty(index))
{return this.ownStyles[index];}
else
{var style=null;if(index==0)
style=globalApplication.GetStyle("vertex","common");else
style=globalApplication.GetStyle("vertex","selected",undefined,index-1);return style;}}
BaseVertex.prototype.hasOwnStyleFor=function(index)
{return this.ownStyles.hasOwnProperty(index);}
const defaultVertexDiameter=30;function VertexModel()
{this.diameter=globalApplication.GetDefaultVertexSize();}
function Graph()
{this.vertices=[];this.edges=[];this.uidGraph=0;this.uidEdge=10000;this.hasDirect=false;this.isMultiGraph=false;};Graph.prototype.infinity=1E8;Graph.prototype.maxVertices=1000;Graph.prototype.edgesOffset=10000;Graph.prototype.AddNewVertex=function(vertex)
{if(this.vertices.length<=this.maxVertices)
{vertex.SetId(this.uidGraph);this.uidGraph=this.uidGraph+1;this.vertices.push(vertex);}
return this.vertices.length-1;}
Graph.prototype.ClearGraph=function(){this.vertices=[];this.edges=[];this.uidGraph=0;this.uidEdge=10000;this.hasDirect=false;this.isMultiGraph=false;}
Graph.prototype.AddNewEdgeSafe=function(graph1,graph2,isDirect,weight,replaceIfExists=true)
{return this.AddNewEdge(new BaseEdge(graph1,graph2,isDirect,weight),replaceIfExists);}
Graph.prototype.AddNewEdge=function(edge,replaceIfExists)
{edge.id=this.uidEdge;this.uidEdge=this.uidEdge+1;var edge1=this.FindEdgeAny(edge.vertex1.id,edge.vertex2.id);var edgeRevert=this.FindEdgeAny(edge.vertex2.id,edge.vertex1.id);if(!edge.isDirect)
{if(edge1!=null&&replaceIfExists)
this.DeleteEdge(edge1);if(edgeRevert!=null&&replaceIfExists)
this.DeleteEdge(edgeRevert);this.edges.push(edge);}
else
{if(edge1!=null&&replaceIfExists)
this.DeleteEdge(edge1);if(edgeRevert!=null&&!edgeRevert.isDirect&&replaceIfExists)
this.DeleteEdge(edgeRevert);this.edges.push(edge);}
this.isMultiGraph=this.checkMutiGraph();return this.edges.length-1;}
Graph.prototype.DeleteEdge=function(edgeObject)
{var index=this.edges.indexOf(edgeObject);if(index>-1)
{this.edges.splice(index,1);}
this.isMultiGraph=this.checkMutiGraph();}
Graph.prototype.DeleteVertex=function(vertexObject)
{var index=this.vertices.indexOf(vertexObject);if(index>-1)
{for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].vertex1==vertexObject||this.edges[i].vertex2==vertexObject)
{this.DeleteEdge(this.edges[i]);i--;}}
this.vertices.splice(index,1);}}
Graph.prototype.HasConnectedNodes=function(vertexObject)
{var res=false;var index=this.vertices.indexOf(vertexObject);if(index>-1)
{for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].vertex1==vertexObject||this.edges[i].vertex2==vertexObject)
{res=true;break;}}}
return res;}
Graph.prototype.FindVertex=function(id)
{var res=null;for(var i=0;i<this.vertices.length;i++)
{if(this.vertices[i].id==id)
{res=this.vertices[i];break;}}
return res;}
Graph.prototype.FindVertexByTitle=function(title)
{var res=null;for(var i=0;i<this.vertices.length;i++)
{if(this.vertices[i].mainText==title)
{res=this.vertices[i];break;}}
return res;}
Graph.prototype.FindEdge=function(id1,id2)
{return this.FindEdgeAny(id1,id2);}
Graph.prototype.FindEdgeById=function(edgeId)
{var res=null;for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].id==edgeId)
{res=this.edges[i];break;}}
return res;}
Graph.prototype.FindEdgeAny=function(id1,id2)
{var res=null;for(var i=0;i<this.edges.length;i++)
{if((this.edges[i].vertex1.id==id1&&this.edges[i].vertex2.id==id2)||(!this.edges[i].isDirect&&this.edges[i].vertex1.id==id2&&this.edges[i].vertex2.id==id1))
{res=this.edges[i];break;}}
return res;}
Graph.prototype.FindEdgeMin=function(id1,id2)
{var res=null;var minWeight=this.infinity;for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if((edge.vertex1.id==id1&&edge.vertex2.id==id2)||(!edge.isDirect&&edge.vertex1.id==id2&&edge.vertex2.id==id1))
{if(edge.weight<minWeight)
{res=edge;minWeight=edge.weight;}}}
return res;}
Graph.prototype.FindEdgeMax=function(id1,id2)
{var res=null;var maxWeight=0;for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if((edge.vertex1.id==id1&&edge.vertex2.id==id2)||(!edge.isDirect&&edge.vertex1.id==id2&&edge.vertex2.id==id1))
{if(edge.weight>maxWeight)
{res=edge;maxWeight=edge.weight;}}}
return res;}
Graph.prototype.FindEdgeMinIgnoreDirection=function(id1,id2)
{var res=null;var minWeight=this.infinity;for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if((edge.vertex1.id==id1&&edge.vertex2.id==id2)||(edge.vertex1.id==id2&&edge.vertex2.id==id1))
{if(edge.weight<minWeight)
{res=edge;minWeight=edge.weight;}}}
return res;}
Graph.prototype.FindAllEdges=function(id1,id2)
{var res=[];for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if((edge.vertex1.id==id1&&edge.vertex2.id==id2)||(!edge.isDirect&&edge.vertex1.id==id2&&edge.vertex2.id==id1))
{res.push(edge);}}
return res;}
Graph.prototype.GetAdjacencyMatrixStr=function()
{var matrix="";for(var i=0;i<this.vertices.length;i++)
{for(var j=0;j<this.vertices.length;j++)
{var edge=this.FindEdgeMin(this.vertices[i].id,this.vertices[j].id);if(edge!=null)
{matrix+=edge.weight;}
else
{matrix+="0";}
if(j!=this.vertices.length)
{matrix+=", ";}}
matrix=matrix+"\n";}
return matrix;}
Graph.prototype.GetAdjacencyMatrix=function()
{var matrix=[];for(var i=0;i<this.vertices.length;i++)
{matrix.push([]);var v1=this.vertices[i];for(var j=0;j<this.vertices.length;j++)
{var v2=this.vertices[j];var edge=this.FindEdgeMin(v1.id,v2.id);if(edge!=null)
{matrix[i][j]=edge.GetWeight();}
else
{matrix[i][j]=this.infinity;}}}
return matrix;}
Graph.prototype.TestAdjacencyMatrix=function(matrix,rowsObj,colsObj,separator)
{if(separator===undefined)
{separator=",";}
var bGoodFormat=true;rowsObj.rows=[];rowsObj.rows=matrix.split("\n");for(j=0;j<rowsObj.rows.length;++j)
{if(rowsObj.rows[j]==="")
{rowsObj.rows.splice(j--,1);}}
colsObj.cols=[];for(var i=0;i<rowsObj.rows.length;i++)
{colsObj.cols[i]=this.SplitMatrixString(rowsObj.rows[i],separator);for(j=0;j<colsObj.cols[i].length;++j)
{if(colsObj.cols[i][j]==="")
{colsObj.cols[i].splice(j--,1);}}
if(colsObj.cols[i].length!=rowsObj.rows.length)
{bGoodFormat=false;break;}}
return bGoodFormat;}
Graph.prototype.TestPair=function(pair)
{let lines=pair.split("\n");let regExp=[/^.+-.+$/g,/^.+\>.+$/g,/^.+<.+$/g,/^.+-\(\d+\.?\d+\)-.+$/g,/^.+-\(\d+\.?\d+\)\>.+$/g,/^.+<\(\d+\.?\d+\)\-.+$/g];let res=true;for(let i=0;i<lines.length;++i)
{let resLine=false;let line=lines[i];if(line==""){continue;}
for(let j=0;j<regExp.length;++j){if(line.match(regExp[j])){resLine=true;}}
res=resLine&&res;}
return res;}
Graph.prototype.IsVerticesHaveSamePosition=function(position,vertexCount)
{var res=false;for(var j=0;j<Math.min(this.vertices.length,vertexCount);j++)
{if(position.distance(this.vertices[j].position)<this.vertices[j].model.diameter*2)
{res=true;break;}}
return res;}
Graph.prototype.GetRandomPosition=function(viewportSize){return new Point(Math.random()*viewportSize.x,Math.random()*viewportSize.y);}
Graph.prototype.GetRandomPositionOfVertex=function(matrix,vertexIndex,viewportSize)
{var point=new Point(0,0);var relatedVertex=[];for(var j=0;j<matrix.length;j++)
{if(j<this.vertices.length&&(cols[vertexIndex][j]>0||cols[j][vertexIndex]>0)&&j!=vertexIndex)
{relatedVertex.push(this.vertices[j]);}}
var diameter=(new VertexModel()).diameter;if(relatedVertex.length>1)
{for(var j=0;j<relatedVertex.length;j++)
{point=point.add(relatedVertex[j].position);}
point=point.multiply(1/relatedVertex.length);point.offset(Math.random()*diameter+(Math.random()?-1:1)*2*diameter,Math.random()*diameter+(Math.random()?-1:1)*2*diameter);}
else
{point=new Point(Math.random()*viewportSize.x,Math.random()*viewportSize.y);}
if(this.IsVerticesHaveSamePosition(point,matrix.length))
{point.offset(Math.random()*diameter+ +(Math.random()?-1:1)*4*diameter,Math.random()*diameter+ +(Math.random()?-1:1)*4*diameter);}
point.x=Math.min(Math.max(point.x,diameter),viewportSize.x);point.y=Math.min(Math.max(point.y,diameter),viewportSize.y);return point;}
Graph.prototype.VerticesReposition=function(viewportSize,newVertices)
{var maxGravityDistanceSqr=Math.max(viewportSize.x,viewportSize.y)/5.0;maxGravityDistanceSqr=maxGravityDistanceSqr*maxGravityDistanceSqr;var velocityDamping=0.85;var diameter=(new VertexModel()).diameter;var maxDistance=diameter*3;var gravityDistanceSqr=10*(maxDistance*maxDistance);var edgeGravityKof=10/(maxDistance);var kCenterForce=10/(maxDistance*10);var centerPoint=viewportSize.multiply(0.5);var velocityMax=maxDistance*10;var edgesMatrix={};for(var i=0;i<this.edges.length;i++)
{edgesMatrix[this.edges[i].vertex1.id+this.edges[i].vertex2.id*1000]=1;edgesMatrix[this.edges[i].vertex2.id+this.edges[i].vertex1.id*1000]=1;}
var startAngel=Math.random()*180.0;for(i=0;i<newVertices.length;i++)
{newVertices[i].position.orbit(new Point(viewportSize.x/2,viewportSize.y/2),(viewportSize.x-diameter*2)/2,(viewportSize.y-diameter*2)/2,360*i/newVertices.length+startAngel);}
var k=0;var bChanged=true;while(k<1000&&bChanged)
{var vertexData=[];for(i=0;i<newVertices.length;i++)
{var currentVertex={};currentVertex.object=newVertices[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++)
{otherVertex=this.vertices[j];if(otherVertex==currentVertex.object)continue;var rsq=currentVertex.object.position.distanceSqr(otherVertex.position);{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++)
{otherVertex=this.vertices[j];if(edgesMatrix.hasOwnProperty(currentVertex.object.id+1000*otherVertex.id))
{var distance=currentVertex.object.position.distance(otherVertex.position);if(distance>maxDistance)
{var force=(otherVertex.position.subtract(currentVertex.object.position)).normalize(edgeGravityKof*(distance-maxDistance));currentVertex.net_force=currentVertex.net_force.add(force);}}}
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);currentVertex.velocity=currentVertex.velocity.add(currentVertex.net_force);}
bChanged=false;for(i=0;i<vertexData.length;i++)
{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++;}
var bbox=this.getGraphBBox();if(bbox.size().length()>viewportSize.length()*1000)
{for(i=0;i<newVertices.length;i++)
{newVertices[i].position.orbit(new Point(viewportSize.x/2,viewportSize.y/2),(viewportSize.x-diameter*2)/2,(viewportSize.y-diameter*2)/2,360*i/newVertices.length+startAngel);}}
else
{var count=10;var angle=360.0/count;var viewportAspect=viewportSize.x/viewportSize.y;var bestIndex=0;var graphSize=bbox.size();var bestAspect=graphSize.x/graphSize.y;var center=bbox.center();for(var i=1;i<count;i++)
{for(j=0;j<newVertices.length;j++)
{newVertices[j].position.rotate(center,angle);}
var newBBox=this.getGraphBBox();var newAspect=newBBox.size().x/newBBox.size().y;if(Math.abs(newAspect-viewportAspect)<Math.abs(bestAspect-viewportAspect))
{bestAspect=newAspect;bestIndex=i;}}
for(j=0;j<newVertices.length;j++)
{newVertices[j].position.rotate(center,-angle*(count-bestIndex-1));}}}
Graph.prototype.SetAdjacencyMatrix=function(matrix,viewportSize,currentEnumVerticesType,separator)
{if(separator===undefined)
{separator=",";}
var rowsObj={};var colsObj={};if(this.TestAdjacencyMatrix(matrix,rowsObj,colsObj,separator))
{rows=rowsObj.rows;cols=colsObj.cols;var clonedEdge=this.edges.slice(0);for(var i=0;i<clonedEdge.length;i++)
{this.DeleteEdge(clonedEdge[i]);}
var newVertices=[];var bWeightGraph=false;for(var i=0;i<rows.length;i++)
{for(var j=0;j<rows.length;j++)
{if(j>=this.vertices.length)
{var newPos=this.GetRandomPositionOfVertex(matrix,j,viewportSize);newVertices.push(new BaseVertex(newPos.x,newPos.y,currentEnumVerticesType));this.AddNewVertex(newVertices[newVertices.length-1]);}
if(cols[i][j]>0)
{var nEdgeIndex=this.AddNewEdgeSafe(this.vertices[i],this.vertices[j],cols[i][j]!=cols[j][i],cols[i][j],true);this.FixEdgeCurve(nEdgeIndex);if(nEdgeIndex>=0)
{bWeightGraph=bWeightGraph||this.edges[nEdgeIndex].weight!=1;}}}}
if(!bWeightGraph)
{this.edges.forEach(function(part,index,theArray){theArray[index].useWeight=false;});}
for(var i=rows.length;i<Math.max(this.vertices.length,rows.length);i++)
{this.DeleteVertex(this.vertices[i]);i--;}
this.VerticesReposition(viewportSize,newVertices);}}
Graph.prototype.SetPair=function(pairs,viewportSize,currentEnumVerticesType)
{if(this.TestPair(pairs))
{this.ClearGraph();let lines=pairs.split("\n");let regExp=[/^(.+)-(.+)$/g,/^(.+)\>(.+)$/g,/^(.+)<(.+)$/g,/^(.+)-\((\d+|\d+\.?\d+)\)-(.+)$/g,/^(.+)-\((\d+|\d+\.?\d+)\)\>(.+)$/g,/^(.+)<\((\d+|\d+\.?\d+)\)\-(.+)$/g,];let bWeightGraph=false;var newVertices=[];for(var i=0;i<lines.length;i++)
{let line=lines[i];if(line==""){continue;}
for(let j=regExp.length-1;j>=0;--j){if(!line.match(regExp[j])){continue;}
let groupes=Array.from(line.matchAll(regExp[j]));let groupe=groupes[0];let vetext1Title=groupe[1];let vertex1=this.FindVertexByTitle(vetext1Title);if(vertex1==null){let newPosition=this.GetRandomPosition(viewportSize);vertex1=this.vertices[this.AddNewVertex(new BaseVertex(newPosition.x,newPosition.y,currentEnumVerticesType))];vertex1.mainText=vetext1Title;newVertices.push(vertex1);}
let vetext2Title=groupe[j<=2?2:3];let vertex2=this.FindVertexByTitle(vetext2Title);if(vertex2==null){let newPosition=this.GetRandomPosition(viewportSize);vertex2=this.vertices[this.AddNewVertex(new BaseVertex(newPosition.x,newPosition.y,currentEnumVerticesType))];vertex2.mainText=vetext2Title;newVertices.push(vertex2);}
let isDirect=j==1||j==2||j==4||j==5;let weight=1;if(j>2){weight=groupe[2];bWeightGraph=true;}
let isRevertEdge=j==2||j==5;let nEdgeIndex=this.AddNewEdgeSafe(isRevertEdge?vertex2:vertex1,isRevertEdge?vertex1:vertex2,isDirect,weight,false);this.FixEdgeCurve(nEdgeIndex);break;}}
if(!bWeightGraph)
{this.edges.forEach(function(part,index,theArray){theArray[index].useWeight=false;});}
this.VerticesReposition(viewportSize,newVertices);}}
Graph.prototype.TestIncidenceMatrix=function(matrix,rowsObj,colsObj,separator)
{if(separator===undefined)
{separator=",";}
var bGoodFormat=true;rowsObj.rows=[];rowsObj.rows=matrix.split("\n");for(j=0;j<rowsObj.rows.length;++j)
{if(rowsObj.rows[j]==="")
{rowsObj.rows.splice(j--,1);}}
colsObj.cols=[];var columnCount=0;for(var i=0;i<rowsObj.rows.length;i++)
{colsObj.cols[i]=this.SplitMatrixString(rowsObj.rows[i],separator);for(j=0;j<colsObj.cols[i].length;++j)
{if(colsObj.cols[i][j]==="")
{colsObj.cols[i].splice(j--,1);}}
if(i==0)
{columnCount=colsObj.cols[i].length;}
if(colsObj.cols[i].length!=columnCount)
{bGoodFormat=false;break;}}
if(bGoodFormat)
{for(var i=0;i<colsObj.cols[0].length;i++)
{var values=[];for(j=0;j<colsObj.cols.length;++j)
{if(colsObj.cols[j][i]!=0)
{values.push(colsObj.cols[j][i]);}}
if(!(values.length<=1||(values.length==2&&(values[0]==values[1]||values[0]==-values[1]))))
{bGoodFormat=false;break;}}}
return bGoodFormat;}
Graph.prototype.SetIncidenceMatrix=function(matrix,viewportSize,currentEnumVerticesType)
{var rowsObj={};var colsObj={};if(this.TestIncidenceMatrix(matrix,rowsObj,colsObj))
{rows=rowsObj.rows;cols=colsObj.cols;var clonedEdge=this.edges.slice(0);for(var i=0;i<clonedEdge.length;i++)
{this.DeleteEdge(clonedEdge[i]);}
var newVertices=[];var bWeightGraph=false;for(var i=0;i<cols[0].length;i++)
{var edgeValue=[];var edgeIndex=[];for(var j=0;j<cols.length;j++)
{if(j>=this.vertices.length)
{var newPos=new Point(0,0);newVertices.push(new BaseVertex(newPos.x,newPos.y,currentEnumVerticesType));this.AddNewVertex(newVertices[newVertices.length-1]);}
if(cols[j][i]!=0)
{edgeValue.push(cols[j][i]);edgeIndex.push(j);}}
if(edgeIndex.length==1)
{edgeValue.push(edgeValue[0]);edgeIndex.push(edgeIndex[0]);}
if(edgeIndex.length==2)
{if(edgeValue[0]!=edgeValue[1])
{if(edgeValue[1]>0)
{edgeValue=edgeValue.swap(0,1);edgeIndex=edgeIndex.swap(0,1);}}
var nEdgeIndex=this.AddNewEdgeSafe(this.vertices[edgeIndex[0]],this.vertices[edgeIndex[1]],edgeValue[0]!=edgeValue[1],Math.abs(edgeValue[1]),false);this.FixEdgeCurve(nEdgeIndex);if(nEdgeIndex>=0)
{bWeightGraph=bWeightGraph||this.edges[nEdgeIndex].weight!=1;}}}
if(!bWeightGraph)
{this.edges.forEach(function(part,index,theArray){theArray[index].useWeight=false;});}
for(var i=cols.length;i<Math.max(this.vertices.length,cols.length);i++)
{this.DeleteVertex(this.vertices[i]);i--;}
this.VerticesReposition(viewportSize,newVertices);}}
Graph.prototype.GetIncidenceMatrix=function()
{var matrix="";for(var i=0;i<this.vertices.length;i++)
{for(var j=0;j<this.edges.length;j++)
{if(this.edges[j].vertex1==this.vertices[i])
{matrix+=this.edges[j].weight;}
else if(this.edges[j].vertex2==this.vertices[i]&&!this.edges[j].isDirect)
{matrix+=this.edges[j].weight;}
else if(this.edges[j].vertex2==this.vertices[i]&&this.edges[j].isDirect)
{matrix+=-this.edges[j].weight;}
else
{matrix+="0";}
if(j!=this.edges.length-1)
{matrix+=", ";}}
matrix=matrix+"\n";}
return matrix;}
Graph.prototype.SplitMatrixString=function(line,separator)
{if(separator===undefined)
{separator=",";}
var res=[];var i=0;var isZeroOneLine=true;for(i=0;i<line.length;i++)
{if(line.charAt(i)!='0'&&line.charAt(i)!='1')
{isZeroOneLine=false;break;}}
if(!isZeroOneLine)
{if(separator!=",")
{line=line.replace(/,/g,".");}
for(i=0;i<line.length;i++)
{if(("0123456789.-e").indexOf(line.charAt(i))<0)
{if(i>0)
{res.push(line.substr(0,i));}
if(i==0)
{i=1;}
line=line.substr(i,line.length-i);i=-1;}}
if(line.length>0)
{res.push(line);}}
else
{for(i=0;i<line.length;i++)
{res.push(line.charAt(i));}}
console.log(res);return res;}
Graph.prototype.SaveToXML=function(additionalData)
{var mainHeader="<?xml version=\"1.0\" encoding=\"UTF-8\"?><graphml>";var header="<graph id=\"Graph\" uidGraph=\""+this.uidGraph+"\""+" uidEdge=\""+this.uidEdge+"\">";var xmlBody="";for(var i=0;i<this.vertices.length;i++)
{xmlBody=xmlBody+this.vertices[i].SaveToXML();}
xmlBody=xmlBody+"";for(var i=0;i<this.edges.length;i++)
{xmlBody=xmlBody+this.edges[i].SaveToXML();}
xmlBody=xmlBody+"";additionalField="";if(additionalData.length>0)
{additionalField="<additional data=\""+additionalData+"\"/>"}
return mainHeader+header+xmlBody+"</graph>"+additionalField+"</graphml>";}
Graph.prototype.LoadFromXML=function(xmlText,additionalData)
{xmlDoc=$.parseXML(xmlText);var $xml=$(xmlDoc);$graphs=$xml.find("graph");var loadedGraphId=0;var loadedEdgeId=0;$graphs.each(function(){loadedGraphId=parseInt($(this).attr('uidGraph'));loadedEdgeId=parseInt($(this).attr('uidEdge'));});if(isNaN(loadedEdgeId))
{loadedEdgeId=this.edgesOffset;}else if(loadedEdgeId<this.edgesOffset)
{loadedEdgeId=this.edgesOffset;}
this.uidGraph=loadedGraphId;this.uidEdge=loadedEdgeId;$nodes=$xml.find("node");var vertices=[];$nodes.each(function(){var vertex=new BaseVertex();vertex.LoadFromXML($(this));vertices.push(vertex);});this.vertices=vertices;$edges=$xml.find("edge");var edges=[];var graph=this;$edges.each(function(){var edge=new BaseEdge();edge.LoadFromXML($(this),graph);if(edge.id<graph.uidEdge){edge.id=graph.uidEdge;graph.uidEdge++;}
edges.push(edge);});this.edges=edges;$additional=$xml.find("additional");if($additional.length!=0&&additionalData!=null)
{additionalData["data"]=$additional.attr('data');}
this.isMultiGraph=this.checkMutiGraph();}
Graph.prototype.hasDirectEdge=function()
{var res=false;for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].isDirect)
{res=true;break;}}
return res;}
Graph.prototype.hasUndirectEdge=function()
{var res=false;for(var i=0;i<this.edges.length;i++)
{if(!this.edges[i].isDirect)
{res=true;break;}}
return res;}
Graph.prototype.hasEdges=function()
{return this.edges.length>0;}
Graph.prototype.clampPositions=function(viewportSize)
{var diameter=(new VertexModel()).diameter;for(i=0;i<this.vertices.length;i++)
{this.vertices[i].position.x=Math.min(Math.max(this.vertices[i].position.x,diameter),viewportSize.x-diameter);this.vertices[i].position.y=Math.min(Math.max(this.vertices[i].position.y,diameter),viewportSize.y-diameter);}}
Graph.prototype.getGraphBBox=function(viewportSize)
{var pointMin=new Point(1e5,1e5);var pointMax=new Point(-1e5,-1e5);var diameter=(new VertexModel()).diameter;for(i=0;i<this.vertices.length;i++)
{var vertex=this.vertices[i];var factor=vertex.diameterFactor();var deltaVector=new Point(factor.x*diameter,factor.y*diameter);pointMin=pointMin.min(vertex.position.subtract(deltaVector));pointMax=pointMax.max(vertex.position.add(deltaVector));}
var max_curve_length=32;for(i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if(edge.model.type==EdgeModels.curve)
{var max_curve=edge.vertex2.position.subtract(edge.vertex1.position).length()/max_curve_length;for(j=0;j<max_curve;j++)
{var point=edge.model.GetCurvePoint(edge.vertex1.position,edge.vertex2.position,j/max_curve);var deltaVector=new Point(max_curve_length,max_curve_length);pointMin=pointMin.min(point.subtract(deltaVector));pointMax=pointMax.max(point.add(deltaVector));}}}
return new Rect(pointMin,pointMax);}
Graph.prototype.hasPair=function(edge)
{return this.FindPairFor(edge)!=null;}
Graph.prototype.FindPairFor=function(edge)
{var res=this.getNeighborEdges(edge);return res.length==1?res[0]:null;}
Graph.prototype.getNeighborEdges=function(edge)
{var res=[];for(var i=0;i<this.edges.length;i++)
{var curEdge=this.edges[i];if(curEdge==edge)
continue;if((curEdge.vertex1.id==edge.vertex1.id&&curEdge.vertex2.id==edge.vertex2.id)||(curEdge.vertex1.id==edge.vertex2.id&&curEdge.vertex2.id==edge.vertex1.id))
{res.push(curEdge);}}
return res;}
Graph.prototype.checkMutiGraph=function()
{var res=false;var start={};for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if(start.hasOwnProperty(edge.vertex1.id)&&start[edge.vertex1.id]==edge.vertex2.id)
{res=true;break;}
start[edge.vertex1.id]=edge.vertex2.id;if(!edge.isDirect)
{if(start.hasOwnProperty(edge.vertex2.id)&&start[edge.vertex2.id]==edge.vertex1.id)
{res=true;break;}
start[edge.vertex2.id]=edge.vertex1.id;}}
return res;}
Graph.prototype.isMulti=function()
{return this.isMultiGraph;}
Graph.prototype.isNeedReposition=function()
{var res=false;for(var i=0;i<this.vertices.length;i++)
{res=res||this.vertices[i].IsUndefinedPosition();}
return res;}
Graph.prototype.FixEdgeCurve=function(edgeIndex)
{var edgeObject=this.edges[edgeIndex];var hasPair=this.hasPair(edgeObject);var neighborEdges=this.getNeighborEdges(edgeObject);if(hasPair)
{if(edgeObject.model.default)
edgeObject.model.type=EdgeModels.curve;var pairEdge=this.FindPairFor(edgeObject);if(pairEdge.model.default)
{pairEdge.model.type=EdgeModels.curve;if(pairEdge.vertex1==edgeObject.vertex1&&pairEdge.vertex2==edgeObject.vertex2)
pairEdge.model.curveValue=-pairEdge.model.curveValue;}}
else if(neighborEdges.length>=2)
{var curve=this.GetAvailableCurveValue(neighborEdges,edgeObject);if(edgeObject.model.default)
{edgeObject.model.type=EdgeModels.curve;edgeObject.model.curveValue=curve;}}}
Graph.prototype.GetAvailableCurveValue=function(neighborEdges,originalEdge)
{var values=[];for(var i=0;i<neighborEdges.length;i++)
{var edge=neighborEdges[i];var sameDirection=(originalEdge.vertex1.id==edge.vertex1.id);if(edge.model.type==EdgeModels.curve)
{values[(sameDirection?edge.model.curveValue:-edge.model.curveValue)]=true;}}
var changeValue=DefaultHandler.prototype.curveValue;var defaultValue=0.0;var maxSearch=10;for(var i=1;i<maxSearch;i++)
{value=i*changeValue;if(!values.hasOwnProperty(value))
return value;value=-i*changeValue;if(!values.hasOwnProperty(value))
return value;}
return defaultValue;}
Graph.prototype.reverseAllEdges=function()
{for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].isDirect)
{let v1=this.edges[i].vertex1;this.edges[i].vertex1=this.edges[i].vertex2;this.edges[i].vertex2=v1;}}
this.isMultiGraph=this.checkMutiGraph();}
Graph.prototype.makeAllEdgesDirected=function()
{for(var i=0;i<this.edges.length;i++)
{if(!this.edges[i].isDirect)
{this.edges[i].isDirect=true;}}
this.isMultiGraph=this.checkMutiGraph();}
Graph.prototype.makeAllEdgesUndirected=function()
{for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].isDirect)
{this.edges[i].isDirect=false;}}
this.isMultiGraph=this.checkMutiGraph();}
moduleLoader.endCacheLoading();
@@ -0,0 +1,11 @@
// Global version needs to force reload scripts from server.
globalVersion = 75;
{
let modulDir = "pages/create_graph_by_matrix/";
doInclude ([
include ("entities/graph/api/index.js")
]);
}
@@ -0,0 +1,594 @@
moduleLoader.beginCacheLoading(["/script/entities/graph/api/index.js?v=75","/script/shared/point.js?v=75","/script/entities/edge/api/index.js?v=75","/script/entities/edge/model/BaseEdge.js?v=75","/script/entities/edge/model/EdgeModel.js?v=75","/script/entities/vertex/api/index.js?v=75","/script/entities/vertex/model/BaseVertex.js?v=75","/script/entities/vertex/model/VertexModel.js?v=75","/script/entities/graph/model/Graph.js?v=75",]);globalVersion=75;{let modulDir="pages/create_graph_by_matrix/";doInclude([include("entities/graph/api/index.js")]);}
{let modulDir="entities/graph/";doInclude([include("shared/point.js"),include("entities/edge/api/index.js"),include("entities/vertex/api/index.js"),include("model/Graph.js",modulDir)])}function Point(x,y){this.x=x||0;this.y=y||0;};Point.prototype.x=null;Point.prototype.y=null;Point.prototype.add=function(v){return new Point(this.x+v.x,this.y+v.y);};Point.prototype.addValue=function(v){return new Point(this.x+v,this.y+v);};Point.prototype.clone=function(){return new Point(this.x,this.y);};Point.prototype.degreesTo=function(v){var dx=this.x-v.x;var dy=this.y-v.y;var angle=Math.atan2(dy,dx);return angle*(180/Math.PI);};Point.prototype.distance=function(v){return Math.sqrt(this.distanceSqr(v));};Point.prototype.distanceSqr=function(v){var x=this.x-v.x;var y=this.y-v.y;return x*x+y*y;};Point.prototype.equals=function(toCompare){return this.x==toCompare.x&&this.y==toCompare.y;};Point.prototype.interpolate=function(v,f){return new Point((this.x+v.x)*f,(this.y+v.y)*f);};Point.prototype.length=function(){return Math.sqrt(this.x*this.x+this.y*this.y);};Point.prototype.normalize=function(thickness){var l=this.length();this.x=this.x/l*thickness;this.y=this.y/l*thickness;return new Point(this.x,this.y);};Point.prototype.normalizeCopy=function(thickness){var l=this.length();return new Point(this.x/l*thickness,this.y/l*thickness);};Point.prototype.orbit=function(origin,arcWidth,arcHeight,degrees){var radians=degrees*(Math.PI/180);this.x=origin.x+arcWidth*Math.cos(radians);this.y=origin.y+arcHeight*Math.sin(radians);};Point.prototype.rotate=function(center,degrees){var radians=degrees*(Math.PI/180);offset=this.subtract(center);this.x=offset.x*Math.cos(radians)-offset.y*Math.sin(radians);this.y=offset.x*Math.sin(radians)+offset.y*Math.cos(radians);this.x=this.x+center.x;this.y=this.y+center.y;return this;};Point.prototype.offset=function(dx,dy){this.x+=dx;this.y+=dy;};Point.prototype.subtract=function(v){return new Point(this.x-v.x,this.y-v.y);};Point.prototype.subtractValue=function(value){return new Point(this.x-value,this.y-value);};Point.prototype.multiply=function(value){return new Point(this.x*value,this.y*value);};Point.prototype.toString=function(){return"(x="+this.x+", y="+this.y+")";};Point.prototype.normal=function(){return new Point(-this.y,this.x);};Point.prototype.min=function(point)
{return new Point(Math.min(this.x,point.x),Math.min(this.y,point.y));};Point.prototype.max=function(point)
{return new Point(Math.max(this.x,point.x),Math.max(this.y,point.y));};Point.prototype.inverse=function()
{return new Point(-this.x,-this.y);};Point.prototype.cross=function(point)
{return this.x*point.y-this.y*point.x;};Point.interpolate=function(pt1,pt2,f){return new Point(pt1.x*(1.0-f)+pt2.x*f,pt1.y*(1.0-f)+pt2.y*f);};Point.polar=function(len,angle){return new Point(len*Math.cos(angle),len*Math.sin(angle));};Point.distance=function(pt1,pt2){var x=pt1.x-pt2.x;var y=pt1.y-pt2.y;return Math.sqrt(x*x+y*y);};Point.center=function(pt1,pt2){return new Point((pt1.x+pt2.x)/2.0,(pt1.y+pt2.y)/2.0);};Point.toString=function(){return x+" "+y;}
Point.projection=function(point,line1,line2)
{var x=line2.y-line1.y;var y=line1.x-line2.x;var l=(line1.cross(line2)+line1.cross(point)+line2.cross(point))/(x*(line2.y-line1.y)+y*(line1.x-line2.x));var res=new Point(point.x+x*l,point.y+y*l);return res;}
Point.hitTest=function(pt11,pt12,pt21,pt22)
{var res=null;var n=0.0;var x1=pt11.x;var y1=pt11.y;var x2=pt12.x;var y2=pt12.y;var x3=pt21.x;var y3=pt21.y;var x4=pt22.x;var y4=pt22.y;if(y2-y1!=0.0)
{var q=(x2-x1)/(y1-y2);var sn=(x3-x4)+(y3-y4)*q;if(sn==0.0)
{return res;}
var fn=(x3-x1)+(y3-y1)*q;n=fn/sn;}
else
{if((y3-y4)==0.0)
{return res;}
n=(y3-y1)/(y3-y4);}
res=new Point(x3+(x4-x3)*n,y3+(y4-y3)*n);var epsilon=1E-5;if(!(res.x>=Math.min(x1,x2)-epsilon&&res.x>=Math.min(x3,x4)-epsilon&&res.x<=Math.max(x1,x2)+epsilon&&res.x<=Math.max(x3,x4)+epsilon&&res.y>=Math.min(y1,y2)-epsilon&&res.y>=Math.min(y3,y4)-epsilon&&res.y<=Math.max(y1,y2)+epsilon&&res.y<=Math.max(y3,y4)+epsilon))
{res=null;}
return res;}
function Rect(minPoint,maxPoint){this.minPoint=minPoint;this.maxPoint=maxPoint;};Rect.prototype.center=function()
{return Point.center(this.minPoint,this.maxPoint);};Rect.prototype.size=function()
{return this.maxPoint.subtract(this.minPoint);};Rect.prototype.left=function()
{return this.minPoint.x;};Rect.prototype.top=function()
{return this.minPoint.y;};Rect.prototype.isIn=function(v)
{return this.minPoint.x<=v.x&&this.minPoint.y<=v.y&&this.maxPoint.x>v.x&&this.maxPoint.y>v.y;};{let modulDir="entities/edge/";doInclude([include("model/BaseEdge.js",modulDir),include("model/EdgeModel.js",modulDir)])}
function BaseEdge(vertex1,vertex2,isDirect,weight,upText)
{this.vertex1=vertex1;this.vertex2=vertex2;this.arrayStyleStart="";this.arrayStyleFinish="";this.isDirect=isDirect;this.weight=0;this.text="";this.useWeight=false;this.id=0;this.model=new EdgeModel();if(upText===undefined)
this.upText="";else
this.upText=upText;if(weight!==undefined)
this.SetWeight(weight);this.ownStyles={};}
BaseEdge.prototype.copyFrom=function(other)
{this.vertex1=other.vertex1;this.vertex2=other.vertex2;this.arrayStyleStart=other.arrayStyleStart;this.arrayStyleFinish=other.arrayStyleFinish;this.isDirect=other.isDirect;this.weight=other.weight;this.text=other.text;this.useWeight=other.useWeight;this.id=other.id;this.model=new EdgeModel();this.model.copyFrom(other.model);this.upText=other.upText;this.ownStyles=FullObjectCopy(other.ownStyles);}
BaseEdge.prototype.SaveToXML=function()
{return"<edge "+"source=\""+this.vertex1.id+"\" "+"target=\""+this.vertex2.id+"\" "+"isDirect=\""+this.isDirect+"\" "+"weight=\""+this.weight+"\" "+"useWeight=\""+this.useWeight+"\" "+"id=\""+this.id+"\" "+"text=\""+gEncodeToHTML(this.text)+"\" "+"upText=\""+gEncodeToHTML(this.upText)+"\" "+"arrayStyleStart=\""+this.arrayStyleStart+"\" "+"arrayStyleFinish=\""+this.arrayStyleFinish+"\" "+
((Object.keys(this.ownStyles).length>0)?"ownStyles = \""+gEncodeToHTML(JSON.stringify(this.ownStyles))+"\" ":"")+
this.model.SaveToXML()+"></edge>";}
BaseEdge.prototype.LoadFromXML=function(xml,graph)
{var attr=xml.attr('vertex1');if(typeof attr==='undefined')
{attr=xml.attr('source');}
this.vertex1=graph.FindVertex(typeof attr!=='undefined'?attr:xml.attr('graph1'));var attr=xml.attr('vertex2');if(typeof attr==='undefined')
{attr=xml.attr('target');}
this.vertex2=graph.FindVertex(typeof attr!=='undefined'?attr:xml.attr('graph2'));this.isDirect=xml.attr('isDirect')=="true";this.weight=parseFloat(xml.attr('weight'));if(isNaN(this.weight))
{this.weight=1;}
this.hasPair=xml.attr('hasPair')=="true";this.useWeight=xml.attr('useWeight')=="true";this.id=xml.attr('id');this.text=xml.attr("text")==null?"":gDecodeFromHTML(xml.attr("text"));this.arrayStyleStart=xml.attr("arrayStyleStart")==null?"":xml.attr("arrayStyleStart");this.arrayStyleFinish=xml.attr("arrayStyleFinish")==null?"":xml.attr("arrayStyleFinish");this.upText=xml.attr('upText');if(typeof this.upText==='undefined')
{this.upText="";}
else
{this.upText=gDecodeFromHTML(this.upText);}
var ownStyle=xml.attr('ownStyles');if(typeof ownStyle!=='undefined')
{var parsedSave=gDecodeFromHTML(JSON.parse(ownStyle));for(var indexField in parsedSave)
{var index=parseInt(indexField);this.ownStyles[index]=FullObjectCopy(this.getStyleFor(index));for(var field in parsedSave[indexField])
{if(this.ownStyles[index].ShouldLoad(field))
this.ownStyles[index][field]=parsedSave[indexField][field];}}}
this.model.LoadFromXML(xml);}
BaseEdge.prototype.GetPixelLength=function()
{if(this.vertex1==this.vertex2)
{return this.model.GetLoopSize()*2*Math.PI;}
else
{return Point.distance(this.vertex1.position,this.vertex2.position);}}
BaseEdge.prototype.GetWeight=function()
{return this.useWeight?this.weight:1;}
BaseEdge.prototype.GetText=function()
{return this.text.length>0?this.text:(this.useWeight?this.weight.toString():"");}
BaseEdge.prototype.GetUpText=function()
{return this.upText;}
BaseEdge.prototype.GetStartEdgeStyle=function()
{return this.arrayStyleStart;}
BaseEdge.prototype.GetFinishEdgeStyle=function()
{return(this.arrayStyleFinish!=""?this.arrayStyleFinish:(this.isDirect?"arrow":""));}
BaseEdge.prototype.HitTest=function(pos)
{var positions=this.GetEdgePositionsShift();return this.model.HitTest(positions[0],positions[1],pos);}
BaseEdge.prototype.GetEdgePositionsShift=function()
{return this.GetEdgePositions();}
BaseEdge.prototype.GetEdgePositions=function()
{var res=[];if(this.vertex1==this.vertex2)
{res.push(this.vertex1.position);res.push(this.vertex2.position);return res;}
var position1=this.vertex1.position;var position2=this.vertex2.position;var diameter1=this.vertex1.model.diameter+parseInt(this.vertex1.currentStyle.GetStyle({},this.vertex1).lineWidth);var diameter2=this.vertex2.model.diameter+parseInt(this.vertex2.currentStyle.GetStyle({},this.vertex2).lineWidth);var direction=position1.subtract(position2);var direction1=direction;var direction2=direction;var d1=diameter1;var d2=diameter2;if(this.model.type==EdgeModels.curve)
{var dist=position1.distance(position2);var point1=this.model.GetCurvePoint(position1,position2,10.0/dist);direction1=position1.subtract(point1);var point2=this.model.GetCurvePoint(position1,position2,1.0-10.0/dist);direction2=position2.subtract(point2);d2=diameter2;}
else
{direction2=direction2.multiply(-1);}
direction1.normalize(1.0);direction2.normalize(1.0);var vertices=[];vertices.push({vertex:this.vertex1,direction:direction1,position:position1,diameter:d1});vertices.push({vertex:this.vertex2,direction:direction2,position:position2,diameter:d2});vertices.forEach(function(data)
{var shape=data.vertex.currentStyle.GetStyle({},data.vertex).shape;if(shape==VertexCircleShape)
{var direction=data.direction.multiply(0.5);res.push(data.position.subtract(direction.multiply(data.diameter)));}
else
{var lineFinish1=data.direction.multiply(-1).multiply(1000.0);var pointsVertex1=GetPointsForShape(shape,data.diameter,data.vertex.mainText);pointsVertex1.push(pointsVertex1[0]);for(var i=0;i<pointsVertex1.length-1;i++)
{var hitText=Point.hitTest(new Point(0,0),lineFinish1,pointsVertex1[i],pointsVertex1[i+1]);if(hitText!=null)
{res.push(data.position.add(hitText));break;}}}});return res;}
BaseEdge.prototype.SetWeight=function(weight)
{var useWeight=false;if(!isNaN(parseInt(weight,10)))
{useWeight=true;}
weight=(!isNaN(parseInt(weight,10))&&weight>=0)?weight:1;this.weight=Number(weight);this.useWeight=useWeight;}
BaseEdge.prototype.SetUpText=function(text)
{this.upText=text;}
BaseEdge.prototype.resetOwnStyle=function(index)
{if(this.ownStyles.hasOwnProperty(index))
{delete this.ownStyles[index];}}
BaseEdge.prototype.setOwnStyle=function(index,style)
{this.ownStyles[index]=style;}
BaseEdge.prototype.getStyleFor=function(index)
{if(this.ownStyles.hasOwnProperty(index))
{return this.ownStyles[index];}
else
{var style=null;if(index==0)
style=globalApplication.GetStyle("edge","common");else
style=globalApplication.GetStyle("edge","selected",undefined,index-1);return style;}}
BaseEdge.prototype.hasOwnStyleFor=function(index)
{return this.ownStyles.hasOwnProperty(index);}
var EdgeModels={"line":0,"curve":1};const defaultEdgeWidth=4;function EdgeModel()
{this.width=globalApplication.GetDefaultEdgeWidth();this.type=EdgeModels.line;this.curveValue=EdgeModel.prototype.defaultCurve;this.default=true;this.sizeOfLoop=24;this.loopShiftAngel=Math.PI/6;}
EdgeModel.prototype.defaultCurve=0.1;EdgeModel.prototype.copyFrom=function(other)
{this.width=other.width;this.type=other.type;this.curveValue=other.curveValue;this.default=other.default;}
EdgeModel.prototype.SaveToXML=function()
{return"model_width=\""+this.width+"\" "+"model_type=\""+this.type+"\" "+"model_curveValue=\""+this.curveValue+"\" "+"model_default=\""+this.default+"\" ";}
EdgeModel.prototype.LoadFromXML=function(xml,graph)
{this.width=xml.attr('model_width')==null?this.width:parseFloat(xml.attr("model_width"));this.type=xml.attr('model_type')==null?this.type:xml.attr("model_type");this.curveValue=xml.attr('model_curveValue')==null?this.curveValue:parseFloat(xml.attr("model_curveValue"));this.default=xml.attr('model_default')==null?this.default:parseFloat(xml.attr("model_default"));}
EdgeModel.prototype.GetCurvePoint=function(position1,position2,t)
{var points=this.GetBezierPoints(position1,position2);var firstBezierPoint=points[0];var secondBezierPoint=points[1];var B0_t=Math.pow(1-t,3);var B1_t=3*t*Math.pow(1-t,2);var B2_t=3*t*t*(1-t)
var B3_t=t*t*t;var ax=position1.x;var ay=position1.y;var dx=position2.x;var dy=position2.y;var bx=firstBezierPoint.x;var by=firstBezierPoint.y;var cx=secondBezierPoint.x;var cy=secondBezierPoint.y;var px_t=(B0_t*ax)+(B1_t*bx)+(B2_t*cx)+(B3_t*dx);var py_t=(B0_t*ay)+(B1_t*by)+(B2_t*cy)+(B3_t*dy);return new Point(px_t,py_t);}
EdgeModel.prototype.GetBezierPoints=function(position1,position2)
{var direction=position2.subtract(position1);var delta=direction.length();direction.normalize(1.0);var normal=direction.normal();var deltaOffsetPixels=delta*this.curveValue;var yOffset=normal.multiply(deltaOffsetPixels);var firstBezierPointShift=(direction.multiply(delta*0.2)).add(yOffset);var secondBezierPointShift=(direction.multiply(-delta*0.2)).add(yOffset);var firstBezierPoint=position1.add(firstBezierPointShift);var secondBezierPoint=position2.add(secondBezierPointShift);return[firstBezierPoint,secondBezierPoint];}
EdgeModel.prototype.HitTest=function(position1,position2,mousePos)
{if(this.type==EdgeModels.line)
return this.HitTestLine(position1,position2,mousePos);else if(this.type==EdgeModels.curve)
return this.HitTestCurve(position1,position2,mousePos);return false;}
EdgeModel.prototype.HitTestLine=function(position1,position2,mousePos,factor)
{if(factor===undefined)
{factor=1.0;}
var pos1=position1;var pos2=position2;var pos0=mousePos;if(pos1.equals(pos2))
{var xCenter=pos1.x-Math.cos(this.GetLoopShiftAngel())*this.GetLoopSize();var yCenter=pos1.y-Math.sin(this.GetLoopShiftAngel())*this.GetLoopSize();return Math.abs((Point.distance(new Point(xCenter,yCenter),pos0))-this.GetLoopSize())<=this.width*1.5*factor;}
var r1=pos0.distance(pos1);var r2=pos0.distance(pos2);var r12=pos1.distance(pos2);if(r1>=(new Point(r2,r12)).length()||r2>=(new Point(r1,r12)).length())
{}
else
{var distance=((pos1.y-pos2.y)*pos0.x+(pos2.x-pos1.x)*pos0.y+(pos1.x*pos2.y-pos2.x*pos1.y))/r12;if(Math.abs(distance)<=this.width*1.5*factor)
{return true;}}
return false;}
EdgeModel.prototype.HitTestCurve=function(position1,position2,mousePos)
{var pos1=position1;var pos2=position2;var pos0=mousePos;if(pos1.equals(pos2))
{var xCenter=pos1.x-Math.cos(this.GetLoopShiftAngel())*this.GetLoopSize();var yCenter=pos1.y-Math.sin(this.GetLoopShiftAngel())*this.GetLoopSize();return Math.abs((Point.distance(new Point(xCenter,yCenter),pos0))-this.GetLoopSize())<=this.width*1.5;}
var interval_count=position1.distance(position2)/100*30;var start=position1;for(var i=0;i<interval_count;i++)
{var finish=this.GetCurvePoint(position1,position2,i/interval_count);if(this.HitTestLine(start,finish,mousePos,2.0))
return true;start=finish;}
return false;}
EdgeModel.prototype.ChangeCurveValue=function(delta)
{if(this.type==EdgeModels.line)
{this.type=EdgeModels.curve;this.curveValue=0.0;}
this.curveValue=this.curveValue+delta;if(Math.abs(this.curveValue)<=0.01)
this.type=EdgeModels.line;this.default=false;}
EdgeModel.prototype.SetCurveValue=function(value)
{if(this.type==EdgeModels.line)
{this.type=EdgeModels.curve;this.curveValue=0.0;}
this.curveValue=value;if(Math.abs(this.curveValue)<=0.01)
this.type=EdgeModels.line;this.default=false;}
EdgeModel.prototype.GetLoopSize=function()
{if(Math.abs(this.curveValue)<=0.01)
{return this.sizeOfLoop;}
else
{let normalCurve=this.curveValue;if(this.type==EdgeModels.line){normalCurve=this.defaultCurve;}
else if(normalCurve>=0.0){normalCurve+=this.defaultCurve}
return this.sizeOfLoop*Math.abs(normalCurve)*(1/this.defaultCurve);}}
EdgeModel.prototype.GetLoopShiftAngel=function()
{if(this.type==EdgeModels.line||this.curveValue>=0.0)
{return this.loopShiftAngel;}
else
{return this.loopShiftAngel+Math.PI;}}
{let modulDir="entities/vertex/";doInclude([include("model/BaseVertex.js",modulDir),include("model/VertexModel.js",modulDir)])}
function BaseVertex(x,y,vertexEnumType)
{this.position=new Point(x,y);this.id=0;this.mainText="";this.upText="";this.vertexEnumType=vertexEnumType;this.model=new VertexModel();this.hasUndefinedPosition=false;this.ownStyles={};};BaseVertex.prototype.position=new Point(0,0);BaseVertex.prototype.copyFrom=function(other)
{this.position=new Point(other.position.x,other.position.y);this.id=other.id;this.mainText=other.mainText;this.upText=other.upText;this.vertexEnumType=other.vertexEnumType;this.model=new VertexModel();this.hasUndefinedPosition=other.hasUndefinedPosition;this.ownStyles=FullObjectCopy(other.ownStyles);}
BaseVertex.prototype.SaveToXML=function()
{return"<node "+"positionX=\""+this.position.x+"\" "+"positionY=\""+this.position.y+"\" "+"id=\""+this.id+"\" "+"mainText=\""+gEncodeToHTML(this.mainText)+"\" "+"upText=\""+gEncodeToHTML(this.upText)+"\" "+
((Object.keys(this.ownStyles).length>0)?"ownStyles = \""+gEncodeToHTML(JSON.stringify(this.ownStyles))+"\" ":"")+"size=\""+this.model.diameter+"\" "+"></node>";}
BaseVertex.prototype.LoadFromXML=function(xml)
{var xmlX=xml.attr('positionX');var xmlY=xml.attr('positionY');this.hasUndefinedPosition=(typeof xmlX==='undefined')||(typeof xmlY==='undefined');this.position=new Point(parseFloat(xmlX),parseFloat(xmlY));this.id=xml.attr('id');this.mainText=xml.attr('mainText');this.upText=xml.attr('upText');if(typeof this.mainText==='undefined')
this.mainText=this.id;else
this.mainText=gDecodeFromHTML(this.mainText);if(typeof this.upText==='undefined')
this.upText="";else
this.upText=gDecodeFromHTML(this.upText);var ownStyle=xml.attr('ownStyles');if(typeof ownStyle!=='undefined')
{var parsedSave=gDecodeFromHTML(JSON.parse(ownStyle));for(var indexField in parsedSave)
{var index=parseInt(indexField);this.ownStyles[index]=FullObjectCopy(this.getStyleFor(index));for(var field in parsedSave[indexField])
{if(this.ownStyles[index].ShouldLoad(field))
this.ownStyles[index][field]=parsedSave[indexField][field];}}}
var size=xml.attr('size');if(typeof size!=='undefined')
this.model.diameter=parseInt(size);}
BaseVertex.prototype.SetId=function(id)
{this.id=id;if(this.vertexEnumType!=null)
this.mainText=this.vertexEnumType.GetVertexText(id);}
BaseVertex.prototype.diameterFactor=function()
{return new Point(1.0+(this.mainText.length?this.mainText.length/8.0:0),1.5);}
BaseVertex.prototype.IsUndefinedPosition=function()
{return this.hasUndefinedPosition;}
BaseVertex.prototype.HitTest=function(pos)
{var shape=this.hasOwnProperty('currentStyle')?this.currentStyle.GetStyle({},this).shape:VertexCircleShape;var width=this.hasOwnProperty('currentStyle')?this.currentStyle.GetStyle({},this).lineWidth:0;if(shape==VertexCircleShape)
{return this.position.distance(pos)<this.model.diameter/2.0+width;}
else
{var relativePos=(new Point(pos.x,pos.y)).subtract(this.position);var lineFinish1=relativePos.add(new Point(1000,0));var lineFinish2=relativePos.add(new Point(-1000,0));var pointsVertex1=GetPointsForShape(shape,this.model.diameter+width,this.mainText);pointsVertex1.push(pointsVertex1[0]);var hitNumber1=0;var hitNumber2=0;for(var i=0;i<pointsVertex1.length-1;i++)
{var hitTest=Point.hitTest(relativePos,lineFinish1,pointsVertex1[i],pointsVertex1[i+1]);if(hitTest!=null)
{hitNumber1++;}
hitTest=Point.hitTest(relativePos,lineFinish2,pointsVertex1[i],pointsVertex1[i+1]);if(hitTest!=null)
{hitNumber2++;}}
return hitNumber1==1&&hitNumber2==1;}
return false;}
BaseVertex.prototype.resetOwnStyle=function(index)
{if(this.ownStyles.hasOwnProperty(index))
{delete this.ownStyles[index];}}
BaseVertex.prototype.setOwnStyle=function(index,style)
{this.ownStyles[index]=FullObjectCopy(style);}
BaseVertex.prototype.getStyleFor=function(index)
{if(this.ownStyles.hasOwnProperty(index))
{return this.ownStyles[index];}
else
{var style=null;if(index==0)
style=globalApplication.GetStyle("vertex","common");else
style=globalApplication.GetStyle("vertex","selected",undefined,index-1);return style;}}
BaseVertex.prototype.hasOwnStyleFor=function(index)
{return this.ownStyles.hasOwnProperty(index);}
const defaultVertexDiameter=30;function VertexModel()
{this.diameter=globalApplication.GetDefaultVertexSize();}
function Graph()
{this.vertices=[];this.edges=[];this.uidGraph=0;this.uidEdge=10000;this.hasDirect=false;this.isMultiGraph=false;};Graph.prototype.infinity=1E8;Graph.prototype.maxVertices=1000;Graph.prototype.edgesOffset=10000;Graph.prototype.AddNewVertex=function(vertex)
{if(this.vertices.length<=this.maxVertices)
{vertex.SetId(this.uidGraph);this.uidGraph=this.uidGraph+1;this.vertices.push(vertex);}
return this.vertices.length-1;}
Graph.prototype.ClearGraph=function(){this.vertices=[];this.edges=[];this.uidGraph=0;this.uidEdge=10000;this.hasDirect=false;this.isMultiGraph=false;}
Graph.prototype.AddNewEdgeSafe=function(graph1,graph2,isDirect,weight,replaceIfExists=true)
{return this.AddNewEdge(new BaseEdge(graph1,graph2,isDirect,weight),replaceIfExists);}
Graph.prototype.AddNewEdge=function(edge,replaceIfExists)
{edge.id=this.uidEdge;this.uidEdge=this.uidEdge+1;var edge1=this.FindEdgeAny(edge.vertex1.id,edge.vertex2.id);var edgeRevert=this.FindEdgeAny(edge.vertex2.id,edge.vertex1.id);if(!edge.isDirect)
{if(edge1!=null&&replaceIfExists)
this.DeleteEdge(edge1);if(edgeRevert!=null&&replaceIfExists)
this.DeleteEdge(edgeRevert);this.edges.push(edge);}
else
{if(edge1!=null&&replaceIfExists)
this.DeleteEdge(edge1);if(edgeRevert!=null&&!edgeRevert.isDirect&&replaceIfExists)
this.DeleteEdge(edgeRevert);this.edges.push(edge);}
this.isMultiGraph=this.checkMutiGraph();return this.edges.length-1;}
Graph.prototype.DeleteEdge=function(edgeObject)
{var index=this.edges.indexOf(edgeObject);if(index>-1)
{this.edges.splice(index,1);}
this.isMultiGraph=this.checkMutiGraph();}
Graph.prototype.DeleteVertex=function(vertexObject)
{var index=this.vertices.indexOf(vertexObject);if(index>-1)
{for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].vertex1==vertexObject||this.edges[i].vertex2==vertexObject)
{this.DeleteEdge(this.edges[i]);i--;}}
this.vertices.splice(index,1);}}
Graph.prototype.HasConnectedNodes=function(vertexObject)
{var res=false;var index=this.vertices.indexOf(vertexObject);if(index>-1)
{for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].vertex1==vertexObject||this.edges[i].vertex2==vertexObject)
{res=true;break;}}}
return res;}
Graph.prototype.FindVertex=function(id)
{var res=null;for(var i=0;i<this.vertices.length;i++)
{if(this.vertices[i].id==id)
{res=this.vertices[i];break;}}
return res;}
Graph.prototype.FindVertexByTitle=function(title)
{var res=null;for(var i=0;i<this.vertices.length;i++)
{if(this.vertices[i].mainText==title)
{res=this.vertices[i];break;}}
return res;}
Graph.prototype.FindEdge=function(id1,id2)
{return this.FindEdgeAny(id1,id2);}
Graph.prototype.FindEdgeById=function(edgeId)
{var res=null;for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].id==edgeId)
{res=this.edges[i];break;}}
return res;}
Graph.prototype.FindEdgeAny=function(id1,id2)
{var res=null;for(var i=0;i<this.edges.length;i++)
{if((this.edges[i].vertex1.id==id1&&this.edges[i].vertex2.id==id2)||(!this.edges[i].isDirect&&this.edges[i].vertex1.id==id2&&this.edges[i].vertex2.id==id1))
{res=this.edges[i];break;}}
return res;}
Graph.prototype.FindEdgeMin=function(id1,id2)
{var res=null;var minWeight=this.infinity;for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if((edge.vertex1.id==id1&&edge.vertex2.id==id2)||(!edge.isDirect&&edge.vertex1.id==id2&&edge.vertex2.id==id1))
{if(edge.weight<minWeight)
{res=edge;minWeight=edge.weight;}}}
return res;}
Graph.prototype.FindEdgeMax=function(id1,id2)
{var res=null;var maxWeight=0;for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if((edge.vertex1.id==id1&&edge.vertex2.id==id2)||(!edge.isDirect&&edge.vertex1.id==id2&&edge.vertex2.id==id1))
{if(edge.weight>maxWeight)
{res=edge;maxWeight=edge.weight;}}}
return res;}
Graph.prototype.FindEdgeMinIgnoreDirection=function(id1,id2)
{var res=null;var minWeight=this.infinity;for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if((edge.vertex1.id==id1&&edge.vertex2.id==id2)||(edge.vertex1.id==id2&&edge.vertex2.id==id1))
{if(edge.weight<minWeight)
{res=edge;minWeight=edge.weight;}}}
return res;}
Graph.prototype.FindAllEdges=function(id1,id2)
{var res=[];for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if((edge.vertex1.id==id1&&edge.vertex2.id==id2)||(!edge.isDirect&&edge.vertex1.id==id2&&edge.vertex2.id==id1))
{res.push(edge);}}
return res;}
Graph.prototype.GetAdjacencyMatrixStr=function()
{var matrix="";for(var i=0;i<this.vertices.length;i++)
{for(var j=0;j<this.vertices.length;j++)
{var edge=this.FindEdgeMin(this.vertices[i].id,this.vertices[j].id);if(edge!=null)
{matrix+=edge.weight;}
else
{matrix+="0";}
if(j!=this.vertices.length)
{matrix+=", ";}}
matrix=matrix+"\n";}
return matrix;}
Graph.prototype.GetAdjacencyMatrix=function()
{var matrix=[];for(var i=0;i<this.vertices.length;i++)
{matrix.push([]);var v1=this.vertices[i];for(var j=0;j<this.vertices.length;j++)
{var v2=this.vertices[j];var edge=this.FindEdgeMin(v1.id,v2.id);if(edge!=null)
{matrix[i][j]=edge.GetWeight();}
else
{matrix[i][j]=this.infinity;}}}
return matrix;}
Graph.prototype.TestAdjacencyMatrix=function(matrix,rowsObj,colsObj,separator)
{if(separator===undefined)
{separator=",";}
var bGoodFormat=true;rowsObj.rows=[];rowsObj.rows=matrix.split("\n");for(j=0;j<rowsObj.rows.length;++j)
{if(rowsObj.rows[j]==="")
{rowsObj.rows.splice(j--,1);}}
colsObj.cols=[];for(var i=0;i<rowsObj.rows.length;i++)
{colsObj.cols[i]=this.SplitMatrixString(rowsObj.rows[i],separator);for(j=0;j<colsObj.cols[i].length;++j)
{if(colsObj.cols[i][j]==="")
{colsObj.cols[i].splice(j--,1);}}
if(colsObj.cols[i].length!=rowsObj.rows.length)
{bGoodFormat=false;break;}}
return bGoodFormat;}
Graph.prototype.TestPair=function(pair)
{let lines=pair.split("\n");let regExp=[/^.+-.+$/g,/^.+\>.+$/g,/^.+<.+$/g,/^.+-\(\d+\.?\d+\)-.+$/g,/^.+-\(\d+\.?\d+\)\>.+$/g,/^.+<\(\d+\.?\d+\)\-.+$/g];let res=true;for(let i=0;i<lines.length;++i)
{let resLine=false;let line=lines[i];if(line==""){continue;}
for(let j=0;j<regExp.length;++j){if(line.match(regExp[j])){resLine=true;}}
res=resLine&&res;}
return res;}
Graph.prototype.IsVerticesHaveSamePosition=function(position,vertexCount)
{var res=false;for(var j=0;j<Math.min(this.vertices.length,vertexCount);j++)
{if(position.distance(this.vertices[j].position)<this.vertices[j].model.diameter*2)
{res=true;break;}}
return res;}
Graph.prototype.GetRandomPosition=function(viewportSize){return new Point(Math.random()*viewportSize.x,Math.random()*viewportSize.y);}
Graph.prototype.GetRandomPositionOfVertex=function(matrix,vertexIndex,viewportSize)
{var point=new Point(0,0);var relatedVertex=[];for(var j=0;j<matrix.length;j++)
{if(j<this.vertices.length&&(cols[vertexIndex][j]>0||cols[j][vertexIndex]>0)&&j!=vertexIndex)
{relatedVertex.push(this.vertices[j]);}}
var diameter=(new VertexModel()).diameter;if(relatedVertex.length>1)
{for(var j=0;j<relatedVertex.length;j++)
{point=point.add(relatedVertex[j].position);}
point=point.multiply(1/relatedVertex.length);point.offset(Math.random()*diameter+(Math.random()?-1:1)*2*diameter,Math.random()*diameter+(Math.random()?-1:1)*2*diameter);}
else
{point=new Point(Math.random()*viewportSize.x,Math.random()*viewportSize.y);}
if(this.IsVerticesHaveSamePosition(point,matrix.length))
{point.offset(Math.random()*diameter+ +(Math.random()?-1:1)*4*diameter,Math.random()*diameter+ +(Math.random()?-1:1)*4*diameter);}
point.x=Math.min(Math.max(point.x,diameter),viewportSize.x);point.y=Math.min(Math.max(point.y,diameter),viewportSize.y);return point;}
Graph.prototype.VerticesReposition=function(viewportSize,newVertices)
{var maxGravityDistanceSqr=Math.max(viewportSize.x,viewportSize.y)/5.0;maxGravityDistanceSqr=maxGravityDistanceSqr*maxGravityDistanceSqr;var velocityDamping=0.85;var diameter=(new VertexModel()).diameter;var maxDistance=diameter*3;var gravityDistanceSqr=10*(maxDistance*maxDistance);var edgeGravityKof=10/(maxDistance);var kCenterForce=10/(maxDistance*10);var centerPoint=viewportSize.multiply(0.5);var velocityMax=maxDistance*10;var edgesMatrix={};for(var i=0;i<this.edges.length;i++)
{edgesMatrix[this.edges[i].vertex1.id+this.edges[i].vertex2.id*1000]=1;edgesMatrix[this.edges[i].vertex2.id+this.edges[i].vertex1.id*1000]=1;}
var startAngel=Math.random()*180.0;for(i=0;i<newVertices.length;i++)
{newVertices[i].position.orbit(new Point(viewportSize.x/2,viewportSize.y/2),(viewportSize.x-diameter*2)/2,(viewportSize.y-diameter*2)/2,360*i/newVertices.length+startAngel);}
var k=0;var bChanged=true;while(k<1000&&bChanged)
{var vertexData=[];for(i=0;i<newVertices.length;i++)
{var currentVertex={};currentVertex.object=newVertices[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++)
{otherVertex=this.vertices[j];if(otherVertex==currentVertex.object)continue;var rsq=currentVertex.object.position.distanceSqr(otherVertex.position);{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++)
{otherVertex=this.vertices[j];if(edgesMatrix.hasOwnProperty(currentVertex.object.id+1000*otherVertex.id))
{var distance=currentVertex.object.position.distance(otherVertex.position);if(distance>maxDistance)
{var force=(otherVertex.position.subtract(currentVertex.object.position)).normalize(edgeGravityKof*(distance-maxDistance));currentVertex.net_force=currentVertex.net_force.add(force);}}}
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);currentVertex.velocity=currentVertex.velocity.add(currentVertex.net_force);}
bChanged=false;for(i=0;i<vertexData.length;i++)
{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++;}
var bbox=this.getGraphBBox();if(bbox.size().length()>viewportSize.length()*1000)
{for(i=0;i<newVertices.length;i++)
{newVertices[i].position.orbit(new Point(viewportSize.x/2,viewportSize.y/2),(viewportSize.x-diameter*2)/2,(viewportSize.y-diameter*2)/2,360*i/newVertices.length+startAngel);}}
else
{var count=10;var angle=360.0/count;var viewportAspect=viewportSize.x/viewportSize.y;var bestIndex=0;var graphSize=bbox.size();var bestAspect=graphSize.x/graphSize.y;var center=bbox.center();for(var i=1;i<count;i++)
{for(j=0;j<newVertices.length;j++)
{newVertices[j].position.rotate(center,angle);}
var newBBox=this.getGraphBBox();var newAspect=newBBox.size().x/newBBox.size().y;if(Math.abs(newAspect-viewportAspect)<Math.abs(bestAspect-viewportAspect))
{bestAspect=newAspect;bestIndex=i;}}
for(j=0;j<newVertices.length;j++)
{newVertices[j].position.rotate(center,-angle*(count-bestIndex-1));}}}
Graph.prototype.SetAdjacencyMatrix=function(matrix,viewportSize,currentEnumVerticesType,separator)
{if(separator===undefined)
{separator=",";}
var rowsObj={};var colsObj={};if(this.TestAdjacencyMatrix(matrix,rowsObj,colsObj,separator))
{rows=rowsObj.rows;cols=colsObj.cols;var clonedEdge=this.edges.slice(0);for(var i=0;i<clonedEdge.length;i++)
{this.DeleteEdge(clonedEdge[i]);}
var newVertices=[];var bWeightGraph=false;for(var i=0;i<rows.length;i++)
{for(var j=0;j<rows.length;j++)
{if(j>=this.vertices.length)
{var newPos=this.GetRandomPositionOfVertex(matrix,j,viewportSize);newVertices.push(new BaseVertex(newPos.x,newPos.y,currentEnumVerticesType));this.AddNewVertex(newVertices[newVertices.length-1]);}
if(cols[i][j]>0)
{var nEdgeIndex=this.AddNewEdgeSafe(this.vertices[i],this.vertices[j],cols[i][j]!=cols[j][i],cols[i][j],true);this.FixEdgeCurve(nEdgeIndex);if(nEdgeIndex>=0)
{bWeightGraph=bWeightGraph||this.edges[nEdgeIndex].weight!=1;}}}}
if(!bWeightGraph)
{this.edges.forEach(function(part,index,theArray){theArray[index].useWeight=false;});}
for(var i=rows.length;i<Math.max(this.vertices.length,rows.length);i++)
{this.DeleteVertex(this.vertices[i]);i--;}
this.VerticesReposition(viewportSize,newVertices);}}
Graph.prototype.SetPair=function(pairs,viewportSize,currentEnumVerticesType)
{if(this.TestPair(pairs))
{this.ClearGraph();let lines=pairs.split("\n");let regExp=[/^(.+)-(.+)$/g,/^(.+)\>(.+)$/g,/^(.+)<(.+)$/g,/^(.+)-\((\d+|\d+\.?\d+)\)-(.+)$/g,/^(.+)-\((\d+|\d+\.?\d+)\)\>(.+)$/g,/^(.+)<\((\d+|\d+\.?\d+)\)\-(.+)$/g,];let bWeightGraph=false;var newVertices=[];for(var i=0;i<lines.length;i++)
{let line=lines[i];if(line==""){continue;}
for(let j=regExp.length-1;j>=0;--j){if(!line.match(regExp[j])){continue;}
let groupes=Array.from(line.matchAll(regExp[j]));let groupe=groupes[0];let vetext1Title=groupe[1];let vertex1=this.FindVertexByTitle(vetext1Title);if(vertex1==null){let newPosition=this.GetRandomPosition(viewportSize);vertex1=this.vertices[this.AddNewVertex(new BaseVertex(newPosition.x,newPosition.y,currentEnumVerticesType))];vertex1.mainText=vetext1Title;newVertices.push(vertex1);}
let vetext2Title=groupe[j<=2?2:3];let vertex2=this.FindVertexByTitle(vetext2Title);if(vertex2==null){let newPosition=this.GetRandomPosition(viewportSize);vertex2=this.vertices[this.AddNewVertex(new BaseVertex(newPosition.x,newPosition.y,currentEnumVerticesType))];vertex2.mainText=vetext2Title;newVertices.push(vertex2);}
let isDirect=j==1||j==2||j==4||j==5;let weight=1;if(j>2){weight=groupe[2];bWeightGraph=true;}
let isRevertEdge=j==2||j==5;let nEdgeIndex=this.AddNewEdgeSafe(isRevertEdge?vertex2:vertex1,isRevertEdge?vertex1:vertex2,isDirect,weight,false);this.FixEdgeCurve(nEdgeIndex);break;}}
if(!bWeightGraph)
{this.edges.forEach(function(part,index,theArray){theArray[index].useWeight=false;});}
this.VerticesReposition(viewportSize,newVertices);}}
Graph.prototype.TestIncidenceMatrix=function(matrix,rowsObj,colsObj,separator)
{if(separator===undefined)
{separator=",";}
var bGoodFormat=true;rowsObj.rows=[];rowsObj.rows=matrix.split("\n");for(j=0;j<rowsObj.rows.length;++j)
{if(rowsObj.rows[j]==="")
{rowsObj.rows.splice(j--,1);}}
colsObj.cols=[];var columnCount=0;for(var i=0;i<rowsObj.rows.length;i++)
{colsObj.cols[i]=this.SplitMatrixString(rowsObj.rows[i],separator);for(j=0;j<colsObj.cols[i].length;++j)
{if(colsObj.cols[i][j]==="")
{colsObj.cols[i].splice(j--,1);}}
if(i==0)
{columnCount=colsObj.cols[i].length;}
if(colsObj.cols[i].length!=columnCount)
{bGoodFormat=false;break;}}
if(bGoodFormat)
{for(var i=0;i<colsObj.cols[0].length;i++)
{var values=[];for(j=0;j<colsObj.cols.length;++j)
{if(colsObj.cols[j][i]!=0)
{values.push(colsObj.cols[j][i]);}}
if(!(values.length<=1||(values.length==2&&(values[0]==values[1]||values[0]==-values[1]))))
{bGoodFormat=false;break;}}}
return bGoodFormat;}
Graph.prototype.SetIncidenceMatrix=function(matrix,viewportSize,currentEnumVerticesType)
{var rowsObj={};var colsObj={};if(this.TestIncidenceMatrix(matrix,rowsObj,colsObj))
{rows=rowsObj.rows;cols=colsObj.cols;var clonedEdge=this.edges.slice(0);for(var i=0;i<clonedEdge.length;i++)
{this.DeleteEdge(clonedEdge[i]);}
var newVertices=[];var bWeightGraph=false;for(var i=0;i<cols[0].length;i++)
{var edgeValue=[];var edgeIndex=[];for(var j=0;j<cols.length;j++)
{if(j>=this.vertices.length)
{var newPos=new Point(0,0);newVertices.push(new BaseVertex(newPos.x,newPos.y,currentEnumVerticesType));this.AddNewVertex(newVertices[newVertices.length-1]);}
if(cols[j][i]!=0)
{edgeValue.push(cols[j][i]);edgeIndex.push(j);}}
if(edgeIndex.length==1)
{edgeValue.push(edgeValue[0]);edgeIndex.push(edgeIndex[0]);}
if(edgeIndex.length==2)
{if(edgeValue[0]!=edgeValue[1])
{if(edgeValue[1]>0)
{edgeValue=edgeValue.swap(0,1);edgeIndex=edgeIndex.swap(0,1);}}
var nEdgeIndex=this.AddNewEdgeSafe(this.vertices[edgeIndex[0]],this.vertices[edgeIndex[1]],edgeValue[0]!=edgeValue[1],Math.abs(edgeValue[1]),false);this.FixEdgeCurve(nEdgeIndex);if(nEdgeIndex>=0)
{bWeightGraph=bWeightGraph||this.edges[nEdgeIndex].weight!=1;}}}
if(!bWeightGraph)
{this.edges.forEach(function(part,index,theArray){theArray[index].useWeight=false;});}
for(var i=cols.length;i<Math.max(this.vertices.length,cols.length);i++)
{this.DeleteVertex(this.vertices[i]);i--;}
this.VerticesReposition(viewportSize,newVertices);}}
Graph.prototype.GetIncidenceMatrix=function()
{var matrix="";for(var i=0;i<this.vertices.length;i++)
{for(var j=0;j<this.edges.length;j++)
{if(this.edges[j].vertex1==this.vertices[i])
{matrix+=this.edges[j].weight;}
else if(this.edges[j].vertex2==this.vertices[i]&&!this.edges[j].isDirect)
{matrix+=this.edges[j].weight;}
else if(this.edges[j].vertex2==this.vertices[i]&&this.edges[j].isDirect)
{matrix+=-this.edges[j].weight;}
else
{matrix+="0";}
if(j!=this.edges.length-1)
{matrix+=", ";}}
matrix=matrix+"\n";}
return matrix;}
Graph.prototype.SplitMatrixString=function(line,separator)
{if(separator===undefined)
{separator=",";}
var res=[];var i=0;var isZeroOneLine=true;for(i=0;i<line.length;i++)
{if(line.charAt(i)!='0'&&line.charAt(i)!='1')
{isZeroOneLine=false;break;}}
if(!isZeroOneLine)
{if(separator!=",")
{line=line.replace(/,/g,".");}
for(i=0;i<line.length;i++)
{if(("0123456789.-e").indexOf(line.charAt(i))<0)
{if(i>0)
{res.push(line.substr(0,i));}
if(i==0)
{i=1;}
line=line.substr(i,line.length-i);i=-1;}}
if(line.length>0)
{res.push(line);}}
else
{for(i=0;i<line.length;i++)
{res.push(line.charAt(i));}}
console.log(res);return res;}
Graph.prototype.SaveToXML=function(additionalData)
{var mainHeader="<?xml version=\"1.0\" encoding=\"UTF-8\"?><graphml>";var header="<graph id=\"Graph\" uidGraph=\""+this.uidGraph+"\""+" uidEdge=\""+this.uidEdge+"\">";var xmlBody="";for(var i=0;i<this.vertices.length;i++)
{xmlBody=xmlBody+this.vertices[i].SaveToXML();}
xmlBody=xmlBody+"";for(var i=0;i<this.edges.length;i++)
{xmlBody=xmlBody+this.edges[i].SaveToXML();}
xmlBody=xmlBody+"";additionalField="";if(additionalData.length>0)
{additionalField="<additional data=\""+additionalData+"\"/>"}
return mainHeader+header+xmlBody+"</graph>"+additionalField+"</graphml>";}
Graph.prototype.LoadFromXML=function(xmlText,additionalData)
{xmlDoc=$.parseXML(xmlText);var $xml=$(xmlDoc);$graphs=$xml.find("graph");var loadedGraphId=0;var loadedEdgeId=0;$graphs.each(function(){loadedGraphId=parseInt($(this).attr('uidGraph'));loadedEdgeId=parseInt($(this).attr('uidEdge'));});if(isNaN(loadedEdgeId))
{loadedEdgeId=this.edgesOffset;}else if(loadedEdgeId<this.edgesOffset)
{loadedEdgeId=this.edgesOffset;}
this.uidGraph=loadedGraphId;this.uidEdge=loadedEdgeId;$nodes=$xml.find("node");var vertices=[];$nodes.each(function(){var vertex=new BaseVertex();vertex.LoadFromXML($(this));vertices.push(vertex);});this.vertices=vertices;$edges=$xml.find("edge");var edges=[];var graph=this;$edges.each(function(){var edge=new BaseEdge();edge.LoadFromXML($(this),graph);if(edge.id<graph.uidEdge){edge.id=graph.uidEdge;graph.uidEdge++;}
edges.push(edge);});this.edges=edges;$additional=$xml.find("additional");if($additional.length!=0&&additionalData!=null)
{additionalData["data"]=$additional.attr('data');}
this.isMultiGraph=this.checkMutiGraph();}
Graph.prototype.hasDirectEdge=function()
{var res=false;for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].isDirect)
{res=true;break;}}
return res;}
Graph.prototype.hasUndirectEdge=function()
{var res=false;for(var i=0;i<this.edges.length;i++)
{if(!this.edges[i].isDirect)
{res=true;break;}}
return res;}
Graph.prototype.hasEdges=function()
{return this.edges.length>0;}
Graph.prototype.clampPositions=function(viewportSize)
{var diameter=(new VertexModel()).diameter;for(i=0;i<this.vertices.length;i++)
{this.vertices[i].position.x=Math.min(Math.max(this.vertices[i].position.x,diameter),viewportSize.x-diameter);this.vertices[i].position.y=Math.min(Math.max(this.vertices[i].position.y,diameter),viewportSize.y-diameter);}}
Graph.prototype.getGraphBBox=function(viewportSize)
{var pointMin=new Point(1e5,1e5);var pointMax=new Point(-1e5,-1e5);var diameter=(new VertexModel()).diameter;for(i=0;i<this.vertices.length;i++)
{var vertex=this.vertices[i];var factor=vertex.diameterFactor();var deltaVector=new Point(factor.x*diameter,factor.y*diameter);pointMin=pointMin.min(vertex.position.subtract(deltaVector));pointMax=pointMax.max(vertex.position.add(deltaVector));}
var max_curve_length=32;for(i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if(edge.model.type==EdgeModels.curve)
{var max_curve=edge.vertex2.position.subtract(edge.vertex1.position).length()/max_curve_length;for(j=0;j<max_curve;j++)
{var point=edge.model.GetCurvePoint(edge.vertex1.position,edge.vertex2.position,j/max_curve);var deltaVector=new Point(max_curve_length,max_curve_length);pointMin=pointMin.min(point.subtract(deltaVector));pointMax=pointMax.max(point.add(deltaVector));}}}
return new Rect(pointMin,pointMax);}
Graph.prototype.hasPair=function(edge)
{return this.FindPairFor(edge)!=null;}
Graph.prototype.FindPairFor=function(edge)
{var res=this.getNeighborEdges(edge);return res.length==1?res[0]:null;}
Graph.prototype.getNeighborEdges=function(edge)
{var res=[];for(var i=0;i<this.edges.length;i++)
{var curEdge=this.edges[i];if(curEdge==edge)
continue;if((curEdge.vertex1.id==edge.vertex1.id&&curEdge.vertex2.id==edge.vertex2.id)||(curEdge.vertex1.id==edge.vertex2.id&&curEdge.vertex2.id==edge.vertex1.id))
{res.push(curEdge);}}
return res;}
Graph.prototype.checkMutiGraph=function()
{var res=false;var start={};for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if(start.hasOwnProperty(edge.vertex1.id)&&start[edge.vertex1.id]==edge.vertex2.id)
{res=true;break;}
start[edge.vertex1.id]=edge.vertex2.id;if(!edge.isDirect)
{if(start.hasOwnProperty(edge.vertex2.id)&&start[edge.vertex2.id]==edge.vertex1.id)
{res=true;break;}
start[edge.vertex2.id]=edge.vertex1.id;}}
return res;}
Graph.prototype.isMulti=function()
{return this.isMultiGraph;}
Graph.prototype.isNeedReposition=function()
{var res=false;for(var i=0;i<this.vertices.length;i++)
{res=res||this.vertices[i].IsUndefinedPosition();}
return res;}
Graph.prototype.FixEdgeCurve=function(edgeIndex)
{var edgeObject=this.edges[edgeIndex];var hasPair=this.hasPair(edgeObject);var neighborEdges=this.getNeighborEdges(edgeObject);if(hasPair)
{if(edgeObject.model.default)
edgeObject.model.type=EdgeModels.curve;var pairEdge=this.FindPairFor(edgeObject);if(pairEdge.model.default)
{pairEdge.model.type=EdgeModels.curve;if(pairEdge.vertex1==edgeObject.vertex1&&pairEdge.vertex2==edgeObject.vertex2)
pairEdge.model.curveValue=-pairEdge.model.curveValue;}}
else if(neighborEdges.length>=2)
{var curve=this.GetAvailableCurveValue(neighborEdges,edgeObject);if(edgeObject.model.default)
{edgeObject.model.type=EdgeModels.curve;edgeObject.model.curveValue=curve;}}}
Graph.prototype.GetAvailableCurveValue=function(neighborEdges,originalEdge)
{var values=[];for(var i=0;i<neighborEdges.length;i++)
{var edge=neighborEdges[i];var sameDirection=(originalEdge.vertex1.id==edge.vertex1.id);if(edge.model.type==EdgeModels.curve)
{values[(sameDirection?edge.model.curveValue:-edge.model.curveValue)]=true;}}
var changeValue=DefaultHandler.prototype.curveValue;var defaultValue=0.0;var maxSearch=10;for(var i=1;i<maxSearch;i++)
{value=i*changeValue;if(!values.hasOwnProperty(value))
return value;value=-i*changeValue;if(!values.hasOwnProperty(value))
return value;}
return defaultValue;}
Graph.prototype.reverseAllEdges=function()
{for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].isDirect)
{let v1=this.edges[i].vertex1;this.edges[i].vertex1=this.edges[i].vertex2;this.edges[i].vertex2=v1;}}
this.isMultiGraph=this.checkMutiGraph();}
Graph.prototype.makeAllEdgesDirected=function()
{for(var i=0;i<this.edges.length;i++)
{if(!this.edges[i].isDirect)
{this.edges[i].isDirect=true;}}
this.isMultiGraph=this.checkMutiGraph();}
Graph.prototype.makeAllEdgesUndirected=function()
{for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].isDirect)
{this.edges[i].isDirect=false;}}
this.isMultiGraph=this.checkMutiGraph();}
moduleLoader.endCacheLoading();
@@ -0,0 +1,13 @@
// Global version needs to force reload scripts from server.
globalVersion = 75;
{
let modulDir = "pages/create_graph_by_matrix/";
doInclude ([
include ("entities/graph/api/index.js"),
include ("model/createByMatrixMain.js", modulDir),
include ("model/main.js", modulDir)
]);
}
@@ -0,0 +1,670 @@
moduleLoader.beginCacheLoading(["/script/entities/graph/api/index.js?v=75","/script/shared/point.js?v=75","/script/entities/edge/api/index.js?v=75","/script/entities/edge/model/BaseEdge.js?v=75","/script/entities/edge/model/EdgeModel.js?v=75","/script/entities/vertex/api/index.js?v=75","/script/entities/vertex/model/BaseVertex.js?v=75","/script/entities/vertex/model/VertexModel.js?v=75","/script/entities/graph/model/Graph.js?v=75","/script/pages/create_graph_by_matrix/model/createByMatrixMain.js?v=75","/script/pages/create_graph_by_matrix/model/main.js?v=75",]);globalVersion=75;{let modulDir="pages/create_graph_by_matrix/";doInclude([include("entities/graph/api/index.js"),include("model/createByMatrixMain.js",modulDir),include("model/main.js",modulDir)]);}
{let modulDir="entities/graph/";doInclude([include("shared/point.js"),include("entities/edge/api/index.js"),include("entities/vertex/api/index.js"),include("model/Graph.js",modulDir)])}function Point(x,y){this.x=x||0;this.y=y||0;};Point.prototype.x=null;Point.prototype.y=null;Point.prototype.add=function(v){return new Point(this.x+v.x,this.y+v.y);};Point.prototype.addValue=function(v){return new Point(this.x+v,this.y+v);};Point.prototype.clone=function(){return new Point(this.x,this.y);};Point.prototype.degreesTo=function(v){var dx=this.x-v.x;var dy=this.y-v.y;var angle=Math.atan2(dy,dx);return angle*(180/Math.PI);};Point.prototype.distance=function(v){return Math.sqrt(this.distanceSqr(v));};Point.prototype.distanceSqr=function(v){var x=this.x-v.x;var y=this.y-v.y;return x*x+y*y;};Point.prototype.equals=function(toCompare){return this.x==toCompare.x&&this.y==toCompare.y;};Point.prototype.interpolate=function(v,f){return new Point((this.x+v.x)*f,(this.y+v.y)*f);};Point.prototype.length=function(){return Math.sqrt(this.x*this.x+this.y*this.y);};Point.prototype.normalize=function(thickness){var l=this.length();this.x=this.x/l*thickness;this.y=this.y/l*thickness;return new Point(this.x,this.y);};Point.prototype.normalizeCopy=function(thickness){var l=this.length();return new Point(this.x/l*thickness,this.y/l*thickness);};Point.prototype.orbit=function(origin,arcWidth,arcHeight,degrees){var radians=degrees*(Math.PI/180);this.x=origin.x+arcWidth*Math.cos(radians);this.y=origin.y+arcHeight*Math.sin(radians);};Point.prototype.rotate=function(center,degrees){var radians=degrees*(Math.PI/180);offset=this.subtract(center);this.x=offset.x*Math.cos(radians)-offset.y*Math.sin(radians);this.y=offset.x*Math.sin(radians)+offset.y*Math.cos(radians);this.x=this.x+center.x;this.y=this.y+center.y;return this;};Point.prototype.offset=function(dx,dy){this.x+=dx;this.y+=dy;};Point.prototype.subtract=function(v){return new Point(this.x-v.x,this.y-v.y);};Point.prototype.subtractValue=function(value){return new Point(this.x-value,this.y-value);};Point.prototype.multiply=function(value){return new Point(this.x*value,this.y*value);};Point.prototype.toString=function(){return"(x="+this.x+", y="+this.y+")";};Point.prototype.normal=function(){return new Point(-this.y,this.x);};Point.prototype.min=function(point)
{return new Point(Math.min(this.x,point.x),Math.min(this.y,point.y));};Point.prototype.max=function(point)
{return new Point(Math.max(this.x,point.x),Math.max(this.y,point.y));};Point.prototype.inverse=function()
{return new Point(-this.x,-this.y);};Point.prototype.cross=function(point)
{return this.x*point.y-this.y*point.x;};Point.interpolate=function(pt1,pt2,f){return new Point(pt1.x*(1.0-f)+pt2.x*f,pt1.y*(1.0-f)+pt2.y*f);};Point.polar=function(len,angle){return new Point(len*Math.cos(angle),len*Math.sin(angle));};Point.distance=function(pt1,pt2){var x=pt1.x-pt2.x;var y=pt1.y-pt2.y;return Math.sqrt(x*x+y*y);};Point.center=function(pt1,pt2){return new Point((pt1.x+pt2.x)/2.0,(pt1.y+pt2.y)/2.0);};Point.toString=function(){return x+" "+y;}
Point.projection=function(point,line1,line2)
{var x=line2.y-line1.y;var y=line1.x-line2.x;var l=(line1.cross(line2)+line1.cross(point)+line2.cross(point))/(x*(line2.y-line1.y)+y*(line1.x-line2.x));var res=new Point(point.x+x*l,point.y+y*l);return res;}
Point.hitTest=function(pt11,pt12,pt21,pt22)
{var res=null;var n=0.0;var x1=pt11.x;var y1=pt11.y;var x2=pt12.x;var y2=pt12.y;var x3=pt21.x;var y3=pt21.y;var x4=pt22.x;var y4=pt22.y;if(y2-y1!=0.0)
{var q=(x2-x1)/(y1-y2);var sn=(x3-x4)+(y3-y4)*q;if(sn==0.0)
{return res;}
var fn=(x3-x1)+(y3-y1)*q;n=fn/sn;}
else
{if((y3-y4)==0.0)
{return res;}
n=(y3-y1)/(y3-y4);}
res=new Point(x3+(x4-x3)*n,y3+(y4-y3)*n);var epsilon=1E-5;if(!(res.x>=Math.min(x1,x2)-epsilon&&res.x>=Math.min(x3,x4)-epsilon&&res.x<=Math.max(x1,x2)+epsilon&&res.x<=Math.max(x3,x4)+epsilon&&res.y>=Math.min(y1,y2)-epsilon&&res.y>=Math.min(y3,y4)-epsilon&&res.y<=Math.max(y1,y2)+epsilon&&res.y<=Math.max(y3,y4)+epsilon))
{res=null;}
return res;}
function Rect(minPoint,maxPoint){this.minPoint=minPoint;this.maxPoint=maxPoint;};Rect.prototype.center=function()
{return Point.center(this.minPoint,this.maxPoint);};Rect.prototype.size=function()
{return this.maxPoint.subtract(this.minPoint);};Rect.prototype.left=function()
{return this.minPoint.x;};Rect.prototype.top=function()
{return this.minPoint.y;};Rect.prototype.isIn=function(v)
{return this.minPoint.x<=v.x&&this.minPoint.y<=v.y&&this.maxPoint.x>v.x&&this.maxPoint.y>v.y;};{let modulDir="entities/edge/";doInclude([include("model/BaseEdge.js",modulDir),include("model/EdgeModel.js",modulDir)])}
function BaseEdge(vertex1,vertex2,isDirect,weight,upText)
{this.vertex1=vertex1;this.vertex2=vertex2;this.arrayStyleStart="";this.arrayStyleFinish="";this.isDirect=isDirect;this.weight=0;this.text="";this.useWeight=false;this.id=0;this.model=new EdgeModel();if(upText===undefined)
this.upText="";else
this.upText=upText;if(weight!==undefined)
this.SetWeight(weight);this.ownStyles={};}
BaseEdge.prototype.copyFrom=function(other)
{this.vertex1=other.vertex1;this.vertex2=other.vertex2;this.arrayStyleStart=other.arrayStyleStart;this.arrayStyleFinish=other.arrayStyleFinish;this.isDirect=other.isDirect;this.weight=other.weight;this.text=other.text;this.useWeight=other.useWeight;this.id=other.id;this.model=new EdgeModel();this.model.copyFrom(other.model);this.upText=other.upText;this.ownStyles=FullObjectCopy(other.ownStyles);}
BaseEdge.prototype.SaveToXML=function()
{return"<edge "+"source=\""+this.vertex1.id+"\" "+"target=\""+this.vertex2.id+"\" "+"isDirect=\""+this.isDirect+"\" "+"weight=\""+this.weight+"\" "+"useWeight=\""+this.useWeight+"\" "+"id=\""+this.id+"\" "+"text=\""+gEncodeToHTML(this.text)+"\" "+"upText=\""+gEncodeToHTML(this.upText)+"\" "+"arrayStyleStart=\""+this.arrayStyleStart+"\" "+"arrayStyleFinish=\""+this.arrayStyleFinish+"\" "+
((Object.keys(this.ownStyles).length>0)?"ownStyles = \""+gEncodeToHTML(JSON.stringify(this.ownStyles))+"\" ":"")+
this.model.SaveToXML()+"></edge>";}
BaseEdge.prototype.LoadFromXML=function(xml,graph)
{var attr=xml.attr('vertex1');if(typeof attr==='undefined')
{attr=xml.attr('source');}
this.vertex1=graph.FindVertex(typeof attr!=='undefined'?attr:xml.attr('graph1'));var attr=xml.attr('vertex2');if(typeof attr==='undefined')
{attr=xml.attr('target');}
this.vertex2=graph.FindVertex(typeof attr!=='undefined'?attr:xml.attr('graph2'));this.isDirect=xml.attr('isDirect')=="true";this.weight=parseFloat(xml.attr('weight'));if(isNaN(this.weight))
{this.weight=1;}
this.hasPair=xml.attr('hasPair')=="true";this.useWeight=xml.attr('useWeight')=="true";this.id=xml.attr('id');this.text=xml.attr("text")==null?"":gDecodeFromHTML(xml.attr("text"));this.arrayStyleStart=xml.attr("arrayStyleStart")==null?"":xml.attr("arrayStyleStart");this.arrayStyleFinish=xml.attr("arrayStyleFinish")==null?"":xml.attr("arrayStyleFinish");this.upText=xml.attr('upText');if(typeof this.upText==='undefined')
{this.upText="";}
else
{this.upText=gDecodeFromHTML(this.upText);}
var ownStyle=xml.attr('ownStyles');if(typeof ownStyle!=='undefined')
{var parsedSave=gDecodeFromHTML(JSON.parse(ownStyle));for(var indexField in parsedSave)
{var index=parseInt(indexField);this.ownStyles[index]=FullObjectCopy(this.getStyleFor(index));for(var field in parsedSave[indexField])
{if(this.ownStyles[index].ShouldLoad(field))
this.ownStyles[index][field]=parsedSave[indexField][field];}}}
this.model.LoadFromXML(xml);}
BaseEdge.prototype.GetPixelLength=function()
{if(this.vertex1==this.vertex2)
{return this.model.GetLoopSize()*2*Math.PI;}
else
{return Point.distance(this.vertex1.position,this.vertex2.position);}}
BaseEdge.prototype.GetWeight=function()
{return this.useWeight?this.weight:1;}
BaseEdge.prototype.GetText=function()
{return this.text.length>0?this.text:(this.useWeight?this.weight.toString():"");}
BaseEdge.prototype.GetUpText=function()
{return this.upText;}
BaseEdge.prototype.GetStartEdgeStyle=function()
{return this.arrayStyleStart;}
BaseEdge.prototype.GetFinishEdgeStyle=function()
{return(this.arrayStyleFinish!=""?this.arrayStyleFinish:(this.isDirect?"arrow":""));}
BaseEdge.prototype.HitTest=function(pos)
{var positions=this.GetEdgePositionsShift();return this.model.HitTest(positions[0],positions[1],pos);}
BaseEdge.prototype.GetEdgePositionsShift=function()
{return this.GetEdgePositions();}
BaseEdge.prototype.GetEdgePositions=function()
{var res=[];if(this.vertex1==this.vertex2)
{res.push(this.vertex1.position);res.push(this.vertex2.position);return res;}
var position1=this.vertex1.position;var position2=this.vertex2.position;var diameter1=this.vertex1.model.diameter+parseInt(this.vertex1.currentStyle.GetStyle({},this.vertex1).lineWidth);var diameter2=this.vertex2.model.diameter+parseInt(this.vertex2.currentStyle.GetStyle({},this.vertex2).lineWidth);var direction=position1.subtract(position2);var direction1=direction;var direction2=direction;var d1=diameter1;var d2=diameter2;if(this.model.type==EdgeModels.curve)
{var dist=position1.distance(position2);var point1=this.model.GetCurvePoint(position1,position2,10.0/dist);direction1=position1.subtract(point1);var point2=this.model.GetCurvePoint(position1,position2,1.0-10.0/dist);direction2=position2.subtract(point2);d2=diameter2;}
else
{direction2=direction2.multiply(-1);}
direction1.normalize(1.0);direction2.normalize(1.0);var vertices=[];vertices.push({vertex:this.vertex1,direction:direction1,position:position1,diameter:d1});vertices.push({vertex:this.vertex2,direction:direction2,position:position2,diameter:d2});vertices.forEach(function(data)
{var shape=data.vertex.currentStyle.GetStyle({},data.vertex).shape;if(shape==VertexCircleShape)
{var direction=data.direction.multiply(0.5);res.push(data.position.subtract(direction.multiply(data.diameter)));}
else
{var lineFinish1=data.direction.multiply(-1).multiply(1000.0);var pointsVertex1=GetPointsForShape(shape,data.diameter,data.vertex.mainText);pointsVertex1.push(pointsVertex1[0]);for(var i=0;i<pointsVertex1.length-1;i++)
{var hitText=Point.hitTest(new Point(0,0),lineFinish1,pointsVertex1[i],pointsVertex1[i+1]);if(hitText!=null)
{res.push(data.position.add(hitText));break;}}}});return res;}
BaseEdge.prototype.SetWeight=function(weight)
{var useWeight=false;if(!isNaN(parseInt(weight,10)))
{useWeight=true;}
weight=(!isNaN(parseInt(weight,10))&&weight>=0)?weight:1;this.weight=Number(weight);this.useWeight=useWeight;}
BaseEdge.prototype.SetUpText=function(text)
{this.upText=text;}
BaseEdge.prototype.resetOwnStyle=function(index)
{if(this.ownStyles.hasOwnProperty(index))
{delete this.ownStyles[index];}}
BaseEdge.prototype.setOwnStyle=function(index,style)
{this.ownStyles[index]=style;}
BaseEdge.prototype.getStyleFor=function(index)
{if(this.ownStyles.hasOwnProperty(index))
{return this.ownStyles[index];}
else
{var style=null;if(index==0)
style=globalApplication.GetStyle("edge","common");else
style=globalApplication.GetStyle("edge","selected",undefined,index-1);return style;}}
BaseEdge.prototype.hasOwnStyleFor=function(index)
{return this.ownStyles.hasOwnProperty(index);}
var EdgeModels={"line":0,"curve":1};const defaultEdgeWidth=4;function EdgeModel()
{this.width=globalApplication.GetDefaultEdgeWidth();this.type=EdgeModels.line;this.curveValue=EdgeModel.prototype.defaultCurve;this.default=true;this.sizeOfLoop=24;this.loopShiftAngel=Math.PI/6;}
EdgeModel.prototype.defaultCurve=0.1;EdgeModel.prototype.copyFrom=function(other)
{this.width=other.width;this.type=other.type;this.curveValue=other.curveValue;this.default=other.default;}
EdgeModel.prototype.SaveToXML=function()
{return"model_width=\""+this.width+"\" "+"model_type=\""+this.type+"\" "+"model_curveValue=\""+this.curveValue+"\" "+"model_default=\""+this.default+"\" ";}
EdgeModel.prototype.LoadFromXML=function(xml,graph)
{this.width=xml.attr('model_width')==null?this.width:parseFloat(xml.attr("model_width"));this.type=xml.attr('model_type')==null?this.type:xml.attr("model_type");this.curveValue=xml.attr('model_curveValue')==null?this.curveValue:parseFloat(xml.attr("model_curveValue"));this.default=xml.attr('model_default')==null?this.default:parseFloat(xml.attr("model_default"));}
EdgeModel.prototype.GetCurvePoint=function(position1,position2,t)
{var points=this.GetBezierPoints(position1,position2);var firstBezierPoint=points[0];var secondBezierPoint=points[1];var B0_t=Math.pow(1-t,3);var B1_t=3*t*Math.pow(1-t,2);var B2_t=3*t*t*(1-t)
var B3_t=t*t*t;var ax=position1.x;var ay=position1.y;var dx=position2.x;var dy=position2.y;var bx=firstBezierPoint.x;var by=firstBezierPoint.y;var cx=secondBezierPoint.x;var cy=secondBezierPoint.y;var px_t=(B0_t*ax)+(B1_t*bx)+(B2_t*cx)+(B3_t*dx);var py_t=(B0_t*ay)+(B1_t*by)+(B2_t*cy)+(B3_t*dy);return new Point(px_t,py_t);}
EdgeModel.prototype.GetBezierPoints=function(position1,position2)
{var direction=position2.subtract(position1);var delta=direction.length();direction.normalize(1.0);var normal=direction.normal();var deltaOffsetPixels=delta*this.curveValue;var yOffset=normal.multiply(deltaOffsetPixels);var firstBezierPointShift=(direction.multiply(delta*0.2)).add(yOffset);var secondBezierPointShift=(direction.multiply(-delta*0.2)).add(yOffset);var firstBezierPoint=position1.add(firstBezierPointShift);var secondBezierPoint=position2.add(secondBezierPointShift);return[firstBezierPoint,secondBezierPoint];}
EdgeModel.prototype.HitTest=function(position1,position2,mousePos)
{if(this.type==EdgeModels.line)
return this.HitTestLine(position1,position2,mousePos);else if(this.type==EdgeModels.curve)
return this.HitTestCurve(position1,position2,mousePos);return false;}
EdgeModel.prototype.HitTestLine=function(position1,position2,mousePos,factor)
{if(factor===undefined)
{factor=1.0;}
var pos1=position1;var pos2=position2;var pos0=mousePos;if(pos1.equals(pos2))
{var xCenter=pos1.x-Math.cos(this.GetLoopShiftAngel())*this.GetLoopSize();var yCenter=pos1.y-Math.sin(this.GetLoopShiftAngel())*this.GetLoopSize();return Math.abs((Point.distance(new Point(xCenter,yCenter),pos0))-this.GetLoopSize())<=this.width*1.5*factor;}
var r1=pos0.distance(pos1);var r2=pos0.distance(pos2);var r12=pos1.distance(pos2);if(r1>=(new Point(r2,r12)).length()||r2>=(new Point(r1,r12)).length())
{}
else
{var distance=((pos1.y-pos2.y)*pos0.x+(pos2.x-pos1.x)*pos0.y+(pos1.x*pos2.y-pos2.x*pos1.y))/r12;if(Math.abs(distance)<=this.width*1.5*factor)
{return true;}}
return false;}
EdgeModel.prototype.HitTestCurve=function(position1,position2,mousePos)
{var pos1=position1;var pos2=position2;var pos0=mousePos;if(pos1.equals(pos2))
{var xCenter=pos1.x-Math.cos(this.GetLoopShiftAngel())*this.GetLoopSize();var yCenter=pos1.y-Math.sin(this.GetLoopShiftAngel())*this.GetLoopSize();return Math.abs((Point.distance(new Point(xCenter,yCenter),pos0))-this.GetLoopSize())<=this.width*1.5;}
var interval_count=position1.distance(position2)/100*30;var start=position1;for(var i=0;i<interval_count;i++)
{var finish=this.GetCurvePoint(position1,position2,i/interval_count);if(this.HitTestLine(start,finish,mousePos,2.0))
return true;start=finish;}
return false;}
EdgeModel.prototype.ChangeCurveValue=function(delta)
{if(this.type==EdgeModels.line)
{this.type=EdgeModels.curve;this.curveValue=0.0;}
this.curveValue=this.curveValue+delta;if(Math.abs(this.curveValue)<=0.01)
this.type=EdgeModels.line;this.default=false;}
EdgeModel.prototype.SetCurveValue=function(value)
{if(this.type==EdgeModels.line)
{this.type=EdgeModels.curve;this.curveValue=0.0;}
this.curveValue=value;if(Math.abs(this.curveValue)<=0.01)
this.type=EdgeModels.line;this.default=false;}
EdgeModel.prototype.GetLoopSize=function()
{if(Math.abs(this.curveValue)<=0.01)
{return this.sizeOfLoop;}
else
{let normalCurve=this.curveValue;if(this.type==EdgeModels.line){normalCurve=this.defaultCurve;}
else if(normalCurve>=0.0){normalCurve+=this.defaultCurve}
return this.sizeOfLoop*Math.abs(normalCurve)*(1/this.defaultCurve);}}
EdgeModel.prototype.GetLoopShiftAngel=function()
{if(this.type==EdgeModels.line||this.curveValue>=0.0)
{return this.loopShiftAngel;}
else
{return this.loopShiftAngel+Math.PI;}}
{let modulDir="entities/vertex/";doInclude([include("model/BaseVertex.js",modulDir),include("model/VertexModel.js",modulDir)])}
function BaseVertex(x,y,vertexEnumType)
{this.position=new Point(x,y);this.id=0;this.mainText="";this.upText="";this.vertexEnumType=vertexEnumType;this.model=new VertexModel();this.hasUndefinedPosition=false;this.ownStyles={};};BaseVertex.prototype.position=new Point(0,0);BaseVertex.prototype.copyFrom=function(other)
{this.position=new Point(other.position.x,other.position.y);this.id=other.id;this.mainText=other.mainText;this.upText=other.upText;this.vertexEnumType=other.vertexEnumType;this.model=new VertexModel();this.hasUndefinedPosition=other.hasUndefinedPosition;this.ownStyles=FullObjectCopy(other.ownStyles);}
BaseVertex.prototype.SaveToXML=function()
{return"<node "+"positionX=\""+this.position.x+"\" "+"positionY=\""+this.position.y+"\" "+"id=\""+this.id+"\" "+"mainText=\""+gEncodeToHTML(this.mainText)+"\" "+"upText=\""+gEncodeToHTML(this.upText)+"\" "+
((Object.keys(this.ownStyles).length>0)?"ownStyles = \""+gEncodeToHTML(JSON.stringify(this.ownStyles))+"\" ":"")+"size=\""+this.model.diameter+"\" "+"></node>";}
BaseVertex.prototype.LoadFromXML=function(xml)
{var xmlX=xml.attr('positionX');var xmlY=xml.attr('positionY');this.hasUndefinedPosition=(typeof xmlX==='undefined')||(typeof xmlY==='undefined');this.position=new Point(parseFloat(xmlX),parseFloat(xmlY));this.id=xml.attr('id');this.mainText=xml.attr('mainText');this.upText=xml.attr('upText');if(typeof this.mainText==='undefined')
this.mainText=this.id;else
this.mainText=gDecodeFromHTML(this.mainText);if(typeof this.upText==='undefined')
this.upText="";else
this.upText=gDecodeFromHTML(this.upText);var ownStyle=xml.attr('ownStyles');if(typeof ownStyle!=='undefined')
{var parsedSave=gDecodeFromHTML(JSON.parse(ownStyle));for(var indexField in parsedSave)
{var index=parseInt(indexField);this.ownStyles[index]=FullObjectCopy(this.getStyleFor(index));for(var field in parsedSave[indexField])
{if(this.ownStyles[index].ShouldLoad(field))
this.ownStyles[index][field]=parsedSave[indexField][field];}}}
var size=xml.attr('size');if(typeof size!=='undefined')
this.model.diameter=parseInt(size);}
BaseVertex.prototype.SetId=function(id)
{this.id=id;if(this.vertexEnumType!=null)
this.mainText=this.vertexEnumType.GetVertexText(id);}
BaseVertex.prototype.diameterFactor=function()
{return new Point(1.0+(this.mainText.length?this.mainText.length/8.0:0),1.5);}
BaseVertex.prototype.IsUndefinedPosition=function()
{return this.hasUndefinedPosition;}
BaseVertex.prototype.HitTest=function(pos)
{var shape=this.hasOwnProperty('currentStyle')?this.currentStyle.GetStyle({},this).shape:VertexCircleShape;var width=this.hasOwnProperty('currentStyle')?this.currentStyle.GetStyle({},this).lineWidth:0;if(shape==VertexCircleShape)
{return this.position.distance(pos)<this.model.diameter/2.0+width;}
else
{var relativePos=(new Point(pos.x,pos.y)).subtract(this.position);var lineFinish1=relativePos.add(new Point(1000,0));var lineFinish2=relativePos.add(new Point(-1000,0));var pointsVertex1=GetPointsForShape(shape,this.model.diameter+width,this.mainText);pointsVertex1.push(pointsVertex1[0]);var hitNumber1=0;var hitNumber2=0;for(var i=0;i<pointsVertex1.length-1;i++)
{var hitTest=Point.hitTest(relativePos,lineFinish1,pointsVertex1[i],pointsVertex1[i+1]);if(hitTest!=null)
{hitNumber1++;}
hitTest=Point.hitTest(relativePos,lineFinish2,pointsVertex1[i],pointsVertex1[i+1]);if(hitTest!=null)
{hitNumber2++;}}
return hitNumber1==1&&hitNumber2==1;}
return false;}
BaseVertex.prototype.resetOwnStyle=function(index)
{if(this.ownStyles.hasOwnProperty(index))
{delete this.ownStyles[index];}}
BaseVertex.prototype.setOwnStyle=function(index,style)
{this.ownStyles[index]=FullObjectCopy(style);}
BaseVertex.prototype.getStyleFor=function(index)
{if(this.ownStyles.hasOwnProperty(index))
{return this.ownStyles[index];}
else
{var style=null;if(index==0)
style=globalApplication.GetStyle("vertex","common");else
style=globalApplication.GetStyle("vertex","selected",undefined,index-1);return style;}}
BaseVertex.prototype.hasOwnStyleFor=function(index)
{return this.ownStyles.hasOwnProperty(index);}
const defaultVertexDiameter=30;function VertexModel()
{this.diameter=globalApplication.GetDefaultVertexSize();}
function Graph()
{this.vertices=[];this.edges=[];this.uidGraph=0;this.uidEdge=10000;this.hasDirect=false;this.isMultiGraph=false;};Graph.prototype.infinity=1E8;Graph.prototype.maxVertices=1000;Graph.prototype.edgesOffset=10000;Graph.prototype.AddNewVertex=function(vertex)
{if(this.vertices.length<=this.maxVertices)
{vertex.SetId(this.uidGraph);this.uidGraph=this.uidGraph+1;this.vertices.push(vertex);}
return this.vertices.length-1;}
Graph.prototype.ClearGraph=function(){this.vertices=[];this.edges=[];this.uidGraph=0;this.uidEdge=10000;this.hasDirect=false;this.isMultiGraph=false;}
Graph.prototype.AddNewEdgeSafe=function(graph1,graph2,isDirect,weight,replaceIfExists=true)
{return this.AddNewEdge(new BaseEdge(graph1,graph2,isDirect,weight),replaceIfExists);}
Graph.prototype.AddNewEdge=function(edge,replaceIfExists)
{edge.id=this.uidEdge;this.uidEdge=this.uidEdge+1;var edge1=this.FindEdgeAny(edge.vertex1.id,edge.vertex2.id);var edgeRevert=this.FindEdgeAny(edge.vertex2.id,edge.vertex1.id);if(!edge.isDirect)
{if(edge1!=null&&replaceIfExists)
this.DeleteEdge(edge1);if(edgeRevert!=null&&replaceIfExists)
this.DeleteEdge(edgeRevert);this.edges.push(edge);}
else
{if(edge1!=null&&replaceIfExists)
this.DeleteEdge(edge1);if(edgeRevert!=null&&!edgeRevert.isDirect&&replaceIfExists)
this.DeleteEdge(edgeRevert);this.edges.push(edge);}
this.isMultiGraph=this.checkMutiGraph();return this.edges.length-1;}
Graph.prototype.DeleteEdge=function(edgeObject)
{var index=this.edges.indexOf(edgeObject);if(index>-1)
{this.edges.splice(index,1);}
this.isMultiGraph=this.checkMutiGraph();}
Graph.prototype.DeleteVertex=function(vertexObject)
{var index=this.vertices.indexOf(vertexObject);if(index>-1)
{for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].vertex1==vertexObject||this.edges[i].vertex2==vertexObject)
{this.DeleteEdge(this.edges[i]);i--;}}
this.vertices.splice(index,1);}}
Graph.prototype.HasConnectedNodes=function(vertexObject)
{var res=false;var index=this.vertices.indexOf(vertexObject);if(index>-1)
{for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].vertex1==vertexObject||this.edges[i].vertex2==vertexObject)
{res=true;break;}}}
return res;}
Graph.prototype.FindVertex=function(id)
{var res=null;for(var i=0;i<this.vertices.length;i++)
{if(this.vertices[i].id==id)
{res=this.vertices[i];break;}}
return res;}
Graph.prototype.FindVertexByTitle=function(title)
{var res=null;for(var i=0;i<this.vertices.length;i++)
{if(this.vertices[i].mainText==title)
{res=this.vertices[i];break;}}
return res;}
Graph.prototype.FindEdge=function(id1,id2)
{return this.FindEdgeAny(id1,id2);}
Graph.prototype.FindEdgeById=function(edgeId)
{var res=null;for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].id==edgeId)
{res=this.edges[i];break;}}
return res;}
Graph.prototype.FindEdgeAny=function(id1,id2)
{var res=null;for(var i=0;i<this.edges.length;i++)
{if((this.edges[i].vertex1.id==id1&&this.edges[i].vertex2.id==id2)||(!this.edges[i].isDirect&&this.edges[i].vertex1.id==id2&&this.edges[i].vertex2.id==id1))
{res=this.edges[i];break;}}
return res;}
Graph.prototype.FindEdgeMin=function(id1,id2)
{var res=null;var minWeight=this.infinity;for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if((edge.vertex1.id==id1&&edge.vertex2.id==id2)||(!edge.isDirect&&edge.vertex1.id==id2&&edge.vertex2.id==id1))
{if(edge.weight<minWeight)
{res=edge;minWeight=edge.weight;}}}
return res;}
Graph.prototype.FindEdgeMax=function(id1,id2)
{var res=null;var maxWeight=0;for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if((edge.vertex1.id==id1&&edge.vertex2.id==id2)||(!edge.isDirect&&edge.vertex1.id==id2&&edge.vertex2.id==id1))
{if(edge.weight>maxWeight)
{res=edge;maxWeight=edge.weight;}}}
return res;}
Graph.prototype.FindEdgeMinIgnoreDirection=function(id1,id2)
{var res=null;var minWeight=this.infinity;for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if((edge.vertex1.id==id1&&edge.vertex2.id==id2)||(edge.vertex1.id==id2&&edge.vertex2.id==id1))
{if(edge.weight<minWeight)
{res=edge;minWeight=edge.weight;}}}
return res;}
Graph.prototype.FindAllEdges=function(id1,id2)
{var res=[];for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if((edge.vertex1.id==id1&&edge.vertex2.id==id2)||(!edge.isDirect&&edge.vertex1.id==id2&&edge.vertex2.id==id1))
{res.push(edge);}}
return res;}
Graph.prototype.GetAdjacencyMatrixStr=function()
{var matrix="";for(var i=0;i<this.vertices.length;i++)
{for(var j=0;j<this.vertices.length;j++)
{var edge=this.FindEdgeMin(this.vertices[i].id,this.vertices[j].id);if(edge!=null)
{matrix+=edge.weight;}
else
{matrix+="0";}
if(j!=this.vertices.length)
{matrix+=", ";}}
matrix=matrix+"\n";}
return matrix;}
Graph.prototype.GetAdjacencyMatrix=function()
{var matrix=[];for(var i=0;i<this.vertices.length;i++)
{matrix.push([]);var v1=this.vertices[i];for(var j=0;j<this.vertices.length;j++)
{var v2=this.vertices[j];var edge=this.FindEdgeMin(v1.id,v2.id);if(edge!=null)
{matrix[i][j]=edge.GetWeight();}
else
{matrix[i][j]=this.infinity;}}}
return matrix;}
Graph.prototype.TestAdjacencyMatrix=function(matrix,rowsObj,colsObj,separator)
{if(separator===undefined)
{separator=",";}
var bGoodFormat=true;rowsObj.rows=[];rowsObj.rows=matrix.split("\n");for(j=0;j<rowsObj.rows.length;++j)
{if(rowsObj.rows[j]==="")
{rowsObj.rows.splice(j--,1);}}
colsObj.cols=[];for(var i=0;i<rowsObj.rows.length;i++)
{colsObj.cols[i]=this.SplitMatrixString(rowsObj.rows[i],separator);for(j=0;j<colsObj.cols[i].length;++j)
{if(colsObj.cols[i][j]==="")
{colsObj.cols[i].splice(j--,1);}}
if(colsObj.cols[i].length!=rowsObj.rows.length)
{bGoodFormat=false;break;}}
return bGoodFormat;}
Graph.prototype.TestPair=function(pair)
{let lines=pair.split("\n");let regExp=[/^.+-.+$/g,/^.+\>.+$/g,/^.+<.+$/g,/^.+-\(\d+\.?\d+\)-.+$/g,/^.+-\(\d+\.?\d+\)\>.+$/g,/^.+<\(\d+\.?\d+\)\-.+$/g];let res=true;for(let i=0;i<lines.length;++i)
{let resLine=false;let line=lines[i];if(line==""){continue;}
for(let j=0;j<regExp.length;++j){if(line.match(regExp[j])){resLine=true;}}
res=resLine&&res;}
return res;}
Graph.prototype.IsVerticesHaveSamePosition=function(position,vertexCount)
{var res=false;for(var j=0;j<Math.min(this.vertices.length,vertexCount);j++)
{if(position.distance(this.vertices[j].position)<this.vertices[j].model.diameter*2)
{res=true;break;}}
return res;}
Graph.prototype.GetRandomPosition=function(viewportSize){return new Point(Math.random()*viewportSize.x,Math.random()*viewportSize.y);}
Graph.prototype.GetRandomPositionOfVertex=function(matrix,vertexIndex,viewportSize)
{var point=new Point(0,0);var relatedVertex=[];for(var j=0;j<matrix.length;j++)
{if(j<this.vertices.length&&(cols[vertexIndex][j]>0||cols[j][vertexIndex]>0)&&j!=vertexIndex)
{relatedVertex.push(this.vertices[j]);}}
var diameter=(new VertexModel()).diameter;if(relatedVertex.length>1)
{for(var j=0;j<relatedVertex.length;j++)
{point=point.add(relatedVertex[j].position);}
point=point.multiply(1/relatedVertex.length);point.offset(Math.random()*diameter+(Math.random()?-1:1)*2*diameter,Math.random()*diameter+(Math.random()?-1:1)*2*diameter);}
else
{point=new Point(Math.random()*viewportSize.x,Math.random()*viewportSize.y);}
if(this.IsVerticesHaveSamePosition(point,matrix.length))
{point.offset(Math.random()*diameter+ +(Math.random()?-1:1)*4*diameter,Math.random()*diameter+ +(Math.random()?-1:1)*4*diameter);}
point.x=Math.min(Math.max(point.x,diameter),viewportSize.x);point.y=Math.min(Math.max(point.y,diameter),viewportSize.y);return point;}
Graph.prototype.VerticesReposition=function(viewportSize,newVertices)
{var maxGravityDistanceSqr=Math.max(viewportSize.x,viewportSize.y)/5.0;maxGravityDistanceSqr=maxGravityDistanceSqr*maxGravityDistanceSqr;var velocityDamping=0.85;var diameter=(new VertexModel()).diameter;var maxDistance=diameter*3;var gravityDistanceSqr=10*(maxDistance*maxDistance);var edgeGravityKof=10/(maxDistance);var kCenterForce=10/(maxDistance*10);var centerPoint=viewportSize.multiply(0.5);var velocityMax=maxDistance*10;var edgesMatrix={};for(var i=0;i<this.edges.length;i++)
{edgesMatrix[this.edges[i].vertex1.id+this.edges[i].vertex2.id*1000]=1;edgesMatrix[this.edges[i].vertex2.id+this.edges[i].vertex1.id*1000]=1;}
var startAngel=Math.random()*180.0;for(i=0;i<newVertices.length;i++)
{newVertices[i].position.orbit(new Point(viewportSize.x/2,viewportSize.y/2),(viewportSize.x-diameter*2)/2,(viewportSize.y-diameter*2)/2,360*i/newVertices.length+startAngel);}
var k=0;var bChanged=true;while(k<1000&&bChanged)
{var vertexData=[];for(i=0;i<newVertices.length;i++)
{var currentVertex={};currentVertex.object=newVertices[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++)
{otherVertex=this.vertices[j];if(otherVertex==currentVertex.object)continue;var rsq=currentVertex.object.position.distanceSqr(otherVertex.position);{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++)
{otherVertex=this.vertices[j];if(edgesMatrix.hasOwnProperty(currentVertex.object.id+1000*otherVertex.id))
{var distance=currentVertex.object.position.distance(otherVertex.position);if(distance>maxDistance)
{var force=(otherVertex.position.subtract(currentVertex.object.position)).normalize(edgeGravityKof*(distance-maxDistance));currentVertex.net_force=currentVertex.net_force.add(force);}}}
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);currentVertex.velocity=currentVertex.velocity.add(currentVertex.net_force);}
bChanged=false;for(i=0;i<vertexData.length;i++)
{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++;}
var bbox=this.getGraphBBox();if(bbox.size().length()>viewportSize.length()*1000)
{for(i=0;i<newVertices.length;i++)
{newVertices[i].position.orbit(new Point(viewportSize.x/2,viewportSize.y/2),(viewportSize.x-diameter*2)/2,(viewportSize.y-diameter*2)/2,360*i/newVertices.length+startAngel);}}
else
{var count=10;var angle=360.0/count;var viewportAspect=viewportSize.x/viewportSize.y;var bestIndex=0;var graphSize=bbox.size();var bestAspect=graphSize.x/graphSize.y;var center=bbox.center();for(var i=1;i<count;i++)
{for(j=0;j<newVertices.length;j++)
{newVertices[j].position.rotate(center,angle);}
var newBBox=this.getGraphBBox();var newAspect=newBBox.size().x/newBBox.size().y;if(Math.abs(newAspect-viewportAspect)<Math.abs(bestAspect-viewportAspect))
{bestAspect=newAspect;bestIndex=i;}}
for(j=0;j<newVertices.length;j++)
{newVertices[j].position.rotate(center,-angle*(count-bestIndex-1));}}}
Graph.prototype.SetAdjacencyMatrix=function(matrix,viewportSize,currentEnumVerticesType,separator)
{if(separator===undefined)
{separator=",";}
var rowsObj={};var colsObj={};if(this.TestAdjacencyMatrix(matrix,rowsObj,colsObj,separator))
{rows=rowsObj.rows;cols=colsObj.cols;var clonedEdge=this.edges.slice(0);for(var i=0;i<clonedEdge.length;i++)
{this.DeleteEdge(clonedEdge[i]);}
var newVertices=[];var bWeightGraph=false;for(var i=0;i<rows.length;i++)
{for(var j=0;j<rows.length;j++)
{if(j>=this.vertices.length)
{var newPos=this.GetRandomPositionOfVertex(matrix,j,viewportSize);newVertices.push(new BaseVertex(newPos.x,newPos.y,currentEnumVerticesType));this.AddNewVertex(newVertices[newVertices.length-1]);}
if(cols[i][j]>0)
{var nEdgeIndex=this.AddNewEdgeSafe(this.vertices[i],this.vertices[j],cols[i][j]!=cols[j][i],cols[i][j],true);this.FixEdgeCurve(nEdgeIndex);if(nEdgeIndex>=0)
{bWeightGraph=bWeightGraph||this.edges[nEdgeIndex].weight!=1;}}}}
if(!bWeightGraph)
{this.edges.forEach(function(part,index,theArray){theArray[index].useWeight=false;});}
for(var i=rows.length;i<Math.max(this.vertices.length,rows.length);i++)
{this.DeleteVertex(this.vertices[i]);i--;}
this.VerticesReposition(viewportSize,newVertices);}}
Graph.prototype.SetPair=function(pairs,viewportSize,currentEnumVerticesType)
{if(this.TestPair(pairs))
{this.ClearGraph();let lines=pairs.split("\n");let regExp=[/^(.+)-(.+)$/g,/^(.+)\>(.+)$/g,/^(.+)<(.+)$/g,/^(.+)-\((\d+|\d+\.?\d+)\)-(.+)$/g,/^(.+)-\((\d+|\d+\.?\d+)\)\>(.+)$/g,/^(.+)<\((\d+|\d+\.?\d+)\)\-(.+)$/g,];let bWeightGraph=false;var newVertices=[];for(var i=0;i<lines.length;i++)
{let line=lines[i];if(line==""){continue;}
for(let j=regExp.length-1;j>=0;--j){if(!line.match(regExp[j])){continue;}
let groupes=Array.from(line.matchAll(regExp[j]));let groupe=groupes[0];let vetext1Title=groupe[1];let vertex1=this.FindVertexByTitle(vetext1Title);if(vertex1==null){let newPosition=this.GetRandomPosition(viewportSize);vertex1=this.vertices[this.AddNewVertex(new BaseVertex(newPosition.x,newPosition.y,currentEnumVerticesType))];vertex1.mainText=vetext1Title;newVertices.push(vertex1);}
let vetext2Title=groupe[j<=2?2:3];let vertex2=this.FindVertexByTitle(vetext2Title);if(vertex2==null){let newPosition=this.GetRandomPosition(viewportSize);vertex2=this.vertices[this.AddNewVertex(new BaseVertex(newPosition.x,newPosition.y,currentEnumVerticesType))];vertex2.mainText=vetext2Title;newVertices.push(vertex2);}
let isDirect=j==1||j==2||j==4||j==5;let weight=1;if(j>2){weight=groupe[2];bWeightGraph=true;}
let isRevertEdge=j==2||j==5;let nEdgeIndex=this.AddNewEdgeSafe(isRevertEdge?vertex2:vertex1,isRevertEdge?vertex1:vertex2,isDirect,weight,false);this.FixEdgeCurve(nEdgeIndex);break;}}
if(!bWeightGraph)
{this.edges.forEach(function(part,index,theArray){theArray[index].useWeight=false;});}
this.VerticesReposition(viewportSize,newVertices);}}
Graph.prototype.TestIncidenceMatrix=function(matrix,rowsObj,colsObj,separator)
{if(separator===undefined)
{separator=",";}
var bGoodFormat=true;rowsObj.rows=[];rowsObj.rows=matrix.split("\n");for(j=0;j<rowsObj.rows.length;++j)
{if(rowsObj.rows[j]==="")
{rowsObj.rows.splice(j--,1);}}
colsObj.cols=[];var columnCount=0;for(var i=0;i<rowsObj.rows.length;i++)
{colsObj.cols[i]=this.SplitMatrixString(rowsObj.rows[i],separator);for(j=0;j<colsObj.cols[i].length;++j)
{if(colsObj.cols[i][j]==="")
{colsObj.cols[i].splice(j--,1);}}
if(i==0)
{columnCount=colsObj.cols[i].length;}
if(colsObj.cols[i].length!=columnCount)
{bGoodFormat=false;break;}}
if(bGoodFormat)
{for(var i=0;i<colsObj.cols[0].length;i++)
{var values=[];for(j=0;j<colsObj.cols.length;++j)
{if(colsObj.cols[j][i]!=0)
{values.push(colsObj.cols[j][i]);}}
if(!(values.length<=1||(values.length==2&&(values[0]==values[1]||values[0]==-values[1]))))
{bGoodFormat=false;break;}}}
return bGoodFormat;}
Graph.prototype.SetIncidenceMatrix=function(matrix,viewportSize,currentEnumVerticesType)
{var rowsObj={};var colsObj={};if(this.TestIncidenceMatrix(matrix,rowsObj,colsObj))
{rows=rowsObj.rows;cols=colsObj.cols;var clonedEdge=this.edges.slice(0);for(var i=0;i<clonedEdge.length;i++)
{this.DeleteEdge(clonedEdge[i]);}
var newVertices=[];var bWeightGraph=false;for(var i=0;i<cols[0].length;i++)
{var edgeValue=[];var edgeIndex=[];for(var j=0;j<cols.length;j++)
{if(j>=this.vertices.length)
{var newPos=new Point(0,0);newVertices.push(new BaseVertex(newPos.x,newPos.y,currentEnumVerticesType));this.AddNewVertex(newVertices[newVertices.length-1]);}
if(cols[j][i]!=0)
{edgeValue.push(cols[j][i]);edgeIndex.push(j);}}
if(edgeIndex.length==1)
{edgeValue.push(edgeValue[0]);edgeIndex.push(edgeIndex[0]);}
if(edgeIndex.length==2)
{if(edgeValue[0]!=edgeValue[1])
{if(edgeValue[1]>0)
{edgeValue=edgeValue.swap(0,1);edgeIndex=edgeIndex.swap(0,1);}}
var nEdgeIndex=this.AddNewEdgeSafe(this.vertices[edgeIndex[0]],this.vertices[edgeIndex[1]],edgeValue[0]!=edgeValue[1],Math.abs(edgeValue[1]),false);this.FixEdgeCurve(nEdgeIndex);if(nEdgeIndex>=0)
{bWeightGraph=bWeightGraph||this.edges[nEdgeIndex].weight!=1;}}}
if(!bWeightGraph)
{this.edges.forEach(function(part,index,theArray){theArray[index].useWeight=false;});}
for(var i=cols.length;i<Math.max(this.vertices.length,cols.length);i++)
{this.DeleteVertex(this.vertices[i]);i--;}
this.VerticesReposition(viewportSize,newVertices);}}
Graph.prototype.GetIncidenceMatrix=function()
{var matrix="";for(var i=0;i<this.vertices.length;i++)
{for(var j=0;j<this.edges.length;j++)
{if(this.edges[j].vertex1==this.vertices[i])
{matrix+=this.edges[j].weight;}
else if(this.edges[j].vertex2==this.vertices[i]&&!this.edges[j].isDirect)
{matrix+=this.edges[j].weight;}
else if(this.edges[j].vertex2==this.vertices[i]&&this.edges[j].isDirect)
{matrix+=-this.edges[j].weight;}
else
{matrix+="0";}
if(j!=this.edges.length-1)
{matrix+=", ";}}
matrix=matrix+"\n";}
return matrix;}
Graph.prototype.SplitMatrixString=function(line,separator)
{if(separator===undefined)
{separator=",";}
var res=[];var i=0;var isZeroOneLine=true;for(i=0;i<line.length;i++)
{if(line.charAt(i)!='0'&&line.charAt(i)!='1')
{isZeroOneLine=false;break;}}
if(!isZeroOneLine)
{if(separator!=",")
{line=line.replace(/,/g,".");}
for(i=0;i<line.length;i++)
{if(("0123456789.-e").indexOf(line.charAt(i))<0)
{if(i>0)
{res.push(line.substr(0,i));}
if(i==0)
{i=1;}
line=line.substr(i,line.length-i);i=-1;}}
if(line.length>0)
{res.push(line);}}
else
{for(i=0;i<line.length;i++)
{res.push(line.charAt(i));}}
console.log(res);return res;}
Graph.prototype.SaveToXML=function(additionalData)
{var mainHeader="<?xml version=\"1.0\" encoding=\"UTF-8\"?><graphml>";var header="<graph id=\"Graph\" uidGraph=\""+this.uidGraph+"\""+" uidEdge=\""+this.uidEdge+"\">";var xmlBody="";for(var i=0;i<this.vertices.length;i++)
{xmlBody=xmlBody+this.vertices[i].SaveToXML();}
xmlBody=xmlBody+"";for(var i=0;i<this.edges.length;i++)
{xmlBody=xmlBody+this.edges[i].SaveToXML();}
xmlBody=xmlBody+"";additionalField="";if(additionalData.length>0)
{additionalField="<additional data=\""+additionalData+"\"/>"}
return mainHeader+header+xmlBody+"</graph>"+additionalField+"</graphml>";}
Graph.prototype.LoadFromXML=function(xmlText,additionalData)
{xmlDoc=$.parseXML(xmlText);var $xml=$(xmlDoc);$graphs=$xml.find("graph");var loadedGraphId=0;var loadedEdgeId=0;$graphs.each(function(){loadedGraphId=parseInt($(this).attr('uidGraph'));loadedEdgeId=parseInt($(this).attr('uidEdge'));});if(isNaN(loadedEdgeId))
{loadedEdgeId=this.edgesOffset;}else if(loadedEdgeId<this.edgesOffset)
{loadedEdgeId=this.edgesOffset;}
this.uidGraph=loadedGraphId;this.uidEdge=loadedEdgeId;$nodes=$xml.find("node");var vertices=[];$nodes.each(function(){var vertex=new BaseVertex();vertex.LoadFromXML($(this));vertices.push(vertex);});this.vertices=vertices;$edges=$xml.find("edge");var edges=[];var graph=this;$edges.each(function(){var edge=new BaseEdge();edge.LoadFromXML($(this),graph);if(edge.id<graph.uidEdge){edge.id=graph.uidEdge;graph.uidEdge++;}
edges.push(edge);});this.edges=edges;$additional=$xml.find("additional");if($additional.length!=0&&additionalData!=null)
{additionalData["data"]=$additional.attr('data');}
this.isMultiGraph=this.checkMutiGraph();}
Graph.prototype.hasDirectEdge=function()
{var res=false;for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].isDirect)
{res=true;break;}}
return res;}
Graph.prototype.hasUndirectEdge=function()
{var res=false;for(var i=0;i<this.edges.length;i++)
{if(!this.edges[i].isDirect)
{res=true;break;}}
return res;}
Graph.prototype.hasEdges=function()
{return this.edges.length>0;}
Graph.prototype.clampPositions=function(viewportSize)
{var diameter=(new VertexModel()).diameter;for(i=0;i<this.vertices.length;i++)
{this.vertices[i].position.x=Math.min(Math.max(this.vertices[i].position.x,diameter),viewportSize.x-diameter);this.vertices[i].position.y=Math.min(Math.max(this.vertices[i].position.y,diameter),viewportSize.y-diameter);}}
Graph.prototype.getGraphBBox=function(viewportSize)
{var pointMin=new Point(1e5,1e5);var pointMax=new Point(-1e5,-1e5);var diameter=(new VertexModel()).diameter;for(i=0;i<this.vertices.length;i++)
{var vertex=this.vertices[i];var factor=vertex.diameterFactor();var deltaVector=new Point(factor.x*diameter,factor.y*diameter);pointMin=pointMin.min(vertex.position.subtract(deltaVector));pointMax=pointMax.max(vertex.position.add(deltaVector));}
var max_curve_length=32;for(i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if(edge.model.type==EdgeModels.curve)
{var max_curve=edge.vertex2.position.subtract(edge.vertex1.position).length()/max_curve_length;for(j=0;j<max_curve;j++)
{var point=edge.model.GetCurvePoint(edge.vertex1.position,edge.vertex2.position,j/max_curve);var deltaVector=new Point(max_curve_length,max_curve_length);pointMin=pointMin.min(point.subtract(deltaVector));pointMax=pointMax.max(point.add(deltaVector));}}}
return new Rect(pointMin,pointMax);}
Graph.prototype.hasPair=function(edge)
{return this.FindPairFor(edge)!=null;}
Graph.prototype.FindPairFor=function(edge)
{var res=this.getNeighborEdges(edge);return res.length==1?res[0]:null;}
Graph.prototype.getNeighborEdges=function(edge)
{var res=[];for(var i=0;i<this.edges.length;i++)
{var curEdge=this.edges[i];if(curEdge==edge)
continue;if((curEdge.vertex1.id==edge.vertex1.id&&curEdge.vertex2.id==edge.vertex2.id)||(curEdge.vertex1.id==edge.vertex2.id&&curEdge.vertex2.id==edge.vertex1.id))
{res.push(curEdge);}}
return res;}
Graph.prototype.checkMutiGraph=function()
{var res=false;var start={};for(var i=0;i<this.edges.length;i++)
{var edge=this.edges[i];if(start.hasOwnProperty(edge.vertex1.id)&&start[edge.vertex1.id]==edge.vertex2.id)
{res=true;break;}
start[edge.vertex1.id]=edge.vertex2.id;if(!edge.isDirect)
{if(start.hasOwnProperty(edge.vertex2.id)&&start[edge.vertex2.id]==edge.vertex1.id)
{res=true;break;}
start[edge.vertex2.id]=edge.vertex1.id;}}
return res;}
Graph.prototype.isMulti=function()
{return this.isMultiGraph;}
Graph.prototype.isNeedReposition=function()
{var res=false;for(var i=0;i<this.vertices.length;i++)
{res=res||this.vertices[i].IsUndefinedPosition();}
return res;}
Graph.prototype.FixEdgeCurve=function(edgeIndex)
{var edgeObject=this.edges[edgeIndex];var hasPair=this.hasPair(edgeObject);var neighborEdges=this.getNeighborEdges(edgeObject);if(hasPair)
{if(edgeObject.model.default)
edgeObject.model.type=EdgeModels.curve;var pairEdge=this.FindPairFor(edgeObject);if(pairEdge.model.default)
{pairEdge.model.type=EdgeModels.curve;if(pairEdge.vertex1==edgeObject.vertex1&&pairEdge.vertex2==edgeObject.vertex2)
pairEdge.model.curveValue=-pairEdge.model.curveValue;}}
else if(neighborEdges.length>=2)
{var curve=this.GetAvailableCurveValue(neighborEdges,edgeObject);if(edgeObject.model.default)
{edgeObject.model.type=EdgeModels.curve;edgeObject.model.curveValue=curve;}}}
Graph.prototype.GetAvailableCurveValue=function(neighborEdges,originalEdge)
{var values=[];for(var i=0;i<neighborEdges.length;i++)
{var edge=neighborEdges[i];var sameDirection=(originalEdge.vertex1.id==edge.vertex1.id);if(edge.model.type==EdgeModels.curve)
{values[(sameDirection?edge.model.curveValue:-edge.model.curveValue)]=true;}}
var changeValue=DefaultHandler.prototype.curveValue;var defaultValue=0.0;var maxSearch=10;for(var i=1;i<maxSearch;i++)
{value=i*changeValue;if(!values.hasOwnProperty(value))
return value;value=-i*changeValue;if(!values.hasOwnProperty(value))
return value;}
return defaultValue;}
Graph.prototype.reverseAllEdges=function()
{for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].isDirect)
{let v1=this.edges[i].vertex1;this.edges[i].vertex1=this.edges[i].vertex2;this.edges[i].vertex2=v1;}}
this.isMultiGraph=this.checkMutiGraph();}
Graph.prototype.makeAllEdgesDirected=function()
{for(var i=0;i<this.edges.length;i++)
{if(!this.edges[i].isDirect)
{this.edges[i].isDirect=true;}}
this.isMultiGraph=this.checkMutiGraph();}
Graph.prototype.makeAllEdgesUndirected=function()
{for(var i=0;i<this.edges.length;i++)
{if(this.edges[i].isDirect)
{this.edges[i].isDirect=false;}}
this.isMultiGraph=this.checkMutiGraph();}
window.onload=function()
{if(document.getElementById('CreateByAdjacencyMatrix'))
{document.getElementById('CreateByAdjacencyMatrix').onclick=function()
{window.location="./?matrix="+$("#AdjacencyMatrixFieldPage").val();}}}
var g_MatrixSize=3;var g_ctrlPressed=false;function PackMatrix()
{var matrix="";for(i=0;i<g_MatrixSize;i++)
{for(j=0;j<g_MatrixSize;j++)
{var element=document.getElementsByName("field"+i+"_"+j)[0];matrix=matrix+(element.value.length>0?element.value:"0")+", ";}
matrix=matrix+"\n";}
return matrix;}
function getCharCode(event)
{if(event.which==null)
{return event.keyCode;}
if(event.which!=0)
{return event.which;}
return null;}
function getChar(event)
{var k=getCharCode(event)
return String.fromCharCode(k);}
function CopyMatrixToTextInput(event)
{document.getElementById("AdjacencyMatrixFieldPage").value=PackMatrix();if(event)
{var key=getChar(event);var code=getCharCode(event);console.log(key+" code="+code);if(g_ctrlPressed)
{var moveFocus=function(offsetX,offsetY)
{var focused_element=document.activeElement;if(focused_element&&focused_element.name.includes("field"))
{var name=focused_element.name;var coords=name.replace('field','').split("_");if(coords.length==2)
{var focusName="field"+(parseInt(coords[0])+offsetY)+"_"+(parseInt(coords[1])+offsetX)
var element=document.getElementsByName(focusName)[0];if(element)
{element.focus();}}}}
switch(code)
{case 38:{moveFocus(0,-1);break;}
case 40:{moveFocus(0,1);break;}
case 37:{moveFocus(-1,0);break;}
case 39:{moveFocus(1,0);break;}}}}}
function _ShowTextInput()
{$("#AdjacencyMatrixFieldPage").show();$("#MatrixForm").hide();$("#TextDescription").show();$("#MatrixDescription").hide();$("#idSeparatorList").show();}
function _ShowMatrixInput()
{$("#MatrixForm").show();$("#AdjacencyMatrixFieldPage").hide();$("#TextDescription").hide();$("#MatrixDescription").show();$("#idSeparatorList").hide();}
function ShowTextInput()
{_ShowTextInput();document.getElementById("showMatrix").className="btn btn-default";document.getElementById("showText").className="btn btn-default active";}
function ShowMatrixInput()
{_ShowMatrixInput();document.getElementById("showMatrix").className="btn btn-default active";document.getElementById("showText").className="btn btn-default";}
function CopyMatrixToMatrixInput()
{var graph=new Graph();var colsObj={};var rowsObj={};if(graph.TestAdjacencyMatrix($("#AdjacencyMatrixFieldPage").val(),rowsObj,colsObj))
{var rows=rowsObj.rows;var cols=colsObj.cols;for(var i=g_MatrixSize;i<rows.length;i++)
{IncSize();}
for(var i=0;i<rows.length;i++)
{for(var j=0;j<rows.length;j++)
{var element=document.getElementsByName("field"+i+"_"+j)[0];element.value=cols[i][j];}}}
else
{ShowTextInput();}}
function CreateInputElement(col,row)
{var input=document.createElement("input");input.type="text";input.size=3;input.name="field"+col+"_"+row;input.value=0;input.onkeyup=function(event){CopyMatrixToTextInput(event);};return input;}
function InsertBeforeElement(element,beforeName,space)
{var parent=document.getElementsByName(beforeName)[0].parentNode;var beforeElement=document.getElementsByName(beforeName)[0];parent.insertBefore(element,beforeElement);if(space)
{parent.insertBefore(document.createTextNode('\u00A0'),beforeElement);}}
function IncSize()
{for(var i=0;i<g_MatrixSize;i++)
{var input=CreateInputElement(g_MatrixSize,i);InsertBeforeElement(input,"matrixEnd",true);}
var br=document.createElement("br");br.setAttribute("name","row"+g_MatrixSize);InsertBeforeElement(br,"matrixEnd",false);for(var i=0;i<g_MatrixSize+1;i++)
{var input=CreateInputElement(i,g_MatrixSize);InsertBeforeElement(input,"row"+i,g_MatrixSize);}
g_MatrixSize++;CopyMatrixToTextInput();}
function checkFormat()
{var graph=new Graph();var separator=$("#spaceSep").is(':checked')?" ":",";if(!graph.TestAdjacencyMatrix($("#AdjacencyMatrixFieldPage").val(),[],[],separator))
{$("#BadFormatMessage").show();}
else
{$("#BadFormatMessage").hide();}}
window.onload=function()
{if(document.getElementById('CreateByAdjacencyMatrix'))
{document.getElementById('CreateByAdjacencyMatrix').onclick=function()
{$("#matrixForm").submit();}}
$("#AdjacencyMatrixFieldPage").on('keyup change',function(eventObject)
{checkFormat();});$("#BadFormatMessage").hide();$("#AdjacencyMatrixFieldPage").hide();$("#showMatrix").on('click',function(eventObject)
{_ShowMatrixInput();});$("#showText").on('click',function(eventObject)
{_ShowTextInput();});$('input:radio[name="separator"]').change(function(){checkFormat()});CopyMatrixToMatrixInput();$(document).keydown(function(event){if(event.which=="17"||event.which=="91")
g_ctrlPressed=true;});$(document).keyup(function(event){if(event.which=="17"||event.which=="91")
g_ctrlPressed=false;});}
moduleLoader.endCacheLoading();
File renamed without changes.
@@ -0,0 +1,272 @@
// Current matrix size
var g_MatrixSize = 3;
var g_ctrlPressed = false;
function PackMatrix()
{
var matrix = "";
for (i = 0; i < g_MatrixSize; i++)
{
for (j = 0; j < g_MatrixSize; j++)
{
var element = document.getElementsByName("field" + i + "_" + j)[0];
matrix = matrix + (element.value.length > 0 ? element.value : "0") + ", ";
}
matrix = matrix + "\n";
}
return matrix;
}
function getCharCode(event)
{
if (event.which == null)
{ // IE
return event.keyCode;
}
if (event.which != 0)
{ // ��� ����� IE
return event.which; // ���������
}
return null; // ����. ������
}
function getChar(event)
{
var k = getCharCode(event)
return String.fromCharCode(k); // ���������
}
function CopyMatrixToTextInput(event)
{
document.getElementById("AdjacencyMatrixFieldPage").value = PackMatrix();
// Move between cells.
if (event)
{
var key = getChar(event);
var code = getCharCode(event);
console.log(key + " code=" + code);
if (g_ctrlPressed)
{
var moveFocus = function(offsetX, offsetY)
{
var focused_element = document.activeElement;
if (focused_element && focused_element.name.includes("field"))
{
var name = focused_element.name;
var coords = name.replace('field','').split("_");
if (coords.length == 2)
{
var focusName = "field" + (parseInt(coords[0]) + offsetY) + "_" + (parseInt(coords[1]) + offsetX)
var element = document.getElementsByName(focusName)[0];
if (element)
{
element.focus();
}
}
}
}
switch (code)
{
case 38: // Up
{
moveFocus(0, -1);
break;
}
case 40: // Down
{
moveFocus(0, 1);
break;
}
case 37: // Left
{
moveFocus(-1, 0);
break;
}
case 39: // Right
{
moveFocus(1, 0);
break;
}
}
}
}
}
function _ShowTextInput()
{
$( "#AdjacencyMatrixFieldPage" ).show();
$( "#MatrixForm" ).hide();
$( "#TextDescription").show();
$( "#MatrixDescription").hide();
$( "#idSeparatorList").show();
}
function _ShowMatrixInput()
{
$( "#MatrixForm" ).show();
$( "#AdjacencyMatrixFieldPage" ).hide();
$( "#TextDescription").hide();
$( "#MatrixDescription").show();
$( "#idSeparatorList").hide();
}
function ShowTextInput()
{
_ShowTextInput();
document.getElementById("showMatrix").className = "btn btn-default";
document.getElementById("showText").className = "btn btn-default active";
}
function ShowMatrixInput()
{
_ShowMatrixInput();
document.getElementById("showMatrix").className = "btn btn-default active";
document.getElementById("showText").className = "btn btn-default";
}
function CopyMatrixToMatrixInput()
{
var graph = new Graph();
var colsObj = {};
var rowsObj = {};
if (graph.TestAdjacencyMatrix($( "#AdjacencyMatrixFieldPage" ).val(), rowsObj, colsObj))
{
var rows = rowsObj.rows;
var cols = colsObj.cols;
for (var i = g_MatrixSize; i < rows.length; i++)
{
IncSize();
}
for (var i = 0; i < rows.length; i++)
{
for (var j = 0; j < rows.length; j++)
{
var element = document.getElementsByName("field" + i + "_"+ j)[0];
element.value = cols[i][j];
}
}
}
else
{
ShowTextInput();
}
}
function CreateInputElement(col, row)
{
var input = document.createElement("input");
input.type = "text";
input.size = 3;
input.name = "field" + col + "_" + row;
input.value = 0;
input.onkeyup = function(event) {CopyMatrixToTextInput(event);};
return input;
}
function InsertBeforeElement(element, beforeName, space)
{
var parent = document.getElementsByName(beforeName)[0].parentNode;
var beforeElement = document.getElementsByName(beforeName)[0];
parent.insertBefore(element, beforeElement);
if (space)
{
// Insert space
parent.insertBefore(document.createTextNode( '\u00A0' ), beforeElement);
}
}
function IncSize()
{
// End one more line:
for (var i = 0; i < g_MatrixSize; i ++)
{
var input = CreateInputElement(g_MatrixSize, i);
InsertBeforeElement(input, "matrixEnd", true);
}
var br = document.createElement("br");
br.setAttribute("name", "row" + g_MatrixSize);
InsertBeforeElement(br, "matrixEnd", false);
for (var i = 0; i < g_MatrixSize + 1; i ++)
{
var input = CreateInputElement(i, g_MatrixSize);
InsertBeforeElement(input, "row" + i, g_MatrixSize);
}
g_MatrixSize++;
CopyMatrixToTextInput();
}
function checkFormat()
{
var graph = new Graph();
var separator = $("#spaceSep").is(':checked') ? " " : ",";
if (!graph.TestAdjacencyMatrix($( "#AdjacencyMatrixFieldPage" ).val(), [], [], separator))
{
$( "#BadFormatMessage" ).show();
}
else
{
$( "#BadFormatMessage" ).hide();
}
}
window.onload = function ()
{
if (document.getElementById('CreateByAdjacencyMatrix'))
{
document.getElementById('CreateByAdjacencyMatrix').onclick = function ()
{
$("#matrixForm").submit();
//window.location = "./?matrix=" + $( "#AdjacencyMatrixFieldPage" ).val().replace(/\n/g,'%0A');
}
}
$( "#AdjacencyMatrixFieldPage" ).on('keyup change', function (eventObject)
{
checkFormat();
});
$( "#BadFormatMessage" ).hide();
$( "#AdjacencyMatrixFieldPage" ).hide();
$( "#showMatrix" ).on('click', function (eventObject)
{
_ShowMatrixInput();
});
$( "#showText" ).on('click', function (eventObject)
{
_ShowTextInput();
});
$('input:radio[name="separator"]').change( function(){
checkFormat()
});
CopyMatrixToMatrixInput();
$(document).keydown(function(event) {
if (event.which == "17" || event.which == "91")
g_ctrlPressed = true;
});
$(document).keyup(function(event) {
if (event.which == "17" || event.which == "91")
g_ctrlPressed = false;
});
}
+55
View File
@@ -0,0 +1,55 @@
// Global version needs to force reload scripts from server.
globalVersion = 75;
{
let asyncFilesLoad = null;
function onloadEditor() {
console.log("onload() call");
asyncFilesLoad();
preLoadPage();
postLoadPage();
}
let modulDir = "pages/editor/";
doInclude ([
include ("shared/utils.js"),
include ("entities/graph/api/index.js"),
include ("features/draw_graph/api/index.js"),
include ("features/algorithms/api/index.js"),
include ("features/base_handler/index.js"),
include ("features/default_handler/index.js"),
include ("features/add_vertices_handler/index.js"),
include ("features/connect_vertices_handler/index.js"),
include ("features/delete_objects_handler/index.js"),
include ("features/algorithm_handler/index.js"),
include ("features/serialization/api/index.js"),
include ("features/enum_vertices/EnumVertices.js"),
include ("model/texts.js", modulDir),
include ("model/Application.js", modulDir),
include ("ui/main.js", modulDir)],
onloadEditor);
asyncFilesLoad = function () {
doIncludeAsync ([
include ("shared/canvas2svg.js"),
include ("features/group_rename_handler/index.js"),
include ("features/saved_graph_handler/index.js"),
include ("features/saved_graph_image_handler/index.js"),
include ("features/show_adjacency_matrix/index.js"),
include ("features/show_distance_matrix/index.js"),
include ("features/show_incidence_matrix/index.js"),
include ("features/setup_background_style/index.js"),
include ("features/setup_edge_style/index.js"),
include ("features/setup_vertex_style/index.js"),
]);
}
}
File diff suppressed because it is too large. Load diff
File renamed without changes.
@@ -420,10 +420,4 @@ function loadTexts()
g_wrongImageFormatPNGAndJPEG = document.getElementById("wrongImageFormatPNGAndJPEG").innerHTML; g_wrongImageFormatPNGAndJPEG = document.getElementById("wrongImageFormatPNGAndJPEG").innerHTML;
g_wrongImageSizeP1 = document.getElementById("wrongImageSizeP1").innerHTML; g_wrongImageSizeP1 = document.getElementById("wrongImageSizeP1").innerHTML;
} }
function formatString(string, params) {
return string.replace(/{(\d+)}/g, (match, index) => {
return typeof params[index] !== 'undefined' ? params[index] : match;
});
}
@@ -1,5 +1,4 @@
var SiteDir = "";
var DisableEmscripten = false; var DisableEmscripten = false;
var algorithmsVersion = 2; var algorithmsVersion = 2;
@@ -33,7 +32,7 @@ var g_ctrlPressed = false;
function restButtons (me) function restButtons (me)
{ {
var needSetDefault = false; var needSetDefault = false;
for (var i = 0; i < buttonsList.length; i ++) for (let i = 0; i < buttonsList.length; i ++)
{ {
if (buttonsList[i] != me) if (buttonsList[i] != me)
{ {
@@ -49,7 +48,7 @@ function restButtons (me)
} }
if (needSetDefault) if (needSetDefault)
{ {
document.getElementById(buttonsList[i]).className = "btn btn-primary btn-sm"; document.getElementById(me).className = "btn btn-primary btn-sm";
} }
else else
{ {
@@ -651,31 +650,7 @@ function postLoadPage()
} }
// Get algorithms list and load it. // Get algorithms list and load it.
$.get( "/" + SiteDir + "cgi-bin/getPluginsList.php", loadAsyncAlgorithms(createAlgorithmMenu);
function( data )
{
var scriptList = JSON.parse(data);
var loadOneScript = function()
{
if (scriptList.length == 0)
{
createAlgorithmMenu();
}
else
{
var script = document.createElement('script');
script.src = "/" + SiteDir + "script/" + scriptList[0] + "?v=" + algorithmsVersion;
scriptList.shift();
script.onload = loadOneScript;
script.onerror = loadOneScript;
document.head.appendChild(script);
}
}
loadOneScript();
});
var devTools = document.getElementById('developerTools'); var devTools = document.getElementById('developerTools');
devTools.style.left = 0; devTools.style.left = 0;
@@ -743,16 +718,16 @@ $(document).ready(function ()
// Try load emscripten implementation // Try load emscripten implementation
var isMobile = navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i); var isMobile = navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i);
if (!isMobile && !DisableEmscripten) { if (!isMobile && !DisableEmscripten) {
const jsScript = document.createElement('script'); let fullPathToGraphffoline = "features/graphoffline/Graphoffline.Emscripten.js";
jsScript.src = '/script/Graphoffline.Emscripten.js?v=1'; doIncludeAsync ([
document.body.appendChild(jsScript); include (fullPathToGraphffoline),
jsScript.addEventListener('load', () => { ], () => {
Module['onRuntimeInitialized'] = onRuntimeInitialized; Module['onRuntimeInitialized'] = onRuntimeInitialized;
var process = Module.cwrap('ProcessAlgorithm', 'string', ['string']); var process = Module.cwrap('ProcessAlgorithm', 'string', ['string']);
function onRuntimeInitialized() { function onRuntimeInitialized() {
application.setEmscripten(process); application.setEmscripten(process);
} }
}); })
} }
/* /*
$(document).ready(function(){ $(document).ready(function(){
File renamed without changes.
+2
View File
@@ -0,0 +1,2 @@
let SiteDir = ""; // Used for load from sub directory
let UseCache = true;
+199
View File
@@ -0,0 +1,199 @@
var include = function(filename, localDir) {
return {filename: filename, localDir: localDir};
};
class ModuleLoader {
constructor(name) {
this.loadingStack = [];
this.startedLoading = new Set();
this.loaded = new Set();
this.isRunningSync = false;
this.syncLoaded = [];
this.cacheLoading = false;
this.callsAfterCacheResolve = [];
}
getFullname = function (filename, localDir)
{
let versionParam = "";
if (typeof globalVersion !== 'undefined') {
versionParam = "?v=" + globalVersion;
}
let localDirParam = "";
if (typeof localDir !== 'undefined') {
localDirParam = localDir;
}
return "/" + SiteDir + "script/" + localDirParam + filename + "?v=" + globalVersion;
}
isAllLoaded = function (includes)
{
self = this;
return includes.every((inc) => {
return self.loaded.has(inc);
});
}
load = function (fullFilename, checkQueue, sync) {
let self = this;
let loadError = function()
{
console.error("Cannot load " + fullFilename);
checkQueue();
}
let loadSuccess = function()
{
self.loaded.add(fullFilename);
console.log(self.loaded.size + ". " + fullFilename);
checkQueue();
}
if (this.loaded.has(fullFilename)) {
this.isRunning = true;
checkQueue();
return;
}
var script = document.createElement('script');
script.src = fullFilename;
script.onload = loadSuccess;
script.onerror = loadError;
document.head.appendChild(script);
this.isRunning = true;
if (sync) {
this.syncLoaded.push(fullFilename);
}
}
loadFromQueue = function (checkQueue) {
if (this.loadingStack.length == 0) {
return;
}
let fullFilename = this.loadingStack.pop();
this.load(fullFilename, checkQueue, true);
this.isRunning = true;
}
// Load modules one by one in sync mode.
// Call fullLoadedCallback when all modules loaded.
doInclude = function (includes, fullLoadedCallback) {
let self = this;
if (this.cacheLoading) {
this.callsAfterCacheResolve.push(
function() {
self.doInclude(includes, fullLoadedCallback);
}
);
return;
}
let checkQueue = function () {
if (self.loadingStack.length != 0) {
self.loadFromQueue(checkQueue);
return;
}
self.isRunning = false;
if (typeof fullLoadedCallback === 'undefined' || fullLoadedCallback === null) {
return;
}
fullLoadedCallback();
}
let pushToQueue = function (fullFilename) {
self.loadingStack.push(fullFilename)
self.startedLoading.add(fullFilename);
}
let reversedIncludes = includes.reverse();
reversedIncludes.forEach((inc) => {
let fullFilename = self.getFullname(inc.filename, inc.localDir);
if (self.startedLoading.has(fullFilename)) {
return;
}
pushToQueue(fullFilename)
});
if (!self.isRunning) {
checkQueue();
}
}
// Load modules async start load all modules.
// Call fullLoadedCallback when all includes loaded.
doIncludeAsync = function (includes, fullLoadedCallback) {
let self = this;
if (this.cacheLoading) {
this.callsAfterCacheResolve.push(
function() {
self.doIncludeAsync(includes, fullLoadedCallback);
}
);
return;
}
let includesFull = [];
let checkLoading = function () {
self.isRunning = false;
if (typeof fullLoadedCallback === 'undefined' || fullLoadedCallback === null) {
return;
}
if (!self.isAllLoaded(includesFull)) {
return;
}
fullLoadedCallback();
}
let pushToQueue = function (fullFilename) {
self.load(fullFilename, checkLoading, false);
self.startedLoading.add(fullFilename);
}
let reversedIncludes = includes.reverse();
reversedIncludes.forEach((inc) => {
let fullFilename = self.getFullname(inc.filename, inc.localDir);
includesFull.push(fullFilename);
if (self.startedLoading.has(fullFilename)) {
return;
}
pushToQueue(fullFilename)
});
checkLoading();
}
beginCacheLoading = function (cachedFiles) {
let self = this;
cachedFiles.forEach((file) => {
self.startedLoading.add(file);
self.loaded.add(file);
});
this.cacheLoading = true;
}
endCacheLoading = function () {
this.cacheLoading = false;
this.callsAfterCacheResolve.forEach((func) => {
func();
});
}
}
let moduleLoader = new ModuleLoader();
function doInclude(includes, callback) {
moduleLoader.doInclude(includes, callback);
}
function doIncludeAsync(includes, callback) {
moduleLoader.doIncludeAsync(includes, callback);
}
View File
File renamed without changes.
+7 -1
View File
@@ -41,4 +41,10 @@ function FullArrayCopy(arr)
}); });
return res; return res;
} }
function formatString(string, params) {
return string.replace(/{(\d+)}/g, (match, index) => {
return typeof params[index] !== 'undefined' ? params[index] : match;
});
}
+3 -2
View File
@@ -1,11 +1,12 @@
<head> <head>
<link rel="stylesheet" type="text/css" href="<?= Root('i/css/create_graph_by_pair.css')?>" /> <link rel="stylesheet" type="text/css" href="<?= Root('i/css/create_graph_by_pair.css')?>" />
<script src="<?= Root('script/Graph.js')?>"></script> <script src="<?= RootCacheJS("script/shared/config.js")?>" ></script>
<script src="<?= RootCacheJS("script/shared/loader.js")?>" ></script>
<script src="<?= RootCacheJS('script/pages/create_graph_by_edge_list/api/index.js')?>"></script>
</head> </head>
<script> <script>
function checkFormat() function checkFormat()
{ {
var graph = new Graph(); var graph = new Graph();
+5 -3
View File
@@ -1,6 +1,8 @@
<head> <head>
<link rel="stylesheet" type="text/css" href="<?= Root('i/css/create_graph_by_incidence_matrix.css')?>" /> <link rel="stylesheet" type="text/css" href="<?= Root('i/css/create_graph_by_incidence_matrix.css')?>" />
<script src="<?= Root('script/Graph.js')?>"></script> <script src="<?= RootCacheJS("script/shared/config.js")?>" ></script>
<script src="<?= RootCacheJS("script/shared/loader.js")?>" ></script>
<script src="<?= RootCacheJS('script/pages/create_graph_by_incidence_matrix/api/index.js')?>"></script>
</head> </head>
<script> <script>
@@ -304,11 +306,11 @@ window.onload = function ()
<form action="./" method="post" id="matrixForm"> <form action="./" method="post" id="matrixForm">
<textarea name="incidenceMatrix" id="IncidenceMatrixFieldPage" wrap="off" style="display: none;"> <textarea name="incidenceMatrix" id="IncidenceMatrixFieldPage" wrap="off" style="display: none;">
<? if (!isset($_GET["incidenceMatrix"])): ?> <?php if (!isset($_GET["incidenceMatrix"])): ?>
1, 0 1, 0
1, 1 1, 1
0, -1 0, -1
<? else: ?><?= $_GET["incidenceMatrix"] ?><? endif;?></textarea> <?php else: ?><?= $_GET["incidenceMatrix"] ?><?php endif;?></textarea>
</form> </form>
<div id="MatrixForm"> <div id="MatrixForm">
<form id="AdjacencyMatrixFieldInput" role="form"> <form id="AdjacencyMatrixFieldInput" role="form">
+5 -285
View File
@@ -1,287 +1,10 @@
<head> <head>
<link rel="stylesheet" type="text/css" href="<?= Root('i/css/create_graph_by_matrix.css')?>" /> <link rel="stylesheet" type="text/css" href="<?= Root('i/css/create_graph_by_matrix.css')?>" />
<script src="<?= Root('script/Graph.js')?>"></script> <script src="<?= RootCacheJS("script/shared/config.js")?>" ></script>
<script src="<?= RootCacheJS("script/shared/loader.js")?>" ></script>
<script src="<?= RootCacheJS('script/pages/create_graph_by_matrix/api/index.js')?>"></script>
</head> </head>
<script>
// Current matrix size
var g_MatrixSize = 3;
var g_ctrlPressed = false;
function PackMatrix()
{
var matrix = "";
for (i = 0; i < g_MatrixSize; i++)
{
for (j = 0; j < g_MatrixSize; j++)
{
var element = document.getElementsByName("field" + i + "_" + j)[0];
matrix = matrix + (element.value.length > 0 ? element.value : "0") + ", ";
}
matrix = matrix + "\n";
}
return matrix;
}
function getCharCode(event)
{
if (event.which == null)
{ // IE
return event.keyCode;
}
if (event.which != 0)
{ // все кроме IE
return event.which; // остальные
}
return null; // спец. символ
}
function getChar(event)
{
var k = getCharCode(event)
return String.fromCharCode(k); // остальные
}
function CopyMatrixToTextInput(event)
{
document.getElementById("AdjacencyMatrixFieldPage").value = PackMatrix();
// Move between cells.
if (event)
{
var key = getChar(event);
var code = getCharCode(event);
console.log(key + " code=" + code);
if (g_ctrlPressed)
{
var moveFocus = function(offsetX, offsetY)
{
var focused_element = document.activeElement;
if (focused_element && focused_element.name.includes("field"))
{
var name = focused_element.name;
var coords = name.replace('field','').split("_");
if (coords.length == 2)
{
var focusName = "field" + (parseInt(coords[0]) + offsetY) + "_" + (parseInt(coords[1]) + offsetX)
var element = document.getElementsByName(focusName)[0];
if (element)
{
element.focus();
}
}
}
}
switch (code)
{
case 38: // Up
{
moveFocus(0, -1);
break;
}
case 40: // Down
{
moveFocus(0, 1);
break;
}
case 37: // Left
{
moveFocus(-1, 0);
break;
}
case 39: // Right
{
moveFocus(1, 0);
break;
}
}
}
}
}
function _ShowTextInput()
{
$( "#AdjacencyMatrixFieldPage" ).show();
$( "#MatrixForm" ).hide();
$( "#TextDescription").show();
$( "#MatrixDescription").hide();
$( "#idSeparatorList").show();
}
function _ShowMatrixInput()
{
$( "#MatrixForm" ).show();
$( "#AdjacencyMatrixFieldPage" ).hide();
$( "#TextDescription").hide();
$( "#MatrixDescription").show();
$( "#idSeparatorList").hide();
}
function ShowTextInput()
{
_ShowTextInput();
document.getElementById("showMatrix").className = "btn btn-default";
document.getElementById("showText").className = "btn btn-default active";
}
function ShowMatrixInput()
{
_ShowMatrixInput();
document.getElementById("showMatrix").className = "btn btn-default active";
document.getElementById("showText").className = "btn btn-default";
}
function CopyMatrixToMatrixInput()
{
var graph = new Graph();
var colsObj = {};
var rowsObj = {};
if (graph.TestAdjacencyMatrix($( "#AdjacencyMatrixFieldPage" ).val(), rowsObj, colsObj))
{
var rows = rowsObj.rows;
var cols = colsObj.cols;
for (var i = g_MatrixSize; i < rows.length; i++)
{
IncSize();
}
for (var i = 0; i < rows.length; i++)
{
for (var j = 0; j < rows.length; j++)
{
var element = document.getElementsByName("field" + i + "_"+ j)[0];
element.value = cols[i][j];
}
}
}
else
{
ShowTextInput();
}
}
function CreateInputElement(col, row)
{
var input = document.createElement("input");
input.type = "text";
input.size = 3;
input.name = "field" + col + "_" + row;
input.value = 0;
input.onkeyup = function(event) {CopyMatrixToTextInput(event);};
return input;
}
function InsertBeforeElement(element, beforeName, space)
{
var parent = document.getElementsByName(beforeName)[0].parentNode;
var beforeElement = document.getElementsByName(beforeName)[0];
parent.insertBefore(element, beforeElement);
if (space)
{
// Insert space
parent.insertBefore(document.createTextNode( '\u00A0' ), beforeElement);
}
}
function IncSize()
{
// End one more line:
for (var i = 0; i < g_MatrixSize; i ++)
{
var input = CreateInputElement(g_MatrixSize, i);
InsertBeforeElement(input, "matrixEnd", true);
}
var br = document.createElement("br");
br.setAttribute("name", "row" + g_MatrixSize);
InsertBeforeElement(br, "matrixEnd", false);
for (var i = 0; i < g_MatrixSize + 1; i ++)
{
var input = CreateInputElement(i, g_MatrixSize);
InsertBeforeElement(input, "row" + i, g_MatrixSize);
}
g_MatrixSize++;
CopyMatrixToTextInput();
}
function checkFormat()
{
var graph = new Graph();
var separator = $("#spaceSep").is(':checked') ? " " : ",";
if (!graph.TestAdjacencyMatrix($( "#AdjacencyMatrixFieldPage" ).val(), [], [], separator))
{
$( "#BadFormatMessage" ).show();
}
else
{
$( "#BadFormatMessage" ).hide();
}
}
window.onload = function ()
{
if (document.getElementById('CreateByAdjacencyMatrix'))
{
document.getElementById('CreateByAdjacencyMatrix').onclick = function ()
{
$("#matrixForm").submit();
//window.location = "./?matrix=" + $( "#AdjacencyMatrixFieldPage" ).val().replace(/\n/g,'%0A');
}
}
$( "#AdjacencyMatrixFieldPage" ).on('keyup change', function (eventObject)
{
checkFormat();
});
$( "#BadFormatMessage" ).hide();
$( "#AdjacencyMatrixFieldPage" ).hide();
$( "#showMatrix" ).on('click', function (eventObject)
{
_ShowMatrixInput();
});
$( "#showText" ).on('click', function (eventObject)
{
_ShowTextInput();
});
$('input:radio[name="separator"]').change( function(){
checkFormat()
});
CopyMatrixToMatrixInput();
$(document).keydown(function(event) {
if (event.which == "17" || event.which == "91")
g_ctrlPressed = true;
});
$(document).keyup(function(event) {
if (event.which == "17" || event.which == "91")
g_ctrlPressed = false;
});
}
</script>
<h1><?= L('head_no_tags')?></h1> <h1><?= L('head_no_tags')?></h1>
<p><?= L('text')?></p> <p><?= L('text')?></p>
@@ -302,11 +25,11 @@ window.onload = function ()
</form> </form>
<form action="./" method="post" id="matrixForm"> <form action="./" method="post" id="matrixForm">
<textarea name="matrix" id="AdjacencyMatrixFieldPage" wrap="off" style="display: none;"> <textarea name="matrix" id="AdjacencyMatrixFieldPage" wrap="off" style="display: none;">
<? if (!isset($_GET["matrix"])): ?> <?php if (!isset($_GET["matrix"])): ?>
0, 1, 0 0, 1, 0
1, 0, 0 1, 0, 0
0, 1, 0 0, 1, 0
<? else: ?><?= $_GET["matrix"] ?><? endif;?></textarea> <?php else: ?><?= $_GET["matrix"] ?><?php endif;?></textarea>
<div id="idSeparatorList" style="display: none;"> <div id="idSeparatorList" style="display: none;">
<?= L('separator') ?> <?= L('separator') ?>
<input type="radio" name="separator" value="commo" id="commoSep" checked> <label for="commoSep"><?= L('separator_commo') ?></label> <input type="radio" name="separator" value="commo" id="commoSep" checked> <label for="commoSep"><?= L('separator_commo') ?></label>
@@ -348,9 +71,6 @@ window.onload = function ()
</fieldset> </fieldset>
</form> </form>
</div> </div>
<script>
CopyMatrixToMatrixInput();
</script>
<? if (L('current_language') == "ru"): ?> <? if (L('current_language') == "ru"): ?>
<section> <section>
+1 -1
View File
@@ -14,7 +14,7 @@
<div class="col-md-4"> <div class="col-md-4">
<div class="thumbnail"> <div class="thumbnail">
<a href="./?graph=<?= $examples[$i]["id"] ?>"> <a href="./?graph=<?= $examples[$i]["id"] ?>">
<img src="/<? echo (getImageFileName($examples[$i]["id"], true)); ?>" alt="<?= $examples[$i]["title_" . $g_lang["current_language"]] ?>" style="width:100%"> <img src="/<?php echo (getImageFileName($examples[$i]["id"], true)); ?>" alt="<?= $examples[$i]["title_" . $g_lang["current_language"]] ?>" style="width:100%">
<div class="caption"> <div class="caption">
<p><?= $examples[$i]["title_" . $g_lang["current_language"]] ?></p> <p><?= $examples[$i]["title_" . $g_lang["current_language"]] ?></p>
</div> </div>
+10 -7
View File
@@ -9,9 +9,10 @@
<link rel="stylesheet" type="text/css" href="<?= Root('i/css/jquery.feedback_me.css')?>" /> <link rel="stylesheet" type="text/css" href="<?= Root('i/css/jquery.feedback_me.css')?>" />
<script src="<?= Root('i/js/dev/jquery-ui.js')?>"></script> <script src="<?= Root('i/js/dev/jquery-ui.js')?>"></script>
<script src="<?= Root('i/js/dev/jquery.feedback_me.js')?>"></script> <script src="<?= Root('i/js/dev/jquery.feedback_me.js')?>"></script>
<script src="<?= Root("script/canvas2svg.js")?>" ></script>
<script src="<?= Root("script/example.js?v=74")?>" ></script> <script src="<?= RootCacheJS("script/shared/config.js")?>" ></script>
<script src="<?= RootCacheJS("script/shared/loader.js")?>" ></script>
<!-- Yandex.RTB --> <!-- Yandex.RTB -->
<script>window.yaContextCb=window.yaContextCb||[]</script> <script>window.yaContextCb=window.yaContextCb||[]</script>
@@ -104,8 +105,8 @@
<li> <button type="button" class="btn btn-default btn-sm btn-submenu" id="MoveWorspace"><span class="glyphicon glyphicon-fullscreen fa-fw"></span> <?= L('move_workspace') ?> </button> </li> <li> <button type="button" class="btn btn-default btn-sm btn-submenu" id="MoveWorspace"><span class="glyphicon glyphicon-fullscreen fa-fw"></span> <?= L('move_workspace') ?> </button> </li>
</ul> </ul>
</div> </div>
<button type="button" class="btn btn-default btn-sm" id="Default"><span class="glyphicon glyphicon-fullscreen fa-fw"></span><span class="hidden-phone"> <?= L('default')?> <sub style="color:#AAAAAA">m</sub></span></button> <button type="button" class="btn btn-primary btn-sm" id="Default"><span class="glyphicon glyphicon-fullscreen fa-fw"></span><span class="hidden-phone"> <?= L('default')?> <sub style="color:#AAAAAA">m</sub></span></button>
<button type="button" class="btn btn-primary btn-sm" id="AddGraph"><span class="glyphicon glyphicon-plus fa-fw"></span><span class="hidden-phone"> <?= L('add_node')?> <sub style="color:#AAAAAA">v</sub></span></button> <button type="button" class="btn btn-default btn-sm" id="AddGraph"><span class="glyphicon glyphicon-plus fa-fw"></span><span class="hidden-phone"> <?= L('add_node')?> <sub style="color:#AAAAAA">v</sub></span></button>
<button type="button" class="btn btn-default btn-sm" id="ConnectGraphs"><span class="glyphicon glyphicon-road fa-fw"></span><span class="hidden-phone"> <?= L('connect_nodes')?> <sub style="color:#AAAAAA">e</sub></span></button> <button type="button" class="btn btn-default btn-sm" id="ConnectGraphs"><span class="glyphicon glyphicon-road fa-fw"></span><span class="hidden-phone"> <?= L('connect_nodes')?> <sub style="color:#AAAAAA">e</sub></span></button>
<!-- Algorithms --> <!-- Algorithms -->
@@ -278,10 +279,10 @@
<?php else: ?> <?php else: ?>
<section style="height:32px;text-align: center;" id="bottom_info" class="hidden-phone"> <section style="height:32px;text-align: center;" id="bottom_info" class="hidden-phone">
<a class="ProgresssBarLink" href="opensource" target="_blank"> <a class="ProgresssBarLink" href="mailto:admin@graphonline.ru" target="_blank">
<div class="ProgressBar" style="height:32px"> <div class="ProgressBar" style="height:32px">
<div class="ProgressBarFill" style="width:0%;"></div> <div class="ProgressBarFill" style="width:0%;"></div>
<span class="ProgressBarText" style="top:-28px"><p><?= L('opensource_message')?></p></span> <span class="ProgressBarText" style="top:-28px"><p><?= L('we_are_improving')?></p></span>
</div> </div>
</a> </a>
</section> </section>
@@ -892,6 +893,8 @@
<p id="wrongImageFormatPNGAndJPEG" class="translation"><?= L('wrong_image_background_format')?></p> <p id="wrongImageFormatPNGAndJPEG" class="translation"><?= L('wrong_image_background_format')?></p>
<p id="wrongImageSizeP1" class="translation"><?= L('wrong_image_background_size')?></p> <p id="wrongImageSizeP1" class="translation"><?= L('wrong_image_background_size')?></p>
</section> </section>
<script src="<?= RootCacheJS("script/pages/editor/api/index.js")?>" ></script>
<!-- <!--
<script> <script>
(adsbygoogle = window.adsbygoogle || []).push({}); (adsbygoogle = window.adsbygoogle || []).push({});