Inadequate handling of node/link removal in force layout causing issues during enter/exit actions

Attempting to visualize a directed acyclic graph using a force layout resulted in some unexpected behavior.

Despite implementing enter/exit conditions for each group element, removed nodes and links were not being removed from the DOM.

Instead, the removed nodes/links seemed to be frozen in the force layout, indicating that the enter/exit conditions were not triggering their removal.

To demonstrate this issue, I isolated the code in a jsfiddle and stack snippet where new nodes/links are added and removed after 3 seconds:

http://jsfiddle.net/dLucxt50/


const nodes = [{
      // node data objects
}];
const links = [{
      // link data objects
}];

// D3 force simulation details
...
            
        

body {
  background-color: #30404d;
}

svg {
  border-radius: 3px;
  box-shadow: inset 0 0 0 1px rgba(16, 22, 26, 0.4);
  background: rgba(16, 22, 26, 0.3);
  color: #f5f8fa;
}

.link {
  stroke: #777;
  stroke-opacity: 0.3;
  stroke-width: 1.5px;
}

.node circle {
  fill: #ccc;
  stroke: #000;
  stroke-width: 1.5px;
}

.node text {
  display: none;
  font: 10px monospace;
  fill: white;
}

.node:hover circle {
  fill: #000;
}

.node:hover text {
  display: inline;
}
            
        
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>

Answer №1

There are two main issues to address, one related to nodes and the other to links.

When dealing with nodes, it's crucial to merge the actual g elements (which are returned by .enter().append("g")) into the selection instead of working with the placeholders returned by .enter(). If you don't do this, your node selection will consist of placeholders, and manipulating them won't have any effect.

Regarding links, there is an interesting aspect to consider.

A force layout modifies the structure of your data - for nodes, the data array items acquire properties like x, y, vx, vy, and

index</code if they don't already possess these attributes.</p>

<p>For links, the properties <code>source
and target become direct references to specific nodes/items in the nodes data array rather than being string identifiers. This is why we can use:

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

However, this also means that we cannot use:

links = links.filter(l => l.source !== popped.id && l.target !== popped.id);

This limitation arises because when initializing the links, l.source and l.target are not strings that can be compared directly to

popped.id</code. Instead, we need to use <code>l.source.id
and l.target.id.

Here is a link to the updated fiddle

Below is a modified snippet with adjusted ids:

// Code snippet 
const nodes=[{"id":"a"}, ... {"id":"ax"}];
let links=[{"source":"a","target":"b"}, ..., {"source":"aw","target":"ax"}];

// D3 code here...

// CSS styles
body {
  background-color: #30404d;
}
...
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<body>
  <svg id="graph" style="width: 1000px; height: 500px;"> </div>
</body>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Upon submitting the form, the dynamic dependent drop-down list fails to offer any available options

Hey there, I've got a form with two drop-down lists: id="dd-1" & id="dd-2". The options in id="dd-2" are generated from the database based on what's selected in id="dd-1"; I'm using onChange=getChildOf(this.value) in id="dd-1" for this ...

Bcrypt.compare failing to match the passwords

I implemented a bcrypt.compare function in my code, but I'm running into an issue where it seems to not be comparing the passwords correctly. Regardless of the input password, the function always returns a status of ok. Can someone take a look at the ...

How can I convert a button to a link within an HTML table?

I have a question regarding buttons in my HTML table. Is it possible that upon clicking a button, the link button changes to "Un-Extend," and then switching back to the previous button when clicked again? How can I achieve this functionality? https://i.sst ...

Determine if the browser displays <select multiple> as a modal dialog

Is it possible to use JavaScript to detect whether a specific browser displays a focused <select multiple> element as a popup or strictly as an inline box? On certain platforms, like the Android Browser and iOS Safari, the appearance of a popup can ...

What is the best way to transfer item information from Flatlist within a React Native application?

I am a newcomer to react. In my App.js file, I have the main code, and in another folder, there is a lists.js file that contains the list data. I successfully import the list from lists.js into my App.js file. Now, I want to add an onPress action to the ...

Dynamically arranging data rows in a table using dates with Vue

