微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

d3.js – D3双击以重置粘性节点

我想在双击时将我的画布粘性节点重置为其原始位置.我将以下代码添加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中.

Sticky Force Layout

解决方法

以下是 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双击监听器.

这是修改后的dragended函数

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;

原文地址:https://www.jb51.cc/js/156855.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