Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

How to create custom data/properties for objects in InDesign

Explorer ,
Apr 05, 2023 Apr 05, 2023

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

TOPICS
How to , Scripting
1.5K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , Apr 06, 2023 Apr 06, 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 t

...
Translate
Community Expert ,
Apr 05, 2023 Apr 05, 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. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Apr 05, 2023 Apr 05, 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.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 05, 2023 Apr 05, 2023

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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 05, 2023 Apr 05, 2023

Yes you could write data from anywhere in accessible object properties to a txt using the File object.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Apr 05, 2023 Apr 05, 2023

"or Prototype another property to the Oval object model." 

 

What does that mean?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 05, 2023 Apr 05, 2023

 

 

Oval.prototype.labelVDistanceToKeyObject = function(key) {
     this.label = this.geometricBounds[1] - key.geometricBounds[1];
}

someOval.labelVDistanceToKeyObject(topOval); //now the distance is in some oval's label property

 

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 05, 2023 Apr 05, 2023

Prototypes don't have to be functions. You could have something like: 

Oval.prototype.vDistance = "";
///then
someOval.vDistance = (topOval.geometricBounds[1] - someOval.geometricBounds[1]).toString();
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 05, 2023 Apr 05, 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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Apr 06, 2023 Apr 06, 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.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 06, 2023 Apr 06, 2023
LATEST

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

 

afterSelectionChanged.gif

 

//@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');
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines