score:1

Accepted answer

I've used your code to assemble a small example, which you can see below.

  1. Inside svg > defs, create one pattern per node and use that pattern (with the ID of the company) to fetch the logo of that company;
  2. Reference the pattern for the node using the information you already have.

Some pointers on your code:

  1. You already use ES6 logic, so you can also use Array.prototype.map and other functions. They're generally much more readable (and natively implemented!) than d3.map;
  2. There is no need to keep so many arrays of values, generally having fewer sources of truth for your data will make the code simpler to maintain and update in the future;
  3. Use clear variable names! LS and LT are logical when you know the context, but when you revisit this code in 6 months you might not instantly know what you were talking about when you wrote it.

const nodes = [{
    id: "Amazon",
    image: "https://images-eu.ssl-images-amazon.com/images/G/02/gc/designs/livepreview/a_generic_10_uk_noto_email_v2016_uk-main._CB485921599_.png"
  },
  {
    id: "Aurora",
    image: "https://res-3.cloudinary.com/crunchbase-production/image/upload/c_lpad,h_170,w_170,f_auto,b_white,q_auto:eco/oeagjbu7wau6o16zdhb1"
  },
  {
    id: "Zoox",
    image: "https://res-4.cloudinary.com/crunchbase-production/image/upload/c_lpad,h_170,w_170,f_auto,b_white,q_auto:eco/kpc7mmk886nbbipbeqau"
  }
];

const links = [{
    src: 'Amazon',
    target: 'Aurora'
  },
  {
    src: 'Amazon',
    target: 'Zoox'
  },
  {
    src: 'Aurora',
    target: 'Zoox'
  }
];

const width = 500,
  height = 500;

function ForceGraph({
  nodes, // an iterable of node objects (typically [{id}, …])
  links // an iterable of link objects (typically [{src, target}, …])
}, {
  nodeId = d => d.id, // given d in nodes, returns a unique identifier (string)
  nodeTitle, // given d in nodes, a title string
  nodeStroke = "teal", // node stroke color
  nodeStrokeWidth = 2, // node stroke width, in pixels
  nodeStrokeOpacity = 1, // node stroke opacity
  nodeRadius = 20, // node radius, in pixels
  nodeStrength = -750,
  linkDistance = 100,
  linkStrokeOpacity = 0.6, // link stroke opacity
  linkStrokeWidth = 7, // given d in links, returns a stroke width in pixels
  linkStrokeLinecap = "round", // link stroke linecap
  linkStrength,
  container
} = {}) {

  // Compute values.
  const N = d3.map(nodes, nodeId);

  // HERE: Don't replace the input nodes using this complex method,
  // just Object.assign({}, n) to essentially perform a deep copy of a node.

  // Replace the input nodes and links with mutable objects for the simulation.
  nodes = nodes.map(n => Object.assign({}, n));
  links = links.map(l => ({
    source: l.src,
    target: l.target
  }));

  const svg = d3.select('body')
    .append("svg")
    .attr("preserveAspectRatio", "xMinYMin meet")
    .attr("viewBox", [-width / 2, -height / 2, width, height])
    .classed("svg-content-responsive", true)

  const defs = svg.append('svg:defs');

  // HERE: See we add one image per node
  defs.selectAll("pattern")
    .data(nodes)
    .join(
      enter => {
        // For every new <pattern>, set the constants and append an <image> tag
        const patterns = enter
          .append("pattern")
          .attr("width", 48)
          .attr("height", 48);
        patterns
          .append("image")
          .attr("width", 48)
          .attr("height", 48)
          .attr("x", 0)
          .attr("y", 0);
        return patterns;
      }
    )
    // For every <pattern>, set it to point to the correct
    // URL and have the correct (company) ID
    .attr("id", d => d.id)
    .select("image")
    .datum(d => {
      debugger;
      return d;
    })
    .attr("xlink:href", d => {
      debugger;
      return d.image;
    })

  const link = svg.append("g")
    .attr("stroke-opacity", linkStrokeOpacity)
    .attr("stroke-width", linkStrokeWidth)
    .attr("stroke-linecap", linkStrokeLinecap)
    .selectAll("line")
    .data(links)
    .join("line");

  // Construct the forces.
  const forceNode = d3.forceManyBody();
  const forceLink = d3.forceLink(links).id(({
    index: i
  }) => N[i]);
  if (nodeStrength !== undefined) forceNode.strength(nodeStrength);
  if (linkStrength !== undefined) forceLink.strength(linkStrength);
  forceLink.distance(linkDistance)
  const simulation = d3.forceSimulation(nodes)
    .force(link, forceLink)
    .force("charge", forceNode)
    .force("x", d3.forceX())
    .force("y", d3.forceY())
    .on("tick", ticked);

  const node = svg.append("g")
    .attr("stroke", nodeStroke)
    .attr("stroke-opacity", nodeStrokeOpacity)
    .attr("stroke-width", nodeStrokeWidth)
    .selectAll("circle")
    .data(nodes)
    .join("circle")
    .style("fill", "#fff")
    .style("fill", d => `url(#${d.id})`)
    .attr("r", nodeRadius);

  function ticked() {
    link
      .attr("x1", d => d.source.x)
      .attr("y1", d => d.source.y)
      .attr("x2", d => d.target.x)
      .attr("y2", d => d.target.y);
    node
      .attr("cx", d => d.x)
      .attr("cy", d => d.y);
  }
} // ForceGraph

ForceGraph({
  nodes,
  links
});
line {
  stroke: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.js"></script>


Related Query

More Query from same tag