summaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorAlon Levy <alon@pobox.com>2015-04-12 15:54:46 +0200
committerAlon Levy <alon@pobox.com>2015-04-12 15:54:47 +0200
commit2f7ebdd01546b78f1584ce3e0b25e30f104523e9 (patch)
treebd715cb818463685fdd13351becdc2365ddd352e /src/client
parent7c5c6a917c8bce9d538c51becaf9a06fb1741bf5 (diff)
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)}
Diffstat (limited to 'src/client')
-rw-r--r--src/client/model/graph.js21
-rw-r--r--src/client/view/selection.js80
2 files changed, 61 insertions, 40 deletions
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;
- };
+function _type_to_state(type) {
+ switch (type) {
+ case 'exit':
+ return 'exit';
+ break;
+ case 'enter':
+ return '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;
- };
- }
- // 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,