10 Replies Latest reply on Jan 28, 2012 3:37 PM by cotcodac

    Drawing a triangle shape thru a script, reading a selection bounds and mouse pointer?

    cotcodac Level 1

      Hello...

      This is a bit trickier I assume...

      dialog sample.jpg

      I am looking for a way to automate some of the work I do for a manga magazine - comics or whatever they are called... So I have a dialog in an oval shape already formated with an object style to look like the oval in the left part of my image. I would like the script to read the mouse pointer‘s position - I would run the script having selected the oval and with the mouse hovering the place where the oval should point... (So in the image you can imagine my mouse pointer somewhere in the lower left part of the image, where in the second part of the image is the corner of the triangle) I imagined this operation in at least two steps, the triangle (arrow) of the oval is a separate object (I would join the two shapes later). The triangle can be with streight lines or maybe a little bent, for a more desirable look. I have no ideea where to start, at the moment I am creating the ovals and duplicate the triangle from an old one, and position it (+rotate) until I am happy, after that I would join them. I Hope the picture can explain better what I am looking for.

      I know this is a difficult job - I would think that it can be helpful for others, as well as it would be a good challange for the very smart scripters of this forum...

      Thank you..

        • 1. Re: Drawing a triangle shape thru a script, reading a selection bounds and mouse pointer?
          [Jongware] Most Valuable Participant

          Nice little challenge!

           

          No, a script cannot "see" where the mouse pointer is -- but it's possible to work around that. Below is a Javascript (so save as "WhoSaidThat.jsx" in your User Script folder) that works on your selection. If you draw an oval -- or just about anything else --, select it and then run this script, it will add a default "who said that" triangle at the bottom.

           

          It does so by temporarily adding a path to the selection, releasing the compound path, and then using the Pathfinder to make it whole again.

           

          Warning: it does not work correctly with text frames! For some reason, the pathfinder fails on this. If you are using the same ovals to type your text in, I'll try and see if there is a way around that.

           

          Here is the script:

           

          // Make sure there is something appropriate selected
          if (app.documents.length && app.selection.length == 1 && app.selection[0].hasOwnProperty("paths"))
          {
            app.doScript(whoSaidThat, ScriptLanguage.JAVASCRIPT, app.selection[0], UndoModes.ENTIRE_SCRIPT, "Who Said That!?");
          } else
          {
            alert ("No valid selection.\nPlease select one single object with the black arrow before running this script.");
          }
          
          
          function whoSaidThat (baseObject)
          {
          //  Set units temporarily to points
            hmmu = app.activeDocument.viewPreferences.horizontalMeasurementUnits;
            vmmu = app.activeDocument.viewPreferences.verticalMeasurementUnits;
            app.activeDocument.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.POINTS;
            app.activeDocument.viewPreferences.verticalMeasurementUnits = MeasurementUnits.POINTS;
          
            // use "try" in case anything goes wrong
            try
            {
              // you got this selected
              oval = app.selection[0];
              // this is the center bottom position to attach the triangle to
              x = (oval.geometricBounds[1] + oval.geometricBounds[3])/2;
              y = oval.geometricBounds[2];
              // glue the new path to this one
              oval.paths.add({entirePath:[ [x-7, y-2], [[x-6,y+4], [x-10,y+14],[x-13,y+20]], [x-14,y+22], [[x+1,y+7],[x+4,y-2], [x+7,y-10]] ] });
              // break apart this new compound path
              objects = oval.releaseCompoundPath();
              // .. and make it into one solid object
              oval.addPath(objects);
            } catch (_)
            {
            }
            // reset your original units
            app.activeDocument.viewPreferences.horizontalMeasurementUnits = hmmu;
            app.activeDocument.viewPreferences.verticalMeasurementUnits = vmmu;
          }
          

           

           

          ... and here is the proof it actually works:

           

          Screen Shot 2012-01-23 at 1.34.44 AM.png

          1 person found this helpful
          • 2. Re: Drawing a triangle shape thru a script, reading a selection bounds and mouse pointer?
            cotcodac Level 1

            We dont need proof from you, Jongware....

            The thing is... I almost never need the arrow pointing down, from the same position of the oval. When you have a complicated background, I need to avoid covering something important and I would put the text somewhere convenient and stretch the arrow a bit, coming from left baybe, of top... That's why I mentioned the mouse pointer, it would have made a simple way to indicate where the aarow should point starting from the center of the selection.

            The workaround whould be to have like 10 scripts each for a different position, and maybe I can figure out a solution to work with the selection even if I already made an arrow, if I dont like it I can run it again (or a different version, different position for the arrow).

            • 3. Re: Drawing a triangle shape thru a script, reading a selection bounds and mouse pointer?
              [Jongware] Most Valuable Participant

              Ahh right. Well, scripting doesn't support freely moving the mouse around, but perhaps you can think of another way to indicate the starting position. Remember, InDesign also needs to "see" the oval to connect to. Just an idea: what if you move the (0,0) ruler point to the position where the caption arrow is to start, then select the oval, and then run a script? (At some point getting to the right initial setup will outweigh the convenience ...)

               

              Anyway, below is a little helper script so you can copy the line parameters for your own custom connectors into my script. Draw a triangle connector as a single path and drag the (0,0) ruler point to where it should connect (make it slightly overlapping) to the oval.

               

              caption.png

               

              Select just this new path and run the following script -- it will put the coordinates of the path in a friendly format on the clipboard. These values should be pasted into the line in the original script right after the line that contains "entirePath:", like this:

               

                  oval.paths.add({entirePath: HERE COMES THE COPIED STRING });

               

              It should start with a '[' and end with an ']'. Then save the adjusted script under a convenient name.

               

               

              if (app.documents.length && app.selection.length == 1 && app.selection[0].hasOwnProperty("paths") && app.selection[0].paths.length == 1)
              {
               sel_path = app.selection[0].paths[0].entirePath;
               hmmu = app.activeDocument.viewPreferences.horizontalMeasurementUnits;
               vmmu = app.activeDocument.viewPreferences.verticalMeasurementUnits;
               app.activeDocument.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.POINTS;
               app.activeDocument.viewPreferences.verticalMeasurementUnits = MeasurementUnits.POINTS;
               result = [];
               for (i=0; i<sel_path.length; i++)
               {
                if (sel_path[i].length == 2)
                {
                 sel_path[i][0] = "x+"+Math.round(sel_path[i][0]);
                 sel_path[i][1] = "y+"+Math.round(sel_path[i][1]);
                 sel_path[i] = "[+"+sel_path[i].join(",")+"]";
                } else
                {
                 for (j=0; j<sel_path[i].length; j++)
                 {
                  sel_path[i][j][0] = "x+"+Math.round(sel_path[i][j][0]);
                  sel_path[i][j][1] = "y+"+Math.round(sel_path[i][j][1]);
                  sel_path[i][j] = "["+sel_path[i][j].join(",")+"]";
                 }
                 sel_path[i] = "["+sel_path[i].join(",")+"]";
                }
                
                result.push (sel_path[i]);
               }
               result = "[ "+result.join(", ")+" ]";
               tempframe = app.activeDocument.textFrames.add({contents:result});
               app.select (tempframe.parentStory.texts[0]);
               app.copy();
               tempframe.remove();
              // reset your original units
               app.activeDocument.viewPreferences.horizontalMeasurementUnits = hmmu;
               app.activeDocument.viewPreferences.verticalMeasurementUnits = vmmu;
              } else
               alert ("Invalid selection or something like that. Please re-do");
              
              1 person found this helpful
              • 4. Re: Drawing a triangle shape thru a script, reading a selection bounds and mouse pointer?
                John Hawkinson Level 5

                Ahh right. Well, scripting doesn't support freely moving the mouse around, but perhaps you can think of another way to indicate the starting position. Remember, InDesign also needs to "see" the oval to connect to. Just an idea: what if you move the (0,0) ruler point to the position where the caption arrow is to start, then select the oval, and then run a script? (At some point getting to the right initial setup will outweigh the convenience ...)

                I think a better UI would be to drag an item out of a Library that consisted of the oval and a single guideline (which would just be a regular InDesign line segment, aka GraphicLine). The guideline would define the endpoints of the arrow, and the script would replace the line with a proper speech indicator oval.

                • 5. Re: Drawing a triangle shape thru a script, reading a selection bounds and mouse pointer?
                  cotcodac Level 1

                  Yes, this is a better idea, in fact, the [0. 0] ruler origin would indicate the top of the arrow, not the starting point. The starting point would be the center of the oval I think... I will try this solution.

                  John I did think of a solution involving other elements, it can work - but takes a bit more clicking then desired. i just tried moving the 0.0 ruler origin while having something selected (it was a long time ago I moved the ruler origin...) and it does it without deselecting my object - which is great...

                  • 6. Re: Drawing a triangle shape thru a script, reading a selection bounds and mouse pointer?
                    Marc Autret Level 4

                    Maybe you could use a simple line to indicate the direction and the place you need to point to.

                    I made Speeech.js to illustrate that approach:

                     

                    http://www.indiscripts.com/post/2012/01/speeech

                     

                    @+

                    Marc

                    • 8. Re: Drawing a triangle shape thru a script, reading a selection bounds and mouse pointer?
                      cotcodac Level 1

                      Mark.. Thank you so much... Works perfectly, well, I saw a 2 glitches I think, but they could be verry well because of my file or something to do withs my objects, because I tried to reproduced them without succes in a new indesign document. Sometimes it draws the arrow bigger than the line, the other is that sometimes the arrow has some corners it shouldnt have - see the yellow part of the image. I didnt try to see if changing a few parametters in the script would help.

                      Corel_1__fd002.jpg

                       

                      Now I have only one problem, ilustrated in this image. When adding arrow on top of an oval... the text will change in an unwanted way... I would manually change the start custom baseline grid, adding in this case x. (I am using align to grid for the text in the ovals - my oval has already a 4mm in that field - helps with the text in my case). Well, I wouldnt calculate the x, I would just increase the value until the text sits just the way it was. Any chance to set this automatically?

                      Corel_1__fd000.jpg

                      • 9. Re: Drawing a triangle shape thru a script, reading a selection bounds and mouse pointer?
                        Marc Autret Level 4

                        Hi cotcodac,

                         

                        About the first issue, I suggest you increase the DEPTH parameter, which is set to 8 by default. Change it to 20, or 30, or even more, to prevent unwanted corners. The right setting depends on the size of your speech balloons. The DEPTH parameter is specified in points. Note that the ATTACH_WIDTH parameter should probably be accordingly adjusted. (It reflects the widening of the arrow.)  Another important setting is PEAK_MIN_DIST, defaulted to 24 pt, which represents the minimal distance from the arrow to the target edge. Reduce that value if you need to allow shorter arrows.

                         

                        About the 2nd issue, I have no clean solution in mind. When you apply Speeech to a text frame, the path of the container changes and this can add space for tiny text to flow within the arrow itself if the inner margin of the frame is very low. If the arrow is set on the top—as in your example—I suppose you could simply add a non-breaking space after the first word. An even better solution would be to apply a non-breaking character style through a GREP style rule such as ^..... (which forces the first five characters of any paragraph to keep together). But this does not solve the problem when the arrow is set on the left or on the right side of the balloon...

                         

                        @+

                        Marc

                        • 10. Re: Drawing a triangle shape thru a script, reading a selection bounds and mouse pointer?
                          cotcodac Level 1

                          I wouldnt want to disagree with you - but most probably I didnt make myself clear... The solution for me is simple - for the second point: If the object resulted is a text frame, then adjust its "start custom baseline grid" by comparing the bounds of the original shape with the new one: if the arrow appears on top, the x of the second object will be diferent than the original‘s, and I would add the difference to the "start custom baseline grid" value. I need to see if its scriptable, and I will try to see if I understand your code enough to be able to apply my desired functionality.

                          Because the text snaps to the baseline of the textframe I can make it stay in the same position even if the arrow will appear on top.

                          Anyway, thanks again for this great solution, I do hope that it will be just as usefull to many others as it is for me.