• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

How to change the StrokeCap of all objects in a few layers

Participant ,
Jan 02, 2022 Jan 02, 2022

Copy link to clipboard

Copied

hello,everyone.

i want to change the strokeCap of all objects in a particular layer.

var document = app.activeDocument;
var allLayers = app.activeDocument.layers; 
var testLayer = ["a", "b"];


function lineFormat(LayerName) {
    //Select objects in layer
    document.activeLayer = document.layers[LayerName]; 
    //document.activeLayer.hasSelectedArtwork = true; 
    //Change Style
    document.activeLayer.pathItems.stroked = true;    // open stroke
    document.activeLayer.pathItems.strokeCap = StrokeCap.BUTTENDCAP;//ROUNDENDCAP, PROJECTINGENDCAP
    document.activeLayer.pathItems.strokeJoin = StrokeJoin.ROUNDENDJOIN;//BEVELENDJOIN, MITERENDJOIN

    //Deselect objects in layer
    //document.activeLayer.hasSelectedArtwork = false;
}


for (var i = 0, il = allLayers.length; i < il; i++) {
    var curLayer = allLayers[i]
    if (curLayer = testLayer[i]) {
        //if layer name found
        lineFormat(testLayer[i]) 
    }
}   

then,i wrote the code as I understood it, but nothing happened to it for now, I don't know how to fix this code

Anyone can help me?

 

 

TOPICS
Scripting

Views

631

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Enthusiast , Jan 03, 2022 Jan 03, 2022

Sorry, had a typo and a faulty condition. Serves me right for so confidently offering recursion thinking I had cracked it so easily ha, I've verified the below on your file:

 

var targetLayers = ["Test"];

