如何创建鼠标悬停时显示可点击元素?

3

我正在展示svg元素,把它们命名为标签,并在鼠标悬停事件上显示在图形节点上。这些元素的显示/隐藏效果很不错,尽管可能还有提升的空间。但是,我希望在鼠标悬停时显示的元素可以被点击。

目前,标签上的鼠标悬停事件无法捕获。如果我禁用清除标签的鼠标移出事件,标签上的事件就可以正确捕获,但很明显标签会一直存在。

有没有办法让这些标签在父元素的鼠标移出事件上可点击并被清除?我考虑在删除标签之前添加1秒的延迟,但我不知道该如何实现,也不确定这是否正确。

下面的代码显示了一个函数示例 - 可以在这里查看: https://jsfiddle.net/pducrot/4eyb81kx/

// graph size
var width = 400;
var height = 400;

var nodes = [{name: 'A'}, {name: 'B'}, {name: 'C'}, {name: 'D'}];
var edges = [{source: 'A', target: 'B'}, {source: 'B', target: 'C'}, {source: 'C', target: 'A'}, {source: 'C', target: 'D'}];
var tags = [10, 35, 56, 9];

var nodeMap = {};
nodes.forEach(function (x) {nodeMap[x.name] = x;});
var links = edges.map(function (x) {
    return {source: nodeMap[x.source], target: nodeMap[x.target], value: 1};
});

var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.attr("pointer-events", "all")
.call(d3.behavior.zoom().on("zoom", redraw))
.append('g');

var force = d3.layout.force()
.gravity(.25)
.distance(140)
.charge(-3500)
.size([width, height]);

var stdDragStart = force.drag().on("dragstart.force");
force.drag()
.on("dragstart", function (d) {
//prevent dragging on the nodes from dragging the canvas
d3.event.sourceEvent.stopPropagation();
stdDragStart.call(this, d);
});

force.nodes(nodes)
.links(links)
.friction(0.8)
.start();

var link = svg.selectAll(".link")
.data(links)
.enter().append("line")
.attr("class", "link");

var node = svg.selectAll(".node")
.data(nodes)
.enter().append("svg:g")
.attr("class", "node")
.attr("id", function (d) {
return d.name
})
.on("dblclick", dblclick)
.on("mouseover", function (d) {
drawTags(tags, d.name);
})
.on("mouseout", function (d) {
d3.select("#" + d.name).selectAll(".tool").remove();
})
.call(force.drag);

node.append("circle")
.attr("class", "circle")
.attr("r", 40);

d3.selectAll(node);

// display name in nodes if node structure
node.append("text")
.attr("text-anchor", "middle")
.attr("dy", ".35em")
.text(function (d) {
return d.name;
});

force.on("tick", function () {
link.attr("x1", function (d) {return d.source.x;})
    .attr("y1", function (d) {return d.source.y;})
    .attr("x2", function (d) {return d.target.x;})
    .attr("y2", function (d) {return d.target.y;});
node.attr("transform", function (d) {
        return "translate(" + d.x + "," + d.y + ")";
    });
});

// redraw after zooming
function redraw() {
    svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
}

function dblclick(d) {
    d3.select(this).classed("fixed", d.fixed = false);
}

function dragstart(d) {
    d3.select(this).classed("fixed", d.fixed = true);
}

function drawTags(tags, onto) {

    var rScale = d3.scale.ordinal()
    .domain(tags)
    .rangeBands([-Math.PI, Math.PI]);

    var local = d3.select("#" + onto).selectAll(".tool")
    .data(tags)
    .enter()
    .append("svg:g")
    .attr("pointer-events", "all")
    .attr("class", "tool")
    .attr("transform", function (d) {
    var x = Math.sin(rScale(d)) * 40;
    var y = Math.cos(rScale(d)) * 40;
    return "translate(" + x + "," + y + ")";
    })
    .on("mouseover", function (d) {
    alert("mouse over tag " + d);
    });
    local.append("circle")
    .attr("class", "circle")
    .attr("r", 15);

    local.append("text")
    .attr("text-anchor", "middle")
    .attr("dy", ".35em")
    .text(function (d) {
    return d
    });
}

enter image description here


“正确的做法”完全取决于您的应用程序,我们无法真正告诉您该怎么做。在您的应用程序中,给用户1秒钟点击工具提示上的某个东西是否合理?父元素是否足够大以提供预期的行为?您还可以仅在悬停在导致另一个工具提示出现的元素时隐藏工具提示。 - Lars Kotthoff
的确。我想我的首选解决方案是将鼠标悬停区域扩展到标记圆圈,而不是延迟1秒钟。正如您在我刚添加的图像中所看到的那样,标记是使用ajax动态从neo4j获取的,我希望在单击或悬停特定标记时显示其他信息。一个想法也可以将主节点带到前面,并且只保留用户从主节点移动鼠标的标记。 - Pierre
小提琴对我不起作用。 - kwoxer
你的意思是你没有访问权限还是代码有误? - Pierre
1个回答

0
一个部分的解决方案是在删除标签之前添加延迟,如上所述。这可以通过对节点变量进行操作来实现:
.on("mouseout", function(d) {
    d3.select("#"+d.name).selectAll(".tool")
    .transition()
    .delay(800)
    .remove();
})

在绘制标签时,减少标签和父节点之间的重叠会更好,因为mouseover仅在父节点上,标签不会被考虑在内。

var x = Math.sin(rScale(d))*50; // vs. 40px previously
var y = Math.cos(rScale(d))*50;

将标签上的鼠标悬停事件更改为点击事件,并使用.attr("pointer-events", "click")使标签和文本只接收点击指针事件。
.on("click", function(d) { alert(d); });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接