mirror of https://gitee.com/bigwinds/arangodb
GraphViewer: A line is now displayed to help connecting two nodes
This commit is contained in:
parent
4ff14a0228
commit
5d2008d4bb
|
@ -50,7 +50,8 @@ function EdgeShaper(parent, flags, idfunc) {
|
||||||
edges = [],
|
edges = [],
|
||||||
toplevelSVG,
|
toplevelSVG,
|
||||||
visibleLabels = true,
|
visibleLabels = true,
|
||||||
|
followEdge = {},
|
||||||
|
followEdgeG,
|
||||||
idFunction = function(d) {
|
idFunction = function(d) {
|
||||||
return d.source._id + "-" + d.target._id;
|
return d.source._id + "-" + d.target._id;
|
||||||
},
|
},
|
||||||
|
@ -319,6 +320,8 @@ function EdgeShaper(parent, flags, idfunc) {
|
||||||
idFunction = idfunc;
|
idFunction = idfunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
followEdgeG = toplevelSVG.append("g");
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////
|
||||||
/// Public functions
|
/// Public functions
|
||||||
|
@ -351,6 +354,24 @@ function EdgeShaper(parent, flags, idfunc) {
|
||||||
}
|
}
|
||||||
shapeEdges();
|
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({
|
EdgeShaper.shapes = Object.freeze({
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
|
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
|
||||||
/*global _, $*/
|
/*global _, $, window*/
|
||||||
/*global EventLibrary*/
|
/*global EventLibrary*/
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief Graph functionality
|
/// @brief Graph functionality
|
||||||
|
@ -80,11 +80,14 @@ function EventDispatcher(nodeShaper, edgeShaper, config) {
|
||||||
|
|
||||||
self.events.STARTCREATEEDGE = function(callback) {
|
self.events.STARTCREATEEDGE = function(callback) {
|
||||||
return function(node) {
|
return function(node) {
|
||||||
|
var e = d3.event || window.event;
|
||||||
edgeStart = node;
|
edgeStart = node;
|
||||||
didInsert = false;
|
didInsert = false;
|
||||||
if (callback !== undefined) {
|
if (callback !== undefined) {
|
||||||
callback();
|
callback(node, e);
|
||||||
}
|
}
|
||||||
|
// Necessary to omit dragging of the graph
|
||||||
|
e.stopPropagation();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
svg = document.createElement("svg");
|
svg = document.createElement("svg");
|
||||||
|
svg.id = "svg";
|
||||||
document.body.appendChild(svg);
|
document.body.appendChild(svg);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -274,6 +275,55 @@
|
||||||
expect($("#1-5 line").attr("x2")).toEqual("28.284271247461902");
|
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() {
|
describe('testing for colours', function() {
|
||||||
|
|
||||||
it('should have a default colouring of no colour flag is given', function() {
|
it('should have a default colouring of no colour flag is given', function() {
|
||||||
|
|
|
@ -61,17 +61,21 @@
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
nodes = [{
|
nodes = [{
|
||||||
_id: 1,
|
_id: 1,
|
||||||
_rev: 1,
|
x: 3,
|
||||||
_key: 1,
|
y: 4,
|
||||||
_data: {
|
_data: {
|
||||||
_id: 1,
|
_id: 1,
|
||||||
|
_rev: 1,
|
||||||
|
_key: 1,
|
||||||
name: "Alice"
|
name: "Alice"
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
_id: 2,
|
_id: 2,
|
||||||
_rev: 2,
|
x: 1,
|
||||||
_key: 2,
|
y: 2,
|
||||||
_data: {
|
_data: {
|
||||||
|
_rev: 2,
|
||||||
|
_key: 2,
|
||||||
_id: 2
|
_id: 2
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
@ -122,6 +126,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
svg = document.createElement("svg");
|
svg = document.createElement("svg");
|
||||||
|
svg.id = "svg";
|
||||||
document.body.appendChild(svg);
|
document.body.appendChild(svg);
|
||||||
nodeShaper = new NodeShaper(d3.select("svg"));
|
nodeShaper = new NodeShaper(d3.select("svg"));
|
||||||
edgeShaper = new EdgeShaper(d3.select("svg"));
|
edgeShaper = new EdgeShaper(d3.select("svg"));
|
||||||
|
@ -265,7 +270,7 @@
|
||||||
helper.simulateMouseEvent("click", "control_event_node_edit_submit");
|
helper.simulateMouseEvent("click", "control_event_node_edit_submit");
|
||||||
expect(adapter.patchNode).toHaveBeenCalledWith(
|
expect(adapter.patchNode).toHaveBeenCalledWith(
|
||||||
nodes[0],
|
nodes[0],
|
||||||
{ _id: "1",
|
{
|
||||||
name: "Bob"
|
name: "Bob"
|
||||||
},
|
},
|
||||||
jasmine.any(Function));
|
jasmine.any(Function));
|
||||||
|
@ -286,9 +291,6 @@
|
||||||
expect(adapter.patchEdge).toHaveBeenCalledWith(
|
expect(adapter.patchEdge).toHaveBeenCalledWith(
|
||||||
edges[0],
|
edges[0],
|
||||||
{
|
{
|
||||||
_id: "12",
|
|
||||||
_rev: "12",
|
|
||||||
_key: "12",
|
|
||||||
_from: "1",
|
_from: "1",
|
||||||
_to: "2",
|
_to: "2",
|
||||||
label: "newLabel"
|
label: "newLabel"
|
||||||
|
@ -373,41 +375,95 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to add a connect control to the list', function() {
|
describe('the connect control', function() {
|
||||||
runs(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();
|
dispatcherUI.addControlConnect();
|
||||||
|
|
||||||
expect($("#control_event_list #control_event_connect").length).toEqual(1);
|
|
||||||
|
|
||||||
helper.simulateMouseEvent("click", "control_event_connect");
|
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("mousedown", "2");
|
||||||
|
|
||||||
helper.simulateMouseEvent("mouseup", "1");
|
expect(edgeShaper.addAnEdgeFollowingTheCursor).toHaveBeenCalledWith(
|
||||||
|
0, 0
|
||||||
expect(adapter.createEdge).toHaveBeenCalledWith(
|
|
||||||
{source: nodes[1], target: nodes[0]},
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 () {
|
it('should be able to add all controls to the list', function () {
|
||||||
dispatcherUI.addAll();
|
dispatcherUI.addAll();
|
||||||
|
|
|
@ -111,6 +111,13 @@ function EventDispatcherControls(list, cursorIconBox, nodeShaper, edgeShaper, di
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getCursorPositionInSVG = function (ev) {
|
||||||
|
var pos = getCursorPosition(ev);
|
||||||
|
pos.x -= $('svg').offset().left;
|
||||||
|
pos.y -= $('svg').offset().top;
|
||||||
|
return pos;
|
||||||
|
},
|
||||||
|
|
||||||
moveCursorBox = function(ev) {
|
moveCursorBox = function(ev) {
|
||||||
var pos = getCursorPosition(ev);
|
var pos = getCursorPosition(ev);
|
||||||
pos.x += 7;
|
pos.x += 7;
|
||||||
|
@ -217,14 +224,25 @@ function EventDispatcherControls(list, cursorIconBox, nodeShaper, edgeShaper, di
|
||||||
callback = function() {
|
callback = function() {
|
||||||
setCursorIcon(icon);
|
setCursorIcon(icon);
|
||||||
rebindNodes({
|
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){
|
mouseup: dispatcher.events.FINISHCREATEEDGE(function(edge){
|
||||||
|
edgeShaper.removeCursorFollowingEdge();
|
||||||
|
dispatcher.bind("svg", "mousemove", function(){});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
rebindEdges();
|
rebindEdges();
|
||||||
rebindSVG({
|
rebindSVG({
|
||||||
mouseup: dispatcher.events.CANCELCREATEEDGE(),
|
mouseup: function() {
|
||||||
mouseout: dispatcher.events.CANCELCREATEEDGE()
|
dispatcher.events.CANCELCREATEEDGE();
|
||||||
|
edgeShaper.removeCursorFollowingEdge();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
createIcon(icon, "connect", callback);
|
createIcon(icon, "connect", callback);
|
||||||
|
|
Loading…
Reference in New Issue