function getAllPathItems(parent) {
  var list = [];
  for (var i = 0; i < parent.pageItems.length; i++) {
    var item = parent.pageItems[i];
    if (item.pageItems && item.pageItems.length)
      list = [].concat(list, getAllPathItems(item));
    else if (/path/i.test(item.typename) && !/compou
...

Votes

Translate

Translate
Adobe
Enthusiast ,
Jan 02, 2022 Jan 02, 2022

Copy link to clipboard

Copied

Hello, consider this:

 

var document = app.activeDocument;
var allLayers = app.activeDocument.layers;
var testLayers = ["Test"];

// Why do this? Because if we query a layer name that doesn't exist, it causes silent failure.
function getLayer(layerName) {
    try {
        return document.layers.getByName(layerName);
    } catch(err) {
        return null;
    }
}

function restyleAllPathItemsWithin(layers) {
    // An alternative to deselect all artwork, though it shouldn't actually matter here
    // because we can change the strokes regardless of whether other art is selected
    app.selection = null;

    // Iterate through our layer list:
    for (var i = 0; i < layers.length; i++) {
        // Get our target layer:
        var layer = getLayer(layers[i]);

        // If a layer wasn't found or there are no items to restyle, continue looping:
        if (!layer || !layer.pathItems.length) continue;
        else {
            // Layer.pathItems is a collection of objects, not a single one.
            // To restyle any given object, we have to iterate over them individually:
            for (var index = 0; index < layer.pathItems.length; index++) {
                var pathItem = layer.pathItems[index];
                pathItem.stroked = true;    // open stroke
                pathItem.strokeCap = StrokeCap.BUTTENDCAP;//ROUNDENDCAP, PROJECTINGENDCAP
                pathItem.strokeJoin = StrokeJoin.ROUNDENDJOIN;//BEVELENDJOIN, MITERENDJOIN
            }
        }
    }
}

restyleAllPathItemsWithin(testLayers);

Essentially you have everything correct here, but the issue is that you're trying to assign properties to an Array-like collection (pathItems) rather than one entry of that collection (i.e., pathItems[0]).

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jan 03, 2022 Jan 03, 2022

Copy link to clipboard

Copied

thanks you for you help!!!but it seems that the straight lines I import from DWG still need to be ungrouped before they work.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Jan 03, 2022 Jan 03, 2022

Copy link to clipboard

Copied

No worries. That's true, it has to do with how AI contains items. For instance:

  • layer.pathItems - This is a collection of root-level paths on the layer.
  • layer.pageItems - This is a collection of any type of root-level object on the layer.

 

Layer.pathItems is not every path inside of the layer, only every path whose parent is the layer. The issue would be that a group counts as a pageItem, so a path inside of a group would be something more like:

  • layer.pageItems[0].pathItems[2] <= Because the pathitem parent is the group, not the layer. Pathitems may exist only in this group

 

Layer.pathItems only contains paths that aren't in a group or a compound path, if the parent is explicitly the layer. We can fix this for shallow groups pretty easily:

 

function getAllPathItemsInLayer(layer) {
  var list = [];
  for (var i = 0; i < layer.pageItems.length; i++) {
    var item = layer.pageItems[i];
    // If this is a group or compound path, we need to add it's pathItems to our list:
    if (
      /group|compound/i.test(item.typename) &&
      item.pathItems &&
      item.pathItems.length
    ) {
      for (var e = 0; e < item.pathItems.length; e++)
        list.push(item.pathItems[e]);
    } else if (/path/i.test(item.typename)) {
      // Otherwise if this is a pathItem, we can add it to the list directly:
      list.push(item);
    }
  }
  return list;
}

function getLayer(layerName) {
  try {
    return document.layers.getByName(layerName);
  } catch (err) {
    return null;
  }
}

function restyleAllPathItemsWithin(layers) {
  app.selection = null;
  for (var i = 0; i < layers.length; i++) {
    var layer = getLayer(layers[i]);
    if (!layer || !layer.pathItems.length) continue;
    else {
      // We need to gather any children pathItems in case their parent is a Group/Compound Path
      var list = getAllPathItemsInLayer(layer);
      for (var index = 0; index < list.length; index++) {
        var pathItem = list[index];
        pathItem.stroked = true; // open stroke
        pathItem.strokeCap = StrokeCap.BUTTENDCAP; //ROUNDENDCAP, PROJECTINGENDCAP
        pathItem.strokeJoin = StrokeJoin.ROUNDENDJOIN; //BEVELENDJOIN, MITERENDJOIN
      }
    }
  }
}

restyleAllPathItemsWithin(testLayers);

 

But for complicated groups (pathItems within groups within groups or any dynamic nesting) then we'd have to do some recursion and it's likely going to look either very intimidating and confusing or very simple and confusing.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jan 03, 2022 Jan 03, 2022

Copy link to clipboard

Copied

i see what you mean, but it still does not happen to work,i uploaded the test file for you.

and Thanks tyour help, I'm afraid it would be difficult for me to write such code (although I can understand it)

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Jan 03, 2022 Jan 03, 2022

Copy link to clipboard

Copied

Sorry, I don't see the file yet. If you happened to try running the above snippet directly though, you'd be missing the value of "testLayers" as the param in case that was the issue.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jan 03, 2022 Jan 03, 2022

Copy link to clipboard

Copied

Sorry, I can't seem to send the file. But I have added "testLayers"

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Jan 03, 2022 Jan 03, 2022

Copy link to clipboard

Copied

Here's recursion in case you have deep nesting:

 

var targetLayers = ["Test"];

function getAllPathItems(parent) {
  var list = [];
  for (var i = 0; i < parent.pageItems.length; i++) {
    var item = parent.pageItems[i];
    if (item.pageItems && item.pageItems.length)
      // We call this same function to rerun within it's own loop:
      list = [].concat(list, getAllPathItems(item));
    else if (/path/i.test(item.typename) && !/compound/i.test(item.typename))
      list.push(item);
  }
  return list;
}

function getLayer(layerName) {
  try {
    return document.layers.getByName(layerName);
  } catch (err) {
    return null;
  }
}

function restyleAllPathItemsWithin(layers) {
  app.selection = null;
  for (var i = 0; i < layers.length; i++) {
    var layer = getLayer(layers[i]);
    if (!layer || !layer.pathItems.length) continue;
    else {
      var list = getAllPathItems(layer);
      for (var index = 0; index < list.length; index++) {
        var pathItem = list[index];
        pathItem.stroked = true; // open stroke
        pathItem.strokeCap = StrokeCap.BUTTENDCAP; //ROUNDENDCAP, PROJECTINGENDCAP
        pathItem.strokeJoin = StrokeJoin.ROUNDENDJOIN; //BEVELENDJOIN, MITERENDJOIN
      }
    }
  }
}

restyleAllPathItemsWithin(targetLayers);

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jan 03, 2022 Jan 03, 2022

Copy link to clipboard

Copied

Sorry, the bad news is that it still doesn't work. I opened the dwg with AI and ran the code directly (the target layer was already there) and nothing happened.
But if I undo one of the groups, the code starts working again.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Jan 03, 2022 Jan 03, 2022

Copy link to clipboard

Copied

🤔 Hmmm, I thought that'd work. It's pretty hard to do this blindly, can you upload the file and link here?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jan 03, 2022 Jan 03, 2022

Copy link to clipboard

Copied

Here is the test file

https://file.io/mbKXVsChYCgn

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Jan 03, 2022 Jan 03, 2022

Copy link to clipboard

Copied

Sorry, had a typo and a faulty condition. Serves me right for so confidently offering recursion thinking I had cracked it so easily ha, I've verified the below on your file:

 

var targetLayers = ["Test"];

function getAllPathItems(parent) {
  var list = [];
  for (var i = 0; i < parent.pageItems.length; i++) {
    var item = parent.pageItems[i];
    if (item.pageItems && item.pageItems.length)
      list = [].concat(list, getAllPathItems(item));
    else if (/path/i.test(item.typename) && !/compound/i.test(item.typename))
      list.push(item);
  }
  return list;
}

function getLayer(layerName) {
  try {
    return app.activeDocument.layers.getByName(layerName);
  } catch (err) {
    return null;
  }
}

function restyleAllPathItemsWithin(layers) {
  app.selection = null;
  for (var i = 0; i < layers.length; i++) {
    var layer = getLayer(layers[i]);
    if (!layer) continue;
    else {
      var list = getAllPathItems(layer);
      for (var index = 0; index < list.length; index++) {
        var pathItem = list[index];
        pathItem.stroked = true; // open stroke
        pathItem.strokeCap = StrokeCap.BUTTENDCAP; //ROUNDENDCAP, PROJECTINGENDCAP
        pathItem.strokeJoin = StrokeJoin.ROUNDENDJOIN; //BEVELENDJOIN, MITERENDJOIN
      }
    }
  }
}

restyleAllPathItemsWithin(targetLayers);

 I'm not sure if you're wanting to target only specific layers by name or if you're just trying to change all document strokes -- you could do that though. If the goal is to change all strokes we could just feed a list of all the layers into the main function, and it might be easier to choose which layers (or names of annotation like "LWPOLYLINE") to exclude rather than include. Or target all "LINE" group children, etc.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jan 03, 2022 Jan 03, 2022

Copy link to clipboard

Copied

LATEST

that cool !!!and you are right, we can narrow down the scope of the code to work 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines