/*
[Link] for Adobe Illustrator
Description: Allows point texts to be vertically aligned based on the baseline of
its font, not its bounds
Date: April, 2023
Modification date: February, 2024
Author: Sergey Osokin, email: hi@[Link]
Installation: [Link]
Release notes:
0.1.1 Removed input activation on Windows OS below CC v26.4
0.1 Initial version
Donate (optional):
If you find this script helpful, you can buy me a coffee
- via Buymeacoffee: [Link]
- via Donatty [Link]
- via DonatePay [Link]
- via YooMoney [Link]
NOTICE:
Tested with Adobe Illustrator CC 2019-2025 (Mac/Win).
This script is provided "as is" without warranty of any kind.
Free to use, not for sale
Released under the MIT license
[Link]
Check my other scripts: [Link]
*/
//@target illustrator
[Link]('ShowExternalJSXWarning', false); // Fix drag
and drop a .jsx file
function main() {
var SCRIPT = {
name: 'Align Text Baseline',
version: 'v0.1.1'
},
CFG = {
space: 10,
dePreview: false,
units: getUnits(),
aiVers: parseFloat([Link]),
isMac: /mac/[Link]($.os),
uiOpacity: .96 // UI window opacity. Range 0-1
};
var isUndo = false;
var tfs = getTextFrames(selection);
sortByPosition(tfs);
// Scale factor for Large Canvas mode
[Link] = [Link] ? [Link] : 1;
// DIALOG
var win = new Window('dialog', [Link] + ' ' + [Link]);
[Link] = ['fill', 'top'];
[Link] = [Link];
// Input
var wrapper = [Link]('group');
[Link] = ['fill', 'center'];
[Link]('statictext', undefined, 'Vertical distribute space, ' + [Link]);
var spaceInp = [Link]('edittext', undefined, [Link]);
if ([Link] || [Link] >= 26.4 || [Link] <= 17) {
[Link] = true;
}
// Buttons
var btns = [Link]('group');
[Link] = ['fill', 'center'];
var isPreview = [Link]('checkbox', undefined, 'Preview');
[Link] = [Link];
var cancel = [Link]('button', undefined, 'Cancel', { name: 'cancel' });
var ok = [Link]('button', undefined, 'Ok', { name: 'ok' });
var copyright = [Link]('statictext', undefined, '\u00A9 Sergey Osokin. Visit
Github');
[Link] = 'center';
[Link]('mousedown', function () {
openURL('[Link]
});
shiftInputNumValue(spaceInp);
if ([Link]) preview();
[Link] = [Link] = preview;
[Link] = [Link];
[Link] = okClick;
[Link] = function () {
try {
if (isUndo) [Link]();
} catch (e) {}
}
function preview() {
try {
if ([Link]) {
if (isUndo) [Link]();
else isUndo = true;
distribute();
redraw();
} else if (isUndo) {
undo();
redraw();
isUndo = false;
}
} catch (e) {}
}
function okClick() {
if ([Link] && isUndo) [Link]();
distribute();
isUndo = false;
[Link]();
}
function distribute() {
var space = strToNum([Link], [Link]) / [Link];
space = convertUnits(space, [Link], 'px');
for (var i = 1, len = [Link]; i < len; i++) {
moveByBaseline(tfs[0], tfs[i], space * i);
}
}
// Use Up / Down arrow keys (+ Shift) for change value
function shiftInputNumValue(item) {
[Link]('keydown', function (kd) {
var step = [Link]['shiftKey'] ? 10 : 1;
if ([Link] == 'Down') {
[Link] = strToNum([Link]) - step;
[Link]();
preview();
}
if ([Link] == 'Up') {
[Link] = strToNum([Link]) + step;
[Link]();
preview();
}
});
}
[Link]();
[Link]();
}
// Get active document ruler units
function getUnits() {
if (![Link]) return '';
var key = [Link]().replace('RulerUnits.', '');
switch (key) {
case 'Pixels': return 'px';
case 'Points': return 'pt';
case 'Picas': return 'pc';
case 'Inches': return 'in';
case 'Millimeters': return 'mm';
case 'Centimeters': return 'cm';
// Added in CC 2023 v27.1.1
case 'Meters': return 'm';
case 'Feet': return 'ft';
case 'FeetInches': return 'ft';
case 'Yards': return 'yd';
// Parse new units in CC 2020-2023 if a document is saved
case 'Unknown':
var xmp = [Link];
if (/stDim:unit/[Link](xmp)) {
var units = /<stDim:unit>(.*?)<\/stDim:unit>/[Link](xmp)[1];
if (units == 'Meters') return 'm';
if (units == 'Feet') return 'ft';
if (units == 'FeetInches') return 'ft';
if (units == 'Yards') return 'yd';
return 'px';
}
break;
default: return 'px';
}
}
// Convert units of measurement
function convertUnits(value, currUnits, newUnits) {
return UnitValue(value, currUnits).as(newUnits);
}
// Get TextFrames array from collection
function getTextFrames(coll) {
var tfs = [];
for (var i = 0, len = [Link]; i < len; i++) {
if (/text/[Link](coll[i].typename))
[Link](coll[i]);
else if (/group/[Link](coll[i].typename))
tfs = [Link](getTextFrames(coll[i].pageItems));
}
return tfs;
}
// Sort array by X and Y positions
// Reference by Hiroyuki Sato, shspage
function sortByPosition(coll) {
var hs = [];
var vs = [];
for (var i = 0, len = [Link]; i < len; i++) {
[Link](coll[i].left);
[Link](coll[i].top);
}
if (arrMax(hs) - arrMin(hs) > arrMax(vs) - arrMin(vs)) {
[Link](function (a, b) {
return comparePosition([Link], [Link], [Link], [Link])
});
} else {
[Link](function (a, b) {
return comparePosition([Link], [Link], [Link], [Link])
});
}
}
// Compare position of two objects
function comparePosition(a1, b1, a2, b2) {
return a1 == b1 ? a2 - b2 : a1 - b1;
}
// Return maximum value in array
function arrMax(arr) {
return [Link](null, arr);
}
// Return minimal value in array
function arrMin(arr) {
return [Link](null, arr);
}
// Convert string to number
function strToNum(str, def) {
if ([Link] == 1 || def == undefined) def = 1;
str = [Link](/,/g, '.').replace(/[^\d.-]/g, '');
str = [Link]('.');
str = str[0] ? str[0] + '.' + [Link](1).join('') : '';
str = [Link](0, 1) + [Link](1).replace(/-/g, '');
if (isNaN(str) || ![Link]) return parseFloat(def);
else return parseFloat(str);
}
// Distribute two point texts by baseline
function moveByBaseline(a, b, space) {
var dist = [Link][1] - [Link][1];
var delta = space - dist;
[Link] = [[Link][0], [Link][1] - delta];
}
// Open link in browser
function openURL(url) {
var html = new File([Link] + '/[Link]');
[Link]('w');
var htmlBody = '<html><head><META HTTP-EQUIV=Refresh CONTENT="0; URL=' + url +
'"></head><body> <p></body></html>';
[Link](htmlBody);
[Link]();
[Link]();
}
try {
main();
} catch (e) {}