Placing Shapes in a Drawing
Determining where to place shapes can be one of the more challenging tasks for a program that creates Microsoft® Visio® drawings, especially in connected diagrams or other kinds of drawings with complex relationships between shapes. The ultimate goal is the same: You'll need to calculate a pair of page coordinates for each shape you place on the drawing page. The approach you take will depend on the kind of drawing you're trying to create and the data on which the drawing is based.
In addition, Visio provides automatic layout capabilities that control how the shapes and connectors between shapes in your drawing interact. You can view the default layout settings in the Page Layout and Shape Layout sections in a ShapeSheet® window. You can customize these settings in your program by working with the formulas in these sections. For details about shapes and automatic layout, see Designing Shapes for Automatic Layout in Chapter 11, Arranging Shapes in Drawings. For details about the Page Layout and Shape Layout sections, see the Microsoft Visio Developer Reference (on the Help menu, click Developer Reference).
In this section…
Placing Shapes Using Automation: an Example
Placing Shapes in Relation to Other Shapes
Placing Shapes Using Automation: an Example
The following CreateDrawing procedure provides an example of placing shapes in a simple network diagram. The example reads data from a two-dimensional array—the first element in the array describes the name of a master in the Basic Network Shapes 3D stencil, and the second element of the array is a shape label. CreateDrawing places a hub in the middle of the page, and then places the components in a circle around the hub.
This example demonstrates several techniques for placing shapes, including the following:
- To place the hub in the middle of the page, the program uses the values in the PageHeight and PageWidth cells of the page sheet.
- To place shapes evenly around the hub, the variable dblDegreeInc was calculated based on the number of elements in the array. This variable was then used to identify the x- and y-coordinates for dropping the shape.
Public Sub CreateDrawing(arrNetData As String) Dim shpObjHUB As Visio.Shape Dim shpObjNodes As Visio.Shape Dim mstObj As Visio.Master Dim stnObj As Visio.Document Dim dblX, dblY As Double Dim dblDegreeInc As Double Dim dblRad As Double Dim dblPageWidth, dblPageHeight As Double Dim i As Integer Const PI = 3.1415 Const CircleRadius = 2 'Divide the circle by the number of objects in the array so they are spaced evenly dblDegreeInc = 360 / UBound(arrNetData) 'Read the PageWidth and PageHeight properties dblPageWidth = ActivePage.PageSheet.Cells("PageWidth").ResultIU dblPageHeight = ActivePage.PageSheet.Cells("PageHeight").ResultIU 'Open the Basic Network Shapes 3D stencil Set stnObj = Application.Documents.OpenEx("Basic Network Shapes 3D.vss", visOpenDocked) 'Process the hub shape Set mstObj = stnObj.Masters(arrNetData(0, 0)) Set shpObjHUB = ActivePage.Drop(mstObj, dblPageWidth / 2, dblPageHeight / 2) 'Set the text of the hub shape shpObjHUB.Text = arrNetData(0, 1) 'Process the nodes For i = 1 To UBound(arrNetData) Set mstObj = stnObj.Masters(arrNetData(i, 0)) 'Determine X, Y location for placement (in circle around hub) dblRad = (dblDegreeInc * i) * PI / 180 dblX = CircleRadius * Cos(dblRad) + (dblPageWidth / 2) dblY = CircleRadius * Sin(dblRad) + (dblPageHeight / 2) 'Add shape to drawing in proper location Set shpobj = ActivePage.Drop(mstObj, dblX, dblY) 'Set shape text shpobj.Text = arrNetData(i, 1) Next End Sub
Notice the use of page sheet properties to get information about positioning on the page. Shapes are spaced evenly around the hub by using the dblDegreeInc variable to calculate the x- and y-coordinates based on the number of elements in the array.
Note To calculate page coordinates that are visible in the drawing window, use the GetViewRect method of a Window object. You can use these coordinates to place shapes in the middle of a window. For details, see the GetViewRect method in the Microsoft Visio Developer Reference (on the Help menu, click Developer Reference).
Placing Shapes in Relation to Other Shapes
If you want to find shapes based on whether they are located on or near other shapes, or modify a shape's behavior relative to another shape, you can use these properties: SpatialRelation, SpatialNeighbors, SpatialSearch, DistanceFrom, DistanceFromPoint, and HitTest.
You can use these properties to create shapes that change their settings based on the other shapes they are dropped on or near. For example, in an office layout solution, you could create smart furniture shapes such as a cabinet shape that attaches itself to a wall when dropped next to it, and takes on the style of a cabinet that is located nearby. Or, you can prevent a user from placing a shape near or on certain other shapes, such as not allowing a user to drop a fire extinguisher near any type of heat source in a building layout.
Properties or methods that determine spatial relationships between shapes
Property or method |
Description |
SpatialRelation property |
Returns an integer that represents the spatial relationship of one shape to another shape. Both shapes must be on the same page or in the same master. Use this property to determine whether one shape contains, is contained by, overlaps, or touches another shape. |
SpatialNeighbors property |
Returns a Selection object that represents the shapes that meet certain criteria in relation to a specified shape. Use this property to find a set of shapes that contain, are contained by, overlap, or touch a specific shape. |
SpatialSearch property |
Returns a Selection object whose shapes meet certain relationship criteria in relation to a point that is expressed in the coordinate space of a page, master, or group. Use this property to find a set of shapes that contain, are contained by, overlap, or touch a specific coordinate space. |
DistanceFrom property |
Returns the distance from one shape to another. Both shapes must be on the same page or in the same master. Use this property to determine if one shape is within a required distance of another shape. |
DistanceFromPoint property |
Returns the distance from a shape to a point. Use this property to determine if a coordinate on a shape is within a required distance of a point. |
HitTest property |
Determines if a given x,y position hits outside, inside, or on the boundary of a shape. Use this property to check one shape against criteria for a limited set of other shapes. |
Using the SpatialRelation property: an example
The SpatialRelation property of a Shape object returns the relationship between the calling shape and another shape (passed as an argument with the property).
The Microsoft® Visual Basic® for Applications (VBA) code in the following example assumes the user can drop any shape from the document stencil onto a page with existing shapes. The text of each shape on the page changes to display the relationship between the dropped shape and each shape in the drawing.
Private Sub Document_ShapeAdded(ByVal Shape As IVShape) Dim ShapeOnPage As Shape Dim dblTolerance As Integer Dim iSpatialRelation As VisSpatialRelationCodes Dim strSpatialRelation As String
On Error GoTo errHandler
'Try setting different tolerance values dblTolerance = 0.25
For Each ShapeOnPage In ActivePage.Shapes If Shape = ShapeOnPage Then 'The shape being tested is the shape that was added 'Display the shape name Shape.Text = Shape.Name ElseIf ShapeOnPage.Name <> "Abstract" Then 'Get the relation between the added shape, and the 'iterated shape on the page iSpatialRelation = Shape.SpatialRelation(ShapeOnPage, _ dblTolerance, 0) 'Convert return code to text Select Case iSpatialRelation Case VisSpatialRelationCodes.visSpatialContain strSpatialRelation = "Contains" Case VisSpatialRelationCodes.visSpatialContainedIn strSpatialRelation = "is Contained in" Case VisSpatialRelationCodes.visSpatialOverlap strSpatialRelation = "overlaps" Case VisSpatialRelationCodes.visSpatialTouching strSpatialRelation = "is touching" Case Else strSpatialRelation = "has no relation with" End Select 'Put relation on shape ShapeOnPage.Text = Shape.Name & " " & strSpatialRelation & _ " " & ShapeOnPage.Name End If Next errHandler:
End Sub
Using the SpatialNeighbors property: an example
You can use the SpatialNeighbors property of a Shape object in your program to determine the relationship between the shape of interest and the rest of the shapes on the page. The property returns the set of shapes (as a Selection object) that meet the criteria set by the arguments passed with the property. For details about using the Selection object, see Working with Selected Shapes later in this chapter.
The VBA code in this example assumes the user will drop a shape within the boundaries of a square, circle, or both, already provided on the drawing page. The text of the dropped shape displays the results of the property being called.
Private Sub Document_ShapeAdded(ByVal Shape As IVShape) Dim ShapeOnPage As Shape Dim dblTolerance As Integer Dim ReturnedSelection As Selection Dim strSpatialRelation As String Dim iSpatialRelation As VisSpatialRelationCodes
On Error GoTo errHandler
strSpatialRelation = ""
'Try setting different tolerance values dblTolerance = 0#
'Try setting different spatial relationships iSpatialRelation = visSpatialContainedIn
Const ISRELATED = " is contained by " Const ISNOTRELATED = " is not contained."
'Get the set of spatially related shapes 'that meet the criteria set by the parameters Set ReturnedSelection = Shape.SpatialNeighbors(iSpatialRelation, _ dblTolerance, 0)
'Evaluate the results If ReturnedSelection.Count = 0 Then 'No shapes met the criteria set by the 'parameters of the method strSpatialRelation = Shape.Name & ISNOTRELATED Else 'Build the positive result string For Each ShapeOnPage In ReturnedSelection strSpatialRelation = strSpatialRelation & Shape.Name _ & ISRELATED & ShapeOnPage.Name & Chr$(10) Next End If
'Put the results on the added shape Shape.Text = strSpatialRelation
errHandler:
End Sub
Using the DistanceFrom and DistanceFromPoint properties: an example
The VBA code in this example demonstrates the DistanceFrom and DistanceFromPoint properties of a Shape object. These properties are used to determine the distance from the calling shape, and a shape passed as an argument with the property. Use DistanceFromPoint to determine the distance from a specific point on the shape.
The VBA code in this example expects the user to drop various shapes onto the page at various distances from a base shape. A message box appears to inform the user if the dropped shapes are too close to the base shape. The minimum acceptable distance is defined by dblMinimumDistance.
To test this example, paste the following code in the ThisDocument code window of a new drawing, save the drawing and close it, reopen the drawing, and then drop shapes onto the page.
Public objBaseShape As Visio.Shape
Public Function MeetsClearanceRequirements(BaseShape As Shape, _ ShapeToCheck As Shape, dblMinimumDistance As Double) As Boolean Dim bRetVal As Boolean On Error GoTo errHandler 'Check distance from specific point 'Use the DistanceFromPoint property dblDistance = ShapeToCheck.DistanceFromPoint(BaseShape.Cells("PinX"), _ BaseShape.Cells("PinY"), 0) 'To check distance from closest points use DistanceFrom property: 'dblDistance = ShapeToCheck.DistanceFrom(BaseShape,0) If dblDistance < dblMinimumDistance Then bRetVal = False Else bRetVal = True End If MeetsClearanceRequirements = bRetVal Exit Function
errHandler: bRetVal = False End Function
Private Sub Document_DocumentOpened(ByVal doc As IVDocument) 'Draw a rectangle on the page; this will be the 'shape that all added shapes are compared to Set objBaseShape = ActivePage.DrawRectangle(3, 7, 4, 6) End Sub
Private Sub Document_ShapeAdded(ByVal Shape As IVShape) Dim strMsg As String Dim dblMinimumDistance As Double
dblMinimumDistance = 2
'Because the objBaseShape is set when the document is opened, 'attempt to compare shapes on different pages If objBaseShape.Parent = Shape.Parent And (objBaseShape <> Shape) Then If MeetsClearanceRequirements(objBaseShape, Shape, _ dblMinimumDistance) Then strMsg = "Distance requirements met" Else strMsg = "Too close" End If 'Display message MsgBox strMsg Else 'Do nothing, shapes are on a different page, or 'BaseShape = Added Shape End If End Sub