In the previous post we examined how the SetAtRef function could be used to keep two Shapesheet cells synchronized. Today we will explore a few advanced capabilities of SetAtRef for manipulating cell values.
Our scenario is a shape with a custom property called Size. We would like this property to control the Width of the shape. Also changes to the Width should update the Size property. A text field displays the current value of the Size property as well.
Notice that the cell values for Width and Prop.Size are not the same. Our previous solution using SetAtRef to synchronize the cells will not work. One unit of Size should correspond with 0.25 inches of Width. What we need is a way to convert between Size and Width as we are synchronizing the cells.
A first attempt might look like this:
We adjust the Width formula to take the Size value and convert it to a width. This works properly whenever the Size changes, but any change to the Width will push the wrong value back to Size. We need to take the incoming Width value and perform a conversion on it before that value is pushed to the Prop.Size cell.
Fortunately, the SetAtRef function supports this capability. You can provide an optional second argument to the function that tells Visio how to transform the incoming value. Our goal is to take the incoming Width value and divide it by the proper conversion factor to calculate the Size. To specify this as an expression in the SetAtRef function, we need a way of referencing the incoming cell value. Visio provides the SetAtRefExpr function for this purpose. SetAtRefExpr starts with no function arguments. Then Visio places the incoming cell value into the function. Like SetAtRef, for recalc SetAtRefExpr evaluates to its function argument: SetAtRefExpr(x) = x.
This almost solves the problem. However, if you look below at the resulting value put in the Prop.Size cell, you can see that Visio is putting the literal expression in the cell rather than the calculated result of the expression. The formula in Prop.Size does evaluate to 4, but we would prefer to have just the final result.
There is another function available to force Visio to evaluate the SetAtRef expression before a value is put in the cell. SetAtRefEval can be used on the entire second argument in SetAtRef or on one or more portions of the expression.
This completely solves our problem. The shape now is able to keep the Width and Size properties synchronized while converting between the two. Our final formula for the Width cell is:
SETATREF(Prop.Size,SETATREFEVAL(SETATREFEXPR(1.25 in)/0.25 in))*0.25 in
Here is a verbose description of this formula. When the Width of the shape changes, do not overwrite the contents of this cell. Place the new Width value into the SetAtRefExpr function argument. Then take the new value and divide it by 0.25 inches. Evaluate that result and place the it in the Prop.Size cell. Then recalculate the Width cell. For recalculation take the current value of Prop.Size and multiply it by 0.25 inches. This is the final value of the Width cell.
As you can see SetAtRef and its related functions allow fairly sophisticated manipulations of cell contents. The result for the user is simply intelligent shape behavior. Next time we’ll look at a few more ways that SetAtRef can be used.
Shape control handles offer users convenient ways to take advantage of the intelligence built into the shape by a designer. Perhaps the most common use for a control handle is to link it to the text on a shape. While Visio provides the Text Block Tool for manipulating shape text, this tool is not very discoverable (it’s underneath the Text tool in the Standard toolbar) and is cumbersome. A control handle is a very convenient alternative. In fact, Visio 2003 has a text control handle built into the default dynamic connector.
The dynamic connector incorporates a couple of behaviors that you may find helpful in the design of your own shapes:
· The control handle is not shown unless there is actual text in the shape
· The user can use either the control handle or the text block to reposition the text
Let’s look at the Shapesheet for a dynamic connector to see how these behaviors are implemented.
The visibility of the control handle is determined by the X Behavior cell. This cell describes how the control handle should resize with the shape, whether it can be moved at all and whether the control handle is visible. An IF statement sets the behavior to 5 to hide the handle or 0 to show it. The conditional statement verifies that the shape has no text or that it is currently not visible. Note the use of the STRSAME function to check for text. This is the recommended practice.
The synchronization of the control handle and text block is accomplished using the SETATREF function. This is a very powerful and complicated function that needs some introduction. We’ll look at the basic capability as it is used in the text control handle here, but there is quite a bit more to cover in a future post.
Consider a typical formula dependency where cell A depends on cell B. As long as the user modifies cell B, then A and B will both be up to date. What happens if the user modifies cell A? This change would blast the formula in cell A, decoupling it from cell B. You could GUARD the formula in cell A to preserve the dependency on cell B, but now the user cannot manipulate cell A at all. SETATREF solves this problem by preserving dependencies and forwarding inputs to the independent cell. SETATREF allows cell A to depend on cell B while also allowing the user to change either A or B.
In the case of the text control handle, the position of the text block is dependent on the position of the control handle. Thus the TxtPinX and TxtPinY cells have formulas with references to Controls.TextPosition and Controls.TextPosition.Y respectively. These references are then wrapped by a SETATREF formula. To understand how SETATREF works, we need to separate what happens during recalculation versus what happens during cell input.
Because TxtPinX and TxtPinY have formulas with references to the control handle position, these cells must be recalculated whenever the control handle position changes. During the recalc operation, the SETATREF function is transparent. SETATREF(x) = x. In other words, the result of the recalc is just like if there were no SETATREF wrapped around the cell references. On the other hand, when the user directly manipulates the TxtPinX or TxtPinY cells (by using the Text Block Tool), SETATREF influences how the new value updates the Shapesheet. Rather than letting the new cell value replace the SETATREF formula, Visio forwards the value to the cell referenced in the SETATREF function. Thus any change to the TxtPinX or TxtPinY cell is actually made to the Controls.TextPosition or Control.TextPosition.Y cell instead. Then the TxtPinX and TxtPinY cells pick up the change through recalculation.
This ability to preserve dependencies and forward input values is extremely versatile for shape development. We’ll look at some more sophisticated uses for SETATREF in a future post.
There are several housekeeping items in today's post.
Chris Roth, a Visio MVP, has begun a new Visio blog: http://www.wanderkind.com/visio/
Check out articles on creating flowcharts from code and hiding parts of shapes.
Recruiting Visio & CAD users
Do you use Visio to view, draw on top of, convert or export CAD drawings? We'd like to hear from you as we plan the next release of Visio. If you are willing to tell us about the way you use Visio with CAD or have some thoughts about what's good or bad about Visio's functionality, please contact us.
Suggest a blog topic
Is there something you would like to see covered by this blog? Send us a suggestion for a topic. We try to hit the most frequently asked questions from the newsgroups. Please let us know what is important to you.
Visio makes it easy for users to place shapes anywhere and provides connectors for maintaining connections between shapes. However, as diagrams get more complicated, users often look to Visio for help organizing shape placement and connector routing on the page. Unfortunately, while Visio's automatic layout functionality is quite powerful, many times the results are not good enough without tweaking the layout settings. In this post we'll look at one such scenario and try making a few changes to improve the final results.
Here is a custom shape with several connection points on each side. Connectors are intended to glue to these points on the shape.
A diagram is created using this shape and connectors are added.
We now would like Visio to rearrange the shapes and reroute the connectors to create a cleaner, more readable diagram. Choosing Shape > Re-layout Shapes gives this result:
This result is not ideal. There are still overlapping connectors and too many bends. Visio is actually constrained by the way the connectors were glued to the shapes. The traditional way to glue connectors is to drag the end of the line to a connection point on the shape. This creates what is known as static glue in Visio. The connector remains associated with that connection point. Static glue has drawbacks for layout because it prevents Visio from routing to the nearest side of the shape. An alternative is using dynamic glue. To glue using dynamic glue, drag the end of the line to the center of the shape. A red outline rectangle will appear to indicate dynamic glue. The resulting red glue square has a slightly different look as well.
By switching all the connections over to dynamic glue, Visio can choose more efficient routes for the connectors. However, now Visio routes to locations on the shapes that we do not want. Our custom shape is not supposed to allow connections on the top or bottom.
There is a Shapesheet cell that allows us to set some restrictions on dynamic glue so that Visio will not choose any arbitrary location to connect. The Shape Layout section has a cell named ShapeFixedCode that determines how connections can be made to a shape. By setting ShapeFixedCode to 64 on the custom shape we can force Visio to connect at connection points.
Now the automatic layout keeps the connectors glued to the connection points. Note that the glue style is still dynamic glue. Visio is free to choose which connection point is used for each connection. The result is better but still not ideal. There are still too many bends in the connectors as Visio must work in and around the shapes.
One final change can clean this layout up. Each drawing page has a default layout spacing, but the shapes you use in the drawing may not be suitable for that default. In this example, the default drawing spacing is 0.375 in. while the custom shape size is 1.25 in. x 1 in. That pushes the shapes too close together. By increasing the spacing between shapes, Visio can find better routes for the connectors. This is done in the Shape > Configure Layout dialog.
The end result is a much simpler arrangement with clean connector routes.
Dynamic glue adds flexibility to Visio's layout and routing optimizations and will result in a better looking diagram. The tradeoff is the inability to specify particular connection points for connectors. Visio assumes all connection points are equally valid. Hopefully the techniques presented in this post help you get better layout results. It is unfortunate that Visio's automatic layout needs this much tweaking to get good results, but it is challenging for a layout engine to produce optimal results across a huge variety of drawing types. As always, tell us your pain points, and we will try to address them in the future.
Here’s a recent question on the newsgroups that has come up several times in the past. It seems that the larger you make a page in Visio, the less you can zoom in to see the details. This is true. There is a maximum zoom limit in Visio, and this maximum depends on the size of your page.
The limitation on zoom is tied to the way Visio uses Windows’ GDI display component to render pages. A Visio page is one big surface that is clipped to fit in the drawing window. This allows capabilities such as smooth panning / scrolling and rapid zoom changes because the rendered image does not need to be constantly reconstructed. In Windows 9x systems this display surface was limited to a maximum size of 32767 x 32767 pixels - basically a 16-bit system limitation.
To calculate the maximum zoom level, Visio uses this basic formula:
Max Zoom = (32767 / (Page size in inches * Screen pixels per inch)) * 100%
Max Zoom = (32767 / (Page size in inches * Screen pixels per inch)) * 100%
Take an example drawing with the largest page dimension equal to 34 inches and a standard monitor pixel density of 96 DPI. This formula evaluates to 1004%. If the page size increases, the maximum zoom decreases proportionally.
More recent versions of Windows support larger ranges in GDI. Starting with the latest service pack of Visio 2003, we have updated our zoom logic to take advantage of this headroom. At a minimum, you can zoom into your drawing at 1000% regardless of page size. The formula above is still used to determine the maximum zoom. Thus the zoom limit is the larger of the formula result or 1000%.
Hopefully this addresses most of the situations where zooming was restricted with large pages.
Visio 2003 introduced a new Reviewer & Markup feature that allows users to add comments to diagrams. A typical question we are asked is “How do I print the comments?” This capability was not included in the markup feature, but our Product Support team has published a solution in a Knowledge Base article:
The solution is a VBA macro that you can add to your document to programmatically collect the comment information and put it into a new shape in the diagram. Please follow the link for detailed instructions and the code. The shape is placed off the page at first. You can resize the shape, format the text to your liking and then move the shape into the printed page region.
The code operates on the current page and also any reviewer pages that may overlay it. Comments are found in the Annotation section of the page’s ShapeSheet.
This “comment report” is one way of addressing the need for printing comments. If you use comments in your diagrams, please tell us how you surface them or how you would like to see Visio display and print them.
There have been several recent newsgroup questions relating to dragging shapes around on the page. Sometimes you get to see the geometry you are dragging around. Other times you only see an outline rectangle. A similar issue is that dragging is quite choppy such that you often don't see what you drag. Both issues deal with performance in Visio. Let's look at each one.
Drag image generation
When you drag a shape around, Visio generates a drag image to display. This is basically a bitmap representation of your shape. Seeing the actual geometry of your shape helps with positioning and alignment. If you select a bunch of shapes to drag around, the drag image that Visio must generate is more complex. This takes more time, which then makes Visio feel sluggish.
To avoid this situation, Visio has a cut-off point of 25 shapes. This 25 shape limit includes any sub-shapes of groups in the selection. If you drag around more than 25 shapes at a time, Visio will only show an outline rectangle for the drag image. You can still pause while dragging, and Visio will go ahead and generate the full image.
An interesting side effect of this threshold is that it causes 2-D glue operations to fail as well. (2-D glue means gluing a 2-D shape to another 2-D shape, while 1-D glue is the normal connector to 2-D shape operation.) 2-D glue only works when the drag image is shown. Even pausing to generate the drag image does not work around the problem. Shapes that have outward connection points on them thus need to be kept simple.
For those that would like to eliminate this threshold entirely, there is a registry key. For Visio 2003 set ‘HKCU\Software\Microsoft\Office\11.0\Visio\Application\DragBitmap’ to “2”. For Visio 2007 set ‘HKCU\Software\Microsoft\Office\12.0\Visio\Application\DragBitmap’ to “2”. The downside is that you will encounter degraded performance as you begin to drag more complex shapes around. This may or may not be noticeable on your computer.
Once you begin dragging and the drag image has been generated, a second issue affects whether you can drag it around smoothly. Visio must update the rendered drawing as you drag this image across it. This involves creating a mask out of the drag image and then doing XOR operations against pixels as things move around. Depending on how complicated the drawing page is behind the drag image, this process can take some time. The longer it takes to re-render, the choppier the drag behavior appears to be in Visio. With some really complicated drawings like inserted CAD objects, it may take more than a second for any update to occur.
Dragging performance really depends on the computer's video card, but many users have reported that dragging is actually slower on their new computers versus their older computers. How can performance be worse on a faster video card? It turns out that Visio's masking code is really old. The code makes specific calls to the video card that are no longer in use today. The cards now support much more efficient ways of doing things. In fact, video card manufacturers likely no longer optimize the legacy calls. Since Visio still does things the old-fashioned way, performance goes down on the newer cards.
There is nothing a user can do to address this second problem. The good news is that Visio 2007 has replaced it's old masking code with newer, mainstream calls to the video cards. The results are dramatic. We measured drag performance to be 150 times faster in Visio 2007! This results in very smooth dragging for even the most complex Visio diagrams.
Keep in mind that both of the two drag issues here impact what you see on the screen. One is a hard-coded limit based on shape count. The other is dependent on the performance of the video card (when used with legacy calls). If the first issue is annoying, you can use the registry fix. If the second issue is frustrating, you will need to wait for Visio 2007.
In an earlier post we talked about Visio being a general purpose diagramming and drawing application that enabled specialized behavior through its extensibility model. Custom shapes are combined with custom code to create an intelligent diagramming solution for a particular scenario. Sometimes users like to take this extensibility notion even further by creating their own shapes to work with the solution. We inevitably are asked how these new shapes can “join the club” or participate in the specialized behavior.
Unfortunately there is no single mechanism for registering a shape with a solution or converting a shape to work with a solution. Some Visio solutions provide this capability. Others do not, forcing the user to discover the secret handshake with the solution. We’ll look at a specific example in this post.
The Legend feature can be found in Visio’s Brainstorming template, or the Legend Shapes stencil can be opened from File > Shapes > Brainstorming. Special legend shapes are added to the diagram, and the Legend shape displays them with counts and labels.
Now imagine that you need a new shape to easily identify issues to be resolved. Here is a simple shape created with the Freeform tool. The initial alignment box for the shape is not ideal, but that can be fixed using Shape > Operations > Combine to fit the geometry into a nice upright rectangle.
It would be helpful to tally the issues in the diagram and have the total displayed in the legend as well. To do this, open the Document Stencil for the diagram by going to File > Shapes > Show Document Stencil. Then drag the issue shape over to the stencil. You should rename the shape from Master.11 (or similar) to Issue. You could also clean up the icon if desired.
Next we need to make the shape work with the legend. Drag the shape from the Document Stencil and drop it on the legend shape in the drawing. The following message will appear.
Choose Yes and then delete the shape sitting on top of the legend. Now drag out Issue shapes from the Document Stencil to annotate the drawing. The legend should reflect the total number of Issue shapes present.