Change script location.

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

View File

@@ -0,0 +1,9 @@
{
let modulDir = "entities/edge/";
doInclude ([
include ("model/BaseEdge.js", modulDir),
include ("model/EdgeModel.js", modulDir)
])
}

View File

@@ -0,0 +1,305 @@
/**
* This is base arc.
*
*
*/
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);
}

View File

@@ -0,0 +1,239 @@
/**
* This is edge model
*
*/
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;
// Self loop case
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;
// Self loop case
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)
{
// without this condition arc disappears when curveValue=0
return this.sizeOfLoop;
}
else
{
// bigger curveValue -> bigger loop size
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)
{ // shift to top-left
return this.loopShiftAngel;
}
else
{ // shift to bottom-right
return this.loopShiftAngel + Math.PI;
}
}

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 diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
{
let modulDir = "entities/vertex/";
doInclude ([
include ("model/BaseVertex.js", modulDir),
include ("model/VertexModel.js", modulDir)
])
}

View File

@@ -0,0 +1,181 @@
/**
* Base node class.
*
*/
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);
}

View File

@@ -0,0 +1,11 @@
/**
* This is graph model used for hit test and draw.
*
*/
const defaultVertexDiameter = 30;
function VertexModel()
{
this.diameter = globalApplication.GetDefaultVertexSize();
}