Adobe Illustrator Script: Hachures (Hatches)
Description
This Adobe Illustrator script, created by Christian Condamine, allows you to add vector hatches to the selected object (path or compound path). It includes a preview function to view live changes related to the settings. The values entered in the dialog box are saved in a .json
file to be reloaded on the next launch of the script.

Usage
- Open Adobe Illustrator.
- Select a path or a compound path in the document.
- Run the script. A dialog box will appear.
- Fill in the following fields in the dialog box:
- Spacing: The distance between the hatches (in mm).
- Gradient: The angle of the hatches (in degrees).
- Thickness: The thickness of the hatches (in mm).
- Preserve color: Check this option to preserve the color of the selected object.
- Click the “OK” button to apply the hatches to the selected object.
- The script will create the hatches based on the input parameters and add them to the selected object.
Script Details
Localization
- The script supports both English and French languages. The language is automatically detected based on the user’s locale settings.
Dialog Box
- Spacing: Input field for the distance between the hatches (default: 4 mm).
- Gradient: Input field for the angle of the hatches (default: 45 degrees).
- Thickness: Input field for the thickness of the hatches (default: 0.5 mm).
- Preserve color: Checkbox to preserve the color of the selected object.
- OK Button: Button to apply the hatches.
- Cancel Button: Button to cancel the operation.
Parameter Saving
- The script saves the entered values in a
.json
file located in the user’s Documents folder (CC_Scripts/Hachures_param.json
). These values are reloaded on the next launch of the script.
Functions
- startGUI: Initializes and displays the dialog box.
- majApercu: Updates the preview of the hatches.
- recueilDonnees: Collects the input data from the dialog box.
- action: Main function to create the hatches and apply them to the selected object.
- gBN: Retrieves a named item from the document.
- verifDossierParam: Verifies and creates the parameter folder if it doesn’t exist.
- sauverParametres: Saves the input data to the
.json
file. - chargerParametres: Loads the input data from the
.json
file. - valider: Finalizes the operation and resets the selection.
JavaScript
Hatches – Illustrator Script (0 downloads )
/*Hachures
>=----------------------------------------------------------------------------------------------------------------------------------------------------------------
Author: Christian Condamine - (christian.condamine@laposte.net)
>=----------------------------------------------------------------------------------------------------------------------------------------------------------------
En: This script allows you to add vector hatches to the selected object (path or compoundpath). A preview function
allows you to view live changes related to settings. The values entered in the dialog box are saved in a .json file to
be reloaded on the next launch of the script.
>=----------------------------------------------------------------------------------------------------------------------------------------------------------------
Fr ; Ce script permet d’ajouter des hachures vectorielles à l’objet sélectionné (tracé ou tracé transparent). Une fonction
d’aperçu permet de visualiser en direct les changements liés aux réglages. Les valeurs entrées dans la boite de
dialogue sont conservées dans un fichier .json pour être rechargées au lancement suivant du script.
*/
#targetengine 'main'
app.preferences.setBooleanPreference('ShowExternalJSXWarning', false); // Fix drag and drop a .jsx file
$.localize = true;
$.locale = null;
if ($.locale.substr(0, 2) != "fr") { $.locale = "en"; }
var nomScript = 'Hachures',
fichierParam = {
name: nomScript + '_param.json',
folder: Folder.myDocuments + '/CC_Scripts/'
};
var selection = app.activeDocument.selection;
if (selection.length < 1) {
alert(localize({en:"You must select one path or one compound path.", fr:"La s\351lection doit \352tre compos\351e d'un trac\351ou d'un trac\351 transparent"}));
throw new Error("No selection found.");
}
var monCalque = selection[0].layer;
var nbSel = selection.length;
var typeObj = 0;
var couleur;
var coulParDefaut;
var perim, x0, y0, L0, H0;
var defaire = false;
if (nbSel === 1) {
coulParDefaut = new RGBColor();
coulParDefaut.red = 0;
coulParDefaut.green = 0;
coulParDefaut.blue = 0;
if (selection[0].typename === "PathItem") {
typeObj = "P";
if (selection[0].stroked === true) {
couleur = selection[0].strokeColor;
selection[0].filled = false;
} else {
couleur = selection[0].fillColor;
selection[0].filled = false;
selection[0].strokeColor = couleur;
}
}
if (selection[0].typename === "CompoundPathItem") {
typeObj = "C";
if (selection[0].pathItems[0].stroked === true) {
couleur = selection[0].pathItems[0].strokeColor;
} else {
couleur = selection[0].pathItems[0].fillColor;
}
}
if (typeObj != 0) {
selection[0].name = "baseSelection";
perim = parseFloat((selection[0].width * 2 + selection[0].height).toFixed(0));
x0 = selection[0].left;
y0 = selection[0].top;
L0 = selection[0].width;
H0 = selection[0].height;
//---------------------------------------------------------------------------------------------------------------------------------------------------------
// Dialog box
//---------------------------------------------------------------------------------------------------------------------------------------------------------
//== Load parameters saved from the previous session
var boiteDial = new Window('dialog', {en:"Hatch", fr:"Hachurer"});
boiteDial.orientation = "column";
boiteDial.alignChildren = ["fill", "center"];
boiteDial.alignment = "left";
//== Espacement Group
var grpEspacement = boiteDial.add('group');
grpEspacement.orientation = "row";
grpEspacement.spacing = 3;
var lblEspacement = grpEspacement.add("statictext", undefined, {en:"Spacing:", fr:"Espacement :"});
lblEspacement.size = [80, 18];
var txtEspacement = grpEspacement.add("edittext", undefined, 4);
txtEspacement.characters = 4;
txtEspacement.size = [60, 23];
var lblUnitEsp = grpEspacement.add("statictext", undefined, 'mm');
lblUnitEsp.size = [25, 18];
//== Inclination Group
var grpAngle = boiteDial.add('group');
grpAngle.orientation = "row";
grpAngle.spacing = 3;
var lblAngle = grpAngle.add("statictext", undefined, {en:"Gradient:", fr:"Inclinaison :"});
lblAngle.size = [80, 18];
var txtAngle = grpAngle.add("edittext", undefined, 45);
txtAngle.characters = 4;
txtAngle.size = [60, 23];
var lblUnitAngle = grpAngle.add("statictext", undefined, {en:"Degrees", fr:"degr\351s"});
lblUnitAngle.size = [50, 18];
//== Stroke Thickness Group
var grpEpTrait = boiteDial.add('group');
grpEpTrait.orientation = "row";
grpEpTrait.spacing = 3;
var lblEpTrait = grpEpTrait.add("statictext", undefined, {en:"Thickness:", fr:"\311paisseur :"});
lblEpTrait.size = [80, 18];
var txtEpTrait = grpEpTrait.add("edittext", undefined, 0.5);
txtEpTrait.characters = 4;
txtEpTrait.size = [60, 23];
var lblUnitEpTrait = grpEpTrait.add("statictext", undefined, 'mm');
lblUnitEpTrait.size = [35, 18];
//== Option to use the color of the selected object
var ckbConserCoul = boiteDial.add("checkbox", undefined, {en:"Preserve color", fr:"Conserver couleur"});
ckbConserCoul.alignment = "left";
var grpBoutons = boiteDial.add('group');
grpBoutons.orientation = "row";
grpBoutons.alignChildren = ["fill", "center"];
var btnOk = grpBoutons.add('button', undefined, 'OK', {name: 'ok'});
var btnAnnuler = grpBoutons.add('button', undefined, {en:"Cancel", fr:"Annuler"}, {name: 'cancel'});
txtEspacement.onChange = function() { majApercu(); };
txtAngle.onChange = function() { majApercu(); };
txtEpTrait.onChange = function() { majApercu(); };
ckbConserCoul.onClick = function() { majApercu(); };
btnOk.onClick = function () { valider(); boiteDial.close(); };
btnAnnuler.onClick = function() {
if (defaire) {
app.activeDocument.selection[0].remove();
gBN(typeObj, "baseSelection").selected = true;
defaire = false;
}
boiteDial.close();
};
boiteDial.onClose = function() { sauverParametres(); };
verifDossierParam();
chargerParametres();
boiteDial.center();
majApercu();
boiteDial.show();
} else {
alert(localize({en:"You must select one path or one compound path.", fr:"La s\351lection doit \352tre compos\351e d'un trac\351ou d'un trac\351 transparent"}));
}
} else {
alert(localize({en:"You must select one path or one compound path.", fr:"La s\351lection doit \352tre compos\351e d'un trac\351ou d'un trac\351 transparent"}));
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------------------------------------------------------------------------------------
function majApercu() {
if (defaire) {
app.activeDocument.selection[0].remove();
app.activeDocument.selection = null;
gBN(typeObj, "baseSelection").selected = true;
} else {
defaire = true;
app.redraw();
}
action();
app.redraw();
}
function recueilDonnees() {
// Convert mm to points: 1mm = 2.834645 points
espacement = parseFloat(txtEspacement.text * 2.834645);
epTrait = parseFloat(txtEpTrait.text * 2.834645);
angle = parseFloat(txtAngle.text);
ConserCoul = ckbConserCoul.value;
}
function action() {
recueilDonnees();
app.copy();
app.executeMenuCommand('pasteFront');
app.activeDocument.selection[0].name = "copieBaseSelection";
if (app.activeDocument.selection[0].typename == "PathItem") {
app.activeDocument.selection[0].filled = true;
app.activeDocument.selection[0].stroked = false;
} else {
for (var n = 0; n < app.activeDocument.selection[0].pathItems.length; n++) {
app.activeDocument.selection[0].pathItems[n].filled = true;
app.activeDocument.selection[0].pathItems[n].stroked = false;
}
}
var grpHachures = monCalque.groupItems.add();
grpHachures.name = "grpHachures";
var lignes = [];
for (var i = 0; i < (perim) / espacement; i++) {
var ligne = grpHachures.pathItems.add();
ligne.name = "ligne" + i;
ligne.setEntirePath([[x0, y0 - (espacement * i)], [x0 + perim, y0 - (espacement * i)]]);
ligne.stroked = true;
ligne.strokeWidth = epTrait;
if (ConserCoul) {
ligne.strokeColor = couleur;
} else {
ligne.strokeColor = coulParDefaut;
}
lignes.push(ligne);
}
grpHachures.rotate(angle, true, false, false, false, Transformation.CENTER);
grpHachures.left = x0 - (grpHachures.width - L0) / 2;
grpHachures.top = y0 + (grpHachures.height - H0) / 2;
var limGH_0 = grpHachures.geometricBounds[0] - 10;
var limGH_1 = grpHachures.geometricBounds[1] + 10;
var limGH_2 = grpHachures.geometricBounds[2] + 10;
var limGH_3 = grpHachures.geometricBounds[3] - 10;
var masque = monCalque.pathItems.add();
masque.name = "masque";
masque.setEntirePath([[limGH_0, limGH_1], [limGH_0, limGH_3], [limGH_2, limGH_3], [limGH_2, limGH_1]]);
masque.closed = true;
monCalque.selection = null;
var groupeTemp = monCalque.groupItems.add();
gBN(typeObj, "copieBaseSelection").move(groupeTemp, ElementPlacement.PLACEATBEGINNING);
gBN("P", "masque").move(groupeTemp, ElementPlacement.PLACEATBEGINNING);
groupeTemp.selected = true;
app.executeMenuCommand('compoundPath');
gBN("G", "grpHachures").selected = true;
app.executeMenuCommand('ungroup');
if (typeObj == "P") {
app.executeMenuCommand('ungroup');
}
app.executeMenuCommand('Make Planet X');
app.executeMenuCommand('Expand Planet X');
app.executeMenuCommand('ungroup');
var j, k = 0;
for (j = 0; j < 2; j++) {
if (app.activeDocument.selection[j].pageItems[0].typename == "CompoundPathItem") {
k = j;
}
if (app.activeDocument.selection[j].pageItems[0].filled == true) {
k = j;
}
}
app.activeDocument.selection[k].remove();
}
function gBN(typeObj, objet) {
var monItem;
if (typeObj === "C") {
monItem = monCalque.compoundPathItems.getByName(objet);
} else if (typeObj === "G") {
monItem = monCalque.groupItems.getByName(objet);
} else {
monItem = monCalque.pathItems.getByName(objet);
}
return monItem;
}
function verifDossierParam() {
var monDossier = new Folder(fichierParam.folder);
if (!monDossier.exists) {
monDossier.create();
}
}
function sauverParametres() {
try {
var paramHach = new File(fichierParam.folder + fichierParam.name);
var donnees = [txtEspacement.text, txtAngle.text, txtEpTrait.text, ckbConserCoul.value].toString();
paramHach.open('w');
paramHach.write(donnees);
paramHach.close();
} catch (e) {
$.errorMessage(e);
}
}
function chargerParametres() {
var paramHach = new File(fichierParam.folder + fichierParam.name);
if (paramHach.exists) {
try {
paramHach.open('r');
var donnees = paramHach.read().split('\n'),
mesValeurs = donnees[0].split(',');
txtEspacement.text = parseFloat(mesValeurs[0]);
txtAngle.text = parseFloat(mesValeurs[1]);
txtEpTrait.text = parseFloat(mesValeurs[2]);
ckbConserCoul.value = (mesValeurs[3] === 'true');
} catch (e) {}
paramHach.close();
}
}
function valider() {
app.activeDocument.selection = null;
gBN(typeObj, "baseSelection").selected = true;
app.activeDocument.selection[0].name = "";
perim = "";
x0 = "";
y0 = "";
L0 = "";
H0 = "";
}