Copy link to clipboard
Copied
Hello
The script below sorta works but fails in bits - below is the background
I want to make a script which can auto make a grid of graphic frames of different sizes, neatly laid out like the screenshot below
I want the user to draw a retectangle the size of the area they want the grid to be, then run the script which prompts the amount of boxes and gutter between them
the script then auto makes a grid of random sizes mainting the gutter
the script could make the random box sizes based on a multiple of cell size if one was to think of the space being devided into cells - rows and columns so frames could span 1x3 or 2x2 etc
My script generates the boxes at different sizes which seems good
but it doesnt make them big enough to match the same size area as the user selection nor does it follow the gutter width, nor does it prevent overlapping.
Any ideas on where to fix it - also i do have a scipt I made which makes a grid based on user input which is sorta what I am using the base this new script on.
Thanks all
Tricky one this!!
This is the code for the auto picture layout
// Define a dialog
var dialog = app.dialogs.add({ name: "Create Graphic Frames" });
// Create a dialog column
var dialogColumn = dialog.dialogColumns.add();
// Create a dialog row for the number of boxes
var numBoxesRow = dialogColumn.dialogRows.add();
numBoxesRow.staticTexts.add({ staticLabel: "Number of Boxes:" });
var numBoxesField = numBoxesRow.textEditboxes.add({ minWidth: 80 }); // Adjust the minWidth value
// Create a dialog row for gutter width
var gutterRow = dialogColumn.dialogRows.add();
gutterRow.staticTexts.add({ staticLabel: "Gutter Width:" });
var gutterField = gutterRow.textEditboxes.add({ minWidth: 80 }); // Adjust the minWidth value
// Show the dialog and get user input
if (dialog.show() === true) {
// Get the number of boxes and gutter width from user input
var numBoxes = parseInt(numBoxesField.editContents);
var gutterWidth = parseFloat(gutterField.editContents);
// Convert the user's preference to points
var gutterWidthPoints;
if (app.activeDocument.viewPreferences.horizontalMeasurementUnits === MeasurementUnits.inches) {
gutterWidthPoints = gutterWidth * 72; // Convert inches to points
} else if (app.activeDocument.viewPreferences.horizontalMeasurementUnits === MeasurementUnits.millimeters) {
gutterWidthPoints = gutterWidth * 2.83465; // Convert millimeters to points
} else if (app.activeDocument.viewPreferences.horizontalMeasurementUnits === MeasurementUnits.centimeters) {
gutterWidthPoints = gutterWidth * 28.3465; // Convert centimeters to points
} else {
// By default, assume the user's input is already in points
gutterWidthPoints = gutterWidth;
}
// Check if the user entered valid numbers
if (!isNaN(numBoxes) && numBoxes > 0 && !isNaN(gutterWidthPoints) && gutterWidthPoints >= 0) {
// Get the user's selection
var userSelection = app.selection[0];
// Check if the selection is valid and is a rectangle or other suitable shape
if (userSelection instanceof Rectangle || userSelection instanceof Oval) {
var doc = app.activeDocument;
var bounds = userSelection.geometricBounds;
// Calculate the width and height of each cell
var cellWidth = (bounds[3] - bounds[1]) / numBoxes;
var cellHeight = (bounds[2] - bounds[0]) / numBoxes;
// Calculate the total area of the user's selection
var userSelectionArea = (bounds[3] - bounds[1]) * (bounds[2] - bounds[0]);
// Create an array to store whether a cell is occupied
var cellOccupied = [];
// Initialize the array to all false (unoccupied)
for (var i = 0; i < numBoxes; i++) {
cellOccupied[i] = [];
for (var j = 0; j < numBoxes; j++) {
cellOccupied[i][j] = false;
}
}
// Create the graphic frames based on the user's input
for (var k = 0; k < numBoxes; k++) {
var i, j;
var tries = 0; // Track attempts to fit the frame
var maxTries = numBoxes * numBoxes; // Maximum attempts before giving up
do {
// Generate random coordinates within the grid
i = Math.floor(Math.random() * numBoxes);
j = Math.floor(Math.random() * numBoxes);
tries++;
// Calculate random dimensions for the box
var randomRows = Math.floor(Math.random() * (numBoxes - i)) + 1;
var randomCols = Math.floor(Math.random() * (numBoxes - j)) + 1;
// Calculate the geometric bounds for the frame
var frameX1 = bounds[0] + i * cellWidth;
var frameY1 = bounds[1] + j * cellHeight;
var frameX2 = frameX1 + randomCols * cellWidth;
var frameY2 = frameY1 + randomRows * cellHeight;
// Calculate the area of the new box
var newBoxArea = (frameX2 - frameX1) * (frameY2 - frameY1);
// Check if the frame fits inside the user's selection and the total area is not exceeded
var frameFits = frameX2 <= bounds[3] && frameY2 <= bounds[2] && (userSelectionArea - newBoxArea) >= 0;
if (frameFits) {
// Update the occupied status of cells
for (var x = i; x < i + randomRows && x < numBoxes; x++) {
for (var y = j; y < j + randomCols && y < numBoxes; y++) {
cellOccupied[x][y] = true;
}
}
// Create the graphic frame
var frame = doc.pages[0].rectangles.add();
frame.geometricBounds = [frameY1, frameX1, frameY2, frameX2];
// Update the total area
userSelectionArea -= newBoxArea;
}
} while (!frameFits && tries < maxTries);
// If the maximum number of tries is reached, exit the loop
if (tries === maxTries) {
alert("Unable to fit all boxes inside the selection while maintaining the same area.");
break;
}
}
// Remove the original user selection
userSelection.remove();
} else {
alert("Please select a suitable shape (e.g., a rectangle or oval) to create graphic frames within.");
}
} else {
alert("Please enter valid numbers for the number of boxes and gutter width.");
}
// Close the dialog
dialog.destroy();
} else {
// User canceled the dialog
dialog.destroy();
}
And this is the working code for the grid maker
// Define a dialog
var dialog = app.dialogs.add({ name: "Create Graphic Frames" });
// Create a dialog column
var dialogColumn = dialog.dialogColumns.add();
// Create a dialog row for number of rows
var numRowsRow = dialogColumn.dialogRows.add();
numRowsRow.staticTexts.add({ staticLabel: "Number of Rows:" });
var numRowsField = numRowsRow.textEditboxes.add({ minWidth: 80 }); // Adjust the minWidth value
// Create a dialog row for number of columns
var numColsRow = dialogColumn.dialogRows.add();
numColsRow.staticTexts.add({ staticLabel: "Number of Columns:" });
var numColsField = numColsRow.textEditboxes.add({ minWidth: 80 }); // Adjust the minWidth value
// Create a dialog row for gutter width
var gutterRow = dialogColumn.dialogRows.add();
gutterRow.staticTexts.add({ staticLabel: "Gutter Width:" });
var gutterField = gutterRow.textEditboxes.add({ minWidth: 80 }); // Adjust the minWidth value
// Show the dialog and get user input
if (dialog.show() === true) {
// Get the number of rows and columns from user input
var numRows = parseInt(numRowsField.editContents);
var numCols = parseInt(numColsField.editContents);
// Get the gutter width from user input (assuming user enters value in their preferred unit)
var gutterWidth = parseFloat(gutterField.editContents);
// Convert the user's preference to points
var gutterWidthPoints;
if (app.activeDocument.viewPreferences.horizontalMeasurementUnits === MeasurementUnits.inches) {
gutterWidthPoints = gutterWidth * 72; // Convert inches to points
} else if (app.activeDocument.viewPreferences.horizontalMeasurementUnits === MeasurementUnits.millimeters) {
gutterWidthPoints = gutterWidth * 2.83465; // Convert millimeters to points
} else if (app.activeDocument.viewPreferences.horizontalMeasurementUnits === MeasurementUnits.centimeters) {
gutterWidthPoints = gutterWidth * 28.3465; // Convert centimeters to points
} else {
// By default, assume the user's input is already in points
gutterWidthPoints = gutterWidth;
}
// Check if the user entered valid numbers
if (!isNaN(numRows) && numRows > 0 && !isNaN(numCols) && numCols > 0 && !isNaN(gutterWidthPoints) && gutterWidthPoints >= 0) {
// Get the user's selection
var userSelection = app.selection[0];
// Check if the selection is valid and is a rectangle or other suitable shape
if (userSelection instanceof Rectangle || userSelection instanceof Oval) {
var doc = app.activeDocument;
var bounds = userSelection.geometricBounds;
// Calculate the total available width and height for frames
var totalWidth = bounds[3] - bounds[1];
var totalHeight = bounds[2] - bounds[0];
// Calculate the width and height of each frame including gutter
var frameWidth = (totalWidth - (numCols - 1) * gutterWidthPoints) / numCols;
var frameHeight = (totalHeight - (numRows - 1) * gutterWidthPoints) / numRows;
// Create a grid of graphic frames based on the user's input and within the selection bounds
for (var i = 0; i < numRows; i++) {
for (var j = 0; j < numCols; j++) {
var frame = doc.pages[0].rectangles.add();
frame.geometricBounds = [
bounds[0] + i * (frameHeight + gutterWidthPoints),
bounds[1] + j * (frameWidth + gutterWidthPoints),
bounds[0] + (i + 1) * (frameHeight + gutterWidthPoints) - gutterWidthPoints,
bounds[1] + (j + 1) * (frameWidth + gutterWidthPoints) - gutterWidthPoints
];
}
}
// Remove the original user selection
userSelection.remove();
} else {
alert("Please select a suitable shape (e.g., a rectangle or oval) to create graphic frames within.");
}
} else {
alert("Please enter valid numbers for the number of rows, columns, and gutter width.");
}
// Close the dialog
dialog.destroy();
} else {
// User canceled the dialog
dialog.destroy();
}
Copy link to clipboard
Copied
Okay differnt idea but working below
makes a random grid based on user bounding box size
no user input - that part i can make later
// Create a reference to the active document
var doc = app.activeDocument;
// Check if a rectangle is selected
if (app.selection.length > 0 && app.selection[0] instanceof Rectangle) {
var userRectangle = app.selection[0];
// Get the bounds of the user's rectangle
var userBounds = userRectangle.geometricBounds;
// Define the grid parameters
var numRows = 5; // Number of rows
var numCols = 5; // Number of columns
// Calculate the width and height of the grid
var gridWidth = userBounds[3] - userBounds[1];
var gridHeight = userBounds[2] - userBounds[0];
// Calculate the maximum random width that can fit within the available space without overlapping
var maxRandomWidth = gridWidth / numCols;
// Calculate the height of each row based on the number of rows divided by the user's selected box height
var rowHeight = gridHeight / numRows;
// Initialize a grid to keep track of used cells
var usedCells = [];
// Loop through rows
for (var i = 0; i < numRows; i++) {
usedCells[i] = []; // Create a new row
// Loop through columns
for (var j = 0; j < numCols; j++) {
// Check if the cell is already used
if (!usedCells[i][j]) {
// Calculate the position for each box
var xPosition = userBounds[1] + j * maxRandomWidth;
var yPosition = userBounds[0] + i * rowHeight;
// Calculate the remaining space in the row
var remainingSpaceInRow = gridWidth - j * maxRandomWidth;
// Calculate the maximum random width for this box based on the remaining space in the row
var maxRandomWidthForBox = Math.min(maxRandomWidth, remainingSpaceInRow);
// Generate a random value for the width (up to a maximum of 3)
var randomWidth = maxRandomWidthForBox * (Math.floor(Math.random() * 3) + 1);
// Check if this is the last box in the row
if (j === numCols - 1) {
// Calculate the width that fits within the remaining space without exceeding the bounds
var widthToFit = gridWidth - (j * maxRandomWidth);
randomWidth = Math.min(widthToFit, maxRandomWidthForBox);
}
// Create a new rectangle (box) inside the user's rectangle
var box = doc.rectangles.add();
var left = xPosition;
var top = yPosition;
var right = left + randomWidth;
var bottom = top + rowHeight;
box.geometricBounds = [top, left, bottom, right];
box.fillColor = doc.swatches.itemByName("Black");
// Mark the cells as used
for (var k = 0; k < Math.ceil(randomWidth / maxRandomWidth); k++) {
for (var l = 0; l < 1; l++) {
if (i + l < numRows && j + k < numCols) {
usedCells[i + l][j + k] = true;
}
}
}
}
}
}
// Delete the original user-drawn rectangle
userRectangle.remove();
} else {
alert("Please select a rectangle drawn by the user.");
}