Add dialog to select original graph or autosaved graph.

Refactor graph styles holding objects.
Small style fixes.
This commit is contained in:
Oleg Sh
2025-01-05 21:05:35 +01:00
parent 7aa6eb8ed1
commit 6c4e18ce99
35 changed files with 1129 additions and 394 deletions

View File

@@ -88,9 +88,9 @@ DefaultHandler.prototype.MouseMove = function(pos)
}
else
{
// Move work space
this.app.onCanvasMove((new Point(pos.x, pos.y)).subtract(this.prevPosition).multiply(this.app.canvasScale));
this.needRedraw = true;
// Move work space
this.app.onCanvasMove((new Point(pos.x, pos.y)).subtract(this.prevPosition).multiply(this.app.canvasScale));
this.needRedraw = true;
}
}
}

View File

@@ -45,8 +45,7 @@ DeleteAllHandler.prototype.clear = function()
{
this.app.PushToStack("DeleteAll");
// Selected Graph.
this.app.graph = new Graph();
this.app.savedGraphName = "";
// Selected Graph.
this.app.CreateNewGraphObject();
this.needRedraw = true;
}

View File

@@ -7,7 +7,8 @@ doInclude ([
include ("model/BaseEdgeDrawer.js", modulDir),
include ("model/VertexShape.js", modulDir),
include ("model/VertexStyle.js", modulDir),
include ("model/BaseVertexDrawer.js", modulDir)
include ("model/BaseVertexDrawer.js", modulDir),
include ("model/GraphFullStyle.js", modulDir)
])
}

View File

@@ -0,0 +1,194 @@
/**
* Graph full style.
*/
function GraphFullStyle(redrawCallback)
{
this.edgeCommonStyle = new CommonEdgeStyle();
this.isEdgeCommonStyleCustom = false;
this.edgeSelectedStyles = FullArrayCopy(DefaultSelectedEdgeStyles);
this.isEdgeSelectedStylesCustom = false;
this.vertexCommonStyle = new CommonVertexStyle();
this.isVertexCommonStyleCustom = false;
this.vertexSelectedVertexStyles = FullArrayCopy(DefaultSelectedGraphStyles);
this.isVertexSelectedVertexStylesCustom = false;
this.backgroundCommonStyle = new CommonBackgroundStyle();
this.isBackgroundCommonStyleCustom = false;
this.defaultVertexSize = null;
this.defaultEdgeWidth = null;
this.redrawCallback = redrawCallback;
}
GraphFullStyle.prototype.Save = function()
{
var res = "";
var needEnd = false;
var checkValue = [];
checkValue.push({field: "edgeCommonStyle",
value: this.edgeCommonStyle,
check: this.isEdgeCommonStyleCustom});
checkValue.push({field: "edgeSelectedStyles",
value: this.edgeSelectedStyles,
check: this.isEdgeSelectedStylesCustom});
checkValue.push({field: "vertexCommonStyle",
value: this.vertexCommonStyle,
check: this.isVertexCommonStyleCustom});
checkValue.push({field: "vertexSelectedVertexStyles",
value: this.vertexSelectedVertexStyles,
check: this.isVertexSelectedVertexStylesCustom});
checkValue.push({field: "backgroundCommonStyle",
value: this.backgroundCommonStyle,
check: this.isBackgroundCommonStyleCustom});
checkValue.push({field: "defaultVertexSize",
value: this.defaultVertexSize,
check: this.defaultVertexSize != null});
checkValue.push({field: "defaultEdgeWidth",
value: this.defaultEdgeWidth,
check: this.defaultEdgeWidth != null});
checkValue.forEach(function(entry) {
if (!entry.check)
return;
if (needEnd)
res = res + ",";
let valueJson = "";
if (typeof entry.value.saveToJson === "function") {
valueJson = entry.value.saveToJson();
} else {
valueJson = JSON.stringify(entry.value);
}
res = res + "\"" + entry.field + "\"" + ":" + valueJson;
needEnd = true;
});
res = res + "";
return gEncodeToHTML(res);
}
GraphFullStyle.prototype.Load = function(json)
{
var checkValue = [];
checkValue.push({field: "edgeCommonStyle",
value: this.edgeCommonStyle,
check: "isEdgeCommonStyleCustom",
deep: false});
checkValue.push({field: "edgeSelectedStyles",
value: this.edgeSelectedStyles,
check: "isEdgeSelectedStylesCustom",
deep: true});
checkValue.push({field: "vertexCommonStyle",
value: this.vertexCommonStyle,
check: "isVertexCommonStyleCustom",
deep: false});
checkValue.push({field: "vertexSelectedVertexStyles",
value: this.vertexSelectedVertexStyles,
check: "isVertexSelectedVertexStylesCustom",
deep: true});
checkValue.push({field: "defaultVertexSize",
value: "defaultVertexSize",
check: null,
deep: false});
checkValue.push({field: "defaultEdgeWidth",
value: "defaultEdgeWidth",
check: null,
deep: false});
checkValue.push({field: "backgroundCommonStyle",
value: this.backgroundCommonStyle,
check: "isBackgroundCommonStyleCustom",
deep: false});
var decoderStr = gDecodeFromHTML(json);
var parsedSave = JSON.parse(decoderStr);
var app = this;
checkValue.forEach(function(entry) {
if (parsedSave.hasOwnProperty(entry.field))
{
if (typeof parsedSave[entry.field] === 'number')
{
app[entry.value] = parseInt(parsedSave[entry.field]);
}
else
{
if (typeof entry.value.loadFromJson === "function") {
entry.value.loadFromJson(parsedSave[entry.field], function () {
setTimeout(
function()
{
if (app.redrawCallback != null)
{
app.redrawCallback();
}
}, 1000);
});
if (entry.check != null)
app[entry.check] = true;
return;
}
if (!entry.deep)
entry.value.Clear();
//console.log(parsedSave[entry.field]);
for(var k in parsedSave[entry.field])
{
if (!entry.deep)
{
if (entry.value.ShouldLoad(k))
{
entry.value[k] = parsedSave[entry.field][k];
}
}
else
{
// Check is number or not
if (k % 1 != 0)
{
continue;
}
// Old saves contains more styles. Just skip it.
if (entry.value[k] == undefined)
{
continue;
}
entry.value[k].Clear();
for(var deepK in parsedSave[entry.field][k])
{
if (k < entry.value.length && entry.value[k].ShouldLoad(deepK))
entry.value[k][deepK] = parsedSave[entry.field][k][deepK];
}
}
}
}
if (entry.check != null)
app[entry.check] = true;
}
});
}

