How can I iterate through all elements in the document - not just one node, but scan all of it?

#1

I have been trying to iterate through all elements of a document. This would include all Graphic nodes and group nodes. Is there a way to iterate through all children, something like root.AllChildren.foreach? Am I missing something here?

1 Like
#2

Try that it works √ perfectly fine

#3

If you have root as the node whose children you’d like to iterate over, something like

root.children.forEach((child, index) => {
  // Do stuff here
});

should work (cf. https://adobexdplatform.com/plugin-docs/reference/SceneNodeList.html?h=scenenodelist). There is also – though that seems to be undocumented, so you might want to be careful with that – SceneNodeList::items, which lets you use a “standard” JS for-of loop:

for (let node of root.children.items) {
  // Do stuff here
}

This has the advantage that you can also use it in an asynchronous context without any further “complications”.

I hope this helps,
Happy Coding,
Pablo

2 Likes
#4

If you want to call a function on each node you could use the function here:

/**
 * Calls the passed in function on the passed in node and it's descendants 
 * @param {SceneNode} node SceneNode 
 * @param {Function} command Function to call on each node
 * @param {*} value Optional value to pass to command
 **/
function walkDownTree(node, command, value = null) {
  command(node, value);

  if (node.isContainer) {
    var childNodes = node.children;

    for(var i=0;i<childNodes.length;i++) {
      let childNode = childNodes.at(i);

      walkDownTree(childNode, command, value);
    }
  }
}

You would create your own function and it would be called on each node:

function showNodeName(node) { 
     console.log("Node name: " + node.name);
}

walkDownTree(root, showNodeName);
2 Likes
#5

Thanks Velara! This is exactly what I was looking for.

#6

Chiming in belatedly with two quick clarifications:

1) For convenience, all scenenodes have a children property (even if length 0), so there’s no need to check isContainer. So walking the scenegraph tree can be as simple as:

function walkTree(node) {
  // ...do some action with `node` here...

  node.children.forEach(walkTree);
}

Or to recast @Velara’s more generalized example:

/**
 * Calls the passed in function on the passed in node and it's descendants 
 * @param {SceneNode} node SceneNode 
 * @param {Function} command Function to call on each node
 * @param {*} value Optional value to pass to command
 **/
function walkDownTree(node, command, value = null) {
  command(node, value);

  node.children.forEach(childNode => {
    walkDownTree(childNode, command, value);
  });
}

Note also that forEach() is going to be faster than repeatedly calling at()… I’ll see if we can make that clearer in the docs.

2) There is no children.items property that you can iterate using a regular for loop. I think you may have been looking at selection.items, which is a regular old Array. If you really need to use a for loop on a child list, you can always copy it into an Array via children.toArray().

3 Likes