【问题标题】:Increasing the Pseudo-Area of D3 Path Link For Easier D3-Tip Event Trigger增加 D3 路径链接的伪区域以更轻松地触发 D3-Tip 事件
【发布时间】:2016-06-16 11:29:51
【问题描述】:

我是 D3.js 的新手,我正在使用它来构建一个树形图,就像在这个 JSFiddle 中一样(注意这不是我的,这正是我的样子)。

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

有没有什么办法可以透明地增加 D3 路径元素的面积并从 Javascript 中,以便更容易触发这些事件?我在 herehere 中看到过其他 SO 示例,但我无法在 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 }
})

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

【问题讨论】:

  • 我会尝试在你的可见线上画一条透明线,并将鼠标事件添加到透明线上。我看到你在编辑中提到了这一点,但看起来你正在采取迂回的方式。只需以与添加可见线完全相同的方式添加透明线。如果您提供特定代码的小提琴,我们很乐意提供帮助。

标签: javascript d3.js svg tooltip


【解决方案1】:

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

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

将鼠标悬停在路径旁边以查看标题。这是小提琴:http://jsfiddle.net/gerardofurtado/JnNwu/1025/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-23
    • 1970-01-01
    • 2021-12-30
    • 2015-08-26
    • 1970-01-01
    • 2013-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多