View File

@@ -0,0 +1,274 @@
/**
* Preview element for graph
*
*/
function GraphPreview(graph, style, canvas, positionUpdateCallback)
{
this.graph = graph;
this.style = style;
this.canvas = canvas;
this.canvasScale = 1.0;
this.canvasPosition = new Point(0, 0);
this.prevMousePos = null;
this.positionUpdateCallback = positionUpdateCallback;
this.AutoAdjustViewport();
let canvasParent = canvas.parentNode;
let zoomPlusArray = canvasParent.getElementsByClassName("zoom-plus");
let preview = this;
let one_scale = 1.2;
let zoomFunc = function(real_scale)
{
let oldRealW = preview.getRealWidth();
let oldRealH = preview.getRealHeight();
preview.canvasScale = preview.canvasScale * real_scale;
let realW = preview.getRealWidth();
let realH = preview.getRealHeight();
preview.canvasPosition = preview.canvasPosition.add(new Point((- oldRealW + realW) / 2, (- oldRealH + realH) / 2));
preview.redraw();
preview.callPositionUpdateCallback();
};
if (zoomPlusArray.length > 0)
{
this.zoomPlusButton = zoomPlusArray[0];
this.zoomPlusButton.onclick = function()
{
zoomFunc(one_scale);
};
}
let zoomMinusArray = canvasParent.getElementsByClassName("zoom-minus");
if (zoomMinusArray.length > 0)
{
this.zoomMinusButton = zoomMinusArray[0];
this.zoomMinusButton.onclick = function()
{
zoomFunc(1.0 / one_scale);
};
}
this.canvas.onmousemove = function (e)
{
return preview.CanvasOnMouseMove(e);
}
this.canvas.onmousedown = function (e)
{
return preview.CanvasOnMouseDown(e);
}
this.canvas.onmouseup = function (e)
{
return preview.CanvasOnMouseUp(e);
}
this.canvas.onwheel = function (e)
{
var e = window.event || e; // old IE support
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
if (delta > 0)
{
zoomFunc(one_scale);
}
else
{
zoomFunc(1.0 / one_scale);
}
}
this.canvas.removeEventListener("touchstart", touchHandler, true);
this.canvas.removeEventListener("touchmove", touchHandler, true);
this.canvas.removeEventListener("touchend", touchHandler, true);
this.canvas.removeEventListener("touchcancel", touchHandler, true);
this.canvas.addEventListener("touchstart", touchHandler, true);
this.canvas.addEventListener("touchmove", touchHandler, true);
this.canvas.addEventListener("touchend", touchHandler, true);
this.canvas.addEventListener("touchcancel", touchHandler, true);
this.redraw();
// Redraw one, because graph may have background.
setTimeout(
function()
{
this.redraw();
}.bind(this),
1000);
}
GraphPreview.prototype.redraw = function()
{
const ctx = this.canvas.getContext("2d");
ctx.save();
ctx.scale(this.canvasScale, this.canvasScale);
ctx.translate(this.canvasPosition.x, this.canvasPosition.y);
this.redrawGraph(ctx, this.canvasPosition);
ctx.restore();
}
GraphPreview.prototype.getRealWidth = function ()
{
return this.canvas.width / this.canvasScale;
}
GraphPreview.prototype.getRealHeight = function ()
{
return this.canvas.height / this.canvasScale;
}
GraphPreview.prototype.redrawGraph = function(context, backgroundPosition)
{
var backgroundDrawer = new BaseBackgroundDrawer(context);
backgroundDrawer.Draw(
this.style.backgroundCommonStyle,
Math.max(this.canvas.width, this.getRealWidth()),
Math.max(this.canvas.height, this.getRealHeight()),
backgroundPosition,
this.canvasScale);
// Update edge styles
for (i = 0; i < this.graph.edges.length; i ++)
{
let edge = this.graph.edges[i];
var currentStyle = null;
if (edge.hasOwnStyleFor(0))
currentStyle = edge.getStyleFor(0);
else
currentStyle = this.style.edgeCommonStyle;
edge.currentStyle = currentStyle;
}
// Upadte current vertexs styles
for (i = 0; i < this.graph.vertices.length; i ++)
{
var currentStyle = null;
let vetrex = this.graph.vertices[i];
if (vetrex.hasOwnStyleFor(0))
currentStyle = vetrex.getStyleFor(0);
else
currentStyle = this.style.vertexCommonStyle;
this.graph.vertices[i].currentStyle = currentStyle;
}
for (i = 0; i < this.graph.edges.length; i ++)
{
let edge = this.graph.edges[i];
var arcDrawer = this.GetBaseArcDrawer(context, edge);
arcDrawer.Draw(edge, edge.currentStyle.GetStyle({}, edge));
}
var graphDrawer = new BaseVertexDrawer(context);
for (i = 0; i < this.graph.vertices.length; i ++)
{
let vertex = this.graph.vertices[i];
graphDrawer.Draw(this.graph.vertices[i], vertex.currentStyle.GetStyle({}, vertex));
}
}
GraphPreview.prototype.GetBaseArcDrawer = function(context, edge)
{
var arcDrawer = new BaseEdgeDrawer(context);
if (edge.model.type == EdgeModels.curve)
{
var curvedArcDrawer = new CurvedArcDrawer(context, edge.model);
arcDrawer = new BaseEdgeDrawer(context,
{
drawArc : curvedArcDrawer,
startArrowDirection : curvedArcDrawer,
finishArrowDirection : curvedArcDrawer,
textCenterObject : curvedArcDrawer,
getPointOnArc : curvedArcDrawer
}
);
}
return arcDrawer;
}
GraphPreview.prototype.AutoAdjustViewport = function()
{
graphBBox = this.graph.getGraphBBox();
bboxCenter = graphBBox.center();
bboxSize = graphBBox.size();
if (bboxSize.length() > 0)
{
// Setup size
if (bboxSize.x > this.getRealWidth() || bboxSize.y > this.getRealHeight())
{
this.canvasScale = Math.min(this.getRealWidth() / bboxSize.x, this.getRealHeight() / bboxSize.y);
}
// Setup position.
if (graphBBox.minPoint.x < 0.0 || graphBBox.minPoint.y < 0.0 ||
graphBBox.maxPoint.x > this.getRealWidth() || graphBBox.maxPoint.y > this.getRealHeight())
{
// Move center.
this.canvasPosition = graphBBox.minPoint.inverse();
}
}
}
GraphPreview.prototype.CanvasOnMouseMove = function(e)
{
if (this.prevMousePos == null)
{
return;
}
// X,Y position.
var pos = this.getMousePos(this.canvas, e);
let newPos = (new Point(pos.x, pos.y)).subtract(this.prevMousePos).multiply(this.canvasScale);
this.canvasPosition = this.canvasPosition.add(newPos.multiply(1 / this.canvasScale));
this.redraw();
this.callPositionUpdateCallback();
}
GraphPreview.prototype.CanvasOnMouseDown = function(e)
{
// Skip non left button.
if(e.which !== 1) return;
var pos = this.getMousePos(this.canvas, e); /// provide this canvas and event
this.prevMousePos = pos;
}
GraphPreview.prototype.CanvasOnMouseUp = function(e)
{
// Skip non left button.
if(e.which !== 1) return;
this.prevMousePos = null;
}
GraphPreview.prototype.getMousePos = function(canvas, e)
{
/// getBoundingClientRect is supported in most browsers and gives you
/// the absolute geometry of an element
var rect = canvas.getBoundingClientRect();
/// as mouse event coords are relative to document you need to
/// subtract the element's left and top position:
return new Point((e.clientX - rect.left) / this.canvasScale - this.canvasPosition.x,
(e.clientY - rect.top) / this.canvasScale - this.canvasPosition.y);
}
GraphPreview.prototype.callPositionUpdateCallback = function()
{
if (this.positionUpdateCallback != null)
{
this.positionUpdateCallback(this.canvasPosition, this.canvasScale);
}
}

