Copy link to clipboard
Copied
I want to get the items in a layer sorted in their stacking order (including any sub-layers).
For example:
Layer 1
item A
Layer 1a
Group B
item C
In the example above, I would get back an array like this:
[item A, layer 1a, Group B, item C]
Of course, you'd think this is a simple enough thing given that zOrderPosition is freely available:
function getChildrenInStackingOrder(layer){
var sublayers=layer.layers;
var pageItems=layer.pageItems;
var result=new Array ();
var size=sublayers.length+pageItems.length;
for(var i=0;i<sublayers.length;i++){
result[sublayers.zOrderPosition]=sublayers; <<<----------- ERROR
}
for(var i=0;i<pageItems.length;i++){
result[pageItems.zOrderPosition]=pageItems;
}
return result;
}
My problem is that AI CS4 throws up at the line marked above with a message "Internal Error 1200". I'm guessing that it's illegal to get the zOrderPosition of a sublayer. Any thoughts?
Anurag.
PS. Do any Adobe engineers read this forum at all? Seems like there's a lot of internal documentation that could help in answering some of our questions.
Copy link to clipboard
Copied
well for once layers and pageitems do not share the same zOrderPosition, so your code will fail to get correct results from the begining ... with a little testing you'll see that even if you didn't expected this there are pageitems that have the same zorder as some layers. Which points us to the fact that document priority is layer and after that page items.
Now regarding your problem ... for example if you have 5 empty layers and a shape within a layer called "ParentLayer" in the order Layer 1, Layer 2, Layer 3, Layer 4, Layer 5, Shape 1 you'll get your zOrderPosition just fine, but if you add a shape to both Layer 2 and Layer 3 you'll get an 1200 Internal Error. My guess it has something to do with indexing in composite layers, probably because of the Document.pathItems collection which makes 2 pathitems with same zOrderPosition. Seems like the problem appears when you have a orphan shape after a layer that contains a shape [this data might be wrong].
My workaround when getting this problem sometime in the past was to get every child that was not a layer into it's own layer, with the layer named as the object or if the situation permitted, get rid of the layers within that layer and keep only page items inside the layer. Keep in mind that this is a problem only with nested layers that have composite layer/shape structure.
hope it helps;
cheers;
Copy link to clipboard
Copied
Copy link to clipboard
Copied
I did not understand this one aren't all objects in objects and there stacking order position by index?
Copy link to clipboard
Copied
well it's not like that ... beside that it would be a dead hand reordering the collections/arrays everytime you move an item up and down, or delete one or whatever else ... "visual" order of the items within a document is made thru the zOrderPosition property, which atm at least in js doesn't seem to work as it should.
hope it helps;
cheers;
Copy link to clipboard
Copied
Sorry I must be missing the point of what was wanted here (that wouldn't be a first!!!)
This does correctly give me the elements of my masked group in there visual stacking order…
If I re-shuffle with bring to front send to back etc. This is right?
#target illustrator
var docRef = app.activeDocument;
// Document Stuff
with (docRef) {
for (var i = 0; i < groupItems[0].pageItems.length; i++) {
var x = groupItems[0].pageItems.typename;
$.write(x + '\r');
}
}
returns
PathItem
GroupItem
GroupItem
GroupItem
PathItem
PlacedItem
PathItem
GroupItem
GroupItem
undefined
Copy link to clipboard
Copied
you`re not missing any point .. infact you`re right ... very right (*head against the wall*) ... however there was situation in the past when i needed this stack order and the index based order was not the same with "visual" order and i got with the idea that the index based array is not in the same order as the "visual" one .. can't remember exactly when and how ... maybe was a bug, maybe was my brain bugging ... hmmm ... pretty sure i was sober. anyhow you`re right on this one ... though the problem with the zOrderPosition failling in certain situations is still a bug, but that's another story.
cheers;
Copy link to clipboard
Copied
Sonic, I have been bashing my head against the desk trying to throw this some curve ball objects in objects.
Convinced there was some thing about the bigger picture that I just wasn't seeing.
There must be some point to the zorder thing? I've never used it and when I did see this I failed to understand why?
I was thinking you could just recursively dig in objects until the page items contains no group items?
Copy link to clipboard
Copied
layers inside of layers (is what I did NOT see)
Copy link to clipboard
Copied
You're right for all items other than sub-layers of a layer. It seems to me that there is no way to get a relative sub-ordering of pageItems and sub-layers within a layer (which was what I wanted in the first place).
A.
Copy link to clipboard
Copied
infact you can sort the composite form of a layer by comparing the orphan pageItem with item with index 0 of every and each sublayer ... but atm i`m not in the mood for coding ... in fact i think i`m going to give myself one month vacation for hollidays. good luck.
cheers;
Copy link to clipboard
Copied
BTW, If you did NOT get this resolved I did happen across looking at layers in layers the other day and layer 'does' have a layers property so I see NO reason why this could NOT be navigated. (Im NOT sure with the syntax of a recursive dig but this did work for my test of layers within layers (sub-layers)
You should get the idea:
#target illustrator
var docRef = app.activeDocument;
// Document Stuff
with (docRef) {
for (var i = 0; i < layers.length; i++) {
var x = layers.name;
$.write(x + '\r');
if (!layers.layers.length == 0) {
for (var j = 0; j < layers.layers.length; j++) {
var y = layers.layers
$.write('\t' + y + '\r');
}
}
}
}
Correctly gives me:
Layer 4
Layer 10
Layer 9
Layer 8
Layer 7
Layer 3
Layer 2
Layer 1
undefined
In console…
Copy link to clipboard
Copied
Yes, that will work, except when you also have groups. Within a layer, there's no direct way of saying whether a group comes before a layer (in the zOrder), or after a layer, and vice versa, which, again was the thing I was looking for.
Thanks,
A.
Copy link to clipboard
Copied
Did anybody ever figure out a reliable solution to this? I've come to agree that the zOrderPosition for a sublayer can't be compared to the zOrderPosition of other items on the layer (as they are sometimes identical values), so you can't tell if a given item on a layer is above or below a sublayer on the same layer. Also, I've seen cases where siblings within a group have identical zOrderPosition values, making it impossible to detect z-order among elements of a group. Further, I'm not convinced the documentation is correct when it declares that the zOrderPosition of a layer (in my case actually a sublayer) is the z-order among all layers in the document -- it seems more to be relative to just the parent layer.
I'd love to see some code that extends the example put forth by Muppet Mark to include (along with sublayers) groups and also pageitems on a layer that also has a sublayer. To really test the solution, though, you need to make sure you re-order these items using the Layers panel, so you don't accidentally get a solution that works simply because the creation order was never disrupted.
Thanks,
- Rich
Copy link to clipboard
Copied
Not sure if it will help, but I posted a little while ago about trying to "flatten" (kinda) some random amount of nested groups and artwork.
Since I was trying to flatten everything, I pretty much disregarded any layers or sub-layers, and therefore didn't really use zOrderPosition for some reason.
Anyway, what I did learn was that, while layers are listed in a different Array than PageItems, at the Document level, all page items will appear in the proper order. So, if your Layer palette looks like:
Layer 1
Item 1
Item 2
Layer 2
Group A
Item 3
Item 4
SubLayer 1
Item 5
Item 6
Item 7
Accessing the doc.pageItems[] array would get you the following:
doc.pageItems[0]; // Item 1
doc.pageItems[1]; // Item 2
doc.pageItems[2]; // Group A
doc.pageItems[3]; // Item 3
doc.pageItems[4]; // Item 4
doc.pageItems[5]; // Item 5
doc.pageItems[6]; // Item 6
doc.pageItems[7]; // Item 7
So, while this doesn't directly tell you the "nesting" order of the items, you can find that doc.pageItems[5].parent == SubLayer 1, and since Item 5 is after Item 4, you can assume that SubLayer 1 is after Item 4?
Obviously it would take smarter logic, but might be a helpful tidbit.
Also, if you start messing around with pageItems[] indices, it's been my experience that it is better to loop through from the "bottom" of the stack and always operate on the last index to keep the indexes intact.
Copy link to clipboard
Copied
Thanks for the tip! Do you know if the document's "pageItems" array will still represent the stacking order if you re-arrange items in the Layers panel? Like move a sublayer and a group around within their parent layer? I had been using the pageItems array previously, but somehow got the idea that it didn't keep track of changes like this -- maybe I assumed wrong?
Copy link to clipboard
Copied
I wasn't using zOrderPosition, so I'm not sure, but I know when I used the pageItem.move() method to move an item to a new layer, that it would change that item's index in the pageItems[] array. I imagine changing zOrderPosition would have a similar effect.
However, you'll have to run some tests, because I don't know if the pageItems[] array will update automatically, or if you should/should not use the app.redraw() method.
For example:
var docPageItems = doc.pageItems;
var myItem = docPageItems[5];
myItem.zOrderPosition += 1;
docPageItems[5]; // Is this the same item?
app.redraw();
docPageItems[5]; // how about now?
docPageItems = doc.pageItems;
docPageItems[5]; // What about now?
The zOrderPosition seems to only apply to the an object's position within its parent... but adjusting that would also adjust its position in the document overall, so it should work, but like I said, it can be tricky because you'll also be changing the indexes of the objects around it as well.
Copy link to clipboard
Copied
This is a BUG. Bugs exist in any software. But when a company allows its users to waste hours and hours trying to figure out what they're doing wrong, only to find it's a bug that Adobe didn't bother to document prominently in their user guides, it borders on cruel. And it will continue to happen to others.
Illustrator's scripting documentation clearly says that zOrderPosition is available (read-only, which is fine) for all PageItem and Layer objects. The fact that it is relative to the parent group or layer is totally OK; it's good, in fact. Or it would be, if it wasn't useless because it is broken. "Internal Error" ? ngngn..
Some of the replies here point to possible workarounds using Document.pageItems, it's unforgiveable that such a workaround is necessary, but here is another, similar trick. It relies on an interesting (undocumented) aspect of how selections behave: If you select a bunch of objects in any order and then iterate through Document.selection, it turns out that the objects in the selection array have been sorted into proper z-order for you.
var doc = app.activeDocument;
var layer = doc.activeLayer; // select your parent layer before running this// Convert a collection to a regular JS Array, so we can use concat()
function toArray(coll) {
var arr = [];
for (var i = 0; i < coll.length; ++i) {
arr.push(coll);
}
return arr;
}// Get all the objects in a layer and its descendent layers
function getAllPageItems(layer) {
var items = toArray(layer.pageItems);
for each (var sublayer in toArray(layer.layers)) {items = items.concat(getAllPageItems(sublayer));
}
return items;
}
var items = getAllPageItems(layer);// Some items here will not be in z-order.
for each (var item in items) {
$.writeln(item);
}
$.writeln("---------------------------");// Select everything in the active layer:
doc.selection = items;//Notice that the objects have been resorted into z-order in doc.selection:
for each (item in doc.selection) {
$.writeln(item);
}
Of course if you want to preserve the original layers without flattening, you'll have to do some additional, ridiculous stuff. But, hope this helps someone.
Anyone out there who looks at this and thinks "What an idiot, doesn't this guy know you can just do 'x' .." PLEASE correct me, and be as disparaging as you want. I will still thank you.
Copy link to clipboard
Copied
I know it's a few years late but thanks for sharing this hacky but nevertheless effective solution of using document.pageItems! This saved me.
Copy link to clipboard
Copied
Does anyone know if there is an easier way to do this with more recent versions of illustrator? Like CC 2014 or 2015? Or maybe the bug has been fixed?
Copy link to clipboard
Copied
Bug still seems to be present in Illustrator CC 2015 and 2017. I have seen internal error 1200 trying to access zOrderPosition on anything. However, I discovered by writing some ExtendScript using the reflection property that there is a new and undocumented property called absoluteZOrderPosition that always seems to return a valid integer. Google suggests this has been around since Illustrator CC 2014.
Copy link to clipboard
Copied
google is right
Copy link to clipboard
Copied
Copy link to clipboard
Copied
There's good news on this old issue. Each layer and pageItem now has an absoluteZOrderPosition property. So we can compare those index numbers to determine exactly how the stacking order is composed.