Skip to main content
Known Participant
April 5, 2023
Answered

How to create custom data/properties for objects in InDesign

  • April 5, 2023
  • 2 replies
  • 1381 views

I'd like to to create custom object data in Indesign. I'm not sure if it is possible. I'll use the following example to explain what I'd like to do:

 

I'd like to be able to put a cirlce at the top of a page in an InDesign document that acts as a reference circle for other objects that I place on that page. I'd then like to run a script to collect the vertical distances from all the objects to the reference circle. Best case senario would be to then have that object data be displayed somewhere with the object within indesign. A not as ideal senario, but satisfactory, would be if a text file was generated with all the objects and there vertical distances from the reference circle. 

 

Is this possible to do in Indesign? Would this be any easier to facilitate in Illusrator?

 

Thanks in advance,

 

Ben

This topic has been closed for replies.
Correct answer m1b

Hi @Ben-ind, there isn't any super-handy method that I can think of to do this.

 

One approach could be to add an event listener (to the document, for example) that would trigger every time the selection changed. It could then add your desired info to the selected item's Script Label panel. A better UI would be to create a CEP panel to show the info, but that is quite a bit more involved unless you've made one before.

 

Here's a quick example implementation to give you the idea. To help manage the event listener, I've set it up to alternate between adding and then removing the listener each time you run the script.

- Mark

 

 

//@targetengine "SetLabelAsVerticalDistance"
function main() {

    var listenerID = 'SetLabelAsVerticalDistance',
        referenceCircleID = 'ReferenceCircle',
        referenceCircleColorID = 'Red';

    app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;

    var doc = app.activeDocument;

    // get the event listener
    var listener = doc.eventListeners.itemByName(listenerID);

    // if it exists already, remove it
    if (listener.isValid) {
        listener.remove();
        alert('Event listener "' + listenerID + '" has been removed from document.');
        return;
    }

    else {
        // make the event listener
        listener = doc.eventListeners.add("afterSelectionChanged", setLabelToDistanceFromVerticalDatum);
        listener.name = listenerID;
        alert('Event listener "' + listenerID + '" has been added to document.');

    }

    // the function that will be called by the event listener
    function setLabelToDistanceFromVerticalDatum() {

        if (doc.selection.length == 0)
            return;

        var page = doc.layoutWindows[0].activePage;

        // get reference circle, if it exists on this page
        var referenceCircle = page.pageItems.itemByName(referenceCircleID);

        if (
            referenceCircle == undefined
            || !referenceCircle.isValid
        )
            referenceCircle = makeCircle(page);

        // I've used the top of the reference circle,
        // but you should set this any way you want
        var referenceCircleVerticalDatum = referenceCircle.geometricBounds[0];

        for (var i = 0; i < doc.selection.length; i++) {

            var item = doc.selection[i];

            if (item == referenceCircle)
                continue;

            if (item.hasOwnProperty('geometricBounds'))
                // add to the script label (rounded to 3 decimals)
                item.label = 'Distance: ' + (Math.round((item.geometricBounds[0] - referenceCircleVerticalDatum) * 1000) / 1000);

        }

    };

    function makeCircle(pg) {

        var circle = pg.ovals.add(doc.activeLayer, undefined, undefined, { geometricBounds: [0, 10, 1, 11], strokeWeight: 1, name: referenceCircleID }),
            red = doc.colors.itemByName(referenceCircleColorID);

        if (!red.isValid)
            red = doc.colors.add({ name: referenceCircleColorID, space: ColorSpace.RGB, colorValue: [255, 0, 0], colorModel: ColorModel.PROCESS });

        circle.strokeColor = red;

        return circle;

    };

};

app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Add event listener to set distance from datum');

2 replies

m1b
Community Expert
Community Expert
April 5, 2023

Hi @Ben-ind, can you give us an example of what the stored data (or txt file written data) would be, for a given sample page? And how do you plan to access it? That will get things moving the quickest I think.

 

One thing to look into is the "insertLabel" and "extractLabel" functions of many Indesign objects. With, say, myOval.insertLabel(key, value) you could probably achieve what you want. At any time you could do myOval.extractLabel(key) to retrieve the value.

- Mark

Ben-indAuthor
Known Participant
April 6, 2023

Here's a simple script that shows what I'm trying to do:

 

