Snap Shapes to Predefined Locations

Started by jthawken, June 03, 2020, 03:20:42 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

jthawken

Forgive me if this has been asked before, but I cannot find a solution.

A group at my work is needing to create some screenshots of a proprietary UI without actually taking a screenshot. I need to create a template such that a user can drag and drop shapes onto the document, and the shapes will automatically snap to a predetermined location. Imagine a sort of "on-screen puzzle" where each piece can only fit in one location. However, not each piece is needed for each screenshot.

While certain graphical elements need to be common throughout most of the screens, dragging and dropping elements is more what I'm looking for than having a master template with everything on it from which the user must then delete what they don't need.

Any ideas on how to accomplish this? I am quite well versed in VBA (for Excel) so I believe that will probably be the solution.

Also, if Visio isn't the best program for this and you have other suggestions, I am open to exploring other software solutions as well.

Thank you!

Yacine

#1
This is an interesting project indeed.

Have shapes that jump on drop to a certain position and return on request to it.
First you would need fields to store this position - independently from the actual position of the shape. --> user.x and user.y
The initial jump to the position can be done by overwriting pinx and piny in the dropevent cell (by using setf/getref).
And the later repositioning can be triggered by action menus (also by means of setf/getref).

Almost there ...
Now you don't want to enter the target coordinates manually in the user cells. --> an action menu can copy the values of pinx and piny to the according user cells.

And last but not least:
You won't want to modify the shapesheet of each shape requiring this behaviour. --> a small routine sets them up:

Sub setup_puzzle()

    Dim shp As Shape
    Dim row_ As row
   
    For Each shp In ActiveWindow.Selection
        With shp
            If Not .SectionExists(visSectionUser, visExistsAnywhere) Then .AddSection visSectionUser
            If Not .SectionExists(visSectionAction, visExistsAnywhere) Then .AddSection visSectionAction
            If Not .CellExists("user.x", visExistsAnywhere) Then .AddNamedRow visSectionUser, "x", visTagDefault
            If Not .CellExists("user.y", visExistsAnywhere) Then .AddNamedRow visSectionUser, "y", visTagDefault
           
            .AddRow visSectionAction, 1, visTagDefault
            .CellsSRC(visSectionAction, 0, visActionAction).FormulaU = "=SETF(GetRef(User.x),PinX)+SETF(GetRef(User.y),PinY)"
            .CellsSRC(visSectionAction, 0, visActionMenu).FormulaU = Chr(34) & "Save position" & Chr(34)
           
            .AddRow visSectionAction, 2, visTagDefault
            .CellsSRC(visSectionAction, 1, visActionAction).FormulaU = "=SETF(GetRef(PinX),User.x)+SETF(GetRef(PinY),User.y)"
            .CellsSRC(visSectionAction, 1, visActionMenu).FormulaU = Chr(34) & "Restore position" & Chr(34)
           
            .CellsSRC(visSectionObject, visRowEvent, visEvtCellDrop).FormulaU = "=SETF(GetRef(PinX),User.x)+SETF(GetRef(PinY),User.y)"
           
        End With
    Next shp
End Sub


Check the attached stencil and have fun. It contains the macro and some shapes which will jump to a predefined position to compose a bigger rectangle.


HTH and thank you for the challenge,
Y.
Yacine

Nikolay

#2
I think the easiest solution to that would be to write code (i.e. you write some macro, add-in, program, whatever).

There is no "stock" feature for this as far as I know, so you may need to go "creative"  ::)
So if you don't want any code or macros,

Visio has a feature called "background", when you drop a background shape, it's auto-placed (with a built-in add-in, i.e. also with code).
Maybe you can think in this direction, like making Visio "think" your shape is actually a background shape (they have special markup) and thus make it auto-place it at specific point.
If your shape has offset (LocalPinX/LocalPinY), with that you could have a fixed positioning wihtout code.

Another idea - you can set up a list container (maybe an invisible one?) on your page :D
When a shape is dropped to a list container, the container auto-adjusts the position of the dropped shape to container's top-left (see the attachment)
The attached is a basic example, simply defining the list. You may think about cutting the area, borders, etc.
About containers: https://surrogate-tm.github.io/visio/2010/01/12/custom-containers-lists-and-callouts-in-visio-2010.htm

Usually I think tasks like this are done with some report builder tools though (you can probably look up that in google using "image placeholder" keywords)
A simple example of that could be just a Word document with a field(s). Here is an example: https://www.youtube.com/watch?v=Up5z1mRsOqE
Or just use the Powerpoint, it has it right out of the box :)

jthawken

Thank you so much Yacine and Nickolay, you guys have given me a few different places to start to solve this problem! I greatly appreciate it and will report back once I nail down a solution!

Yacine

Quote from: jthawken on June 04, 2020, 01:22:28 PM
... will report back once I nail down a solution!

I thought I nailed down the solution. Download and test the stencil I attached to my first post.
Yacine

vojo

so why doesn't this work?

eventondrop = setf(getref(pinx), 200mm) + setf(getref(piny), 300mm)

or

eventondrop = docmd(1312)
<launches shape data GUI...set a xval, yval>
user.setlocal = setf(getref(pinx), props.xval) + setf(getref(piny), props.yval)

Yacine

Quote from: vojo on June 07, 2020, 04:01:34 AM
so why doesn't this work?

eventondrop = setf(getref(pinx), 200mm) + setf(getref(piny), 300mm)

I used
.CellsSRC(visSectionObject, visRowEvent, visEvtCellDrop).FormulaU = "=SETF(GetRef(PinX),User.x)+SETF(GetRef(PinY),User.y)"
on the selected shape and it worked just fine. ???
Yacine