首页 > 解决方案 > 如何创建一个拖动和克隆网络 d3

问题描述

我正在尝试创建一个创建网络访问的区域。从这个区域,我想将一个节点拖放到另一个区域。我的当前代码有两个问题。

(1) 我有拖放工作,但不知道如何为网络 vis 创建一个容器,这样它就不会溢出到其他区域。

这是一个带有工作示例的可观察笔记本。在此示例中,网络包含不是一个大问题,因为它是一个小型网络,但我想知道如何为更大的网络创建一个容器。

(2) 另外,一个节点一旦被拖放,就不能再被拖放,这是为什么呢?

const w = 600, h = 600;
//Create SVG element
const svg = d3.select("body")
  .append("svg")
  .attr("id", "#network")
  .attr("viewBox", [0, 0, w, h]);

svg
  .append("rect") // Schema Box
  .attr("id", "network")
  .attr("width", w)
  .attr("height", h / 4 * 3)
  .attr("stroke", "black")
  .attr("fill", "none");

let network = svg.append("g");
const scale = d3.scaleOrdinal(d3.schemeCategory10)
const colors = d => scale(d.group);

//SET UP MOTIF
let motifSVG = svg
  .append("svg")
  .attr("width", w)
  .attr("height", h / 4);

let motifRect = motifSVG.append("rect")
  .attr("id", "motif")
  .attr("width", w)
  .attr("height", h / 4)

motifRect
  .attr("stroke", "black")
  .attr("fill", "none")
  .attr("transform", `translate(0, ${h - (h/4)})`);

d3.json("https://static.observableusercontent.com/files/a54fa5363b4035634b31bda01f902f2620a54a6366986631347558458e2484388de6575e5015e38bccc7db6637d87f80ad4ed7bdcab81ec3f31b75908a22a42d?response-content-disposition=attachment%3Bfilename*%3DUTF-8%27%27miserables%2520(1).json").then((dataset) => {
  const linksData = dataset.links
  const nodesData = dataset.nodes

  //Initialize a simple force layout, using the nodes and edges in dataset
  const force = d3.forceSimulation(nodesData)
    .force("charge", d3.forceManyBody())
    .force("link", d3.forceLink(linksData).id(d => d.id))
    .force("center", d3.forceCenter().x(w / 2).y(h / 2));

  //Create edges as lines
  var edges = network
    .append("g")
    .attr("class", "link")
    .selectAll("line")
    .data(linksData)
    .enter()
    .append("line")
    .style("stroke", "#ccc")
    .style("stroke-width", 1);

  //Create nodes as circles
  var nodes = network.selectAll("circle")
    .data(nodesData)
    .enter()
    .append("circle")
    .attr("r", 10)
    .style("fill", colors)
    .attr("id", d => d.id)

  //Add a simple tooltip
  nodes.append("title")
    .text((d) => d.id);

  nodes.call(
    d3
    .drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended)
  );


  //Every time the simulation "ticks", this will be called
  force.on("tick", function() {

    edges.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;
      });

    nodes.attr("cx", function(d) {
        return d.x;
      })
      .attr("cy", function(d) {
        return d.y;
      });

  });
});

function dragstarted(d) {
  d3.select(this).clone()
  d3.select(this).raise().attr("stroke", "black").classed("clone", true);
}

function dragged(d) {
  d3.select(this)
    .attr("cx", (d.x = d3.event.x))
    .attr("cy", (d.y = d3.event.y));
}

function dragended(d) {
  var mouseCoordinates = d3.mouse(this);

  let networkHeight = d3.select("#network").attr("height");

  if (mouseCoordinates[1] > networkHeight) {
      d3.select(this)
        .attr("r", 20);
  } else {
    d3.select(this).remove();
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

标签: svgd3.jsdrag-and-dropclone

解决方案


推荐阅读