我是D3.js的新手,正在使用它来构建一个树形图,就像在JSFiddle中一样(注意这不是我的,这正是我的样子)。
我正在尝试使用D3-tip创建工具提示,这些工具提示会在将鼠标悬停在树中的路径链接上时触发。但是,由于路径元素的实际大小非常小,因此很难触发。
有没有办法透明地增加D3路径元素的区域和Javascript,以便更容易触发这些事件?我已经看到其他SO示例,例如here和here,但我无法在Javascript中正确实现它们。我显然试图增加路径元素的行程,但这看起来很傻。
谢谢。
我的代码如下:
export function createTree(json) {
var width = 600;
var height = 300;
var maxLabel = 120;
var duration = 200;
var radius = 8;
var i = 0;
var root;
var tree = d3.layout.tree()
.size([height - 20, width - 20]);
var diagonal = d3.svg.diagonal()
.projection(function (d) {
return [d.y, d.x];
});
var tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(d) {
var html = "<div id='popover-permission' align='center'> <div class='col-md-12'>" +
"<div class='row text-center'><span style='color:#444444;'>Distribution Contract:</span><br>" +
"<span class='textSmall' style='color:#444444;'>" + "3473247xxx78728347" + "</span></div></div></div>";
return html;
})
var svg = d3.select("#tree")
.append("div")
.classed("svg-container", true) //container class to make it responsive
.append("svg")
//responsive SVG needs these 2 attributes and no width and height attr
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 " + width + " " + height)
//class to make it responsive
.classed("svg-content-responsive", true)
.append("g")
.attr("transform", "translate(" + maxLabel + ",0)");
svg.call(tip);
root = json;
root.x0 = height / 2;
root.y0 = 0;
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
var links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function (d) {
d.y = d.depth * maxLabel;
});
// Update the nodes…
var node = svg.selectAll("g.node")
.data(nodes, function (d) {
return d.id || (d.id = ++i);
});
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter()
.append("g")
.attr("class", "node")
.attr("transform", function (d) {
return "translate(" + source.y0 + "," + source.x0 + ")";
})
.on("click", click);
nodeEnter.append("circle")
.attr("r", 0)
.style("fill", function (d) {
return d._children ? "lightsteelblue" : "white";
});
nodeEnter.append("text")
.attr("text-anchor", "middle")
.attr('x', 0)
.attr('y', 30)
.attr("dy", "-30")
.attr("class", "node-text textSmall")
.append('tspan')
.attr('x', 0)
.attr('dy', 10)
.text(function(d) { return d.name; })
.append('tspan')
.attr('x', 0)
.attr('dy', 20)
.attr("class", "textSmall tree-balance")
.text(function(d) {
return "(" + d.value + " ETH)";
})
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + d.y + "," + d.x + ")";
});
nodeUpdate.select("circle")
.attr("r", function (d) {
return computeRadius(d);
})
.style("fill", function (d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeUpdate.select("text").style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + source.y + "," + source.x + ")";
})
.remove();
nodeExit.select("circle").attr("r", 0);
nodeExit.select("text").style("fill-opacity", 0);
// Update the links…
var link = svg.selectAll("path.link")
.data(links, function (d) {
return d.target.id;
});
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("id", function(d) {
return d.target.address;
})
.attr("d", function (d) {
//console.log(d.source.name + d.target.name + " ");
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
})
.on('mouseover', tip.show)
.on('mouseleave', tip.hide);
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function (d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function (d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
function computeRadius(d) {
if (d.children || d._children) return radius + (radius * nbEndNodes(d) / 10);
else return radius;
}
function nbEndNodes(n) {
nb = 0;
if (n.children) {
n.children.forEach(function (c) {
nb += nbEndNodes(c);
});
}
else if (n._children) {
n._children.forEach(function (c) {
nb += nbEndNodes(c);
});
}
else nb++;
return nb;
}
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
}
else {
d.children = d._children;
d._children = null;
}
update(d);
}
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
update(root);
}
编辑:我还找到了this解决方案并为每条路径添加了一条透明线,如下所示:
lines = gEnter
.selectAll('.path').data(['visible', 'invisible'])
lines.enter()
.append('line')
.attr('class', 'path')
.attr('marker-end', function(d, i, j) {
// j is the parent's i
if (j === 2) {
return 'url(#arrow)';
} else {
return null;
}
})
.attr({
// returning null from these functions simply defaults to whatever the
// .path class's CSS props are doing
'stroke-width': function(d, i) { return d == 'invisible' ? 10 : null },
'stroke': function(d, i) { return d == 'invisible' ? 'transparent' : null }
})
问题是,即使绘制了线条,它也不会在浏览器中显示为元素,因此根本不会影响该区域。有没有办法改变这个?
答案 0 :(得分:1)
这就是我所做的:我将link
复制为link2
,具有所有相同的属性,但使用不同的类,我在CSS中设置如下:
.link2{
fill: none;
stroke: lightgray;
stroke-width: 20px;
opacity: 0;
}
将鼠标悬停在路径旁边以查看标题。这是小提琴:http://jsfiddle.net/gerardofurtado/JnNwu/1025/