From 2f7ebdd01546b78f1584ce3e0b25e30f104523e9 Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Sun, 12 Apr 2015 15:54:46 +0200 Subject: client: for more then one selected node, related is the mutual neighbours i.e. related = |selected| == 1 N(selected) else intersection_{s in S}{neighbours(s)} --- src/client/model/graph.js | 21 ++++++++---- src/client/view/selection.js | 80 ++++++++++++++++++++++++++------------------ 2 files changed, 61 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/client/model/graph.js b/src/client/model/graph.js index 24d305a7..580ff660 100644 --- a/src/client/model/graph.js +++ b/src/client/model/graph.js @@ -243,10 +243,16 @@ function Graph(spec) { * NOTE: return doesn't include original nodes * * @return - { - * 'node': [node] - * 'link': [link] + * 'nodes': [{ + * node: node, + * kind: kind, + * sources: {node_id: true} + * }] + * 'links: [{link: link, kind: kind}] * } * + * kind: exit/enter + * * TODO: implement for d !== 1 * */ @@ -283,7 +289,7 @@ function Graph(spec) { } function make_status(kind, node) { - return {node: node, kind: kind, links: [], depth: Infinity}; + return {node: node, kind: kind, links: [], depth: Infinity, sources: {}}; } var nodes = get_nodes(), @@ -303,7 +309,7 @@ function Graph(spec) { visited = _.object(_.map(start, get_name), _.map(start, _.partial(make_status, selected))); - function visit(link, getter, kind, depth) { + function visit(source, link, getter, kind, depth) { var node = getter(link), name = get_name(node), data = visited[name]; @@ -314,6 +320,7 @@ function Graph(spec) { data.kind |= kind; data.links.push({link: link, kind: kind}); data.depth = Math.min(data.depth, depth); + data.sources[source.id] = true; return data; } @@ -332,10 +339,10 @@ function Graph(spec) { var N = neighbours[node.id]; _.each(N.src, function (link) { - visit(link, function (link) { return link.__dst; }, enter); + visit(node, link, function (link) { return link.__dst; }, enter); }); _.each(N.dst, function (link) { - visit(link, function (link) { return link.__src; }, exit); + visit(node, link, function (link) { return link.__src; }, exit); }); }); _.values(visited).forEach(function (data) { @@ -346,7 +353,7 @@ function Graph(spec) { if ((kind & selected) === selected) { return; } - ret.nodes.push({type: kind_to_string(kind), node: node}); + ret.nodes.push({type: kind_to_string(kind), node: node, sources: data.sources}); _.each(links, function (data) { ret.links.push({link: data.link, kind: kind_to_string(kind)}); }); diff --git a/src/client/view/selection.js b/src/client/view/selection.js index 252b8dea..3e76e93b 100644 --- a/src/client/view/selection.js +++ b/src/client/view/selection.js @@ -109,40 +109,55 @@ function byVisitors(node_selector, link_selector) { inner_select_nodes(sum_nodes(new_selection.nodes, links_to_nodes(new_selection.links))); } -function connectedComponent(nodes) { - var connected = get_main_graph().neighbourhood(nodes, 1), - i, - node, - link, - data; - - for (i = 0 ; i < connected.nodes.length ; ++i) { - data = connected.nodes[i]; - node = data.node; - switch (data.type) { - case 'exit': - node.state = 'exit'; - break; - case 'enter': - node.state = 'enter'; - break; - }; - } - for (i = 0 ; i < connected.links.length ; ++i) { - data = connected.links[i]; - link = data.link; - switch (data.type) { - case 'exit': - link.state = 'exit'; - break; - case 'enter': - link.state = 'enter'; - break; - }; +function _type_to_state(type) { + switch (type) { + case 'exit': + return 'exit'; + break; + case 'enter': + return 'enter'; + break; } - // XXX side effect, should not be here + return ''; +} + +function _select_nodes_helper(nodes, connected) { + _.each(connected.nodes, function (data) { + data.node.state = _type_to_state(data.type); + }); + _.each(connected.links, function (data) { + data.link.state = _type_to_state(data.type); + }); nodes.forEach(function (n) { n.state = 'selected'; }); return connected.nodes.map(function (d) { return d.node; }).concat(nodes.slice()); + +} + +function mutual_neighbours(nodes) { + var connected = get_main_graph().neighbourhood(nodes, 1), + ids; + + connected.nodes = connected.nodes.filter(function (data) { + return _.size(data.sources) > 1; + }); + ids = _.object(_.map(connected.nodes, function (data) { return data.node.id; }), + _.map(connected.nodes, function () { return true; })); + connected.links = connected.links.filter(function (data) { + return ids[data.link.__src.id] || ids[data.link.__dst.id]; + }); + return _select_nodes_helper(nodes, connected); +} + +/** + * neighbours(nodes) + * + * set state of graph nodes and links that are neighbours of the nodes, + * and the nodes themselves. + */ +function neighbours(nodes) { + var connected = get_main_graph().neighbourhood(nodes, 1); + + return _select_nodes_helper(nodes, connected); } var node_related = function(node) { @@ -192,7 +207,7 @@ function arr_compare(a1, a2) var inner_select_nodes = function(nodes) { - inner_select(nodes, connectedComponent(nodes)); + inner_select(nodes, nodes.length == 1 ? neighbours(nodes) : mutual_neighbours(nodes)); } var select_nodes = function(nodes) @@ -289,7 +304,6 @@ clear(); return { byVisitors: byVisitors, - connectedComponent: connectedComponent, is_empty: is_empty, clear: clear, select_nodes: select_nodes, -- cgit v1.3.1