javascriptangularsvgd3.jsd3-force-directed

Force Directed Graph, apply <line> style from nearest .on selector


StackBlitz demo - stackblitz is flaky in chrome, may not show preview. I use edge with stackBlitz, also fine on chrome for mobile.

I've created this force directed graph that has multiple labels attached to paths that sit on a <line>.

The label turns blue when individually clicked. What I have tried to do net is change the appearance of the <line> style depending on which label has been clicked. Each label has its own data, so I use an attribute in the data to determine what style the line should be upon .on click. Demo line 292:

  d3.select(this).each(function(d){
    if (d.lineStyle === "Confirmed"){
      _d3.select('.link').style('stroke', '#444');
      _d3.select('.link').style('stroke-dasharray', '0');
    } else if (d.lineStyle === "Unconfirmed"){
      _d3.select('.link').style('stroke-dasharray', '8, 5');
    }
  });

If lineStyle equals "confirm" apply one style or if lineStyle equals "Unconfirmed" show another style.

The issue with the above is it only applies the style to one line regardless of what label you click.

I need to find the nearest line to the label and apply the style to that line only.

I tried using this.parentNode something like _d3.select(this.parentNode).selectAll('.link').style('stroke-dasharray', '8, 5');

Is there a way I can find the nearest .link class in relation to the label maybe?

I have also seen a way to build a relationship function and call that somehow.


Solution

  • Firstly, that each inside the listener is unnecessary, since you have just one element being clicked.

    The problem is that d3.select('.link') will simply select the first .link it finds on the page, top to down. So, the behaviour you have is expected.

    What you probably want is filtering a line according to the text clicked. That could be done with parentNode, nextSibling etc., but that's not possible due to the structure you created. Thus, you can do it based on data:

    const thisLine = linkEnter.filter(e => e.index === d.index);
    

    Then:

    if (d.lineStyle === "Confirmed"){
        thisLine.style('stroke', '#444');
        thisLine.style('stroke-dasharray', '0');
    } else if (d.lineStyle === "Unconfirmed"){
        thisLine.style('stroke-dasharray', '8, 5');
    };
    

    There's nothing in your code to revert the change, but that's trivial to do.

    Here is the forked code: https://stackblitz.com/edit/github-dzry6q-6vj5yx?file=src%2Fapp%2Fdirected-graph-experiment.service.ts,src%2Fapp%2Fapp.component.ts