javascript - 增加 D3 路径链接的伪区域以更轻松地触发 D3-Tip 事件

标签 javascript d3.js svg tooltip

我是 D3.js 的新手,正在使用它来构建树形图,如 JSFiddle 所示。 (请注意,这不是我的,这正是我的样子)。

我正在尝试使用 D3-tip 创建将鼠标悬停在树中的路径链接上时触发的工具提示。但由于路径元素的实际尺寸太小,触发起来非常困难。

是否有任何方法可以通过 Javascript 透明地增加 D3 路径元素的面积,以便更容易触发这些事件?我见过其他例子,例如 herehere但我无法在 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 }
})

问题是,即使绘制了线条,它也不会在浏览器中显示为元素,因此根本不会影响该区域。有什么办法可以改变这个吗?

最佳答案

这就是我所做的:我将您的 link 复制为 link2,具有所有相同的属性,但具有不同的类,我在 CSS 中设置如下:

.link2{
  fill: none;
  stroke: lightgray;
  stroke-width: 20px;
  opacity: 0;
}

将鼠标悬停在路径旁边即可查看标题。这是 fiddle :http://jsfiddle.net/gerardofurtado/JnNwu/1025/

关于javascript - 增加 D3 路径链接的伪区域以更轻松地触发 D3-Tip 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37857885/

相关文章:

javascript - 使用不显眼的验证插件时,如何禁用 1 个特定 html 元素的 keyup 和 focusout 上的 jquery 验证?

Javascript 密码正则表达式

java - 尝试保存到数据库时返回 403 Forbidden

html - Leaflet + D3 - Safari 上没有鼠标悬停

javascript - dc.js 二维有序堆积条形图,获取 NaN 值并且不显示堆积条形图

javascript - 复圆图

javascript - 我有一组字符串数据,我希望将其绘制在所需的分区中,并将字符串整齐地靠近绘制的圆圈

javascript - 如何在 Angularjs 服务中使用作为 ES6 模块导入的外部 JavaScript 库?

javascript - 使用 D3 和 d3.slider 显示 SVG 元素 : Uncaught ReferenceError: svg is not defined

javascript - 使用 React 在 SVG 中居中文本