Edit in GitHubLog an issue

How to work with a SceneNodeList

This sample demonstrates how to work with a SceneNodeList in Adobe XD. The short version of this story is that a SceneNodeList is not an Array. Read on for details.

Prerequisites#

Development Steps#

Info Complete code for this plugin can be found on GitHub.

1. Prepare your plugin scaffold#

First, edit the manifest file for the plugin you created in our Quick Start Tutorial.

Replace the uiEntryPoints field of the manifest with the following:

Copied to your clipboard
1"uiEntryPoints": [
2 {
3 "type": "menu",
4 "label": "Create Elements",
5 "commandId": "createElements"
6 },
7 {
8 "type": "menu",
9 "label": "Filter and Color",
10 "commandId": "filterAndColor"
11 }
12]

If you're curious about what each entry means, see the manifest documentation, where you can also learn about all manifest requirements for a plugin to be published in the XD Plugin Manager.

Then, update your main.js file, mapping both of the manifest's commandId to their respective handler functions.

Replace the content of your main.js file with the code below.

Copied to your clipboard
1function createElements(selection) {
2 // The body of this function is added later
3}
4
5function filterAndColor(selection, documentRoot) {
6 // The body of this function is added later
7}
8
9module.exports = {
10 commands: {
11 createElements,
12 filterAndColor,
13 },
14};

Note the different use of contextual arguments in each function: the first function only makes use of selection, which the second makes use of both selection and documentRoot. We'll look at why documentRoot is used in a later step.

The remaining steps in this tutorial describe additional edits to the main.js file.

2. Require in XD API dependencies#

For this tutorial, we just need access to two XD scenegraph classes and one XD module.

Add the following lines to the top of your main.js file:

Copied to your clipboard
1// Add this to the top of your main.js file
2const { Artboard, Rectangle, Ellipse, Text, Color } = require("scenegraph");

Now the Artboard, Rectangle, Ellipse, Text, and Color classes are required in and ready to be used.

3. Create the handler function for createElements#

This function will do what it says on the label: create elements in the XD document. It's just here for the purpose of generating elements that will help us learn about the SceneNodeList in the next section.

Because of that, we won't go into detail about the createElements function. In short, it will create a number of rectangles, ellipses, and text elements, and put them on your XD artboard.

Copied to your clipboard
1function createElements(selection) {
2 for (let i = 0; i < 5; i++) {
3 let rectangle = new Rectangle();
4 rectangle.width = 30 * i;
5 rectangle.height = 20 * i;
6 rectangle.fill = new Color("gray");
7 selection.insertionParent.addChild(rectangle);
8 rectangle.moveInParentCoordinates(50 * i, 50 * i);
9
10 let ellipse = new Ellipse();
11 ellipse.radiusX = 20 * i;
12 ellipse.radiusY = 20 * i;
13 ellipse.fill = new Color("gray");
14 selection.insertionParent.addChild(ellipse);
15 ellipse.moveInParentCoordinates(100 * i, 200 * i);
16
17 let text = new Text();
18 text.text = `example text ${i}`;
19 text.styleRanges = [
20 {
21 length: text.text.length,
22 fill: new Color("gray"),
23 fontSize: 20,
24 },
25 ];
26 selection.insertionParent.addChild(text);
27 text.moveInParentCoordinates(200 * i, 100 * i);
28 }
29}

We'll run the command for this function in a later step.

4. Create the handler function for filterAndColor#

So let's take a look at working with a SceneNodeList!

The function we create in this step will filter all content on the artboard for rectangles, and then color only the rectangles red.

Recall that in the first step, we made a note of contextual arguments in command handlers, and particularly that this filterAndColor function makes use of the second documentRoot argument.

Like any SceneNode, documentRoot has a .children property that returns a SceneNodeList.

info A SceneNodeList is not an Array. One notable difference is that, with a SceneNodeList, you access elements in the list using the #at method (for example, node.children.at(0) to get the first node in the list). You can learn more about the SceneNodeList class here.

Let's fill out our handler function. Each of the numbered comments are explained below the code:

Copied to your clipboard
1function filterAndColor(selection, documentRoot) {
2 documentRoot.children.forEach((node) => {
3 // [1]
4 if (node instanceof Artboard) {
5 // [2]
6 let artboard = node;
7 let rectangles = artboard.children.filter((artboardChild) => {
8 // [3]
9 return artboardChild instanceof Rectangle;
10 });
11 rectangles.forEach((rectangle) => {
12 // [4]
13 rectangle.fill = new Color("red");
14 });
15 }
16 });
17}
  1. Start from the documentRoot node and traverse down the tree using the .children property. Since .children is a SceneNodeList, it has a #forEach method that will let us iterate through the list, node by node.
  2. Since we started at the documentRoot level, the first thing we need to do is look for the artboards in the document. This line ensures that we only traverse down further if the current child node is an artboard.
  3. Once we've found an artboard, we look at its .children property, which is also a SceneNodeList. This SceneNodeList will contain all of the elements we created earlier. We use the SceneNodeList#filtermethod to filter the artboard's children down to arectangles` array.
  4. Finally, we iteracte over the rectangles array with #forEach, coloring each rectangle red as we go.

5. Run the plugin#

After saving all your changes, reload the plugin in XD.

First, select an artboard and run the "Create Elements" command. You plugin will pull shapes on the artboard.

Then, run the "Filter and Color" command:

multiple texts, rectangles, and circles

You've worked with a SceneNodeList to iterate through an artboard's contents and filter based on element type!

Was this helpful?
Copyright © 2021 Adobe. All rights reserved.