1
0
Fork 0

GraphViewer: A line is now displayed to help connecting two nodes

This commit is contained in:
Michael Hackstein 2013-05-29 13:53:34 +02:00
parent 4ff14a0228
commit 5d2008d4bb
5 changed files with 190 additions and 42 deletions

View File

@ -50,7 +50,8 @@ function EdgeShaper(parent, flags, idfunc) {
edges = [],
toplevelSVG,
visibleLabels = true,
followEdge = {},
followEdgeG,
idFunction = function(d) {
return d.source._id + "-" + d.target._id;
},
@ -319,6 +320,8 @@ function EdgeShaper(parent, flags, idfunc) {
idFunction = idfunc;
}
followEdgeG = toplevelSVG.append("g");
/////////////////////////////////////////////////////////
/// Public functions
@ -351,6 +354,24 @@ function EdgeShaper(parent, flags, idfunc) {
}
shapeEdges();
};
self.addAnEdgeFollowingTheCursor = function(x, y) {
followEdge = followEdgeG.append("line");
followEdge.attr("stroke", "black")
.attr("id", "connectionLine")
.attr("x1", x)
.attr("y1", y)
.attr("x2", x)
.attr("y2", y);
return function(x, y) {
followEdge.attr("x2", x).attr("y2", y);
};
};
self.removeCursorFollowingEdge = function() {
followEdge.remove();
followEdge = {};
};
}
EdgeShaper.shapes = Object.freeze({

View File

@ -1,5 +1,5 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global _, $*/
/*global _, $, window*/
/*global EventLibrary*/
////////////////////////////////////////////////////////////////////////////////
/// @brief Graph functionality
@ -80,11 +80,14 @@ function EventDispatcher(nodeShaper, edgeShaper, config) {
self.events.STARTCREATEEDGE = function(callback) {
return function(node) {
var e = d3.event || window.event;
edgeStart = node;
didInsert = false;
if (callback !== undefined) {
callback();
callback(node, e);
}
// Necessary to omit dragging of the graph
e.stopPropagation();
};
};

View File

@ -42,6 +42,7 @@
beforeEach(function () {
svg = document.createElement("svg");
svg.id = "svg";
document.body.appendChild(svg);
});
@ -274,6 +275,55 @@
expect($("#1-5 line").attr("x2")).toEqual("28.284271247461902");
});
it('should be able to draw an edge that follows the cursor', function() {
var line,
jqLine,
cursorX,
cursorY,
nodeX = 15,
nodeY = 20,
shaper = new EdgeShaper(d3.select("svg")),
moveCB = shaper.addAnEdgeFollowingTheCursor(nodeX, nodeY);
cursorX = 20;
cursorY = 30;
moveCB(cursorX, cursorY);
expect($("#connectionLine").length).toEqual(1);
jqLine = $("#connectionLine");
line = document.getElementById("connectionLine");
expect(line.tagName.toLowerCase()).toEqual("line");
expect(jqLine.attr("x1")).toEqual(String(nodeX));
expect(jqLine.attr("y1")).toEqual(String(nodeY));
expect(jqLine.attr("x2")).toEqual(String(cursorX));
expect(jqLine.attr("y2")).toEqual(String(cursorY));
cursorX = 45;
cursorY = 12;
moveCB(cursorX, cursorY);
expect(jqLine.attr("x2")).toEqual(String(cursorX));
expect(jqLine.attr("y2")).toEqual(String(cursorY));
});
it('should be able to remove the cursor-following edge on demand', function() {
var line,
cursorX,
cursorY,
nodeX = 15,
nodeY = 20,
shaper = new EdgeShaper(d3.select("svg")),
moveCB;
moveCB = shaper.addAnEdgeFollowingTheCursor(nodeX, nodeY);
cursorX = 20;
cursorY = 30;
moveCB(cursorX, cursorY);
shaper.removeCursorFollowingEdge();
expect($("#connectionLine").length).toEqual(0);
});
describe('testing for colours', function() {
it('should have a default colouring of no colour flag is given', function() {

View File

@ -61,17 +61,21 @@
beforeEach(function () {
nodes = [{
_id: 1,
_rev: 1,
_key: 1,
x: 3,
y: 4,
_data: {
_id: 1,
_rev: 1,
_key: 1,
name: "Alice"
}
},{
_id: 2,
_rev: 2,
_key: 2,
x: 1,
y: 2,
_data: {
_rev: 2,
_key: 2,
_id: 2
}
}];
@ -122,6 +126,7 @@
};
svg = document.createElement("svg");
svg.id = "svg";
document.body.appendChild(svg);
nodeShaper = new NodeShaper(d3.select("svg"));
edgeShaper = new EdgeShaper(d3.select("svg"));
@ -265,7 +270,7 @@
helper.simulateMouseEvent("click", "control_event_node_edit_submit");
expect(adapter.patchNode).toHaveBeenCalledWith(
nodes[0],
{ _id: "1",
{
name: "Bob"
},
jasmine.any(Function));
@ -286,9 +291,6 @@
expect(adapter.patchEdge).toHaveBeenCalledWith(
edges[0],
{
_id: "12",
_rev: "12",
_key: "12",
_from: "1",
_to: "2",
label: "newLabel"
@ -373,42 +375,96 @@
});
});
it('should be able to add a connect control to the list', function() {
runs(function() {
describe('the connect control', function() {
it('should be added to the list', function() {
runs(function() {
dispatcherUI.addControlConnect();
expect($("#control_event_list #control_event_connect").length).toEqual(1);
helper.simulateMouseEvent("click", "control_event_connect");
expect(nodeShaper.changeTo).toHaveBeenCalledWith({
actions: {
reset: true,
mousedown: jasmine.any(Function),
mouseup: jasmine.any(Function)
}
});
expect(edgeShaper.changeTo).toHaveBeenCalledWith({
actions: {
reset: true
}
});
expect(mousePointerbox.className).toEqual("mousepointer icon-resize-horizontal");
helper.simulateMouseEvent("mousedown", "2");
helper.simulateMouseEvent("mouseup", "1");
expect(adapter.createEdge).toHaveBeenCalledWith(
{source: nodes[1], target: nodes[0]},
jasmine.any(Function)
);
});
});
it('should draw a line from startNode following the cursor', function() {
var line,
cursorX,
cursorY;
spyOn(edgeShaper, "addAnEdgeFollowingTheCursor");
dispatcherUI.addControlConnect();
expect($("#control_event_list #control_event_connect").length).toEqual(1);
helper.simulateMouseEvent("click", "control_event_connect");
expect(nodeShaper.changeTo).toHaveBeenCalledWith({
actions: {
reset: true,
mousedown: jasmine.any(Function),
mouseup: jasmine.any(Function)
}
});
expect(edgeShaper.changeTo).toHaveBeenCalledWith({
actions: {
reset: true
}
});
expect(mousePointerbox.className).toEqual("mousepointer icon-resize-horizontal");
helper.simulateMouseEvent("mousedown", "2");
helper.simulateMouseEvent("mouseup", "1");
expect(adapter.createEdge).toHaveBeenCalledWith(
{source: nodes[1], target: nodes[0]},
jasmine.any(Function)
expect(edgeShaper.addAnEdgeFollowingTheCursor).toHaveBeenCalledWith(
0, 0
);
});
it('the cursor-line should follow the cursor on mousemove over svg', function() {
dispatcherUI.addControlConnect();
helper.simulateMouseEvent("click", "control_event_connect");
helper.simulateMouseEvent("mousedown", "2");
helper.simulateMouseMoveEvent("svg", 40, 50);
var line = $("#connectionLine");
expect(line.attr("x1")).toEqual(String(nodes[1].x));
expect(line.attr("y1")).toEqual(String(nodes[1].y));
expect(line.attr("x2")).toEqual("40");
expect(line.attr("y2")).toEqual("50");
});
it('the cursor-line should disappear on mouseup on svg', function() {
spyOn(edgeShaper, "removeCursorFollowingEdge");
dispatcherUI.addControlConnect();
helper.simulateMouseEvent("click", "control_event_connect");
helper.simulateMouseEvent("mousedown", "2");
helper.simulateMouseEvent("mouseup", "1-2");
expect(edgeShaper.removeCursorFollowingEdge).toHaveBeenCalled();
});
it('the cursor-line should disappear on mouseup on svg', function() {
spyOn(edgeShaper, "removeCursorFollowingEdge");
dispatcherUI.addControlConnect();
helper.simulateMouseEvent("click", "control_event_connect");
helper.simulateMouseEvent("mousedown", "2");
helper.simulateMouseEvent("mouseup", "1");
expect(edgeShaper.removeCursorFollowingEdge).toHaveBeenCalled();
});
});
it('should be able to add all controls to the list', function () {
dispatcherUI.addAll();

View File

@ -111,6 +111,13 @@ function EventDispatcherControls(list, cursorIconBox, nodeShaper, edgeShaper, di
return res;
},
getCursorPositionInSVG = function (ev) {
var pos = getCursorPosition(ev);
pos.x -= $('svg').offset().left;
pos.y -= $('svg').offset().top;
return pos;
},
moveCursorBox = function(ev) {
var pos = getCursorPosition(ev);
pos.x += 7;
@ -217,14 +224,25 @@ function EventDispatcherControls(list, cursorIconBox, nodeShaper, edgeShaper, di
callback = function() {
setCursorIcon(icon);
rebindNodes({
mousedown: dispatcher.events.STARTCREATEEDGE(),
mousedown: dispatcher.events.STARTCREATEEDGE(function(startNode, ev) {
var pos = getCursorPositionInSVG(ev);
var moveCB = edgeShaper.addAnEdgeFollowingTheCursor(pos.x, pos.y);
dispatcher.bind("svg", "mousemove", function(ev) {
var pos = getCursorPositionInSVG(ev);
moveCB(pos.x, pos.y);
});
}),
mouseup: dispatcher.events.FINISHCREATEEDGE(function(edge){
edgeShaper.removeCursorFollowingEdge();
dispatcher.bind("svg", "mousemove", function(){});
})
});
rebindEdges();
rebindSVG({
mouseup: dispatcher.events.CANCELCREATEEDGE(),
mouseout: dispatcher.events.CANCELCREATEEDGE()
mouseup: function() {
dispatcher.events.CANCELCREATEEDGE();
edgeShaper.removeCursorFollowingEdge();
}
});
};
createIcon(icon, "connect", callback);