summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Levy <alon@pobox.com>2015-04-05 15:32:56 +0300
committerAlon Levy <alon@pobox.com>2015-04-05 16:27:19 +0300
commit13e3769e1ff9a5f599f22b3d1d3d9eb872117b32 (patch)
treeb9734c4ac6179c4f50011fcc8abbec4eeefaf738 /src
parent46dbb0240987578060fdabc2c8f91490cd820b73 (diff)
client: graph construction: text below circles. resolve #429
remind myself svg doesn't respect z-index, flatten back the svg structure: svg - zoom - graph g path 1 link text 1 node text 1 node text 2 node circle 1 node circle 2 per SVG 1.1 spec the last node is the top most.
Diffstat (limited to 'src')
-rw-r--r--src/client/view/graph_view.js201
1 files changed, 124 insertions, 77 deletions
diff --git a/src/client/view/graph_view.js b/src/client/view/graph_view.js
index 38d580e2..7f1a9a32 100644
--- a/src/client/view/graph_view.js
+++ b/src/client/view/graph_view.js
@@ -361,18 +361,92 @@ function GraphView(spec) {
link,
link_g,
link_text,
- node_text,
circle,
unselected_selector = '#' + graph_name + ' #link-group',
selected_selector = '#' + graph_name + ' #selected-link-group',
unselected_link_group = document.querySelector(unselected_selector),
selected_link_group = document.querySelector(selected_selector);
+ var nodeTextX = function(d) {
+ return urlValid(d) ? node_text_dx + node_url_dx : node_text_dx;
+ }
+
+ function model_id_from_dom_id(dom_id) {
+ return dom_id.split('__')[0];
+ }
+
+ var urlValid = function(d) {
+ return d.url !== undefined && d.url !== null && d.url.length > 0;
+ };
+
+ function node_text_setup() {
+ var node_text,
+ node_url_dx = 15;
+
+ node_text = vis.selectAll("g.nodetext")
+ .data(graph.nodes(), function(d) {
+ return d.id;
+ });
+ node_text.enter().insert('g')
+ .attr('id', function (d) { return text_node_id(d.id); })
+ .attr("class", "nodetext graph")
+ .on("click", function(d, i) {
+ if (d3.event.defaultPrevented) {
+ // drag happened, ignore click https://github.com/mbostock/d3/wiki/Drag-Behavior#on
+ return;
+ }
+ if (!temporary) {
+ svgInput.enable(this.querySelector('text'), d, nodeTextX(d));
+ (d3.event.shiftKey ? selection.invert : selection.update)([d]);
+ showNodeInfo(graph.find_node__by_id(model_id_from_dom_id(this.id)));
+ }
+ d3.event.stopPropagation();
+ })
+ .insert("text")
+ .attr("class", "nodetext graph")
+ .attr("dy", node_text_dy);
+ node_text.exit().remove();
+ var nodeText = function(d) {
+ var selected = selection.node_selected(d);
+
+ if (!d.name) {
+ return "_";
+ }
+ if (temporary || selected) {
+ return d.name;
+ } else {
+ if (d.name.length < 28) {
+ return d.name;
+ } else {
+ return d.name.substring(0, 25) + "...";
+ }
+ }
+ };
+ node_text.select('text').text(nodeText)
+ .attr("dx", nodeTextX);
+ }
+ var link_on_hover = function (d, debug_name) {
+ $('#' + d.id).hover(function (e) {
+ add_class(this, 'hovering');
+ // show text if not selected
+ if (!selection.link_selected(d)) {
+ set_link_label_text(this.id, link_text__short(d));
+ }
+ }, function (e) {
+ remove_class(this, 'hovering');
+ // hide text if not selected
+ if (!selection.link_selected(d)) {
+ set_link_label_text(this.id, "");
+ }
+ });
+ }
+
relayout = (relayout === undefined && true) || relayout;
link = d3.select(unselected_link_group).selectAll("g.link")
.data(graph.links(), function(d) { return d.id; });
+ // link group - container for paths. Created after text so it is above (see z-order for SVG 1.1)
link_g = link.enter()
.append('g')
.attr('id', function(d){ return d.id; }) // append link id to enable data->visual mapping
@@ -391,10 +465,10 @@ function GraphView(spec) {
.append("path")
.attr("class", "ghostlink");
- // add link label
+ // add link label third
link_g
.append("text")
- .attr('id', function(d){ return 'text_' + d.id; }) // append link id to enable data->visual mapping
+ .attr('id', function(d){ return text_link_id(d.id); }) // append link id to enable data->visual mapping
.attr("text-anchor", "middle")
.attr("class", "linklabel graph")
.on("click", function(d, i) {
@@ -403,33 +477,30 @@ function GraphView(spec) {
}
});
+ function text_link_id(id) {
+ return id + '__link_text';
+ }
+
+ function text_node_id(id) {
+ return id + '__node_text';
+ }
+
function visit_one_down(base, visitor) {
visitor(base);
_.forEach(base.childNodes, visitor);
}
function add_class(base, clazz) {
- visit_one_down(base, function (e) { e.classList.add(clazz); });
+ visit_one_down(base, function (e) { e.classList && e.classList.add(clazz); });
}
function remove_class(base, clazz) {
- visit_one_down(base, function (e) { e.classList.remove(clazz); });
+ visit_one_down(base, function (e) { e.classList && e.classList.remove(clazz); });
}
function set_link_label_text(link_id, text) {
- $('#text_' + link_id).text(text);
+ $('#' + text_link_id(link_id)).text(text);
}
+
link_g.each(function (d) {
- $(this).hover(function (e) {
- add_class(this, 'hovering');
- // show text if not selected
- if (!selection.link_selected(d)) {
- set_link_label_text(this.id, link_text__short(d));
- }
- }, function (e) {
- remove_class(this, 'hovering');
- // hide text if not selected
- if (!selection.link_selected(d)) {
- set_link_label_text(this.id, "");
- }
- });
+ link_on_hover(d, 'link-g');
});
link_g.on("click", function(d, i) {
if (zoomInProgress) {
@@ -470,9 +541,6 @@ function GraphView(spec) {
this.link = d;
});
- link_text = vis.selectAll(".linklabel")
- .data(graph.links(), function(d) { return d.id; });
-
function link_text__short(d) {
var name = d.name || "";
@@ -482,6 +550,9 @@ function GraphView(spec) {
return name.substring(0, consts.link_text_short_length) + "...";
}
+ link_text = vis.selectAll(".linklabel")
+ .data(graph.links(), function(d) { return d.id; });
+
link_text
.text(function(d) {
var src_selected = selection.node_selected(d.__src),
@@ -506,6 +577,8 @@ function GraphView(spec) {
return d.id;
});
+ node_text_setup();
+
var nodeEnter = node.enter()
.append("g")
.attr('id', function(d){ return d.id; }) // append node id to enable data->visual mapping
@@ -567,62 +640,18 @@ function GraphView(spec) {
};
}); //();
- var node_url_dx = 15;
- var nodeTextX = function(d) {
- return urlValid(d) ? node_text_dx + node_url_dx : node_text_dx;
- }
-
- node_text = nodeEnter.insert("text")
- .attr("class", "nodetext graph")
- .attr("dy", node_text_dy)
- .on("click", function(d, i) {
- if (d3.event.defaultPrevented) {
- // drag happened, ignore click https://github.com/mbostock/d3/wiki/Drag-Behavior#on
- return;
- }
- if (!temporary) {
- svgInput.enable(this, d, nodeTextX(d));
- (d3.event.shiftKey ? selection.invert : selection.update)([d]);
- showNodeInfo(graph.find_node__by_id(this.parentNode.id));
- }
- d3.event.stopPropagation();
- });
var noderef = nodeEnter.insert('a')
.attr("class", "nodeurl graph")
.attr("transform", "translate(10,-7)")
.attr("dy", node_text_dy);
noderef.insert("image");
- var urlValid = function(d) {
- return d.url !== undefined && d.url !== null && d.url.length > 0;
- };
-
- var nodeText = function(d) {
- var selected = selection.node_selected(d);
-
- if (!d.name) {
- return "_";
- }
- if (temporary || selected) {
- return d.name;
- } else {
- if (d.name.length < 28) {
- return d.name;
- } else {
- return d.name.substring(0, 25) + "...";
- }
- }
- };
- node.select('g.node text')
- .text(nodeText);
node.select('g.node a')
.attr("xlink:href", function (d) { return d.url; })
.attr("xlink:title", function (d) { return d.url; })
.attr("target", "_blank")
.attr("visibility", function(d) { return urlValid(d) ? "visible" : "hidden"; })
.attr("pointer-events", function(d) { return urlValid(d) ? "all" : "none"; });
- node.select('g.node text')
- .attr("dx", nodeTextX);
node.select('g.node a image')
.each(function (d, i) {
var element = this,
@@ -1009,24 +1038,38 @@ function GraphView(spec) {
return d.id;
});
var link_text = vis.selectAll(".linklabel").data(graph.links());
+ var node_text = vis.selectAll("g.nodetext").data(graph.nodes());
var bubble_radius = selection.is_empty() || temporary ? gv.bubble_radius : selection_outer_radius;
- function transform(d) {
+ if (temporary) {
+ // XXX convert to a layout
+ circle__set_positions();
+ }
+
+ // XXX This computes every node ignoring filter.
+ graph.nodes().forEach(function (d) {
if (check_for_nan(d.x) || check_for_nan(d.y)) {
return;
}
+ if (d.x === undefined || d.y === undefined) {
+ console.log('oops, undefined position');
+ }
var d2 = d.__selection !== undefined ? d : bubble_transform(d, bubble_radius);
d.bx = d2.x;
d.by = d2.y;
- return "translate(" + d2.x + "," + d2.y + ")";
- }
+ });
- if (temporary) {
- circle__set_positions();
+ function translate(x, y) {
+ if (x === undefined || y === undefined) {
+ console.log('oops, undefined translate');
+ }
+ return "translate(" + x + "," + y + ")";
}
+ function transform(d) { return translate(d.bx, d.by); }
// transform nodes first to record bubble x & y (bx & by)
node.attr("transform", transform);
+ node_text.attr("transform", transform);
function same_zoom(d) {
if (d.zoom_obj === null || parent_graph_zoom_obj === null) {
@@ -1068,12 +1111,16 @@ function GraphView(spec) {
.attr('tabindex', function(d, i) { return i + 100; });
// After initial placement we can make the nodes visible.
- node.attr('visibility', function (d, i) {
- return node__is_shown(d) ? 'visible' : 'hidden';
- });
- link.attr('visibility', function (d, i) {
- return link__is_shown(d) ? 'visible' : 'hidden';
- });
+ [node, node_text].forEach(function (list) {
+ list.attr('visibility', function (d, i) {
+ return node__is_shown(d) ? 'visible' : 'hidden';
+ });
+ });
+ [link, link_text].forEach(function (list) {
+ link.attr('visibility', function (d, i) {
+ return link__is_shown(d) ? 'visible' : 'hidden';
+ });
+ });
}
// SVG rendering order is last rendered on top, so to make sure