function example() {
	// create document
	var myDocument = app.documents.add();
	myDocument.documentPreferences.pageWidth = "11in";
	myDocument.documentPreferences.pageHeight = "8.5in";
	myDocument.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.INCHES; 
	myDocument.viewPreferences.verticalMeasurementUnits = MeasurementUnits.INCHES;
	// create reference circle
	with (myrefCircle = myDocument.pages.item(0).ovals.add(myDocument.layers.item(0), undefined, undefined, {geometricBounds:[0, 10, 1, 11], strokeWeight: 1, name: "Reference Circle"})) {
		myColor_Red = app.activeDocument.colors.add({name:"Red", space:ColorSpace.RGB, colorValue:[255,0,0], colorModel:ColorModel.PROCESS})
		mySwatch_Red = myDocument.swatches.item("Red")
		myrefCircle.strokeColor = mySwatch_Red
	}
	// create rectangle at center of page
	myRectangle = myDocument.pages.item(0).rectangles.add(myDocument.layers.item(0), undefined, undefined, {geometricBounds:[3.75, 4.5, 4.75, 6.5], strokeWeight: .5, strokeColor: "Black", name: "Rectangle"})

	// From here I want to get the vertical distance from top of "Rectangle" to top of "Reference Circle". Thats not difficult.
	Vdistance = myrefCircle.geometricBounds[1] - myRectangle.geometricBounds[1]
	// I then want that vertical distance to be seen somewhere with "Rectangle" within the Indesign UI if possible. This part I'm unsure of how to do.


	
	// I then want Vdistance to be exported as a text file to the file location of the users choosing. Also unsure of how to do this.
}

app.doScript(example, ScriptLanguage.JAVASCRIPT, [], UndoModes.FAST_ENTIRE_SCRIPT, "Example");

 

I'm hoping you can fill in the blanks here. I'm having trouble applying protoypes to me example. I'm a bit unclear of what they are.

m1b
Community Expert
m1bCommunity ExpertCorrect answer
Community Expert
April 7, 2023

Hi @Ben-ind, there isn't any super-handy method that I can think of to do this.

 

One approach could be to add an event listener (to the document, for example) that would trigger every time the selection changed. It could then add your desired info to the selected item's Script Label panel. A better UI would be to create a CEP panel to show the info, but that is quite a bit more involved unless you've made one before.

 

Here's a quick example implementation to give you the idea. To help manage the event listener, I've set it up to alternate between adding and then removing the listener each time you run the script.

- Mark

 

 

//@targetengine "SetLabelAsVerticalDistance"
function main() {

    var listenerID = 'SetLabelAsVerticalDistance',
        referenceCircleID = 'ReferenceCircle',
        referenceCircleColorID = 'Red';

    app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;

    var doc = app.activeDocument;

    // get the event listener
    var listener = doc.eventListeners.itemByName(listenerID);

    // if it exists already, remove it
    if (listener.isValid) {
        listener.remove();
        alert('Event listener "' + listenerID + '" has been removed from document.');
        return;
    }

    else {
        // make the event listener
        listener = doc.eventListeners.add("afterSelectionChanged", setLabelToDistanceFromVerticalDatum);
        listener.name = listenerID;
        alert('Event listener "' + listenerID + '" has been added to document.');

    }

    // the function that will be called by the event listener
    function setLabelToDistanceFromVerticalDatum() {

        if (doc.selection.length == 0)
            return;

        var page = doc.layoutWindows[0].activePage;

        // get reference circle, if it exists on this page
        var referenceCircle = page.pageItems.itemByName(referenceCircleID);

        if (
            referenceCircle == undefined
            || !referenceCircle.isValid
        )
            referenceCircle = makeCircle(page);

        // I've used the top of the reference circle,
        // but you should set this any way you want
        var referenceCircleVerticalDatum = referenceCircle.geometricBounds[0];

        for (var i = 0; i < doc.selection.length; i++) {

            var item = doc.selection[i];

            if (item == referenceCircle)
                continue;

            if (item.hasOwnProperty('geometricBounds'))
                // add to the script label (rounded to 3 decimals)
                item.label = 'Distance: ' + (Math.round((item.geometricBounds[0] - referenceCircleVerticalDatum) * 1000) / 1000);

        }

    };

    function makeCircle(pg) {

        var circle = pg.ovals.add(doc.activeLayer, undefined, undefined, { geometricBounds: [0, 10, 1, 11], strokeWeight: 1, name: referenceCircleID }),
            red = doc.colors.itemByName(referenceCircleColorID);

        if (!red.isValid)
            red = doc.colors.add({ name: referenceCircleColorID, space: ColorSpace.RGB, colorValue: [255, 0, 0], colorModel: ColorModel.PROCESS });

        circle.strokeColor = red;

        return circle;

    };

};

app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Add event listener to set distance from datum');
brian_p_dts
Community Expert
Community Expert
April 5, 2023

Sure that's doable. You could name the reference circle in your Layers panel, then for each page in the doc, find page.ovals.itemByName("reference"), then calculate its bounds, then the bounds of other page.ovals that don't share its name. Then populate another named text frame with the values. 

Ben-indAuthor
Known Participant
April 5, 2023

Yes, but I dont want another named text frame. I want that object data to be stored somewhere with the object, like in the properties tab or something. This is the part that I am finding to be not possible in Indesign. Would you agree?

 

Going off your proposed soltution, are you able to export text frames as .txt files? That would be the end goal here.

brian_p_dts
Community Expert
Community Expert
April 5, 2023

You could add it to the oval's label property, or Prototype another property to the Oval object model.