Copy link to clipboard
Copied
Hi there!
I'm new to scripting and I can't find an example of a javascript that mimics Transform panel behaviour.
I need to change width or height of all selected objects that are on different layers (without grouping) by certain set of multipliers (I don't wanna input them manually every time). And that objects should be transformed relative to the center reference point.
I've tried different solutions that I've found on the internet but I can't figure out how to do that.
When I do it manually I hit Ctrl+A, then type in Transform panel [*0,6512], hit Enter. So I want to automate it.
Is that possible? Could someone help me please?
Copy link to clipboard
Copied
Transfomations are both easy to apply and tough to acquire (Understanding CoordinateSpaces, reference points, bridges between points and contextual units). You may be interested in PageItem Collection's transform() method :
InDesign ExtendScript API (10.0)
And in UnitValue, always valuable to use in combination with transform:
http://www.indesignjs.de/extendscriptAPI/indesign10/#UnitValue.html
Copy link to clipboard
Copied
Loic, I don't believe Illustrator has that same functionality as the Illustrator API is severely anemic compared with InDesign's API.
eoneof, What you're looking for is definitely doable, but requires a few custom components and calculations to make sure the art is resized relative to the center of a given reference point.
Do you have any code written you'd like us to help with or are you looking for someone to write the code?
Copy link to clipboard
Copied
I have a suitable piece of code from other script:
if ( documents.length > 0)
mySelection = activeDocument.selection;
if (mySelection instanceof Array) {
initBounds = mySelection[0].visibleBounds;
ul_x = initBounds[0];
ul_y = initBounds[1];
lr_x = initBounds[2];
lr_y = initBounds[3];
for (i=1; i<mySelection.length; i++) {
groupBounds = mySelection.visibleBounds;
if (groupBounds[0]<ul_x){ul_x=groupBounds[0]}
if (groupBounds[1]>ul_y){ul_y=groupBounds[1]}
if (groupBounds[2]>lr_x){lr_x=groupBounds[2]}
if (groupBounds[3]<lr_y){lr_y=groupBounds[3]}
var wid = lr_x-ul_x
alert (wid)
}
}
Here I managed to get to know current objects' width, but I have no idea what's next.
Copy link to clipboard
Copied
when you say "current object" do you mean the current selection?
That snippet seems needlessly cryptic. But perhaps it's just a different style than i'm used to writing. It looks like that snippet alerts the difference between lr_x and ul_x (initBounds[2] - initBounds[0]) which is the right edge - left edge.
This is a way to give you the information about the width of multiple ungrouped objects, but it will not help you to resize anything since you cannot resize a selection of objects. You can only resize a single object at a time. So you can either loop each object and resize it individually (which would then require additional logic to reposition it so it's in the same relative position to your chosen reference point) or else you could take the existing selection, temporarily group it together, resize the entire group at once, then ungroup it.
Copy link to clipboard
Copied
Yes, you are right, I meant current selection.
I added these rows to be shure I'm on the right way:
- var wid = lr_x-ul_x
- alert (wid)
It shows width:
Unfortunately grouping is not acceptable as I need objects to be on certain layers. It would take more manual work to sort them back, than transforming
Anyway, I'd like to know how to transform group?
Copy link to clipboard
Copied
williamadowling I constantly jump from InDesign Scripting forum to here and sometimes I miss the fact I am not in the good room My apologises for those being misleaded.
Copy link to clipboard
Copied
So to be illustratorly useful :
var sel = app.selection;
var n = sel.length;
while ( n-- ) sel
Copy link to clipboard
Copied
Loic,
This will work to resize each item, but each item will be resized relative to it's own center, which means that if you resize two items, their positions (relative to one another) will change. See this screenshot as an example.
In order to resize each piece individually, you'll also have to include logic that repositions the art after it's resized so it's placement relative to the desired reference point, remains the same.
Copy link to clipboard
Copied
You can perform a transform like how you wish by script only, without having to necessarily use a document selection. This can be done by temporarily changing your document's origin to a desired location and performing the transform scripting commands then. The origin would be in the center of the bounding box of the art in question, or any arbitrary point.
Copy link to clipboard
Copied
Ok I think I got it :
Before reduction ( reduced objects have been converted to rulers so we can have a clue of where objects have to be eventually)
Once the script is applied, objects are nicely resized:
HTH
Loic
Ozalto | Productivity Oriented - Loïc Aigon
//Main routine
var main = function() {
var sel;
//Exit if no documents open
if ( !app.documents.length ) return;
sel = app.selection;
//Exit if no selection
if ( !sel.length ) return;
//Exit if selection is range of text characters
if ( sel.typename == "TextRange" ) {
alert( "Please select pageItems and run again…");
return;
}
//Apply reduction
try {
reduceSelection ( sel, 50, 50 );
}
catch ( err ) {
alert( err.line+">>"+err.message );
}
};
//reduction routine
var reduceSelection = function( sel, wRatio, hRatio ) {
//-- VARS
var n = sel.length, gx1, gx2, gy1, gy2, items = [], item,
ix1, ix2, iy1, iy2, mx, my, iLeft, iTop;
// Looping through selection items
// to compute the boundaries of the pseudo group
// and in extenso the reference point in the center of that area
while ( n-- ) {
item = sel
; ix1 = item.left;
ix2 = item.left+item.width;
iy1 = item.top;
iy2 = item.top-item.height;
(typeof(gx1)=="undefined"||ix1<gx1) && gx1 = ix1;
(typeof(gx2)=="undefined"||ix2>gx2) && gx2 = ix2;
(typeof(gy1)=="undefined"||iy1>gy1) && gy1 = iy1;
(typeof(gy2)=="undefined"||iy2<gy2) && gy2 = iy2;
}
//Computing central point values
mx = gx1+(gx2-gx1)/2;
my = gy1+(gy2-gy1)/2;
//Looping over items so they can be resized and relocated in reference to the central point in [mx,my]
n = sel.length;
while ( n-- ) {
item = sel
; ix1 = item.left;
iy1 = item.top;
//Storing initial value of top/left position of the item
iLeft = item.left;
iTop = item.top;
//resizing item
item.resize ( wRatio, hRatio );
//Moving item to its initial location in order to prevent computation corruption
item.left = iLeft;
item.top = iTop;
//Moving resized item to the correct location
if ( iLeft<mx ) {
item.left+= (mx-iLeft)*wRatio/100;
}
else {
item.left-= (iLeft-mx)*wRatio/100;
}
if ( iTop<mx ) {
item.top+= (my-iTop)*hRatio/100;
}
else {
item.top-= (my-iTop)*hRatio/100;
}
}
}
//YOLO
main();
Copy link to clipboard
Copied
Wow, that's quite complicated. I didn't even know that that "simple" operation would take so many computations. I apreciate your help.
The script works as expected but... Excuse me for my noob quiestion: what exactly should I change to transform W & H separately with custom values ?
Copy link to clipboard
Copied
Line 21. The second and third arguments. the second argument is "wRatio" and the third is "hRatio".
So let's say you wanted to scale the width to 20% and the height to 65%. Change line 21 to this:
reduceSelection ( sel, 20, 65 );
Copy link to clipboard
Copied
Hi Loic, there has a problem with your above code: if the document's rulerOrigin is lower than the selection's bottom, objects will be wrongly positioned after scaled.
It's more easy to use Silly-V's method.
Copy link to clipboard
Copied
Indeed.
Copy link to clipboard
Copied
This is exactly what I had in mind, Loic. Good work.
Copy link to clipboard
Copied
Thanks williamadowling
Copy link to clipboard
Copied
Exactly.