【问题标题】:How to drag nodes in d3.js in javascript?如何在javascript中拖动d3.js中的节点?
【发布时间】:2021-01-25 19:39:33
【问题描述】:

以下是使用 d3.js 制作力有向图的代码:

如何才能使节点只有在拖动节点时才能拖动

目前,当您在舞台上的任意位置拖动时,会拖动附近的某个节点。相反,只有在拖动真实节点(而不是周围区域)时,如何才能限制拖动发生

另外,我怎样才能使舞台可缩放和可拖动?

const graph = {
  nodes: [{
      name: 'john',
      age: 35
    },
    {
      name: 'simon',
      age: 37
    },
    {
      name: 'manjoor',
      age: 35
    },
    {
      name: 'lorg',
      age: 34
    },
    {
      name: 'kilvin',
      age: 32
    },
  ],
  links: [{
      source: 'john',
      target: 'simon'
    },
    {
      source: 'john',
      target: 'manjoor'
    },
    {
      source: 'simon',
      target: 'lorg'
    },
    {
      source: 'simon',
      target: 'kilvin'
    },
    {
      source: 'manjoor',
      target: 'kilvin'
    },
    {
      source: 'lorg',
      target: 'john'
    },
    {
      source: 'lorg',
      target: 'manjoor'
    },
    {
      source: 'kilvin',
      target: 'manjoor'
    },
  ]
}


const canvas = d3.select('#network')

const width = canvas.attr('width')
const height = canvas.attr('height')
const r = 30
const ctx = canvas.node().getContext('2d')

const color = d3.scaleOrdinal(d3.schemeAccent);

const simulation = d3.forceSimulation()
  .force('x', d3.forceX(width / 2))
  .force('y', d3.forceY(height / 2))
  .force('collide', d3.forceCollide(r + 20))
  .force('charge', d3.forceManyBody().strength(-100))
  .force('link', d3.forceLink().id(node => node.name))
  .on('tick', update)


simulation.nodes(graph.nodes)
simulation.force('link').links(graph.links)

canvas.call(d3.drag()
  .container(canvas.node())
  .subject(dragsubject).on('start', dragstarted)
  .on('drag', dragged).on('end', dragended)
)



function update() {
  ctx.clearRect(0, 0, width, height)

  ctx.beginPath()
  ctx.globalAlpha = 0.5
  ctx.strokeStyle = 'blue'
  graph.links.forEach(drawLink)
  ctx.stroke()


  ctx.beginPath()
  ctx.globalAlpha = 1
  graph.nodes.forEach(drawNode)
  ctx.fill()
}



function dragsubject(event) {
  return simulation.find(event.x, event.y);
}

function drawNode(d) {

  ctx.fillStyle = color(d.party)
  ctx.moveTo(d.x, d.y)
  ctx.arc(d.x, d.y, r, 0, Math.PI * 2)
}

function drawLink(l) {
  ctx.moveTo(l.source.x, l.source.y)
  ctx.lineTo(l.target.x, l.target.y)
}

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

function dragged(event) {
  event.subject.fx = event.x;
  event.subject.fy = event.y;
}

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

update()
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.js"></script>
<canvas id="network" width="600" height="300"></canvas>

【问题讨论】:

    标签: javascript d3.js html5-canvas


    【解决方案1】:

    来自documentation

    simulation.find(x, y[, radius]) - 返回具有给定搜索半径的最接近位置 ⟨x,y⟩ 的节点。如果未指定半径,则默认为无穷大。如果搜索区域内没有节点,则返回 undefined。

    通过r 的半径 - 这与球的半径相同 - 使得只有当动作是从节点中心r 时才可以注册拖动。

    const graph = {
      nodes: [{
          name: 'john',
          age: 35
        },
        {
          name: 'simon',
          age: 37
        },
        {
          name: 'manjoor',
          age: 35
        },
        {
          name: 'lorg',
          age: 34
        },
        {
          name: 'kilvin',
          age: 32
        },
      ],
      links: [{
          source: 'john',
          target: 'simon'
        },
        {
          source: 'john',
          target: 'manjoor'
        },
        {
          source: 'simon',
          target: 'lorg'
        },
        {
          source: 'simon',
          target: 'kilvin'
        },
        {
          source: 'manjoor',
          target: 'kilvin'
        },
        {
          source: 'lorg',
          target: 'john'
        },
        {
          source: 'lorg',
          target: 'manjoor'
        },
        {
          source: 'kilvin',
          target: 'manjoor'
        },
      ]
    }
    
    
    const canvas = d3.select('#network')
    
    const width = canvas.attr('width')
    const height = canvas.attr('height')
    const r = 30
    const ctx = canvas.node().getContext('2d')
    
    const color = d3.scaleOrdinal(d3.schemeAccent);
    
    const simulation = d3.forceSimulation()
      .force('x', d3.forceX(width / 2))
      .force('y', d3.forceY(height / 2))
      .force('collide', d3.forceCollide(r + 20))
      .force('charge', d3.forceManyBody().strength(-100))
      .force('link', d3.forceLink().id(node => node.name))
      .on('tick', update)
    
    
    simulation.nodes(graph.nodes)
    simulation.force('link').links(graph.links)
    
    canvas.call(d3.drag()
      .container(canvas.node())
      .subject(dragsubject)
      .on('start', dragstarted)
      .on('drag', dragged)
      .on('end', dragended)
    )
    
    function update() {
      ctx.clearRect(0, 0, width, height)
    
      ctx.beginPath()
      ctx.globalAlpha = 0.5
      ctx.strokeStyle = 'blue'
      graph.links.forEach(drawLink)
      ctx.stroke()
    
      ctx.beginPath()
      ctx.globalAlpha = 1
      graph.nodes.forEach(drawNode)
      ctx.fill()
    }
    
    function dragsubject(event) {
      return simulation.find(event.x, event.y, r);
    }
    
    function drawNode(d) {
      ctx.fillStyle = color(d.party)
      ctx.moveTo(d.x, d.y)
      ctx.arc(d.x, d.y, r, 0, Math.PI * 2)
    }
    
    function drawLink(l) {
      ctx.moveTo(l.source.x, l.source.y)
      ctx.lineTo(l.target.x, l.target.y)
    }
    
    function dragstarted(event) {
      if (!event.active) simulation.alphaTarget(0.3).restart();
      event.subject.fx = event.subject.x;
      event.subject.fy = event.subject.y;
    }
    
    function dragged(event) {
      event.subject.fx = event.x;
      event.subject.fy = event.y;
    }
    
    function dragended(event) {
      if (!event.active) simulation.alphaTarget(0);
      event.subject.fx = null;
      event.subject.fy = null;
    }
    
    update()
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.js"></script>
    <canvas id="network" width="600" height="300"></canvas>

    【讨论】:

      猜你喜欢
      • 2018-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-05
      • 2015-11-26
      • 2022-01-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多