The correct way to scale Font Size or Line Weight when the shape is resized.

Started by nashwaan, December 20, 2013, 09:00:13 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

nashwaan

Its a very common requirement to scale Font Size of the text whenever the shape is resized.



In many articles (see DMVS 2002, VisGuy, Visio Insights) the solution offered to automatically scale Font Size (and sometimes Line Weight) when a shape is resized is based on the assumption that the user will not need to change the Font Size or Line Weight after the formulas are written.

Usually, the solution is:
LineWeight = 1 pt * Width / 2 in
Char.Size = 12 pt * Width / 2 in
problem: User can mistakenly make changes to Font Size or Line Weight in the GUI and the formulas will be overwritten by single values.

some other solutions suggest:
LineWeight = GUARD(1 pt * Width / 2 in)
Char.Size = GUARD(12 pt * Width / 2 in)
Although, the scale behavior is correct; but the user is handcuffed. No changes allowed in the GUI for Font Size or Line Weight.

A better solution:
LineWeight = SETATREFEXPR(1 pt) * Width / 2 in
Char.Size = SETATREFEXPR(12 pt) * Width / 2 in
Scale behavior is correct. User can make changes in GUI, however, if the change happen when Width / 2 in does not equal to 1, then the User will see different result than desired.

The problem happens because of the 2 in value. It should not be a fixed value. It should be semi-fixed!




The proper solution:

create two User rows:
User.Width_LineWeight = 2 in
User.Width_CharSize = 2 in

Use the following correct formulas:
LineWeight = SETATREFEXPR(1 pt) * Width / SETATREF(User.Width_LineWeight, SETATREFEVAL(Width))
Char.Size = SETATREFEXPR(12 pt) * Width / SETATREF(User.Width_CharSize, SETATREFEVAL(Width))


The trick lies in the time when SETATREF(User.Width_LineWeight, SETATREFEVAL(Width)) get executed.
User.Width_LineWeight will get updated ONLY when the user makes changes to Line Weight in the GUI. Only then, our SETATREF() will set User.Width_LineWeight to Width which means Width / SETATREF(User.Width_LineWeight, SETATREFEVAL(Width)) will equal to 1.
When the user resizes the shape, the whole formula SETATREFEXPR(1 pt) * Width / SETATREF(User.Width_LineWeight, SETATREFEVAL(Width)) will be evaluated WITHOUT setting new Width value to User.Width_LineWeight!

It looks like SETATREF(cell_ref, set_expr) function executes set_expr and pass it to cell_ref when the change initiated from the same cell that this function is part of. In the event the change initiated from other cells, SETATREF(cell_ref, set_expr) will merely fetch the result from cell_ref without setting set_expr to cell_ref.

I am not sure if this is the correct explanation but this is how I find it behaving.

Attached is a working example.

Regards,
Yousuf.
Give me six hours to chop down a tree and I will spend the first four sharpening the axe — Abraham Lincoln

nashwaan

In case the aspect ratio is not locked, i.e. LockAspect = 0

then we would need the following User cells
User.Width_LineWeight = 2 in
User.Height_LineWeight = 1 in
User.Width_CharSize = 2 in
User.Height_CharSize = 1 in

and calculate the average change of Width and Height when the shape is resized.
LineWeight  = SETATREFEXPR(1 pt) * (Width / SETATREF(User.Width_LineWeight, SETATREFEVAL(Width)) + Height / SETATREF(User.Height_LineWeight, SETATREFEVAL(Height))) / 2
Char.Size = SETATREFEXPR(12 pt) * (Width / SETATREF(User.Width_CharSize, SETATREFEVAL(Width)) + Height / SETATREF(User.Height_CharSize, SETATREFEVAL(Height))) / 2

If the auto scaling of text when the drawing scale and/or page size changes is desired (as explained by VisGuy), then we need to add a fifth User row:
User.AntiScale = ThePage!PageScale/ThePage!DrawingScale

then the formulas become even more monstrous:
LineWeight  = SETATREFEXPR(1 pt) * (Width / SETATREF(User.Width_LineWeight, SETATREFEVAL(Width)) + Height / SETATREF(User.Height_LineWeight, SETATREFEVAL(Height))) / 2  *  User.AntiScale
Char.Size = SETATREFEXPR(12 pt) * (Width / SETATREF(User.Width_CharSize, SETATREFEVAL(Width)) + Height / SETATREF(User.Height_CharSize, SETATREFEVAL(Height))) / 2  *  User.AntiScale

The last formulas achieve the following:

  • Scale the Font Size / Line Weight when the user changes the shape's size (our basic requirement)
  • Allow the user to change Font Size / Line Weight correctly to the desired values in Formatting toolbar even when the shape has gone through multiple resize operations
  • Independently allow change of Font Size and Line Weight without one affecting the other
  • Resizing the shape in one direction only, say Width, will scale the Font Size / Line Weight by the average (Width+Height)/2
  • Adjust Font Size / Line Weight when page or drawing scale is changed.

Attached is a working example (you need to login to visguy.com/vgforum to download it).

Note that there are other cells that affects the behavior of Text scale with shape size:
  • Margin cells: LeftMargin, RightMargin, TopMargin, BottomMargin
  • Character cells: Char.Size, Char.Scale, Char.Letterspace, Char.ComplexScriptSize
  • Paragraph cells: Para.IndFirst, Para.IndLeft, Para.IndRight, Para.SpLine, Para.SpBefore, Para.SpAfter, Para.TextPosAfterBullet, Para.BulletFontSize
  • other less obvious cells in: Additional Effect Properties, shadow properties ...etc

Regards,
Yousuf.
Give me six hours to chop down a tree and I will spend the first four sharpening the axe — Abraham Lincoln

vojo

for what its worth...this is how I do it

- Create the shape and text I want
- Go into shapesheet and note the width 
- set lineweight = <nominal value> * width / <noted width in mm>

For example, if a square is 20mm x 20mm then

Lineweight = guard(2pt * width / 20mm)       // obviously could use area approach as well...sqrt(width^2 + height^2) and 400mm

As the shape grows, so does the line...as shape shrinks...so does the line.

I have found with stencil shapes, its fairly rare that somebody messes with the specifics of the shape (otherwise why have a stencil).
Typically its color and any custom properties.

On a rare occasion where I did have to change a shapes specifics....I would use custom props and use 1312 in doubleclk to open
up the custom props page.

lineweight = guard(props.lineweight * width / 20mm)

Obviously, I never figured out the subtitles of setatref stuff...so just found a different, perhaps, less slick way to do it.

Yacine

Yacine

nashwaan

@Yacine: Never scale the line weight of shapes!

Usually you wouldn't need to scale LineWeight with Shape size. However, there are many situations where you might want to do so. See the below examples:


Note: for the arrow in the heart shape, I had to scale "LineWeight", "BeginArrowSize" and "EndArrowSize" cells with the shape size.


For a close comparison of Person shape (from 'Work Flow Objects - 3D' stencil) when resizing a shape without scaling LineWeight (on the left) and with scaling LineWeight (on the right):


Note: these are the same shapes from the first image which are resized at 30% of the original. I had only zoom in at 1000% to show the difference.

Regards,
Yousuf.
Give me six hours to chop down a tree and I will spend the first four sharpening the axe — Abraham Lincoln