我想在双击时将我的画布粘性节点重置为其原始位置.我将以下代码添加到
this example但它不起作用:
function dblclick() { graph.nodes.forEach(function(d) { d.fx = d.fy = null; }) };
将dblclick添加到节点:
simulation .nodes(graph.nodes) .on("tick",ticked) .on("dblclick",dblclick);
在以下示例中,双击节点时,它将重置为其原始位置,但此示例位于SVG中.
解决方法
以下是
Andrew’s force layout的修改版本,双击时释放粘性节点:
var canvas = document.querySelector("canvas"),context = canvas.getContext("2d"),width = canvas.width,height = canvas.height; var simulation = d3.forceSimulation() .force("link",d3.forceLink().id(function(d) { return d.id; })) .force("charge",d3.forceManyBody()) .force("center",d3.forceCenter(width / 2,height / 2)); d3.json("https://gist.githubusercontent.com/mbostock/4062045/raw/5916d145c8c048a6e3086915a6be464467391c62/miserables.json",function(error,graph) { if (error) throw error; simulation .nodes(graph.nodes) .on("tick",ticked); simulation.force("link") .links(graph.links); d3.select(canvas) .call(d3.drag() .container(canvas) .subject(dragsubject) .on("start",dragstarted) .on("drag",dragged) .on("end",dragended)); function ticked() { var margin = 20; graph.nodes.forEach(function(d) { d.x = Math.max(margin,Math.min(width - margin,d.x)) d.y = Math.max(margin,Math.min(height - margin,d.y)) }) context.clearRect(0,width,height); context.beginPath(); graph.links.forEach(drawLink); context.strokeStyle = "#aaa"; context.stroke(); context.beginPath(); graph.nodes.forEach(drawNode); context.fill(); context.strokeStyle = "#fff"; context.stroke(); } function dragsubject() { return simulation.find(d3.event.x,d3.event.y); } }); var clickDate = new Date(); var difference_ms; function dragstarted() { if (!d3.event.active) simulation.alphaTarget(0.3).restart(); d3.event.subject.fx = Math.max(10,Math.min(width - 10,d3.event.subject.x)); d3.event.subject.fy = Math.max(10,Math.min(height - 10,d3.event.subject.y)); } function dragged() { d3.event.subject.fx = Math.max(10,d3.event.x)); d3.event.subject.fy = Math.max(10,d3.event.y)); } function dragended() { if (!d3.event.active) simulation.alphaTarget(0); difference_ms = (new Date()).getTime() - clickDate.getTime(); clickDate = new Date(); if (difference_ms < 200) { simulation.alphaTarget(0.3).restart() d3.event.subject.fx = null; d3.event.subject.fy = null; } } function drawLink(d) { context.moveTo(d.source.x,d.source.y); context.lineTo(d.target.x,d.target.y); } function drawNode(d) { context.moveTo(d.x + 3,d.y); context.arc(d.x,d.y,3,2 * Math.PI); }
<!DOCTYPE html> <Meta charset="utf-8"> <canvas width="700" height="550"></canvas> <script src="https://d3js.org/d3.v4.min.js"></script>
这是trick的直接应用,它通过在我们的例子中使用拖动侦听器的dragended部分来添加simili双击监听器.
function dragended() { if (!d3.event.active) simulation.alphaTarget(0); // Time between 2 ends of drag: difference_ms = (new Date()).getTime() - clickDate.getTime(); clickDate = new Date(); // if the time between these 2 ends of drag is short enough,then // it's considered a double click: if (difference_ms < 200) { // And we can release the node: simulation.alphaTarget(0.3).restart() d3.event.subject.fx = null; d3.event.subject.fy = null; } }
这个想法包括一个全局变量,它存储一个元素最后一次被拉伸的日期,以便知道下一次再次触发dragended时,自上一次触发以来已经过了多少时间.
因此,通过在两个dragended之间设置最大时间阈值(例如200ms),我们可以确定我们处于双击状态.
一旦我们确定它是双击,那么我们可以通过重置它的强制设置来释放被点击节点上的约束:
simulation.alphaTarget(0.3).restart() d3.event.subject.fx = null; d3.event.subject.fy = null;