DrawSimpleShape ( IVertex oVertex, VertexShape eShape, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, DrawingVisualPlus oDrawingVisual, VisibilityKeyValue eVisibility, Boolean bDrawAsSelected, String sAnnotation, VertexLabelDrawer oVertexLabelDrawer, CollapsedGroupDrawingManager oCollapsedGroupDrawingManager ) { Debug.Assert(oVertex != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oDrawingVisual != null); Debug.Assert(oVertexLabelDrawer != null); Debug.Assert(oCollapsedGroupDrawingManager != null); AssertValid(); Double dRadius = GetRadius(oVertex); Color oColor = GetColor(oVertex, eVisibility, bDrawAsSelected); Point oVertexLocation = GetVertexLocation(oVertex); oDrawingVisual.SetEffect( GetSimpleShapeEffect( oGraphDrawingContext, dRadius, oColor) ); Rect oVertexBounds; if (eShape == VertexShape.Triangle || eShape == VertexShape.SolidTriangle) { oVertexBounds = WpfGraphicsUtil.TriangleBoundsFromCenterAndHalfWidth( oVertexLocation, dRadius); } else if (eShape == VertexShape.SolidTaperedDiamond) { // Note that the bounds of a tapered diamond can't be calculated // using simple equations. Instead, create the tapered diamond and // let WPF compute the bounds. // // There is some inefficiency here, because the tapered diamond // gets created again before it is drawn, in its possibly-moved // location. oVertexBounds = WpfPathGeometryUtil.GetTaperedDiamond( oVertexLocation, dRadius).Bounds; } else if (eShape == VertexShape.SolidRoundedX) { // Note that the bounds of a rounded X can't be calculated // using simple equations. Instead, create the rounded X and // let WPF compute the bounds. // // There is some inefficiency here, because the rounded X // gets created again before it is drawn, in its possibly-moved // location. oVertexBounds = WpfPathGeometryUtil.GetRoundedX( oVertexLocation, dRadius).Bounds; } else { oVertexBounds = WpfGraphicsUtil.SquareFromCenterAndHalfWidth( oVertexLocation, dRadius); } // Move the vertex if it falls outside the graph rectangle. MoveVertexIfNecessary(oVertex, oGraphDrawingContext, oCollapsedGroupDrawingManager, ref oVertexBounds); oVertexLocation = GetVertexLocation(oVertex); VertexDrawingHistory oVertexDrawingHistory = null; // Note that for the "hollow" shapes -- Circle, Square, Diamond, and // Triangle -- Brushes.Transparent is used instead of a null brush. // This allows the entire area of these shapes to be hit-tested. Using // a null brush would cause hit-testing to fail if the shapes' // interiors were clicked. switch (eShape) { case VertexShape.Circle: case VertexShape.Disk: Boolean bIsDisk = (eShape == VertexShape.Disk); oDrawingContext.DrawEllipse( bIsDisk ? GetBrush(oColor) : Brushes.Transparent, bIsDisk ? null : GetPen(oColor, DefaultPenThickness), oVertexLocation, dRadius, dRadius ); oVertexDrawingHistory = bIsDisk ? new DiskVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius) : new CircleVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.Sphere: RadialGradientBrush oRadialGradientBrush = new RadialGradientBrush(); oRadialGradientBrush.GradientOrigin = oRadialGradientBrush.Center = new Point(0.3, 0.3); GradientStopCollection oGradientStops = oRadialGradientBrush.GradientStops; oGradientStops.Add( new GradientStop( WpfGraphicsUtil.SetWpfColorAlpha(Colors.White, oColor.A), 0.0) ); oGradientStops.Add( new GradientStop(oColor, 1.0) ); WpfGraphicsUtil.FreezeIfFreezable(oRadialGradientBrush); oDrawingContext.DrawEllipse(oRadialGradientBrush, null, oVertexLocation, dRadius, dRadius); oVertexDrawingHistory = new SphereVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.Square: WpfGraphicsUtil.DrawPixelAlignedRectangle(oDrawingContext, Brushes.Transparent, GetPen(oColor, DefaultPenThickness), oVertexBounds); oVertexDrawingHistory = new SquareVertexDrawingHistory(oVertex, oDrawingVisual, bDrawAsSelected, oVertexBounds); break; case VertexShape.SolidSquare: oDrawingContext.DrawRectangle(GetBrush(oColor), null, oVertexBounds); oVertexDrawingHistory = new SolidSquareVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, oVertexBounds); break; case VertexShape.Diamond: case VertexShape.SolidDiamond: Boolean bIsSolidDiamond = (eShape == VertexShape.SolidDiamond); PathGeometry oDiamond = WpfPathGeometryUtil.GetDiamond(oVertexLocation, dRadius); oDrawingContext.DrawGeometry( bIsSolidDiamond ? GetBrush(oColor) : Brushes.Transparent, bIsSolidDiamond ? null : GetPen(oColor, DefaultPenThickness), oDiamond ); oVertexDrawingHistory = bIsSolidDiamond ? new SolidDiamondVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius) : new DiamondVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.Triangle: case VertexShape.SolidTriangle: Boolean bIsSolidTriangle = (eShape == VertexShape.SolidTriangle); PathGeometry oTriangle = WpfPathGeometryUtil.GetTriangle(oVertexLocation, dRadius); oDrawingContext.DrawGeometry( bIsSolidTriangle ? GetBrush(oColor) : Brushes.Transparent, bIsSolidTriangle ? null : GetPen(oColor, DefaultPenThickness), oTriangle ); oVertexDrawingHistory = bIsSolidTriangle ? new SolidTriangleVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius) : new TriangleVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.SolidTaperedDiamond: Geometry oTaperedDiamond = WpfPathGeometryUtil.GetTaperedDiamond( oVertexLocation, dRadius); // Note that as of August 2012, the tapered diamond shape is // used only for collapsed connector motifs. Collapsed motifs // have an outline, so draw an outline here. oDrawingContext.DrawGeometry(GetBrush(oColor), GetPen( CollapsedGroupDrawingManager .GetCollapsedMotifOutlineColor(oColor.A), DefaultPenThickness), oTaperedDiamond); oVertexDrawingHistory = new SolidTaperedDiamondVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; case VertexShape.SolidRoundedX: Geometry oRoundedX = WpfPathGeometryUtil.GetRoundedX( oVertexLocation, dRadius); // Note that as of August 2012, the rounded X shape is // used only for collapsed clique motifs. Collapsed motifs // have an outline, so draw an outline here. oDrawingContext.DrawGeometry(GetBrush(oColor), GetPen(CollapsedGroupDrawingManager .GetCollapsedMotifOutlineColor(oColor.A), DefaultPenThickness), oRoundedX); oVertexDrawingHistory = new SolidRoundedXVertexDrawingHistory( oVertex, oDrawingVisual, bDrawAsSelected, dRadius); break; default: Debug.Assert(false); break; } if (sAnnotation != null) { oVertexLabelDrawer.DrawLabel(oDrawingContext, oGraphDrawingContext, oVertexDrawingHistory, CreateFormattedTextWithWrap(sAnnotation, oColor, m_oFormattedTextManager.FontSize), oColor); } Debug.Assert(oVertexDrawingHistory != null); return (oVertexDrawingHistory); }
DrawLabelShape ( IVertex oVertex, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, DrawingVisualPlus oDrawingVisual, VisibilityKeyValue eVisibility, Boolean bDrawAsSelected, String sLabel, CollapsedGroupDrawingManager oCollapsedGroupDrawingManager ) { Debug.Assert(oVertex != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oDrawingVisual != null); Debug.Assert( !String.IsNullOrEmpty(sLabel) ); Debug.Assert(oCollapsedGroupDrawingManager != null); AssertValid(); // Figure out what colors to use. Color oOutlineColor; Color oTextColor = GetColor(oVertex, eVisibility, false); Color oFillColor = GetColor(oVertex, eVisibility, ReservedMetadataKeys.PerVertexLabelFillColor, m_oLabelFillColor, true); if (bDrawAsSelected) { // The outline color is always the selected color. oOutlineColor = m_oSelectedColor; // The text color is the default or per-vertex color with no alpha. oTextColor.A = 255; // The fill color is the default or per-vertex fill color with no // alpha. oFillColor.A = 255; } else { // The outline color is the default or per-vertex color with alpha. oOutlineColor = oTextColor; // The text color is the default or per-vertex color with alpha. // The fill color is the default or per-vertex fill color with // alpha. } Double dLabelFontSize = GetLabelFontSize(oVertex); FormattedText oFormattedText = CreateFormattedTextWithWrap( sLabel, oTextColor, dLabelFontSize); Rect oVertexRectangle = GetVertexRectangle( GetVertexLocation(oVertex), oFormattedText.Width, oFormattedText.Height); // Pad the text. Rect oVertexRectangleWithPadding = oVertexRectangle; Double dLabelPadding = GetLabelPadding(dLabelFontSize); oVertexRectangleWithPadding.Inflate(dLabelPadding, dLabelPadding * 0.7); if (m_oFormattedTextManager.Typeface.Style != FontStyles.Normal) { // This is a hack to move the right edge of the padded rectangle // to the right to adjust for wider italic text, which // FormattedText.Width does not account for. What is the correct // way to do this? It might involve the FormattedText.Overhang* // properties, but I'll be darned if I can understand how those // properties work. Double dItalicCompensation = dLabelFontSize / 7.0; oVertexRectangleWithPadding.Inflate(dItalicCompensation, 0); oVertexRectangleWithPadding.Offset(dItalicCompensation, 0); } // Move the vertex if it falls outside the graph rectangle. Double dOriginalVertexRectangleWithPaddingX = oVertexRectangleWithPadding.X; Double dOriginalVertexRectangleWithPaddingY = oVertexRectangleWithPadding.Y; MoveVertexIfNecessary(oVertex, oGraphDrawingContext, oCollapsedGroupDrawingManager, ref oVertexRectangleWithPadding); oVertexRectangle.Offset( oVertexRectangleWithPadding.X - dOriginalVertexRectangleWithPaddingX, oVertexRectangleWithPadding.Y - dOriginalVertexRectangleWithPaddingY ); oDrawingVisual.SetEffect( GetRectangleEffect( oGraphDrawingContext, oOutlineColor) ); // Draw the padded rectangle, then the text. WpfGraphicsUtil.DrawPixelAlignedRectangle(oDrawingContext, GetBrush(oFillColor), GetPen(oOutlineColor, DefaultPenThickness), oVertexRectangleWithPadding); oDrawingContext.DrawText(oFormattedText, oVertexRectangle.Location); // Return information about how the vertex was drawn. return ( new LabelVertexDrawingHistory(oVertex, oDrawingVisual, bDrawAsSelected, oVertexRectangleWithPadding) ); }
TryDrawVertex ( IVertex vertex, GraphDrawingContext graphDrawingContext, out VertexDrawingHistory vertexDrawingHistory ) { AssertValid(); vertexDrawingHistory = null; CheckDrawVertexArguments(vertex, graphDrawingContext); if (graphDrawingContext.GraphRectangleMinusMarginIsEmpty) { return (false); } // If the vertex is hidden, do nothing. VisibilityKeyValue eVisibility = GetVisibility(vertex); if (eVisibility == VisibilityKeyValue.Hidden) { return (false); } // Check whether the vertex represents a collapsed group and perform // collapsed group tasks if necessary. CollapsedGroupDrawingManager oCollapsedGroupDrawingManager = new CollapsedGroupDrawingManager(); oCollapsedGroupDrawingManager.PreDrawVertex(vertex); // 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); DrawingVisualPlus oDrawingVisual = new DrawingVisualPlus(); VertexShape eShape = GetShape(vertex); VertexLabelDrawer oVertexLabelDrawer = new VertexLabelDrawer(m_eLabelPosition, m_btBackgroundAlpha); 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, oCollapsedGroupDrawingManager); } else { // 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, oCollapsedGroupDrawingManager); } else { // Default to something usable. eShape = VertexShape.Disk; } } if (vertexDrawingHistory == null) { // Draw the vertex as a simple shape. vertexDrawingHistory = DrawSimpleShape(vertex, eShape, graphDrawingContext, oDrawingContext, oDrawingVisual, eVisibility, bDrawAsSelected, sLabel, oVertexLabelDrawer, oCollapsedGroupDrawingManager); } // Perform collapsed group tasks if necessary. oCollapsedGroupDrawingManager.PostDrawVertex(eShape, GetColor(vertex, eVisibility, bDrawAsSelected), graphDrawingContext, oDrawingContext, bDrawAsSelected, m_dGraphScale, oVertexLabelDrawer, m_oFormattedTextManager, vertexDrawingHistory); } return (true); }
DrawImageShape ( IVertex oVertex, GraphDrawingContext oGraphDrawingContext, DrawingContext oDrawingContext, DrawingVisualPlus oDrawingVisual, VisibilityKeyValue eVisibility, Boolean bDrawAsSelected, String sAnnotation, ImageSource oImageSource, VertexLabelDrawer oVertexLabelDrawer, CollapsedGroupDrawingManager oCollapsedGroupDrawingManager ) { Debug.Assert(oVertex != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oDrawingContext != null); Debug.Assert(oDrawingVisual != null); Debug.Assert(oImageSource != null); Debug.Assert(oVertexLabelDrawer != null); Debug.Assert(oCollapsedGroupDrawingManager != null); AssertValid(); // Move the vertex if it falls outside the graph rectangle. Rect oVertexRectangle = GetVertexRectangle( GetVertexLocation(oVertex), oImageSource.Width * m_dGraphScale, oImageSource.Height * m_dGraphScale); MoveVertexIfNecessary(oVertex, oGraphDrawingContext, oCollapsedGroupDrawingManager, ref oVertexRectangle); Byte btAlpha = 255; if (!bDrawAsSelected) { // Check for a non-opaque alpha value. btAlpha = GetAlpha(oVertex, eVisibility, btAlpha); } VertexDrawingHistory oVertexDrawingHistory = new ImageVertexDrawingHistory(oVertex, oDrawingVisual, bDrawAsSelected, oVertexRectangle); if (btAlpha > 0) { oDrawingContext.DrawImage(oImageSource, oVertexRectangle); Color oColor = GetColor(oVertex, eVisibility, bDrawAsSelected); oDrawingVisual.SetEffect( GetRectangleEffect( oGraphDrawingContext, oColor) ); // Draw an outline rectangle. WpfGraphicsUtil.DrawPixelAlignedRectangle(oDrawingContext, null, GetPen(oColor, DefaultPenThickness), oVertexRectangle); if (btAlpha < 255) { // Real transparency can't be achieved with arbitrary images, // so simulate transparency by drawing on top of the image with // a translucent brush the same color as the graph's // background. // // This really isn't a good solution. Is there are better way // to simulate transparency? Color oTranslucentColor = oGraphDrawingContext.BackColor; oTranslucentColor.A = (Byte)( (Byte)255 - btAlpha ); oDrawingContext.DrawRectangle( CreateFrozenSolidColorBrush(oTranslucentColor), null, oVertexRectangle); } if (sAnnotation != null) { oVertexLabelDrawer.DrawLabel(oDrawingContext, oGraphDrawingContext, oVertexDrawingHistory, CreateFormattedTextWithWrap(sAnnotation, oColor, m_oFormattedTextManager.FontSize), oColor ); } } return (oVertexDrawingHistory); }