5

I am trying to programmatically open d3.js nodes in a collapsible tree:

d3_collapsible_tree_viz

I load the data with the following d3.js snippet (which collapses the nodes after the second level),

d3.json("js/ontology.json", function(error, treeData) {
  if (error) throw error;
  root = d3.hierarchy(treeData, function(d) { return d.children; });
  root.x0 = height / 2;
  root.y0 = 0;
  // Collapse after the second level:
  root.children.forEach(collapse);
  update(root);
});

I then use the following d3.js code

var nodeEnter = node.enter().append('g')
    .attr('class', 'node')
    .attr('node-name', d => d.data.name.toLowerCase())
    .attr("transform", function(d) {
      return "translate(" + source.y0 + "," + source.x0 + ")";
  })
.on('click', click);

and this function

function expandNode() {
  const node = d3.select('.node[node-name="Nature"]').node();
  console.log('NODE: ', node);
  node.dispatchEvent(new Event('click'));
  }
expandNode();

to programmatically open the "Nature" node.

However, when I substitute "Nature" (visible node) with "Earth" (nested child of "Nature", not visible) this expression

const node = d3.select('.node[node-name="Earth"]').node();

will expand the "Earth" node only if it is visible.

That statement will not expand "Nature" to show "Earth" (and subsequently expand "Earth") if "Earth" is not visible.

Suggestions?


Edit 1. This is closely related to my earlier StackOverflow question,

Programmatically opening d3.js v4 collapsible tree nodes?

If needed, please refer to the JSFiddle referenced there,

https://jsfiddle.net/vstuart/acx5zfgn/62/

The labels are different but otherwise the data and code are similar.


Edit 2. Follow-on question

Accessing promised data in d3.js v6 [programmatically opening nested collapsed nodes]

relating to:

  • d3.js v6;
  • loading external JSON data via d3.js callback/promise;
  • this question, in that updated context.

ontology.json

{ "name": "Root",
  "children": [
    { "name": "Culture",
      "children": [
        { "name": "LGBT" }
      ]
    },

    { "name": "Nature",
      "id": "nature",
      "children": [
        { "name": "Earth",
          "id": "earth",
          "children": [
            { "name": "Environment" },
            { "name": "Geography" },
            { "name": "Geology" },
            { "name": "Geopolitical" },
            { "name": "Geopolitical - Countries" },
            { "name": "Geopolitical - Countries - Canada" },
            { "name": "Geopolitical - Countries - United States" },
            { "name": "Nature" },
            { "name": "Regions" }
          ]
        },
        { "name": "Cosmos" },
        { "name": "Outer space" }
      ]
    },

    { "name": "Humanities",
      "children": [
          { "name": "History" },
          { "name": "Philosophy" },
          { "name": "Philosophy - Theology" }
      ]
    },

    { "name": "Miscellaneous",
      "children": [
          { "name": "Wikipedia",
            "url": "https://wikipedia.com" },
          { "name": "Example.com",
            "url": "https://example.com" }
      ]
    },
      
    { "name": "Science",
      "children": [
          { "name": "Biology" },
          { "name": "Health" },
          { "name": "Health - Medicine" },
          { "name": "Sociology" }
      ]
    },

    { "name": "Technology",
      "children": [
            { "name": "Computers" },
            { "name": "Computers - Hardware" },
            { "name": "Computers - Software" },
            { "name": "Computing" },
            { "name": "Computing - Programming" },
            { "name": "Internet" },
            { "name": "Space" },
          { "name": "Transportation" }
      ]
    },

  { "name": "Society",
      "children": [
            { "name": "Business" },
            { "name": "Economics" },
            { "name": "Economics - Business" },
            { "name": "Economics - Capitalism" },
            { "name": "Economics - Commerce" },
            { "name": "Economics - Finance" },
            { "name": "Politics" },
          { "name": "Public services" }
      ]
    }
  ]
}
Victoria Stuart
  • 4,610
  • 2
  • 44
  • 37

1 Answers1

2

You need to discover the node ancestors recursively and then expand them on by one:

const findNodeAncestors = (root, name) => {
  if (root.name === name) {
    return [name];
  }

  if (root.children) {
    for (let i = 0; i < root.children.length; i++) {
      const chain = findNodeAncestors(root.children[i], name);
      if (chain) {
        chain.push(root.name);
        return chain;
      }
    }
  }
  return null;
}; 
   

const chain = findNodeAncestors(treeData.data, 'Earth');
  
for (let i = chain.length - 1; i >= 0; i--) {
  const node = d3.select(`.node[node-name="${chain[i]}"]`);
  const nodeData = node.datum();
  if (!nodeData.children && nodeData.data.children) {  // Node has children and collapsed
    node.node().dispatchEvent(new Event('click'));     // Expand the node
  }
}

See it's working in a fiddle.

Michael Rovinsky
  • 6,807
  • 7
  • 15
  • 30
  • @VictoriaStuart Hi :) I realize we have multiple problems here, so maybe it's better to split the issue into different questions and solve them one by one. So I suggest to keep the original question here and move the follow-ups to a new question. – Michael Rovinsky May 15 '21 at 12:46