Occasionally, in Visio, you want to create a ShapeSheet reference to a cell in a shape that may not exist. For example, you might want one shape to behave differently depending on whether another shape is already on the page, such as a title block or some other container style shape. In my case, I want to be able to set a target shape ID and have the another shape track its position.
(Knowing the ID won't always be ideal, but it works for my debugging scenario, which I'll come onto in the next post.)
Here's a screenshot of five shapes. The connector, whose ID is 5, is the target shape the circles want to track.
I'll break this into two part - first I'll deal with getting a valid reference, and then I'll attack the location tracking part.
Getting a reference
So, starting with the green circle shape - This technique starts off by the user setting the ID of the target shape via Shape Data (Prop.TargetId
). I've set this to 5, which, as I mentioned, is the ID of the connector shape. The Shape Data cell is referenced in User.CandidateNameID
cell. This in turn is referenced by the User.TargetTrigger
cell, so that when the value in User.CandidateId
changes the SETF
(Set Formula) function is fired.
SETF
pushes a formula to a given cell - User.CandiateId
and the formula that I'm pushing in is the string name Sheet.5 concatenated with the ID
function.
The way that SETF
works is that if the formula that you're pushing is syntactically correct then the formula will appear in the chosen cell as expected, but, if the formula is not correct then it will fail silently.
This means that if it is successful then you can expect the ID of the target shape to be equal to the ID that was set in Shape Data and if not then the opposite will be true.
The final part therefore is the User.IDsMatch
cell that carries out this check and allows you, in other formulas, to know whether you have a correct reference to the target shape.
Note, if you're wondering why
User.CandidateId
reads as "Dynamic Connector!ID()" and not "Sheet.5!ID()" it's because Visio automatically translates references into their local name format.
Getting to the point
Let's move on to the second part of the challenge, which is to actually track a location in the target shape. For this, I'm going to focus on the orange circle.
Now that you have a method for knowing if the referenced shape is correct, you can add additional cells that you want to target by extending the trigger cell formula:
The image is too narrow so I'll expand the formula for User.TargetTrigger
:
You can see that you've got the same starting SETF
in line 1, but now there's an additional one at line 4. The job of this second SETF
is to push a POINTALONGPATH
function into User.TargetPnt
and, because that function returns a point in the local coordinate space of the connector, it is wrapped in a LOCTOLOC
function to convert it back to page coords.
The result is that User.TargetPnt
ends up with the actual point formula:
Finally you can use User.TargetPnt
from the circle's PinX
/ PinY
cells to move it to the correct position.
This allows you to either track the target postion or, manually position the shape when you don't have a 'lock' on your target. A couple of notes about this formula:
-
although I'm passing a
point
, Visio is able to extract the correct X/Y component when in an X/Y cell (Shape Transform, Geometry, Connections, Scratch XY etc). -
SETATREFEXPR
is a function that allows incoming values from gestures in the UI to be consumed without changing the formula.
Not for everywhere
It's worth saying that I'm not advocating this technique for regular use, but for the utility/debug shape I have in mind, and for this, I think it works reasonably well.