Jump to content

Copyfit multiple frames with the same factor


Recommended Posts

Good Afternoon,


I'm posting a fresh thread that evolved out of my previous thread entitled,

"Copyfit with connected frames work, but vertical alignment is off"


I understand the logic of how copyfit could be customized to force multiple frames to copyfit using the same scaling factor, however, I'm at a loss as to how to code this.


The logic is entered below. Could anyone provide sample code to get me started?


In this scenario, my template has many frames, and 3 of them are labeled

Frame1, Frame2, and Frame3. Any combination of these may appear (via page usage settings).


These named frames, when present, need to have their copyfit based on copyfitting the frame with the largest text width.





Factor = 0



If Frame1's text width exists


Factor = Frame1 text width;



If Frame2's text width exists



If Frame2's text wdith > Factor

Factor = Frame2's text width;



If Frame3's text width exists


If Frame3's text width > Factor

Factor = Frame3's text width;




If the current Frame is Frame1, Frame2, or Frame3

copyfit using Factor



Copyfit using the regular method



Sample Project.zip

Link to comment
Share on other sites

Okay, I've decided to take up the challenge here on a Friday afternoon. Attached is a modified version of the template which Parrish uploaded in the original post. I think this solves the stated problem. Basically, as I suggested in the other thread, it uses the FusionProTextMeasure object to determine what magnification factor each frame needs, and then applies the smaller of those two factors to the text in both frames.


A few caveats about this solution:


  1. This takes advantage of some of the new features in FusionPro 6.0, so you'll need that version or later.
  2. Since this uses the FusionProTextMeasure object, it only works in simple rectangular single-frame text flows with no other frames to wrap text around. It doesn't have the ability that full-flow Copyfitting does to take into account things like multi-frame flows and text wrapping.
  3. The Text Measurement logic relies on the text returned by the rules specifying the initial font and point size, rather than that being set in the Text Editor. (Although theoretically a solution which takes the GUI settings into account should be possible by using the FusionProTextFrame.content property, but that's an exercise for another day.)
  4. I've removed all the <f> tags which reference variations of the "Berthold" font and just left everything in Arial, so that I (and anyone else who doesn't have those non-standard fonts installed) can see this working. (Parrish, you can feel free to put those calls to fonts you're using back in; I just couldn't test with fonts I don't have.)
  5. It's not exactly fast. Composition isn't too bad, but rule validation takes a while. The MagnifyFactorForFrame function just uses a simple linear algorithm to find the closest integral (whole number) magnification factor; as the comment in the function notes, this could be greatly optimized by using a binary search algorithm instead. But that's also an exercise for a different day.

If you try this, you can turn on Preview, and you should see that as you change records or resize either of the two frames, the text in both will be adjusted proportionately, and the vertical alignment will still be honored in both. This solution should be scalable to three or more frames as well.


You'll want to download the attached template (and the input file from Parrish's original post) to see this in action, but what makes it go is some JavaScript logic, both in the JavaScript Globals and in OnRecordStart, which I'll include here.


Here's what's in the JavaScript Globals:

function GetSettableTextHeight(frame)
 if ((!frame instanceof FusionProFrame) || (typeof frame.columns == "undefined"))
   ThrowError("GetSettableTextWidth", "The parameter is not a valid FusionProTextFrame.");

 return frame.height - (frame.borderThickness * 2) - (frame.textInsetY * 2);
FusionProFrame.GetSettableTextHeight = function()
 return GetSettableTextHeight(this);

function MagnifyText(text, factor, isTagged, type)
 if (!isTagged)
   text = TaggedTextFromRaw(text);
 return "<magnify type=" + (type || "text") +
        " factor=" + factor + ">" + text + "</magnify>";

function MagnifyFactorForFrame(name, text, isTagged, type)
 var frame = FindTextFrame(name);
 var width = frame.GetSettableTextWidth();
 var height = frame.GetSettableTextHeight(); //frame.height;

 var tm = new FusionProTextMeasure;
 tm.maxWidth = width;

 // TODO: optimize to binary sort instead of linear
 for (var factor = 100; factor > 0; factor--)
   tm.CalculateTextExtent(MagnifyText(text, factor, isTagged, type));
   if (tm.messages)
     ThrowError("MagnifyFactorForFrame", tm.messages);

   if (tm.textHeight < height)
     return factor;

 return 0;

The FusionProFrame.GetSettableTextHeight function is very similar to the FusionProFrame.GetSettableTextWidth function in Builtins.js (not surprising since I wrote both). It takes any border and text inset on the frame into account.


The logic in MagnifyFactorForFrame is similar to CopyfitLine, but instead of trying to make a single line of text fit within a particular amount of horizontal space, it tries to make the multiple lines fit within a specific amount of both horizontal and vertical space.


And here's what's in OnRecordStart:

var text1 = Rule("Location1RULE");
var text2 = Rule("Location2RULE")

var factor1 = MagnifyFactorForFrame("Location1", text1, true);
var factor2 = MagnifyFactorForFrame("Location2", text2, true);

var factor = Math.min(factor1, factor2);
var newtext1 = MagnifyText(text1, factor, true);
var newtext2 = MagnifyText(text2, factor, true);

FusionPro.Composition.AddVariable("Location1New", newtext1, true);
FusionPro.Composition.AddVariable("Location2New", newtext2, true);

This is basically the implementation of the algorithm in Parrish's pseudocode. I'm using FusionPro.Composition.AddVariable function to "inject" the results into new variables which can ultimately be accessed in the text frames.


As I said earlier, I've modified the rules "Location1RULE" and "Location2RULE" to specify the point size and font (specifically Arial, since it's a standard font). And, of course, I've disconnected the two frames, named them, turned off full-flow Copyfitting, and changed their contents to reference the new variables being set up in OnRecordStart. (Again, this could be reworked to directly modify the text contents in the frame, but this is what I've got for now.) Enjoy!


Link to comment
Share on other sites


This topic is now archived and is closed to further replies.

  • Create New...