In my Vue application, I am currently processing data for employees, including their hours and swipes, and multiplying this data for each employee every day. This process is generating new rows of data so that I have a complete set of information for each ...

Eliminating unnecessary whitespace between the bottom of the document and an element

I have a HTML page that when scrolled should limit scroll to the document height. It must not exceed the bottom of an element. Here is a screenshot for better understanding: https://i.stack.imgur.com/RaVg8.jpg The scrolling should be limited after the En ...

Is there a way to refresh CSS styles when the window width is adjusted?

Is there a way to refresh CSS styles when the window width changes? I attempted this method, but unfortunately it did not work as expected. A simple refresh (F5) helps to rectify the CSS tags. jQuery(function($){ var windowWidth = $(window).width(); ...

EasyWaySaveArchive in ninja training - mastering the art of retrieving components

Recently started learning about dojo and JavaScript in general. I am currently working on a code snippet that requires a button to change based on the result of a php database query. The PHP script is already complete, and the code I am using so far looks ...

Efficiently expanding and collapsing multiple levels with Bootstrap through AJAX data responses using jQuery

Looking for help with creating a multi-level expand-collapse feature using JSON data response with jQuery AJAX. As I am new to AJAX, I would appreciate any assistance with implementing the JSON data and expand-collapse plugin. All the data for different l ...

What is the reason that utilizing $("input").first() does not function properly on Google Forms?

While practicing with Selenium, I encountered an issue while using this Google form. Specifically, I found that I couldn't select the first input field by using $("input").first() To confirm this issue, I turned to the web browser (Firefox) console t ...

Utilizing Node.js Build System in Sublime Text 3 for JavaScript development

I'm currently running JavaScript code in Sublime Text 3 using Node version 9.4.0 as the build system. I’m curious to understand why, when I execute the following code: function Person() { } var manu = new Person(); console.log(Person.prototyp ...

Support for Vertex JS and Redis Sentinel integration

Are there any plans for Vertx 3.5.0 to support Redis Sentinel? Are there alternative methods to achieve this? I currently have a Master and Slave Architecture set up in Redis, with failover implementation concepts in place. I am able to accomplish this us ...

updating an object using its instance in angular: step-by-step guide

Having multiple nested arrays displaying data through HTML recursion in Angular, I am faced with the task of updating specific fields. Directly editing a field is simple and involves assigning its instance to a variable. arr=[{ "name":"f ...

The text is not displaying as expected due to a timeout issue

Trying to create a pop-up that functions as follows: After 3 seconds, the close button should appear, but during those 3 seconds, there will be a countdown. However, I'm encountering an issue where no text is being displayed. var n = 3; function p ...

Angular Reactive Forms may not properly update other inputs when binding a control to multiple inputs

While working with reactive forms, I encountered an issue where accessing the same control in multiple inputs seemed to result in one-way data binding (input-to-model). If I make edits in one input, it updates the model correctly but does not refresh the o ...

Traverse nested "for of" Loops recursively in JavaScript

As I delve into learning NodeJS, I find myself grappling with the challenge of crafting a more compact and refined logic for the code block shown below. I am eager to explore the possibility of incorporating recursion or leveraging ES6 methods to enhance e ...

Node JS encountered an error: ECONNRESET was read at TCP.onStreamRead on line 211, column 20 in the node internal stream base commons

I am facing an issue while trying to insert a large array of data into my MySQL database using node.js. Everything works fine when dealing with smaller arrays, around 300 elements, but as soon as I try to insert an array with 1 million elements, I encounte ...

Looking to apply a filter using an object in lodash that includes a condition for a range of values

We have developed a video game database and now we need to filter users based on their game and rank preferences. The data structure is outlined below: [{ "key": 86, "position": [ 40.369, -3.5419 ], "info": { "gamesplayin ...

Issue with SweetAlert2 cancel button being unresponsive while an ajax request is in progress

I have a custom function triggered when a dropdown item is selected, which triggers a sweetalert2 popup. Here's the function: function SwalPopup(ip, method) { var methodmsg = method.charAt(0).toUpperCase() + method.slice(1); swal.fire({ ...