D3.js - Labeling nodes with image in Force-Layout

早过忘川 提交于 2021-01-29 03:21:59

问题


I have the following code in my Codepen that's able to render the sprites flags (from CSS), yet it's not in the position where it should be based on the nodes's position.

In fact, I am able to drag the nodes from the flags sprites from the top!

Looking at some console.logs, it seems that d.x and d.y position from function ticked() is not passing when the nodes are called.

I am not sure how to fix this issue

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(-4))
    .force("center", d3.forceCenter(width/2, height/2))

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)
        )

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


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

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

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

//functions provided by D3.js
//
function ticked() {
    link
        .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;});

    node
        .style("left", function(d) {return d.x})
        .style("top", function(d) {return d.y});
  }

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


回答1:


You are super close! This took me quite a while to figure out.

I ended up creating a flag folder filled with country pngs in my project directory. Then dynamically loaded them using the country code.

Here is how I solved the problem:

const node = svg.selectAll(".flag")
    .data(data.nodes)
    .enter().append("image")
    .attr("xlink:href", d => require(`./flag/${d.code}.png`))
    .attr("width", radius)
    .attr("height", radius)
    .call(d3.drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended))


来源:https://stackoverflow.com/questions/39908583/d3-js-labeling-nodes-with-image-in-force-layout

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!