Перетаскивание не работает в этом макете моделирования

#d3.js

#d3.js

Вопрос:

Я изменил некоторый код от Roger Veciana (спасибо, Роджер), чтобы он работал с d3js v5:

Вот исходный код:

http://bl.ocks.org/rveciana/6184054/bd294b921ebf2180eccc3aca548c895367fca2d2

Проблема в том, что перетаскивание не работает, и я не уверен, как я могу заставить его работать. Может ли кто-нибудь помочь мне с этим?

Вот код, который я изменил, чтобы он работал с v5:

 //Based in
///http://bl.ocks.org/mbostock/1804919
var margin = {
    top: 0,
    right: 0,
    bottom: 0,
    left: 0
  },
  width = 960 - margin.left - margin.right,
  height = 500 - margin.top - margin.bottom;

var rect = [50, 50, width - 50, height - 50];

var n = 20,
  m = 4,
  padding = 6,
  maxSpeed = 3,
  radius = d3.scaleSqrt().range([0, 8]),
  color = d3.scaleOrdinal(d3.schemeCategory10).domain(d3.range(m));
var nodes = [];

for (i in d3.range(n)) {
  nodes.push({
    radius: radius(1   Math.floor(Math.random() * 4)),
    color: color(Math.floor(Math.random() * m)),
    x: rect[0]   (Math.random() * (rect[2] - rect[0])),
    y: rect[1]   (Math.random() * (rect[3] - rect[1])),
    speedX: (Math.random() - 0.5) * 2 * maxSpeed,
    speedY: (Math.random() - 0.5) * 2 * maxSpeed
  });
}


/*var force = d3.layout.force()
.nodes(nodes)
.size([width, height])
.gravity(0)
.charge(0)
.on("tick", tick)
.start();*/

var simulation = d3.forceSimulation()
  .force("charge", d3.forceManyBody().strength(0))
  .force("collide", d3.forceCollide().radius(3))
  .nodes(nodes)
  .force("gravity", gravity(0))
  .on("tick", tick);


var svg = d3.select("body").append("svg")
  .attr("width", width   margin.left   margin.right)
  .attr("height", height   margin.top   margin.bottom)
  .append("g")
  .attr("transform", "translate("   margin.left   ","   margin.top   ")");

svg.append("svg:rect")
  .attr("width", rect[2] - rect[0])
  .attr("height", rect[3] - rect[1])
  .attr("x", rect[0])
  .attr("y", rect[1])
  .style("fill", "None")
  .style("stroke", "#222222");

var circle = svg.selectAll("circle")
  .data(nodes)
  .enter().append("circle")
  .attr("r", function(d) {
    return d.radius;
  })
  .attr("cx", function(d) {
    return d.x;
  })
  .attr("cy", function(d) {
    return d.y;
  })
  .style("fill", function(d) {
    return d.color;
  })
  .call(d3.drag());

var flag = false;

function tick(e) {
  simulation.alpha(0.1)
  circle
    .each(gravity(this.alpha()))
    .each(collide(.5))
    .attr("cx", function(d) {
      return d.x;
    })
    .attr("cy", function(d) {
      return d.y;
    });
}



// Move nodes toward cluster focus.
function gravity(alpha) {
  return function(d) {
    if ((d.x - d.radius - 2) < rect[0]) d.speedX = Math.abs(d.speedX);
    if ((d.x   d.radius   2) > rect[2]) d.speedX = -1 * Math.abs(d.speedX);
    if ((d.y - d.radius - 2) < rect[1]) d.speedY = -1 * Math.abs(d.speedY);
    if ((d.y   d.radius   2) > rect[3]) d.speedY = Math.abs(d.speedY);

    d.x = d.x   (d.speedX * alpha);
    d.y = d.y   (-1 * d.speedY * alpha);

  };
}

// Resolve collisions between nodes.
function collide(alpha) {
  var quadtree = d3.quadtree(nodes);
  return function(d) {
    var r = d.radius   radius.domain()[1]   padding,
      nx1 = d.x - r,
      nx2 = d.x   r,
      ny1 = d.y - r,
      ny2 = d.y   r;
    quadtree.visit(function(quad, x1, y1, x2, y2) {
      if (quad.point amp;amp; (quad.point !== d)) {
        var x = d.x - quad.point.x,
          y = d.y - quad.point.y,
          l = Math.sqrt(x * x   y * y),
          r = d.radius   quad.point.radius   (d.color !== quad.point.color) * padding;
        if (l < r) {
          l = (l - r) / l * alpha;
          d.x -= x *= l;
          d.y -= y *= l;
          quad.point.x  = x;
          quad.point.y  = y;
        }
      }
      return x1 > nx2 ||
        x2 < nx1 ||
        y1 > ny2 ||
        y2 < ny1;
    });
  };
}  
 <script src="https://d3js.org/d3.v5.js"></script>  

Спасибо!

Ответ №1:

Начиная с версии d3 v4, больше нет связи между d3-drag и d3-force . См. Также эту проблему.

Вместо этого вам нужно самостоятельно реализовать поведение перетаскивания. Я также установил радиус столкновения для radius свойства каждого круга, иначе вы не увидите правильного поведения.

 //Based in
