I’m attempting to create objects into a group, but mask.addChild() doesn’t work (“Plugin made a change outside the current edit context”).
I have been trying to access the mask several ways, but none of them work.
See second to last line in code here
// rename current selection
let frame = selection.items[0]
frame.name = 'mask'
// create first element
const rect1 = new Rectangle()
rect1.name = 'rect1'
rect1.width = 100
rect1.height = 200
rect1.fill = new Color('red')
selection.insertionParent.addChild(rect1)
rect1.moveInParentCoordinates(10,20)
// bring original frame to the front
selection.items = [frame]
commands.bringToFront()
// mask rectangle with frame
selection.items = [frame,rect1]
commands.createMaskGroup()
// from now on, use mask as reference point
let mask = selection.items[0]
mask.name = 'Timeline'
console.log('is mask a group?', mask instanceof Group);
// create another rectangle and add it into the mask
const rect3 = new Rectangle()
rect3.name = 'rect3'
rect3.width = 20
rect3.height = 22
rect3.fill = new Color('lime')
mask.addChild(rect3) // THIS LINE
rect3.moveInParentCoordinates(75,100)
I only ever end up with the mask successfully created with the red rect1 inside, but the green rect3 is never added (sometimes fails silently in the console)
Hi @johannes,
so:
• user creates a rectangle;
• your plugin adds some elements into the same artboard;
• your plugin masks all these elements with the rectangle.
Is this what you want to achieve?
Creates group at this point (since you can’t create groups organically)
then
Plugin will continue to create objects that are supposed to go into the group
I know I can create all the elements first, and then mask only in the end, but code-wise that’s a pain because I’d have to keep track of all the objects created in the meantime and then create a huuuuge selection and then mask in the end.
I thought it would be so much more efficient to create the group/mask as soon as possible and then keep adding into it with addChild()
This may not be 100% what you’re looking for, but it may clear some stuff up (explanation to follow):
function myPluginCommand(selection) {
// Go to Plugins > Development > Developer Console to see this log output
console.log("Plugin command is running!");
console.log(selection.items[0]);
// create first element
const rect1 = new Rectangle();
rect1.name = "rect1";
rect1.width = 100;
rect1.height = 200;
rect1.fill = new Color("red");
selection.insertionParent.addChild(rect1);
rect1.moveInParentCoordinates(10, 20);
const rect3 = new Rectangle();
rect3.name = "rect3";
rect3.width = 20;
rect3.height = 100;
rect3.fill = new Color("lime");
selection.insertionParent.addChild(rect3);
rect3.moveInParentCoordinates(75, 100);
commands.bringToFront(); // Bring the current selection (the frame) to the front
selection.items = [selection.items[0], rect1, rect3]; // Order doesn't matter
commands.createMaskGroup(); // Uses as mask shape the front-most object
console.log(
selection.items[0] instanceof Group && selection.items[0].mask
? "Masked group"
: "Plain group"
);
}
In your example above, it appears that you’re attempting to add rect3 to the mask, but rect3 doesn’t overlap with the mask shape.
If that’s the case, this operation isn’t possible in the app UI from what I could tell. In the API, a better error message would be helpful here.
In my example above, I’ve changed the .height of rect3 to ensure it overlaps, and it works. (Although I recognize that the order is different than what you originally had; more on that in a sec.)
In real life, if you don’t have control over where the elements land in relation to the mask shape (for example, maybe you’re randomly adding elements programmatically), you could do some collision detection by doing math on the bounds of the elements.
As for the order of creating elements, would expanding on the above suffice, or do you need to add more elements after the mask is initially created?
I realize that I can wait until the very end of the command and then select everything that I created and group/mask at that point.
But that’s impractical for two reasons:
during the command, I need to create individual groups, so I’m going to change selection and use the group command
then I’d have to keep track of all the objects I created and change the selection again, in a very very complex selection.items = [] before I can group again
Besides, what if I want to add something to a group that the user selected before executing the command?
I don’t have a problem creating groups or masks (and thanks Ash for the tip to make sure objects are inside the mask before creating the mask). I have a problem adding into an existing group.
but something (edit context?) is preventing me from executing that method. It’s the only practical way I see besides managing a long array of all the objects and groups I created (which is impractical because I cannot assume that all elements have been created, since they depend on other conditions)
I chatted offline with @ashryan — and this is really only about the edit context. Now that I understand it better, there’s not a way to add a new node into a group that the script created, because the content of that group are off limits.
Without the ability to change the edit context programmatically, my only option is to create the mask/group at the very end of running the script