//************************************************************************* // Method: TryDrawVertex() // /// <summary> /// Draws a vertex after moving it if necessary. /// </summary> /// /// <param name="vertex"> /// The vertex to draw. /// </param> /// /// <param name="graphDrawingContext"> /// Provides access to objects needed for graph-drawing operations. /// </param> /// /// <param name="vertexDrawingHistory"> /// Where a <see cref="VertexDrawingHistory" /> object that retains /// information about how the vertex was drawn gets stored if true is /// returned. /// </param> /// /// <returns> /// true if the vertex was drawn, false if the vertex is hidden. /// </returns> /// /// <remarks> /// This method should be called repeatedly while a graph is being drawn, /// once for each of the graph's vertices. The <see /// cref="IVertex.Location" /> property on all of the graph's vertices must /// be set by ILayout.LayOutGraph before this method is called. /// /// <para> /// If the vertex falls outside the graph rectangle, it gets moved before /// being drawn. /// </para> /// /// </remarks> //************************************************************************* public Boolean TryDrawVertex( IVertex vertex, GraphDrawingContext graphDrawingContext, out VertexDrawingHistory vertexDrawingHistory ) { AssertValid(); vertexDrawingHistory = null; CheckDrawVertexArguments(vertex, graphDrawingContext); // If the vertex is hidden, do nothing. VisibilityKeyValue eVisibility = GetVisibility(vertex); if (eVisibility == VisibilityKeyValue.Hidden) { return (false); } // Check for a per-vertex label. Object oLabelAsObject; String sLabel = null; if ( vertex.TryGetValue(ReservedMetadataKeys.PerVertexLabel, typeof(String), out oLabelAsObject) ) { sLabel = (String)oLabelAsObject; if ( String.IsNullOrEmpty(sLabel) ) { sLabel = null; } else { sLabel = TruncateLabel(sLabel); } } Boolean bDrawAsSelected = GetDrawAsSelected(vertex); Point oLocation = WpfGraphicsUtil.PointFToWpfPoint(vertex.Location); DrawingVisual oDrawingVisual = new DrawingVisual(); VertexShape eShape = GetShape(vertex); VertexLabelDrawer oVertexLabelDrawer = new VertexLabelDrawer(m_eLabelPosition); using ( DrawingContext oDrawingContext = oDrawingVisual.RenderOpen() ) { if (eShape == VertexShape.Label) { if (sLabel != null) { // Draw the vertex as a label. vertexDrawingHistory = DrawLabelShape(vertex, graphDrawingContext, oDrawingContext, oDrawingVisual, eVisibility, bDrawAsSelected, sLabel); return (true); } // Default to something usable. eShape = VertexShape.Disk; } else if (eShape == VertexShape.Image) { Object oImageSourceAsObject; if (vertex.TryGetValue(ReservedMetadataKeys.PerVertexImage, typeof(ImageSource), out oImageSourceAsObject) ) { // Draw the vertex as an image. vertexDrawingHistory = DrawImageShape(vertex, graphDrawingContext, oDrawingContext, oDrawingVisual, eVisibility, bDrawAsSelected, sLabel, (ImageSource)oImageSourceAsObject, oVertexLabelDrawer); return (true); } // Default to something usable. eShape = VertexShape.Disk; } // Draw the vertex as a simple shape. vertexDrawingHistory = DrawSimpleShape(vertex, eShape, graphDrawingContext, oDrawingContext, oDrawingVisual, eVisibility, bDrawAsSelected, sLabel, oVertexLabelDrawer); } return (true); }
//************************************************************************* // Method: DrawPlusSign() // /// <summary> /// Draws a plus sign on top of the vertex. /// </summary> /// /// <param name="eShape"> /// The simple vertex shape. /// </param> /// /// <param name="oGraphDrawingContext"> /// Provides access to objects needed for graph-drawing operations. /// </param> /// /// <param name="oVertexLocation"> /// The location of the vertex. /// </param> /// /// <param name="oDrawingContext"> /// The DrawingContext to use. /// </param> /// /// <param name="oVertexColor"> /// The color of the vertex. /// </param> /// /// <param name="oVertexLabelDrawer"> /// Object that draws a vertex label as an annotation. /// </param> /// /// <param name="oVertexDrawingHistory"> /// A <see cref="VertexDrawingHistory" /> object that retains information /// about how the vertex was drawn. /// </param> /// /// <param name="oVertexBounds"> /// The rectangle defining the bounds of the vertex. /// </param> //************************************************************************* protected void DrawPlusSign( VertexShape eShape, Point oVertexLocation, Rect oVertexBounds, Color oVertexColor, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, VertexLabelDrawer oVertexLabelDrawer, VertexDrawingHistory oVertexDrawingHistory ) { Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oVertexLabelDrawer != null); Debug.Assert(oVertexDrawingHistory != null); AssertValid(); Color oFillColor; switch (eShape) { case VertexShape.Circle: case VertexShape.Square: case VertexShape.Diamond: case VertexShape.Triangle: // The fill color is the color of the background. Adjust the // fill color for the opacity of the vertex. oFillColor = WpfGraphicsUtil.SetWpfColorAlpha( oGraphDrawingContext.BackColor, oVertexColor.A); break; default: oFillColor = oVertexColor; break; } Color oContrastingColor = WpfGraphicsUtil.GetContrastingColor(oFillColor); // The font size used below was chosen so that it is large enough to be // easily readable, but small enough to fit within the smallest // collapsed group vertex created by the NodeXLControl. oVertexLabelDrawer.DrawLabel( oDrawingContext, oGraphDrawingContext, oVertexDrawingHistory, oVertexBounds, VertexLabelPosition.MiddleCenter, CreateFormattedText("+", oContrastingColor, 15.0) ); }
//************************************************************************* // Method: GetEdgeEndpoint() // /// <summary> /// Gets the endpoint of an edge that is connected to <see /// cref="Vertex" />. /// </summary> /// /// <param name="otherVertexDrawingHistory"> /// The <paramref name="VertexDrawingHistory" /> object that retains /// information about how the edge's other vertex was drawn. /// </param> /// /// <param name="edgeEndpoint"> /// Where the edge endpoint gets stored. The endpoint is somewhere on <see /// cref="Vertex" />. /// </param> //************************************************************************* public override void GetEdgeEndpoint( VertexDrawingHistory otherVertexDrawingHistory, out Point edgeEndpoint ) { AssertValid(); GetEdgeEndpointOnRectangle(this.VertexLocation, this.Rectangle, otherVertexDrawingHistory.VertexLocation, out edgeEndpoint); }
//************************************************************************* // Method: GetEdgeEndpoint() // /// <summary> /// Gets the endpoint of an edge that is connected to <see /// cref="Vertex" />. /// </summary> /// /// <param name="otherVertexDrawingHistory"> /// The <paramref name="VertexDrawingHistory" /> object that retains /// information about how the edge's other vertex was drawn. /// </param> /// /// <param name="edgeEndpoint"> /// Where the edge endpoint gets stored. The endpoint is somewhere on <see /// cref="Vertex" />. /// </param> //************************************************************************* public override void GetEdgeEndpoint( VertexDrawingHistory otherVertexDrawingHistory, out Point edgeEndpoint ) { AssertValid(); Point oVertexLocation = this.VertexLocation; Point oOtherVertexLocation = otherVertexDrawingHistory.VertexLocation; // Instead of doing geometry calculations similar to what is done in // VertexDrawingHistory.GetEdgePointOnRectangle(), make use of that // method by making the triangle look like a rectangle. First, figure // out how to rotate the triangle about the vertex location so that the // side containing the endpoint is vertical and to the right of the // vertex location. Double dEdgeAngle = WpfGraphicsUtil.GetAngleBetweenPoints( oVertexLocation, oOtherVertexLocation); Double dEdgeAngleDegrees = MathUtil.RadiansToDegrees(dEdgeAngle); Double dAngleToRotateDegrees; if (dEdgeAngleDegrees >= -30.0 && dEdgeAngleDegrees < 90.0) { dAngleToRotateDegrees = 30.0; } else if (dEdgeAngleDegrees >= -150.0 && dEdgeAngleDegrees < -30.0) { dAngleToRotateDegrees = 270.0; } else { dAngleToRotateDegrees = 150.0; } // Now create a rotated rectangle that is centered on the vertex // location and that has the vertical, endpoint-containing triangle // side as the rectangle's right edge. Double dWidth = 2.0 * m_dHalfWidth; Rect oRotatedRectangle = new Rect( oVertexLocation.X, oVertexLocation.Y - m_dHalfWidth, dWidth * WpfGraphicsUtil.Tangent30Degrees, dWidth ); Matrix oMatrix = WpfGraphicsUtil.GetRotatedMatrix(oVertexLocation, dAngleToRotateDegrees); // Rotate the other vertex location. Point oRotatedOtherVertexLocation = oMatrix.Transform(oOtherVertexLocation); // GetEdgeEndpointOnRectangle will compute an endpoint on the // rectangle's right edge. Point oRotatedEdgeEndpoint; GetEdgeEndpointOnRectangle(oVertexLocation, oRotatedRectangle, oRotatedOtherVertexLocation, out oRotatedEdgeEndpoint); // Now rotate the edge endpoint in the other direction. oMatrix = WpfGraphicsUtil.GetRotatedMatrix(oVertexLocation, -dAngleToRotateDegrees); edgeEndpoint = oMatrix.Transform(oRotatedEdgeEndpoint); }
//************************************************************************* // Method: DrawLabel() // /// <summary> /// Draws a vertex label as an annotation at a specified position. /// </summary> /// /// <param name="drawingContext"> /// The DrawingContext to use. /// </param> /// /// <param name="graphDrawingContext"> /// Provides access to objects needed for graph-drawing operations. /// </param> /// /// <param name="vertexDrawingHistory"> /// Describes how the vertex was drawn. /// </param> /// /// <param name="vertexBounds"> /// The vertex's bounding rectangle. /// </param> /// /// <param name="labelPosition"> /// The label's position. /// </param> /// /// <param name="formattedText"> /// The FormattedText object to use. Several properties get changed by /// this method. /// </param> //************************************************************************* public void DrawLabel( DrawingContext drawingContext, GraphDrawingContext graphDrawingContext, VertexDrawingHistory vertexDrawingHistory, Rect vertexBounds, VertexLabelPosition labelPosition, FormattedText formattedText ) { Debug.Assert(drawingContext != null); Debug.Assert(graphDrawingContext != null); Debug.Assert(vertexDrawingHistory != null); Debug.Assert(formattedText != null); AssertValid(); Double dHalfVertexBoundsWidth = vertexBounds.Width / 2.0; Double dHalfVertexBoundsHeight = vertexBounds.Height / 2.0; Double dLabelHeight = formattedText.Height; Double dHalfLabelHeight = dLabelHeight / 2.0; Double dLabelWidth = formattedText.Width; Double dHalfLabelWidth = dLabelWidth / 2.0; TextAlignment eTextAlignment = TextAlignment.Left; formattedText.MaxLineCount = 1; // This is the point where the label will be drawn. It initially // assumes a text height of zero with no margin, but that will be // adjusted within the switch statement below. Point oDraw = vertexDrawingHistory.GetLabelLocation(labelPosition); Double dDrawX = oDraw.X; Double dDrawY = oDraw.Y; // These are the bounds of the label text. Double dLabelBoundsLeft = 0; Double dLabelBoundsRight = 0; switch (labelPosition) { case VertexLabelPosition.TopLeft: eTextAlignment = TextAlignment.Right; dDrawY -= (dLabelHeight + VerticalMargin); dLabelBoundsLeft = dDrawX - dLabelWidth; dLabelBoundsRight = dDrawX; break; case VertexLabelPosition.TopCenter: eTextAlignment = TextAlignment.Center; dDrawY -= (dLabelHeight + VerticalMargin); dLabelBoundsLeft = dDrawX - dHalfLabelWidth; dLabelBoundsRight = dDrawX + dHalfLabelWidth; break; case VertexLabelPosition.TopRight: // eTextAlignment = TextAlignment.Left; dDrawY -= (dLabelHeight + VerticalMargin); dLabelBoundsLeft = dDrawX; dLabelBoundsRight = dDrawX + dLabelWidth; break; case VertexLabelPosition.MiddleLeft: eTextAlignment = TextAlignment.Right; dDrawX -= HorizontalMargin; dDrawY -= dHalfLabelHeight; dLabelBoundsLeft = dDrawX - dLabelWidth; dLabelBoundsRight = dDrawX; break; case VertexLabelPosition.MiddleCenter: eTextAlignment = TextAlignment.Center; dDrawY -= dHalfLabelHeight; dLabelBoundsLeft = dDrawX - dHalfLabelWidth; dLabelBoundsRight = dDrawX + dHalfLabelWidth; break; case VertexLabelPosition.MiddleRight: // eTextAlignment = TextAlignment.Left; dDrawX += HorizontalMargin; dDrawY -= dHalfLabelHeight; dLabelBoundsLeft = dDrawX; dLabelBoundsRight = dDrawX + dLabelWidth; break; case VertexLabelPosition.BottomLeft: eTextAlignment = TextAlignment.Right; dDrawY += VerticalMargin; dLabelBoundsLeft = dDrawX - dLabelWidth; dLabelBoundsRight = dDrawX; break; case VertexLabelPosition.BottomCenter: eTextAlignment = TextAlignment.Center; dDrawY += VerticalMargin; dLabelBoundsLeft = dDrawX - dHalfLabelWidth; dLabelBoundsRight = dDrawX + dHalfLabelWidth; break; case VertexLabelPosition.BottomRight: // eTextAlignment = TextAlignment.Left; dDrawY += VerticalMargin; dLabelBoundsLeft = dDrawX; dLabelBoundsRight = dDrawX + dLabelWidth; break; default: Debug.Assert(false); break; } // Don't let the text exceed the bounds of the graph rectangle. Double dLabelBoundsTop = dDrawY; Double dLabelBoundsBottom = dDrawY + dLabelHeight; Rect oGraphRectangleMinusMargin = graphDrawingContext.GraphRectangleMinusMargin; dDrawX += Math.Max(0, oGraphRectangleMinusMargin.Left - dLabelBoundsLeft); dDrawX -= Math.Max(0, dLabelBoundsRight - oGraphRectangleMinusMargin.Right); dDrawY += Math.Max(0, oGraphRectangleMinusMargin.Top - dLabelBoundsTop); dDrawY -= Math.Max(0, dLabelBoundsBottom - oGraphRectangleMinusMargin.Bottom); formattedText.TextAlignment = eTextAlignment; drawingContext.DrawText( formattedText, new Point(dDrawX, dDrawY) ); }
//************************************************************************* // Method: DrawLabel() // /// <summary> /// Draws a vertex label as an annotation. /// </summary> /// /// <summary> /// Draws a vertex label as an annotation at a position determined by the /// vertex's metadata. /// </summary> /// /// <param name="drawingContext"> /// The DrawingContext to use. /// </param> /// /// <param name="graphDrawingContext"> /// Provides access to objects needed for graph-drawing operations. /// </param> /// /// <param name="vertexDrawingHistory"> /// Describes how the vertex was drawn. /// </param> /// /// <param name="vertexBounds"> /// The vertex's bounding rectangle. /// </param> /// /// <param name="formattedText"> /// The FormattedText object to use. Several properties get changed by /// this method. /// </param> //************************************************************************* public void DrawLabel( DrawingContext drawingContext, GraphDrawingContext graphDrawingContext, VertexDrawingHistory vertexDrawingHistory, Rect vertexBounds, FormattedText formattedText ) { Debug.Assert(drawingContext != null); Debug.Assert(graphDrawingContext != null); Debug.Assert(vertexDrawingHistory != null); Debug.Assert(formattedText != null); AssertValid(); DrawLabel(drawingContext, graphDrawingContext, vertexDrawingHistory, vertexBounds, GetLabelPosition(vertexDrawingHistory.Vertex), formattedText); }