View File

@@ -0,0 +1,86 @@
doInclude ([
include ("features/base_handler/index.js"),
include ("features/graph_preview/index.js"),
])
/**
* Dialog to select first or second graph.
*
*/
function SelectGraphDialog(app, originalGraph, originalGraphStyle,
autoSavedGraph, autoSavedGraphStyle,
originalCallback, autoSaveCallback)
{
BaseHandler.apply(this, arguments);
this.message = "";
this.originalGraph = originalGraph;
this.autoSavedGraph = autoSavedGraph;
this.originalCallback = originalCallback;
this.autoSaveCallback = autoSaveCallback;
this.originalGraphStyle = originalGraphStyle;
this.autoSavedGraphStyle = autoSavedGraphStyle;
}
// inheritance.
SelectGraphDialog.prototype = Object.create(BaseHandler.prototype);
SelectGraphDialog.prototype.show = function()
{
var handler = this;
var dialogButtons = {};
var graph = this.app.graph;
var app = this.app;
dialogButtons[g_originalGraph] =
{
text: g_originalGraph,
class : "MarginLeft",
click : function() {
handler.originalGraphPreview = null;
handler.originalGraph = null;
handler.autoSavedGraph = null;
handler.originalCallback();
$( this ).dialog( "destroy" );
}
};
dialogButtons[g_autoSavedGraph] = function() {
handler.originalGraphPreview = null;
handler.originalGraph = null;
handler.autoSavedGraph = null;
handler.autoSaveCallback();
$( this ).dialog( "destroy" );
};
$( "#autoSaveOrOriginalGraph" ).dialog({
resizable: false,
height: "auto",
width: "auto",
modal: true,
title: g_selectGraphToLoad,
buttons: dialogButtons,
dialogClass: 'EdgeDialog',
close: function( event, ui )
{
handler.originalCallback();
}
});
let originalGraphPositionUpdate = function(pos, scale)
{
handler.autoSavedGraphPreview.canvasScale = scale;
handler.autoSavedGraphPreview.canvasPosition = pos;
handler.autoSavedGraphPreview.redraw();
};
let autoSavedGraphPreviewUpdate = function(pos, scale)
{
handler.originalGraphPreview.canvasScale = scale;
handler.originalGraphPreview.canvasPosition = pos;
handler.originalGraphPreview.redraw();
};
this.originalGraphPreview = new GraphPreview(this.originalGraph, this.originalGraphStyle,
document.getElementById("OriginalGraphpPreview"), originalGraphPositionUpdate);
this.autoSavedGraphPreview = new GraphPreview(this.autoSavedGraph, this.autoSavedGraphStyle,
document.getElementById("AutoSaveGraphpPreview"), autoSavedGraphPreviewUpdate);
}

