如何在javascript中的d3.js中拖动节点? [英] How to drag nodes in d3.js in javascript?

查看:73
本文介绍了如何在javascript中的d3.js中拖动节点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是使用d3.js生成力向图的代码:


仅当您拖动节点时,如何才能使节点拖动


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


此外,如何使舞台可缩放&可拖动的吗?


  const graph = {
节点:[{
名称:'john',
年龄:35
},
{
名称:'simon',
年龄:37
},
{
名称: manjoor,
年龄:35
},
{
名称: lorg,
年龄:34
},
{
名称: kilvin,
年龄:32
},
],
链接:[{
来源: john,
目标: simon
},
{
来源: john,
目标: manjoor
},
{
来源: simon,
目标: lorg
},
{
来源: simon,
目标:开尔文
},
{
来源: manjoor,
目标:开尔文
},
{
来源: lorg,
目标: john
},
{
来源: lorg,
目标: manjoor
},
{
来源:开尔文,
目标: 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模拟= d3.forceSimulation()
.force('x',d3.forceX(width / 2))
.force('y',d3.forceY (高度/ 2))
.force('collide',d3.forceCollide(r + 20))
.force('charge',d3.forceManyBody()。strength(-100))
.force('link',d3.forceLink()。id(node => node.name))
.on('tick',更新)


Simulation.nodes(graph.nodes)
Simulation.force('link')。links(graph.links)

canvas.call(d3.drag()
.container(canvas.node())
.subject(dragsubject).on('开始',拖动开始)
.on('drag',拖动).on('结束',拖动)




函数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()
}



函数dragsub ject(event){
return Simulation.find(event.x,event.y);
}

函数drawNode(d){

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

函数drawLink(l){
ctx.moveTo(l。 source.x,l.source.y)
ctx.lineTo(l.target.x,l.target.y)
}

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

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

函数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>

解决方案

来自文档


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


传递半径 r -与球的半径相同-仅当动作是从节点中心开始 r 时,才可以注册拖动。


< pre class = snippet-code-js lang-js prettyprint-override> const graph = {
节点:[{
名称:'john',
年龄:35
},
{
名称: simon,
年龄:37
},
{
名称: manjoor ,
年龄:35
},
{
名称:'lorg',
年龄:34
},
{
名称: kilvin,
年龄:32
},
],
链接:[{
来源: john,
目标: 'simon'
},
{
来源:'john',
目标:'manjoor'
},
{
来源: simon,
目标: lorg
},
{
来源: simon,
目标:'kilvin'
},
{
来源:'manjoor',
目标:'kilvin'
},
{
来源: lorg,
目标: john
},
{
来源: lorg,
目标: manjoor
},
{
来源:'kilvin',
目标:'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模拟= d3.forceSimulation()
.force('x',d3.forceX(width / 2))
.force('y',d3.forceY (高度/ 2))
.force('collide',d3.forceCollide(r + 20))
.force('charge',d3.forceManyBody()。strength(-100))
.force('link',d3.forceLink()。id(node => node.name))
.on('tick',更新)


Simulation.nodes(graph.nodes)
Simulation.force('link')。links(graph.links)

canvas.call(d3.drag()
.container(canvas.node())
.subject(dragsubject)
.on('开始',拖动开始)
.on('拖动',拖动)
.on ('end',dragended)


函数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()
}

函数dragsubject(event){
return Simulation.find(event.x,event.y,r);
}

函数drawNode(d){
ctx.fillStyle = color(d.party)
ctx.moveTo(dx,dy)
ctx .arc(dx,dy,r,0,Math.PI * 2)
}

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

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

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

函数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>


Following is the code for making a force directed graph using d3.js:

How can I make dragging a node only when you drag a node?

Cause currently when you drag anywhere over the stage some nearby node get dragged. Instead, how can I constrain the drag to occur only if I'm dragging a real node (rather than the surrounding area)

Also how can I make the stage zoomable & draggable?

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>

解决方案

From the documentation:

simulation.find(x, y[, radius]) - Returns the node closest to the position ⟨x,y⟩ with the given search radius. If radius is not specified, it defaults to infinity. If there is no node within the search area, returns undefined.

Passing a radius of r - which is the same as the ball radius - made it possible to only register dragging when the action is r from the centre of the node.

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>

这篇关于如何在javascript中的d3.js中拖动节点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