d3.js - 强制布局边界问题V4 [英] d3.js - Force-Layout boundary issue V4

查看:324
本文介绍了d3.js - 强制布局边界问题V4的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前我正在开展FCC的项目之一 National Contiguity

Currently I am working one of FCC's project National Contiguity

基本上我能够弄清楚如何渲染标志精灵并连接节点及其链接。

Essentially I was able to figure it out how to render the flags sprites and connect the nodes and its links.

我唯一遇到的问题是如何实现类似FCC的示例的。具体来说,我正在尝试让节点像示例中那样排斥边界。

The only thing that I am having trouble is implementing is how to behave similar to FCC's example. Specifically I am trying ways to have the nodes to repel away from the boundries like in the example.

然而,我的行为并不那样(事实上,它非常已集群,但我不确切知道 d3.js强制文档中的哪些属性V4 我应该研究一下)。相反,似乎虽然节点和链接在边界附近停止,但它在那时停止

However, mine doesn't behave that way (in fact, it's very clustered but I don't know exactly what properties in the d3.js Force Documents V4 I should look into). Instead, it seems that though the node and the links stops near the boundary, it stops at that point

const width = w - (margin.left + margin.right);
const height = h - (margin.top + margin.bottom);

let flagNodes = d3.select("#canvas")
                  .append("div")
                  .classed("flag-nodes",true)


let svg = d3.select("#canvas")
              .append("svg")
              .attr("id","chart")
              .attr("width", w)
              .attr("height", h)


let chart = svg.append("g")
                .classed("display", true)
                .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

let simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d,i) {
      return i;
    }))
    .force("charge", d3.forceManyBody().strength(-60).distanceMax(50).distanceMin(5))
    .force("center", d3.forceCenter(width/2, height/2))
    .force("collide", d3.forceCollide().radius(35))
    // .force("centering", d3.forceCenter(,height))
    // .force("position", d3.forceX(0).strength(.01))
    // .force("position", d3.forceY(-18))


let link = chart.append("g")
        .classed("links",true)
        .selectAll("line")
        .data(data.links)
        .enter()
          .append("line")

simulation
    .nodes(data.nodes)
    .on("tick", ticked);

simulation
    .force("link")
    .links(data.links);

let node = flagNodes.selectAll(".flag-nodes")
        .data(data.nodes)
        .enter()
          .append("div")
          .attr("class", function(d,i){
            return `flag flag-${d.code}`
          })
          .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended)
        )

node.append("title")
.text(function(d) { return d.country; });

d3.forceX(width)

//functions provided by D3.js
//
function ticked() {
    node
        .style("left", function(d) {
          let xlimit = Math.max(radius, Math.min(width - radius, d.x))
          return (xlimit) + 'px'
        })
        .style("top", function(d) {
          let ylimit = Math.max(radius, Math.min(height - radius, d.y))
          return (ylimit - 2) + 'px'
        });
    link
        .attr("x1", function(d) {
          let x1 = Math.max(radius, Math.min(width - radius, d.source.x))
          return x1;
        })
        .attr("y1", function(d) {
          let y1 = Math.max(radius, Math.min(height - radius, d.source.y))
          return y1
        })
        .attr("x2", function(d) {
          let x2 = Math.max(radius, Math.min(width - radius, d.target.x))
          return x2;
        })
        .attr("y2", function(d) {
          let y2 = Math.max(radius, Math.min(height - radius, d.target.y))
          return y2
        });
  }

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;
}

Codepen

推荐答案

在每个刻度线上运行此函数在模拟的节点上:

On every tick, run this function on the simulation's nodes:

fixBounds() {
    const graphNodes = this.forceSimulation.nodes();

    graphNodes.forEach((node) => {
        if (node.x - this.nodeRadius < 0) {
            node.x = this.nodeRadius;
            node.vx = 0;
        }

        if (node.y - this.nodeRadius < 0) {
            node.y = this.nodeRadius;
            node.vy = 0;
        }

        if (this.width && node.x + this.nodeRadius > this.width) {
            node.x = this.width - this.nodeRadius;
            node.vx = 0;
        }

        if (this.height && node.y + this.nodeRadius > this.height) {
            node.y = this.height - this.nodeRadius;
            node.yx = 0;
        }
    })
} 

这会导致节点卡在边框上,节点之间的力会导致它们移动远离边境。

This will cause the nodes to get stuck on the border, and the forces between the nodes will cause them to move away from the border.

这篇关于d3.js - 强制布局边界问题V4的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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