diff --git a/html/admin/js/graphViewer/graph/abstractAdapter.js b/html/admin/js/graphViewer/graph/abstractAdapter.js index ae0daec5b2..1386466e38 100644 --- a/html/admin/js/graphViewer/graph/abstractAdapter.js +++ b/html/admin/js/graphViewer/graph/abstractAdapter.js @@ -620,6 +620,7 @@ function AbstractAdapter(nodes, edges, descendant, config) { expandNode = function(n, startCallback) { if (n._isCommunity) { + console.log("Adapter Explore!"); self.expandCommunity(n, startCallback); } else { n._expanded = true; diff --git a/html/admin/js/graphViewer/graph/communityNode.js b/html/admin/js/graphViewer/graph/communityNode.js index a90b9abe9c..d07f19a27f 100644 --- a/html/admin/js/graphViewer/graph/communityNode.js +++ b/html/admin/js/graphViewer/graph/communityNode.js @@ -309,12 +309,12 @@ function CommunityNode(parent, initial) { shapeFunc(g); }, - addCollapsedShape = function(g, shapeFunc, colourMapper) { - g.attr("stroke", colourMapper.getForegroundCommunityColour()); - shapeFunc(g, 9); - shapeFunc(g, 6); - shapeFunc(g, 3); - shapeFunc(g); + addColour = function (g, colourFunc) { + colourFunc(g); + }, + + addEvents = function (g, eventsFunc) { + eventsFunc(g); }, addCollapsedLabel = function(g, colourMapper) { @@ -342,7 +342,24 @@ function CommunityNode(parent, initial) { .text(self._size); }, - addNodeShapes = function(g, shapeFunc, colourMapper) { + addCollapsedShape = function(g, shapeFunc, colourFunc, start, colourMapper) { + var inner = g.append("g"); + inner.attr("stroke", colourMapper.getForegroundCommunityColour()); + shapeFunc(inner, 9); + shapeFunc(inner, 6); + shapeFunc(inner, 3); + shapeFunc(inner); + colourFunc(inner); + inner.on("click", function() { + self.expand(); + start(); + }); + addCollapsedLabel(inner, colourMapper); + }, + + + + addNodeShapes = function(g, shapeFunc, colourFunc, eventsFunc, start, colourMapper) { var interior = g.selectAll(".node") .data(nodeArray, function(d) { return d._id; @@ -357,9 +374,11 @@ function CommunityNode(parent, initial) { interior.exit().remove(); interior.selectAll("* > *").remove(); addShape(interior, shapeFunc, colourMapper); + addColour(interior, colourFunc); + addEvents(interior, eventsFunc); }, - addBoundingBox = function(g) { + addBoundingBox = function(g, start) { bBox = g.append("g"); bBoxBorder = bBox.append("rect") .attr("rx", "8") @@ -373,21 +392,29 @@ function CommunityNode(parent, initial) { .attr("fill", "#686766") .attr("stroke", "none"); var dissolveBtn = bBox.append("image") + .attr("id", self._id + "_dissolve") .attr("xlink:href", "img/icon_delete.png") .attr("width", "16") .attr("height", "16") .attr("x", "5") .attr("y", "2") .attr("style", "cursor:pointer") - .on("click", dissolve), + .on("click", function() { + self.dissolve(); + start(); + }), collapseBtn = bBox.append("image") + .attr("id", self._id + "_collapse") .attr("xlink:href", "img/gv_collapse.png") .attr("width", "16") .attr("height", "16") .attr("x", "25") .attr("y", "2") .attr("style", "cursor:pointer") - .on("click", collapse), + .on("click", function() { + self.collapse(); + start(); + }), title = bBox.append("text") .attr("x", "45") .attr("y", "15") @@ -403,15 +430,16 @@ function CommunityNode(parent, initial) { }); }, - shapeAll = function(g, shapeFunc, colourMapper) { + shapeAll = function(g, shapeFunc, colourFunc, eventsFunc, start, colourMapper) { + // First unbind all click events that are proably still bound + g.on("click", null); if (self._expanded) { - addBoundingBox(g); + addBoundingBox(g, start); addDistortion(); - addNodeShapes(g, shapeFunc, colourMapper); + addNodeShapes(g, shapeFunc, colourFunc, eventsFunc, start, colourMapper); return; } - addCollapsedShape(g, shapeFunc, colourMapper); - addCollapsedLabel(g, colourMapper); + addCollapsedShape(g, shapeFunc, colourFunc, start, colourMapper); }; //////////////////////////////////// diff --git a/html/admin/js/graphViewer/graph/eventDispatcher.js b/html/admin/js/graphViewer/graph/eventDispatcher.js index f28348a445..ad3d5fd404 100644 --- a/html/admin/js/graphViewer/graph/eventDispatcher.js +++ b/html/admin/js/graphViewer/graph/eventDispatcher.js @@ -167,6 +167,10 @@ function EventDispatcher(nodeShaper, edgeShaper, config) { if (config.expand !== undefined) { if (eventlib.checkExpandConfig(config.expand)) { self.events.EXPAND = new eventlib.Expand(config.expand); + nodeShaper.setGVStartFunction(function() { + config.expand.reshapeNodes(); + config.expand.startCallback(); + }); } } if (config.drag !== undefined) { diff --git a/html/admin/js/graphViewer/graph/nodeShaper.js b/html/admin/js/graphViewer/graph/nodeShaper.js index 2c0999da43..00381ffd83 100644 --- a/html/admin/js/graphViewer/graph/nodeShaper.js +++ b/html/admin/js/graphViewer/graph/nodeShaper.js @@ -82,7 +82,6 @@ function NodeShaper(parent, flags, idfunc) { var self = this, nodes = [], visibleLabels = true, - splitLabel = function(label) { if (label === undefined) { return [""]; @@ -103,6 +102,7 @@ function NodeShaper(parent, flags, idfunc) { noop = function (node) { }, + start = noop, defaultDistortion = function(n) { return { x: n.x, @@ -165,13 +165,13 @@ function NodeShaper(parent, flags, idfunc) { }); addShape(normal); community.each(function(c) { - c.shape(d3.select(this), addShape, colourMapper); + c.shape(d3.select(this), addShape, addColor, addEvents, start, colourMapper); }); if (visibleLabels) { addLabel(normal); } - addColor(g); - addEvents(g); + addColor(normal); + addEvents(normal); addDistortion(); }, @@ -512,6 +512,10 @@ function NodeShaper(parent, flags, idfunc) { colourMapper.setChangeListener(callback); }; + self.setGVStartFunction = function(func) { + start = func; + }; + } NodeShaper.shapes = Object.freeze({ diff --git a/html/admin/js/graphViewer/jasmine_test/specCommunityNode/communityNodeSpec.js b/html/admin/js/graphViewer/jasmine_test/specCommunityNode/communityNodeSpec.js index e86d8844c8..79626683a8 100644 --- a/html/admin/js/graphViewer/jasmine_test/specCommunityNode/communityNodeSpec.js +++ b/html/admin/js/graphViewer/jasmine_test/specCommunityNode/communityNodeSpec.js @@ -363,8 +363,8 @@ describe('shaping functionality', function() { - var tSpan1, tSpan2, tSpan3, text, g, shaper, colourMapper, box, boxGroup, boxRect, - parent, c, width, titleBG, disBtn, titleText, colBtn; + var tSpan1, tSpan2, tSpan3, text, g, shaper, gv, colourMapper, box, boxGroup, boxRect, + parent, c, width, titleBG, disBtn, titleText, colBtn, comShapeInner; beforeEach(function() { parent = { @@ -462,6 +462,22 @@ return this; } }; + comShapeInner = { + attr: function() {}, + on: function() {}, + select: function() { + return { + attr: function() { + return width; + } + }; + }, + append: function(type) { + if (type === "text") { + return text; + } + } + }; text = { attr: function() { return this; @@ -480,28 +496,26 @@ } } }; - g = { - select: function() { - return { - attr: function() { - return width; - } - }; - }, + g = { attr: function() { return this; }, append: function(type) { - if (type === "text") { - return text; - } if (type === "g") { return boxGroup; } + }, + on: function() { + return this; } }; shaper = { - shapeFunc: function() {} + shapeFunc: function() {}, + colourFunc: function() {}, + eventsFunc: function() {} + }; + gv = { + start: function() {} }; colourMapper = { getForegroundCommunityColour: function() { @@ -548,33 +562,70 @@ expect(otherC._isCommunity).toBeTruthy(); }); - it('should shape the collapsed community with given functions', function() { - spyOn(g, "attr").andCallThrough(); + it('should shape the collapsed community with given functions', function() { + g = { + on: function() { + return this; + }, + append: function() { + return comShapeInner; + } + }; spyOn(g, "append").andCallThrough(); + spyOn(g, "on").andCallThrough(); spyOn(shaper, "shapeFunc").andCallThrough(); + spyOn(comShapeInner, "attr").andCallThrough(); spyOn(colourMapper, "getForegroundCommunityColour").andCallThrough(); - c.shape(g, shaper.shapeFunc, colourMapper); + c.shape( + g, + shaper.shapeFunc, + shaper.colourFunc, + shaper.eventsFunc, + gv.start, + colourMapper + ); expect(colourMapper.getForegroundCommunityColour).wasCalled(); - expect(g.attr).wasCalledWith("stroke", "black"); - expect(shaper.shapeFunc).wasCalledWith(g, 9); - expect(shaper.shapeFunc).wasCalledWith(g, 6); - expect(shaper.shapeFunc).wasCalledWith(g, 3); - expect(shaper.shapeFunc).wasCalledWith(g); + expect(g.append).wasCalledWith("g"); + expect(g.on).wasCalledWith("click", null); + expect(comShapeInner.attr).wasCalledWith("stroke", "black"); + expect(shaper.shapeFunc).wasCalledWith(comShapeInner, 9); + expect(shaper.shapeFunc).wasCalledWith(comShapeInner, 6); + expect(shaper.shapeFunc).wasCalledWith(comShapeInner, 3); + expect(shaper.shapeFunc).wasCalledWith(comShapeInner); }); it('should add a label containing the size of a community', function() { + g = { + on: function() { + return this; + }, + append: function() { + return comShapeInner; + } + }; + spyOn(g, "append").andCallThrough(); + spyOn(comShapeInner, "append").andCallThrough(); spyOn(text, "attr").andCallThrough(); spyOn(text, "append").andCallThrough(); spyOn(tSpan1, "attr").andCallThrough(); spyOn(tSpan1, "text").andCallThrough(); spyOn(colourMapper, "getForegroundCommunityColour").andCallThrough(); - c.shape(g, shaper.shapeFunc, colourMapper); + c.shape( + g, + shaper.shapeFunc, + shaper.colourFunc, + shaper.eventsFunc, + gv.start, + colourMapper + ); - expect(g.append).wasCalledWith("text"); + + expect(g.append).wasCalledWith("g"); + expect(comShapeInner.append).wasCalledWith("text"); expect(text.attr).wasCalledWith("text-anchor", "middle"); expect(text.attr).wasCalledWith("fill", "black"); expect(text.attr).wasCalledWith("stroke", "none"); @@ -588,12 +639,20 @@ }); it('should add a label if a reason is given', function() { + g = { + on: function() { + return this; + }, + append: function() { + return comShapeInner; + } + }; c._reason = { key: "key", value: "label" }; - spyOn(g, "append").andCallThrough(); + spyOn(comShapeInner, "append").andCallThrough(); spyOn(text, "attr").andCallThrough(); spyOn(text, "append").andCallThrough(); spyOn(tSpan1, "attr").andCallThrough(); @@ -603,9 +662,17 @@ spyOn(tSpan3, "attr").andCallThrough(); spyOn(tSpan3, "text").andCallThrough(); spyOn(colourMapper, "getForegroundCommunityColour").andCallThrough(); - c.shape(g, shaper.shapeFunc, colourMapper); + c.shape( + g, + shaper.shapeFunc, + shaper.colourFunc, + shaper.eventsFunc, + gv.start, + colourMapper + ); - expect(g.append).wasCalledWith("text"); + + expect(comShapeInner.append).wasCalledWith("text"); expect(text.attr).wasCalledWith("text-anchor", "middle"); expect(text.attr).wasCalledWith("fill", "black"); expect(text.attr).wasCalledWith("stroke", "none"); @@ -697,7 +764,14 @@ spyOn(titleText, "attr").andCallThrough(); - c.shape(g, shaper.shapeFunc, colourMapper); + c.shape( + g, + shaper.shapeFunc, + shaper.colourFunc, + shaper.eventsFunc, + gv.start, + colourMapper + ); expect(g.append).wasCalledWith("g"); expect(boxGroup.append).wasCalledWith("rect"); @@ -747,7 +821,15 @@ spyOn(observer, "observe").andCallThrough(); spyOn(observer, "disconnect").andCallThrough(); - c.shape(g, shaper.shapeFunc, colourMapper); + c.shape( + g, + shaper.shapeFunc, + shaper.colourFunc, + shaper.eventsFunc, + gv.start, + colourMapper + ); + expect(document.getElementById).wasCalledWith(c._id); expect(observer.observe).wasCalledWith( @@ -785,7 +867,15 @@ spyOn(iAll, "remove").andCallThrough(); - c.shape(g, shaper.shapeFunc, colourMapper); + c.shape( + g, + shaper.shapeFunc, + shaper.colourFunc, + shaper.eventsFunc, + gv.start, + colourMapper + ); + expect(g.selectAll).wasCalledWith(".node"); expect(nodeSelector.data).wasCalledWith(c.getNodes(), jasmine.any(Function)); @@ -812,7 +902,15 @@ nodes[4].x = 20; nodes[4].y = -20; - c.shape(g, shaper.shapeFunc, colourMapper); + c.shape( + g, + shaper.shapeFunc, + shaper.colourFunc, + shaper.eventsFunc, + gv.start, + colourMapper + ); + expect(nodes[0].position).toEqual({ x: -20, @@ -1304,6 +1402,31 @@ }); + describe('user interaction', function() { + + describe('if community is collapsed', function() { + + }); + + describe('if the community is expanded', function() { + + var c, parent; + + beforeEach(function() { + parent = { + dissolveCommunity: function() {} + }; + c = new CommunityNode(parent, nodes.slice(0, 5)); + }); + + it('should be possible to collapse the community', function() { + + }); + + }); + + }); + describe('convenience methods', function() { var parent; diff --git a/html/admin/js/graphViewer/ui/eventDispatcherControls.js b/html/admin/js/graphViewer/ui/eventDispatcherControls.js index efc6e2d4f2..f76f057eb9 100644 --- a/html/admin/js/graphViewer/ui/eventDispatcherControls.js +++ b/html/admin/js/graphViewer/ui/eventDispatcherControls.js @@ -2,7 +2,7 @@ /*global $, _, d3*/ /*global document, window*/ /*global modalDialogHelper, uiComponentsHelper */ -/*global EventDispatcher, EventLibrary*/ +/*global EventDispatcher*/ //////////////////////////////////////////////////////////////////////////////// /// @brief Graph functionality /// @@ -76,7 +76,6 @@ function EventDispatcherControls(list, nodeShaper, edgeShaper, dispatcherConfig) edit: "edit" }, baseClass = "event", - eventlib = new EventLibrary(), dispatcher = new EventDispatcher(nodeShaper, edgeShaper, dispatcherConfig), setCursorIcon = function(icon) {