View File

@@ -55,7 +55,7 @@ SetupBackgroundStyle.prototype.show = function()
var dialogButtons = {};
var graph = this.app.graph;
var app = this.app;
var style = FullObjectCopy(app.backgroundCommonStyle);
var style = FullObjectCopy(app.style.backgroundCommonStyle);
var fillFields = function()
{

View File

@@ -29,7 +29,7 @@ SetupEdgeStyle.prototype.show = function(index, selectedEdges)
var applyIndex = function(index)
{
self.index = index;
var originStyle = (self.index == 0 ? app.edgeCommonStyle : app.edgeSelectedStyles[self.index - 1]);
var originStyle = (self.index == 0 ? app.style.edgeCommonStyle : app.style.edgeSelectedStyles[self.index - 1]);
if (!forAll)
{
originStyle = selectedEdges[0].getStyleFor(self.index);
@@ -65,10 +65,10 @@ SetupEdgeStyle.prototype.show = function(index, selectedEdges)
// Fill color presets.
var stylesArray = [];
stylesArray.push(app.edgeCommonStyle);
stylesArray.push(app.style.edgeCommonStyle);
for (i = 0; i < app.edgeSelectedStyles.length; i ++)
stylesArray.push(app.edgeSelectedStyles[i]);
for (i = 0; i < app.style.edgeSelectedStyles.length; i ++)
stylesArray.push(app.style.edgeSelectedStyles[i]);
var colorSet = {};
for (i = 0; i < stylesArray.length; i ++)
@@ -128,7 +128,7 @@ SetupEdgeStyle.prototype.show = function(index, selectedEdges)
context.save();
var backgroundDrawer = new BaseBackgroundDrawer(context);
backgroundDrawer.Draw(app.backgroundCommonStyle, canvas.width, canvas.height, new Point(0, 0), 1.0);
backgroundDrawer.Draw(app.style.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));
@@ -190,11 +190,11 @@ SetupEdgeStyle.prototype.show = function(index, selectedEdges)
click : function() {
app.PushToStack("ChangeStyle");
applyWidth(forAll ? (new EdgeModel()).width : app.GetDefaultEdgeWidth());
applyWidth(forAll ? defaultEdgeWidth : app.GetDefaultEdgeWidth());
var indexes = [];
if (self.index == "all")
{
for (i = 0; i < app.edgeSelectedStyles.length; i ++)
for (i = 0; i < app.style.edgeSelectedStyles.length; i ++)
indexes.push(i + 1);
}
else
@@ -231,7 +231,7 @@ SetupEdgeStyle.prototype.show = function(index, selectedEdges)
{
indexes.push({index : 1, style : self.style});
for (i = 1; i < app.edgeSelectedStyles.length; i ++)
for (i = 1; i < app.style.edgeSelectedStyles.length; i ++)
{
var style = (new BaseEdgeStyle());
style.baseStyles.push("selected");

View File

@@ -28,7 +28,7 @@ SetupVertexStyle.prototype.show = function(index, selectedVertices)
var applyIndex = function(index)
{
self.index = index;
self.originStyle = (self.index == 0 ? app.vertexCommonStyle : app.vertexSelectedVertexStyles[self.index - 1]);
self.originStyle = (self.index == 0 ? app.style.vertexCommonStyle : app.style.vertexSelectedVertexStyles[self.index - 1]);
if (!forAll)
{
self.originStyle = selectedVertices[0].getStyleFor(self.index);
@@ -64,10 +64,10 @@ SetupVertexStyle.prototype.show = function(index, selectedVertices)
// Fill color presets.
var stylesArray = [];
stylesArray.push(app.vertexCommonStyle);
stylesArray.push(app.style.vertexCommonStyle);
for (i = 0; i < app.vertexSelectedVertexStyles.length; i ++)
stylesArray.push(app.vertexSelectedVertexStyles[i]);
for (i = 0; i < app.style.vertexSelectedVertexStyles.length; i ++)
stylesArray.push(app.style.vertexSelectedVertexStyles[i]);
var colorSet = {};
for (i = 0; i < stylesArray.length; i ++)
@@ -132,7 +132,7 @@ SetupVertexStyle.prototype.show = function(index, selectedVertices)
context.save();
var backgroundDrawer = new BaseBackgroundDrawer(context);
backgroundDrawer.Draw(app.backgroundCommonStyle, canvas.width, canvas.height, new Point(0, 0), 1.0);
backgroundDrawer.Draw(app.style.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));
@@ -189,12 +189,12 @@ SetupVertexStyle.prototype.show = function(index, selectedVertices)
app.PushToStack("ChangeStyle");
applyDiameter(forAll ? (new VertexModel()).diameter : app.GetDefaultVertexSize());
applyDiameter(forAll ? defaultVertexDiameter : app.GetDefaultVertexSize());
var indexes = [];
if (self.index == "all")
{
for (i = 0; i < app.vertexSelectedVertexStyles.length; i ++)
for (i = 0; i < app.style.vertexSelectedVertexStyles.length; i ++)
indexes.push(i + 1);
}
else
@@ -230,7 +230,7 @@ SetupVertexStyle.prototype.show = function(index, selectedVertices)
if (self.index == "all")
{
indexes.push({index : 1, style : self.style});
for (i = 1; i < app.vertexSelectedVertexStyles.length; i ++)
for (i = 1; i < app.style.vertexSelectedVertexStyles.length; i ++)
{
var style = (new BaseVertexStyle());
style.baseStyles.push("selected");