Copy link to clipboard
Copied
I've just started to learn scripting, and don't know enough about JS to really figure out even the easiest problems.
Right now, I'm trying to write a script that will create swatches and add them to a swatch group as a simple exercise to get introduced to scripting.
I'm experiencing a failure when I try to create a string with the name of a CMYKColor and assign that to the swatch using swatch.color.
It seems like this is probably something rudimentary, but after googling and searching these forums for a couple of days, I can't figure it out on my own.
The part that ExtendScript highlights is in bold italics.
var docRef = app.activeDocument;
// Insert number of new swatches here:
var n = 4
// Insert number of new swatches above:
// Create a new SwatchGroup
var swatchGroup = docRef.swatchGroups.add();
swatchGroup.name = "EMSwatches";
// Create the new color for the swatch
var Color1 = new CMYKColor();
Color1.cyan = 0;
Color1.magenta = 0;
Color1.yellow = 0;
Color1.black = 100;
// Create the new color for the swatch
var Color2 = new CMYKColor();
Color2.cyan = 0;
Color2.magenta = 0;
Color2.yellow = 0;
Color2.black = 80;
// Create the new color for the swatch
var Color3 = new CMYKColor();
Color3.cyan = 0;
Color3.magenta = 0;
Color3.yellow = 0;
Color3.black = 60;
// Create the new color for the swatch
var Color4 = new CMYKColor();
Color4.cyan = 0;
Color4.magenta = 0;
Color4.yellow = 0;
Color4.black = 40;
//loop to create a new swatch with name & color "Color1", "Color 2", etc. and add to swatch group.
var i = 1
while (i<=n){
var cn = "Color"
cn += i //concatenate string to "Color#"
//create new swatch and assign color and name
var swatch = docRef.swatches.add();
//the line below is where it fails.
swatch.color = cn;
swatch.name = cn;
var genSwatchGroup = docRef.swatchGroups[0];
var swatches = genSwatchGroup.getAllSwatches();
var swatchCount = swatches.length;
var swatchIndex = swatchCount
//add new swatch to swatch group "EMSwatches"
swatchGroup.addSwatch(swatches[swatchIndex-1]);
i++;
}
Copy link to clipboard
Copied
you're attempting to set the "color" property of the new swatch to a string. These are incompatible. You need to set the color property to your newly created CMYKColor objects instead, like so:
function test()
{
var docRef = app.activeDocument;
var newSwatchColor = new CMYKColor();
newSwatchColor.cyan = 0;
newSwatchColor.magenta = 0;
newSwatchColor.yellow = 0;
newSwatchColor.black = 40;
var newSwatch = docRef.swatches.add();
newSwatch.color = newSwatchColor;
newSwatch.name = "Test";
}
test();
Copy link to clipboard
Copied
William, thanks for the answer. So, I think I understand what you're saying. My logic was that I would call my new CMYKColors variables "Color1", "Color2", etc. and then in my loop i'm trying to cycle through those variables in ascending order. That's why I tried to concatenate "Color" + i, where i = 1, 2, 3, 4 etc. But, I get that I can't pass a string in place of the variable (right?) How would I turn your solution into a loop?
I don't want to write that block of code in for each new swatch... What if I have 30 new swatches to make?
I have an idea, but currently at work so I can't test it yet. Could I save each new CMYK color to an array when I create it, then reference that array in my while loop?
var n = 4
var i = 1
while (i < n){
var newSwatch = docRef.swatches.add();
newSwatch.color = array
i++
}
Or, is it a matter of plugging something into the test(___); function in between those parenthesis?
Copy link to clipboard
Copied
I'm not in a position to test it, but I'd use arrays for everything. I'd loop through an array to assign the values and properties to a new CMYKColor object, then send the result and name to another function to then add() the swatches, just to make it a bit cleaner:
generateSwatchColor(0,0,40,0,'testSwatch')
function generateSwatchColor(c,m,y,k,name){
// one array for the color property names
var params = ['cyan', 'magenta', 'yellow', 'black'];
// another array for the input values
var values = [c,m,y,k];
var newSwatchColor = new CMYKColor();
// Loop through both arrays at the same time.
for (var i = 0; i < params.length, i++) {
var param = params;
// Assign this input value to this color property
newSwatchColor[param] = values;
}
// Send the result to another function
assignSwatch(newSwatchColor, name)
}
function assignSwatch(color, name)
{
// add new swatch, assign color and name from previous function
var docRef = app.activeDocument;
var newSwatch = docRef.swatches.add();
newSwatch.name = name;
newSwatch.color = color;
}
You could do this in much better ways even, like sending a full array as the first parameter instead of having four arguments for this function, or using array methods like .push(), .pop(), shift/unshift, have arrays within arrays and iterate the entire length of 30 swatches, etc. One more function before this could iterate through a parent array which itself contains child arrays (whose contents would feed into the c,m,y,k parameters of the generateSwatchColor function) and automate 30 swatches decently easily
Copy link to clipboard
Copied
Tom, how did you get your code to be formatted like that instead of plain body text?
Copy link to clipboard
Copied
No problem! Should note there's a typo in my code at the for loop, I have a normal comma instead of semi-colon: 'i < params.length, i++' should be 'i < params.length; i++). Not sure how to edit on mobile, lol.
If you're on desktop, use the Advanced Editor. A WYSIWYG editor pops up and in the toolbar you can see a greater than bracket (<), click on it for dropdown of syntax highlighting choices, select JavaScript. It drops a line of code format that you can paste into easily, but the display glitches and you sometimes need to toggle from HTML and back to show it correctly.
Array methods are very useful but there's no need to rush in learning and be overwhelmed. Coding is exciting though, if you have any more trouble I'll try to implement simple uses of array methods in another response.
Copy link to clipboard
Copied
To your last question about the test() function. I've gotten into the habit of putting all of my scripts inside a container function. This helps to prevent global variables from being created which can cause problems later. It isn't strictly necessary, but it's generally agreed that when scripting illustrator, it's good practice to wrap everything in a container so that when the script is finished executing, all of the variables created will disappear with it.
Back to your original question about creating swatches dynamically without re-writing the logic each time.
There are a million different ways to do this. The better and more efficient you want to do it, the more difficult and complex it becomes. So let's look at a really simple (though prone to problems) example. You were right that you need to use a loop, but in my opinion, you should use a for loop when possible, instead of a while loop. While loops, if not treated carefully, can result in infinite loops with little or no explanation of what's going on. that said, this is just my preference. I'm sure someone else could provide a compelling argument for why they should be used.
function test()
{
var docRef = app.activeDocument;
var swatches = docRef.swatches;
var newSwatchGroup = docRef.swatchGroups.add();
newSwatchGroup.name = "EMSwatches";
var numberOfSwatchesNeeded = 5;
var blackValue = 100;
var currentSwatch,currentColor;
//begin the loop
for(var x=0; x<numberOfSwatchesNeeded;x++)
{
//here is the logic for creating the swatches
//make a new CMYKColor object
currentColor = new CMYKColor();
currentColor.cyan = 0;
currentColor.magenta = 0;
currentColor.yellow = 0;
currentColor.black = blackValue;
//add the new swatch
currentSwatch = swatches.add();
//since x starts at zero, we want to add one
//to get the correct number in the swatch name
currentSwatch.name = "Color" + (x + 1);
currentSwatch.color = currentColor;
newSwatchGroup.addSwatch(currentSwatch);
//as per your original example, we will decrement the black value by 20
blackValue -= 20;
}
}
test();
As stated before, this is prone to errors because if you increased the number of swatches that you need to 7 instead of 5, you'd get an error because on the 7th created swatch, your blackValue would be negative. This is just one example of how you could condense the logic into one block. As was previously stated, arrays may be a good way to go about doing this as well.
I hope this example gives you some insight. But if you have more specific questions, we are here to help.
Copy link to clipboard
Copied
Tom and William, thank you both! I'm not familiar enough with JS yet to know how push and pop work, but I'll dig into it. I'm on day 2 of learning JS, and so far it's super exciting - but there is still so much to get into. You both have been really helpful. I'm going to give these methods a shot and I'm sure will run into more questions.
Copy link to clipboard
Copied
So great to see more people getting involved. just a couple of years ago i was here in these forums doing exactly what you're doing! Now i write JS for illustrator full time and i love it!
Just curious, are you just new to JS or are you new to coding all together?
Copy link to clipboard
Copied
I'm currently a designer at an architecture firm, and have used a program called Grasshopper for about 7 years now to do "visual programming" within a 3D modeling software. So, I have a good idea of how data structures like arrays work in principle, and a solid foundation of the logic behind programming, but I'm brand new to actual coding. I'm curious how you made the leap from hobby to career. I'll send you a DM.
Get ready! An upgraded Adobe Community experience is coming in January.
Learn more