///http://bl.ocks.org/mbostock/1804919
var margin = {
    top: 0,
    right: 0,
    bottom: 0,
    left: 0
  },
  width = 960 - margin.left - margin.right,
  height = 500 - margin.top - margin.bottom;

var rect = [50, 50, width - 50, height - 50];

var n = 20,
  m = 4,
  padding = 6,
  maxSpeed = 3,
  radius = d3.scaleSqrt().range([0, 8]),
  color = d3.scaleOrdinal(d3.schemeCategory10).domain(d3.range(m));
var nodes = [];

for (i in d3.range(n)) {
  nodes.push({
    radius: radius(1   Math.floor(Math.random() * 4)),
    color: color(Math.floor(Math.random() * m)),
    x: rect[0]   (Math.random() * (rect[2] - rect[0])),
    y: rect[1]   (Math.random() * (rect[3] - rect[1])),
    speedX: (Math.random() - 0.5) * 2 * maxSpeed,
    speedY: (Math.random() - 0.5) * 2 * maxSpeed
  });
}


/*var force = d3.layout.force()
.nodes(nodes)
.size([width, height])
.gravity(0)
.charge(0)
.on("tick", tick)
.start();*/

var simulation = d3.forceSimulation()
  .force("charge", d3.forceManyBody().strength(0))
  .force("collide", d3.forceCollide().radius(function(d) {
    return d.radius;
  }))
  .nodes(nodes)
  .force("gravity", gravity(0))
  .on("tick", tick);


var svg = d3.select("body").append("svg")
  .attr("width", width   margin.left   margin.right)
  .attr("height", height   margin.top   margin.bottom)
  .append("g")
  .attr("transform", "translate("   margin.left   ","   margin.top   ")");

svg.append("svg:rect")
  .attr("width", rect[2] - rect[0])
  .attr("height", rect[3] - rect[1])
  .attr("x", rect[0])
  .attr("y", rect[1])
  .style("fill", "None")
  .style("stroke", "#222222");

var circle = svg.selectAll("circle")
  .data(nodes)
  .enter().append("circle")
  .attr("r", function(d) {
    return d.radius;
  })
  .attr("cx", function(d) {
    return d.x;
  })
  .attr("cy", function(d) {
    return d.y;
  })
  .style("fill", function(d) {
    return d.color;
  })
  .call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended));

function dragstarted(d) {
  if (!d3.event.active) simulation.alphaTarget(0.3).restart();
  d.fx = d.x, d.fy = d.y;
}

function dragged(d) {
  d.fx = d3.event.x, d.fy = d3.event.y;
}

function dragended(d) {
  if (!d3.event.active) simulation.alphaTarget(0);
  d.fx = null, d.fy = null;
}

var flag = false;

function tick(e) {
  simulation.alpha(0.1)
  circle
    .each(gravity(this.alpha()))
    .each(collide(.5))
    .attr("cx", function(d) {
      return d.x;
    })
    .attr("cy", function(d) {
      return d.y;
    });
}



// Move nodes toward cluster focus.
function gravity(alpha) {
  return function(d) {
    if ((d.x - d.radius - 2) < rect[0]) d.speedX = Math.abs(d.speedX);
    if ((d.x   d.radius   2) > rect[2]) d.speedX = -1 * Math.abs(d.speedX);
    if ((d.y - d.radius - 2) < rect[1]) d.speedY = -1 * Math.abs(d.speedY);
    if ((d.y   d.radius   2) > rect[3]) d.speedY = Math.abs(d.speedY);

    d.x = d.x   (d.speedX * alpha);
    d.y = d.y   (-1 * d.speedY * alpha);

  };
}

// Resolve collisions between nodes.
function collide(alpha) {
  var quadtree = d3.quadtree(nodes);
  return function(d) {
    var r = d.radius   radius.domain()[1]   padding,
      nx1 = d.x - r,
      nx2 = d.x   r,
      ny1 = d.y - r,
      ny2 = d.y   r;
    quadtree.visit(function(quad, x1, y1, x2, y2) {
      if (quad.point amp;amp; (quad.point !== d)) {
        var x = d.x - quad.point.x,
          y = d.y - quad.point.y,
          l = Math.sqrt(x * x   y * y),
          r = d.radius   quad.point.radius   (d.color !== quad.point.color) * padding;
        if (l < r) {
          l = (l - r) / l * alpha;
          d.x -= x *= l;
          d.y -= y *= l;
          quad.point.x  = x;
          quad.point.y  = y;
        }
      }
      return x1 > nx2 ||
        x2 < nx1 ||
        y1 > ny2 ||
        y2 < ny1;
    });
  };
}  
 <script src="https://d3js.org/d3.v5.js"></script>  

Комментарии:

1. Один вопрос @ruben Helsloot . Если я сделаю это с изображением (значком) вместо круга, это должно сработать? потому что это не работает с изображением. Еще раз спасибо

2. Используете ли вы x и y или transform ? Вам нужно изменить tick , потому что круги используют cx/cy , но все остальное обычно использует x и y или transform . Если это не поможет, задайте новые вопросы, если вы не можете найти ответ здесь. Используйте случайный значок из Интернета, чтобы заставить его работать.