Home > Net >  Calling a function to feed an .attr() in d3
Calling a function to feed an .attr() in d3

Time:02-03

I have .attr that create my link paths in d3 as below, Lines 42 in the demo:

link.each(function (d){})
  .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;
  });

The above draws my path links. I've changed this to calculate making the link paths smaller. However, there is a lot of repeated logic and not sure how to call a function to return my the values required. As below:

  link.attr("x1", function(d) {
      // Total difference in x and y from source to target
      let diffX = d.target.x - d.source.x;
      let diffY = d.target.y - d.source.y;

      // Length of path from center of source node to center of target node
      let pathLength = Math.sqrt((diffX * diffX)   (diffY * diffY));

      // x and y distances from center to outside edge of target node
      let offsetX = (diffX * 40) / pathLength;
      return d.source.x   offsetX;
    }).attr("y1", function(d) {
      let diffX = d.target.x - d.source.x;
      let diffY = d.target.y - d.source.y;

      let pathLength = Math.sqrt((diffX * diffX)   (diffY * diffY));

      let offsetY = (diffY * 40) / pathLength;

      return d.source.y   offsetY;
    }).attr("x2", function(d) {
      let diffX = d.target.x - d.source.x;
      let diffY = d.target.y - d.source.y;

      let pathLength = Math.sqrt((diffX * diffX)   (diffY * diffY));

      let offsetX = (diffX * 40) / pathLength;

      return d.target.x - offsetX;
    }).attr("y2", function(d) {
      let diffX = d.target.x - d.source.x;
      let diffY = d.target.y - d.source.y;

      let pathLength = Math.sqrt((diffX * diffX)   (diffY * diffY));

      let offsetY = (diffY * 40) / pathLength;

      return d.target.y - offsetY;
    })

It returns offsetX for d.source.x/d.target.x values and offsetY for d.source.y/d.target.y.

Ideally i dont want all this repeated logic and have tried doing a .call() on the link which goes into a function but then I dont know how to return the result into the attributes themselves e.g.

  .attr('x1', function (d) {
    return d.source.x; //function return from .call()
  })

I've also tried putting the function call within the above attribute but get an error of "is not a function" e.g

  .attr('x1', function (d) {
    return this.myNewPathFunction(d); 
  })

Lines 42 in the demo

CodePudding user response:

You could move your logic to a function like so:

const coordinate = (position, d, index, nodes) => {
  // Total difference in x and y from source to target
  let diffX = d.target.x - d.source.x;
  let diffY = d.target.y - d.source.y;

  // Length of path from center of source node to center of target node
  let pathLength = Math.sqrt(diffX * diffX   diffY * diffY);

  // x and y distances from center to outside edge of target node
  let offsetX = (diffX * 40) / pathLength;
  let offsetY = (diffY * 40) / pathLength;

  if (position === 'x1') return d.source.x   offsetX;
  if (position === 'y1') return d.source.y   offsetY;
  if (position === 'x2') return d.target.x - offsetX;
  if (position === 'y2') return d.target.y - offsetY;
};

link
  .attr('x1', (d, i, nodes) => coordinate('x1', d, i, nodes))
  .attr('y1', (d, i, nodes) => coordinate('y1', d, i, nodes))
  .attr('x2', (d, i, nodes) => coordinate('x2', d, i, nodes))
  .attr('y2', (d, i, nodes) => coordinate('y2', d, i, nodes));
  • Related