Search code examples
javascriptscriptingadobe-illustrator

Script to fill objects with colours - uniform distribution but in no discernible pattern


I am working on writing a script for Adobe Illustrator in javascript to fill objects with selected colours.

I have 32 objects and 12 colour swatches. I want to fill the 32 objects using each colour twice and then fill the remainder 8 objects with a random selection. I want to fill the objects in no discernible pattern, so just looping through each object and assigning it the next swatch colour will not do.

This is what I have so far, however it is not using each colour at least twice and filling at random.

myObjects = app.activeDocument.selection;
myDocument = app.activeDocument;

if (myObjects instanceof Array) {
    colourSwatches = myDocument.swatches.getSelected();

    //if there are swatches
    if (colourSwatches.length != 0) {
        for (i = 0; i < myObjects.length; i++) {

            //if the selection is a path or compound path
            if (myObjects[i].typename == "PathItem" || myObjects[i].typename == "CompoundPathItem") {

                selItem = myObjects[i];
                selItem.filled = true;

                //select colour from swatches at random and then fill 
                swatchIndex = Math.round( Math.random() * (colourSwatches.length - 1 ));

                if (selItem.typename == "PathItem") {
                    selItem.fillColor = colourSwatches[swatchIndex].color;
                } else {
                    selItem.pathItems[0].fillColor = colourSwatches[swatchIndex].color;
                }
            }
        }
    }
}

Solution

  • Instead of picking swatches at random (that's where you lose control), do this:

    1. Build an array of your target size (32) and fill it with the required swatches (12). You don't have to randomize this array.
    2. For every object, pick a random entry.
    3. Remove the picked entry from the array.
    4. Loop until satisfied.

    I.e., untested, but something like this:

    var targetArray = [];
    // fill with the set of required colors, times 2
    for (i=0; i < 12; i++)
    {
      targetArray[2*i] = i;
      targetArray[2*i+1] = i;
    }
    // fill up to contain 32 items
    for (i=24; i<32; i++)
      targetArray[i] = Math.floor(Math.random() * colourSwatches.length);
    

    (see Getting random value from an array for that random expression.)

    Now you have an array containing the indexes for swatches to use. Loop over your objects and pick random items from the array until you are finished (which would be good) or you run out of items to pick (which would indicate your count of items to fill is not correct):

    for (i = 0; i < myObjects.length; i++)
    {
        arrayIndex = Math.floor(Math.random() * targetArray.length);
        swatchIndex = targetArray[arrayIndex];
        targetArray.splice (arrayIndex,1);
        selItem.fillColor = colourSwatches[swatchIndex].color;
    }