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?
Try that it works √ perfectly fine
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
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);
Thanks Velara! This is exactly what I was looking for.
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()
.