DrawCombinedIntergroupEdge ( DrawingContext oDrawingContext, GraphDrawingContext oGraphDrawingContext, IntergroupEdgeInfo oCombinedIntergroupEdge, GroupLayoutDrawingInfo oGroupLayoutDrawingInfo ) { Debug.Assert(oDrawingContext != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(oCombinedIntergroupEdge != null); Debug.Assert(oGroupLayoutDrawingInfo != null); AssertValid(); Rect oGroupRectangle1, oGroupRectangle2; if ( !TryGetGroupRectangle( oGroupLayoutDrawingInfo.GroupsToDraw[ oCombinedIntergroupEdge.Group1Index], out oGroupRectangle1) || !TryGetGroupRectangle( oGroupLayoutDrawingInfo.GroupsToDraw[ oCombinedIntergroupEdge.Group2Index], out oGroupRectangle2) ) { return; } Point oGroupRectangle1Center = WpfGraphicsUtil.GetRectCenter(oGroupRectangle1); Point oGroupRectangle2Center = WpfGraphicsUtil.GetRectCenter(oGroupRectangle2); Point oBezierControlPoint = GetBezierControlPoint(oGraphDrawingContext, oGroupRectangle1Center, oGroupRectangle2Center, CombinedIntergroupEdgeBezierDisplacementFactor ); PathGeometry oBezierCurve = WpfPathGeometryUtil.GetQuadraticBezierCurve(oGroupRectangle1Center, oGroupRectangle2Center, oBezierControlPoint); Color oColor = GetContrastingColor( oGraphDrawingContext, CombinedIntergroupEdgeAlpha, true); Pen oPen = CreateFrozenPen(CreateFrozenSolidColorBrush(oColor), GetCombinedIntergroupEdgePenWidth(oCombinedIntergroupEdge) * this.GraphScale, DashStyles.Solid, PenLineCap.Round); oDrawingContext.DrawGeometry(null, oPen, oBezierCurve); }
SaveObject ( Object oObject, String sFileName ) { Debug.Assert(oObject is GraphImageInfo); Debug.Assert(!String.IsNullOrEmpty(sFileName)); GraphImageInfo oGraphImageInfo = (GraphImageInfo)oObject; Int32 iWidth = oGraphImageInfo.Width; Int32 iHeight = oGraphImageInfo.Height; GraphImageCompositor oGraphImageCompositor = new GraphImageCompositor(oGraphImageInfo.NodeXLControl); UIElement oCompositeElement = null; try { if (m_oSaveFileDialog.FilterIndex <= SaveableImageFormats.ImageFormats.Length) { // The graph must be saved as a bitmap. oCompositeElement = oGraphImageCompositor.Composite( iWidth, iHeight, oGraphImageInfo.HeaderText, oGraphImageInfo.FooterText, oGraphImageInfo.HeaderFooterFont, oGraphImageInfo.LegendControls); System.Drawing.Bitmap oBitmap = WpfGraphicsUtil.VisualToBitmap( oCompositeElement, iWidth, iHeight); base.SaveObject(oBitmap, sFileName); oBitmap.Dispose(); } else { // The graph must be saved as an XPS. Double documentWidth = ToWpsUnits(iWidth); Double documentHeight = ToWpsUnits(iHeight); oCompositeElement = oGraphImageCompositor.Composite( documentWidth, documentHeight, oGraphImageInfo.HeaderText, oGraphImageInfo.FooterText, oGraphImageInfo.HeaderFooterFont, oGraphImageInfo.LegendControls); Size oDocumentSize = new Size(documentWidth, documentHeight); Rect oDocumentRectangle = new Rect(new Point(), oDocumentSize); FixedDocument oFixedDocument = new FixedDocument(); oFixedDocument.DocumentPaginator.PageSize = oDocumentSize; PageContent oPageContent = new PageContent(); FixedPage oFixedPage = new FixedPage(); oFixedPage.Width = documentWidth; oFixedPage.Height = documentHeight; oFixedPage.Children.Add(oCompositeElement); ((System.Windows.Markup.IAddChild)oPageContent).AddChild( oFixedPage); oFixedDocument.Pages.Add(oPageContent); XpsDocument oXpsDocument = new XpsDocument(sFileName, FileAccess.Write); XpsDocumentWriter oXpsDocumentWriter = XpsDocument.CreateXpsDocumentWriter(oXpsDocument); oXpsDocumentWriter.Write(oFixedDocument); oXpsDocument.Close(); } } finally { if (oCompositeElement != null) { oGraphImageCompositor.RestoreNodeXLControl(); } } }
TransferToGraphDrawer ( GraphDrawer graphDrawer ) { Debug.Assert(graphDrawer != null); AssertValid(); this.LabelUserSettings.TransferToGraphDrawer(graphDrawer); graphDrawer.BackColor = WpfGraphicsUtil.ColorToWpfColor(this.BackColor); if (!String.IsNullOrEmpty(this.BackgroundImageUri)) { graphDrawer.BackgroundImage = (new WpfImageUtil()).GetImageSynchronousIgnoreDpi( this.BackgroundImageUri); } else { graphDrawer.BackgroundImage = null; } EdgeDrawer oEdgeDrawer = graphDrawer.EdgeDrawer; VertexDrawer oVertexDrawer = graphDrawer.VertexDrawer; EdgeWidthConverter oEdgeWidthConverter = new EdgeWidthConverter(); AlphaConverter oAlphaConverter = new AlphaConverter(); oEdgeDrawer.Width = oEdgeWidthConverter.WorkbookToGraph(this.EdgeWidth); oEdgeDrawer.Color = WpfGraphicsUtil.ColorToWpfColor( Color.FromArgb(oAlphaConverter.WorkbookToGraphAsByte( this.EdgeAlpha), this.EdgeColor) ); oEdgeDrawer.CurveStyle = this.EdgeCurveStyle; oEdgeDrawer.BezierDisplacementFactor = this.EdgeBezierDisplacementFactor; oEdgeDrawer.SelectedColor = WpfGraphicsUtil.ColorToWpfColor( this.SelectedEdgeColor); oEdgeDrawer.RelativeArrowSize = this.RelativeArrowSize; oVertexDrawer.Shape = this.VertexShape; oVertexDrawer.Radius = (new VertexRadiusConverter()).WorkbookToGraph( this.VertexRadius); oVertexDrawer.Effect = this.VertexEffect; oVertexDrawer.RelativeOuterGlowSize = this.VertexRelativeOuterGlowSize; oVertexDrawer.Color = WpfGraphicsUtil.ColorToWpfColor( Color.FromArgb(oAlphaConverter.WorkbookToGraphAsByte( this.VertexAlpha), this.VertexColor) ); oVertexDrawer.SelectedColor = WpfGraphicsUtil.ColorToWpfColor( this.SelectedVertexColor); }
GetEdgeEndpointOnRectangle ( Point oVertexALocation, Rect oVertexARectangle, Point oVertexBLocation, out Point oEdgeEndpoint ) { AssertValid(); if (oVertexALocation == oVertexBLocation) { oEdgeEndpoint = oVertexALocation; return; } Double dVertexAX = oVertexALocation.X; Double dVertexAY = oVertexALocation.Y; Double dVertexBX = oVertexBLocation.X; Double dVertexBY = oVertexBLocation.Y; Double dHalfVertexARectangleWidth = oVertexARectangle.Width / 2.0; Double dHalfVertexARectangleHeight = oVertexARectangle.Height / 2.0; // Get the angle between vertex A and vertex B. Double dEdgeAngle = WpfGraphicsUtil.GetAngleBetweenPointsRadians( oVertexALocation, oVertexBLocation); // Get the angle that defines the aspect ratio of vertex A's rectangle. Double dAspectAngle = Math.Atan2( dHalfVertexARectangleHeight, dHalfVertexARectangleWidth); if (dEdgeAngle >= -dAspectAngle && dEdgeAngle < dAspectAngle) { // For a square, this is -45 degrees to 45 degrees. Debug.Assert(dVertexBX != dVertexAX); oEdgeEndpoint = new Point( dVertexAX + dHalfVertexARectangleWidth, dVertexAY + dHalfVertexARectangleWidth * ((dVertexBY - dVertexAY) / (dVertexBX - dVertexAX)) ); return; } if (dEdgeAngle >= dAspectAngle && dEdgeAngle < Math.PI - dAspectAngle) { // For a square, this is 45 degrees to 135 degrees. Debug.Assert(dVertexBY != dVertexAY); oEdgeEndpoint = new Point( dVertexAX + dHalfVertexARectangleHeight * ((dVertexBX - dVertexAX) / (dVertexAY - dVertexBY)), dVertexAY - dHalfVertexARectangleHeight ); return; } if (dEdgeAngle < -dAspectAngle && dEdgeAngle >= -Math.PI + dAspectAngle) { // For a square, this is -45 degrees to -135 degrees. Debug.Assert(dVertexBY != dVertexAY); oEdgeEndpoint = new Point( dVertexAX + dHalfVertexARectangleHeight * ((dVertexBX - dVertexAX) / (dVertexBY - dVertexAY)), dVertexAY + dHalfVertexARectangleHeight ); return; } // For a square, this is 135 degrees to 180 degrees and -135 degrees to // -180 degrees. Debug.Assert(dVertexAX != dVertexBX); oEdgeEndpoint = new Point( dVertexAX - dHalfVertexARectangleWidth, dVertexAY + dHalfVertexARectangleWidth * ((dVertexBY - dVertexAY) / (dVertexAX - dVertexBX)) ); }
GetBezierControlPoint ( GraphDrawingContext oGraphDrawingContext, Point oEndpoint1, Point oEndpoint2, Double dBezierDisplacementFactor ) { Debug.Assert(oGraphDrawingContext != null); Debug.Assert(dBezierDisplacementFactor >= 0); AssertValid(); // This method finds the midpoint of the straight line between the two // endpoints, then calculates a point that is displaced from the // midpoint at a right angle. This is analagous to pulling a taut // string at its midpoint. // // The calculations are based on the anonymous post "How Can I // Calculate The Cartesian Coordinates Of A The Third Corner Of A // Triangle If I Have The Lengths Of All Three Sides And The // Coordinates Of The First Two Corners?" at // http://www.blurtit.com/q9044151.html. // Point a, the first endpoint, is one vertex of a right triangle. Double dPointAX = oEndpoint1.X; Double dPointAY = oEndpoint1.Y; // Point b, the midpoint of the line between the two endpoints, is // another vertex of the right triangle. The angle at b is 90 degrees. Double dPointBX = dPointAX + (oEndpoint2.X - dPointAX) / 2.0; Double dPointBY = dPointAY + (oEndpoint2.Y - dPointAY) / 2.0; // Side C connects points a and b. Double dSideCLength = WpfGraphicsUtil.GetDistanceBetweenPoints( new Point(dPointBX, dPointBY), oEndpoint1); // Side A connects points b and c, where c is the point we need to // calculate. Make the length of A, which is the displacement // mentioned above, proportional to the length of the line between the // two endpoints, so that a longer line gets displaced more than a // shorter line. Double dSideALength = dSideCLength * dBezierDisplacementFactor; // Calculate the angle of the line between the two endpoints. Double dAbsAtan2 = Math.Abs(Math.Atan2( Math.Max(oEndpoint2.Y, dPointAY) - Math.Min(oEndpoint2.Y, dPointAY), Math.Max(oEndpoint2.X, dPointAX) - Math.Min(oEndpoint2.X, dPointAX) )); Rect oGraphRectangle = oGraphDrawingContext.GraphRectangle; if (dAbsAtan2 >= Math.PI / 4.0 && dAbsAtan2 <= 3.0 * Math.PI / 4.0) { // The line between the two endpoints is closer to vertical than // horizontal. // // As explained in the post mentioned above, the length of side A // can be negative or positive, depending on which direction point // c should be displaced. The following adjustments to // dSideALength were determined experimentally. if (oEndpoint2.Y > dPointAY) { dSideALength *= -1.0; } if (dPointBX - oGraphRectangle.Left < oGraphRectangle.Right - dPointBX) { dSideALength *= -1.0; } } else { // The line between the two endpoints is closer to horizontal than // vertical. if (oEndpoint2.X < dPointAX) { dSideALength *= -1.0; } if (dPointBY - oGraphRectangle.Top < oGraphRectangle.Bottom - dPointBY) { dSideALength *= -1.0; } } // Calculate point c. Double dPointCX = dPointBX + (dSideALength * (dPointAY - dPointBY)) / dSideCLength; Double dPointCY = dPointBY + (dSideALength * (dPointBX - dPointAX)) / dSideCLength; // Don't let point c fall outside the graph's margins. return(WpfGraphicsUtil.MovePointWithinBounds( new Point(dPointCX, dPointCY), oGraphDrawingContext.GraphRectangleMinusMargin)); }
DrawArrow ( DrawingContext oDrawingContext, Point oArrowTipLocation, Double dArrowAngle, Color oColor, Double dEdgeWidth ) { Debug.Assert(oDrawingContext != null); Debug.Assert(dEdgeWidth > 0); AssertValid(); // Compute the arrow's dimensions. The width factor is arbitrary and // was determined experimentally. const Double WidthFactor = 1.5; Double dArrowTipX = oArrowTipLocation.X; Double dArrowTipY = oArrowTipLocation.Y; Double dArrowWidth = WidthFactor * dEdgeWidth * m_dRelativeArrowSize; Double dArrowHalfHeight = dArrowWidth / 2.0; Double dX = dArrowTipX - dArrowWidth; // Compute the arrow's three points as if the arrow were at an angle of // zero degrees, then use a rotated transform to adjust for the actual // specified angle. Point [] aoPoints = new Point [] { // Index 0: Arrow tip. oArrowTipLocation, // Index 1: Arrow bottom. new Point(dX, dArrowTipY - dArrowHalfHeight), // Index 2: Arrow top. new Point(dX, dArrowTipY + dArrowHalfHeight), // Index 3: Center of the flat end of the arrow. // // Note: The 0.2 is to avoid a gap between the edge endcap and the // flat end of the arrow, but it sometimes causes the two to // overlap slightly, and that can show if the edge isn't opaque. // What is the correct way to get the endcap to merge invisibly // with the arrow? new Point(dX + 0.2, dArrowTipY) }; Matrix oMatrix = WpfGraphicsUtil.GetRotatedMatrix(oArrowTipLocation, -MathUtil.RadiansToDegrees(dArrowAngle)); oMatrix.Transform(aoPoints); PathGeometry oArrow = WpfGraphicsUtil.PathGeometryFromPoints( aoPoints[0], aoPoints[1], aoPoints[2]); oDrawingContext.DrawGeometry(GetBrush(oColor), null, oArrow); return(aoPoints[3]); }
GetEdgeEndpoint ( Point otherEndpoint, out Point edgeEndpoint ) { AssertValid(); Point oVertexLocation = this.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.GetAngleBetweenPointsRadians( oVertexLocation, otherEndpoint); 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(otherEndpoint); // 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); }
GetDashStyle ( IEdge oEdge, Double dWidth, Boolean bDrawAsSelected ) { Debug.Assert(oEdge != null); Debug.Assert(dWidth >= 0); AssertValid(); // Note: // // An early implementation used the predefined DashStyle objects // provided by the DashStyles class, but those did not look good at // smaller edge widths. This implementation builds the DashStyle's // Dashes collection from scratch. Double [] adDashes = null; if (!bDrawAsSelected) { Object oPerEdgeStyleAsObject; // Check for a per-edge style. if (oEdge.TryGetValue(ReservedMetadataKeys.PerEdgeStyle, typeof(EdgeStyle), out oPerEdgeStyleAsObject)) { switch ((EdgeStyle)oPerEdgeStyleAsObject) { case EdgeStyle.Solid: break; case EdgeStyle.Dash: adDashes = new Double[] { 4.0, 2.0 }; break; case EdgeStyle.Dot: adDashes = new Double[] { 1.0, 2.0 }; break; case EdgeStyle.DashDot: adDashes = new Double[] { 4.0, 2.0, 1.0, 2.0 }; break; case EdgeStyle.DashDotDot: adDashes = new Double[] { 4.0, 2.0, 1.0, 2.0, 1.0, 2.0 }; break; default: throw new FormatException(String.Format( "{0}: The edge with the ID {1} has an invalid {2}" + " value." , this.ClassName, oEdge.ID, "ReservedMetadataKeys.PerEdgeStyle" )); } } } if (adDashes == null) { return(DashStyles.Solid); } DashStyle oDashStyle = new DashStyle(); oDashStyle.Dashes = new DoubleCollection(adDashes); WpfGraphicsUtil.FreezeIfFreezable(oDashStyle); return(oDashStyle); }
TryDrawEdge ( IEdge edge, GraphDrawingContext graphDrawingContext, out EdgeDrawingHistory edgeDrawingHistory ) { Debug.Assert(edge != null); Debug.Assert(graphDrawingContext != null); AssertValid(); edgeDrawingHistory = null; // If the edge is hidden, do nothing. VisibilityKeyValue eVisibility = GetVisibility(edge); if (eVisibility == VisibilityKeyValue.Hidden) { return(false); } Boolean bDrawAsSelected = GetDrawAsSelected(edge); Color oColor = GetColor(edge, eVisibility, bDrawAsSelected); Double dWidth = GetWidth(edge, bDrawAsSelected); DashStyle oDashStyle = GetDashStyle(edge, dWidth, bDrawAsSelected); Boolean bDrawArrow = (m_bDrawArrowOnDirectedEdge && edge.IsDirected); IVertex [] aoVertices = edge.Vertices; DrawingVisual oDrawingVisual = new DrawingVisual(); using (DrawingContext oDrawingContext = oDrawingVisual.RenderOpen()) { if (edge.IsSelfLoop) { if (!TryDrawSelfLoop(aoVertices[0], oDrawingContext, graphDrawingContext, oColor, dWidth, bDrawArrow)) { // The edge's vertex is hidden, so the edge should be // hidden also. return(false); } } else { Point oEdgeEndpoint1, oEdgeEndpoint2; if (!TryGetEdgeEndpoints(aoVertices[0], aoVertices[1], graphDrawingContext, out oEdgeEndpoint1, out oEdgeEndpoint2)) { // One of the edge's vertices is hidden, so the edge should // be hidden also. return(false); } if (bDrawArrow) { // Draw the arrow and set the second endpoint to the center // of the flat end of the arrow. Double dArrowAngle = WpfGraphicsUtil.GetAngleBetweenPoints( oEdgeEndpoint1, oEdgeEndpoint2); oEdgeEndpoint2 = DrawArrow(oDrawingContext, oEdgeEndpoint2, dArrowAngle, oColor, dWidth); } // Draw the edge. oDrawingContext.DrawLine(GetPen(oColor, dWidth, oDashStyle), oEdgeEndpoint1, oEdgeEndpoint2); // Draw the edge's label, if there is one. Object oLabelAsObject; if (edge.TryGetValue(ReservedMetadataKeys.PerEdgeLabel, typeof(String), out oLabelAsObject) && oLabelAsObject != null) { DrawLabel(oDrawingContext, graphDrawingContext, oEdgeEndpoint1, oEdgeEndpoint2, (String)oLabelAsObject, oColor); } } // Retain information about the edge that was drawn. edgeDrawingHistory = new EdgeDrawingHistory( edge, oDrawingVisual, bDrawAsSelected); return(true); } }
DrawLabel ( DrawingContext oDrawingContext, GraphDrawingContext oGraphDrawingContext, Point oEdgeEndpoint1, Point oEdgeEndpoint2, String sLabel, Color oColor ) { Debug.Assert(oDrawingContext != null); Debug.Assert(oGraphDrawingContext != null); Debug.Assert(sLabel != null); AssertValid(); if (sLabel.Length == 0) { return; } sLabel = TruncateLabel(sLabel); if (oEdgeEndpoint2.X < oEdgeEndpoint1.X) { // Don't let text be drawn upside-down. Point oTemp = oEdgeEndpoint2; oEdgeEndpoint2 = oEdgeEndpoint1; oEdgeEndpoint1 = oTemp; } Double dEdgeAngleDegrees = MathUtil.RadiansToDegrees( WpfGraphicsUtil.GetAngleBetweenPoints( oEdgeEndpoint1, oEdgeEndpoint2)); Double dEdgeLength = WpfGraphicsUtil.GetDistanceBetweenPoints( oEdgeEndpoint1, oEdgeEndpoint2); // To avoid trigonometric calculations, use a RotateTransform to make // the edge look as if it is horizontal, with oEdgeEndpoint2 to the // right of oEdgeEndpoint1. RotateTransform oRotateTransform = new RotateTransform( dEdgeAngleDegrees, oEdgeEndpoint1.X, oEdgeEndpoint1.Y); oEdgeEndpoint2 = oRotateTransform.Transform(oEdgeEndpoint2); oRotateTransform.Angle = -dEdgeAngleDegrees; oDrawingContext.PushTransform(oRotateTransform); FormattedText oFormattedText = CreateFormattedText(sLabel, oColor); oFormattedText.Trimming = TextTrimming.CharacterEllipsis; if (sLabel.IndexOf('\n') == -1) { // Unless the label includes line breaks, don't allow the // FormattedText class to break the text into multiple lines. oFormattedText.MaxLineCount = 1; } Double dTextWidth = oFormattedText.Width; // The ends of the label text are between one and two "buffer units" // from the ends of the edge. The buffer unit is the width of an // arbitrary character. Double dBufferUnit = CreateFormattedText("i", oColor).Width; Double dEdgeLengthMinusBuffers = dEdgeLength - 2 * dBufferUnit; if (dEdgeLengthMinusBuffers <= 0) { return; } // Determine where to draw the label text, and where to draw a // translucent rectangle behind the text. The translucent rectangle // serves to obscure, but not completely hide, the underlying edge. Point oLabelOrigin = oEdgeEndpoint1; Rect oTranslucentRectangle; if (dTextWidth > dEdgeLengthMinusBuffers) { // The label text should start one buffer unit from the first // endpoint, and terminate with ellipses approximately one buffer // length from the second endpoint. oLabelOrigin.Offset(dBufferUnit, 0); oFormattedText.MaxTextWidth = dEdgeLengthMinusBuffers; // The translucent rectangle should be the same width as the text. oTranslucentRectangle = new Rect(oLabelOrigin, new Size(dEdgeLengthMinusBuffers, oFormattedText.Height)); } else { // The label should be centered along the edge's length. oLabelOrigin.Offset(dEdgeLength / 2.0, 0); oFormattedText.TextAlignment = TextAlignment.Center; // The translucent rectangle should extend between zero and one // buffer units beyond the ends of the text. This provides a // margin between the text and the unobscured edge, if there is // enough space. oTranslucentRectangle = new Rect(oLabelOrigin, new Size( Math.Min(dTextWidth + 2 * dBufferUnit, dEdgeLengthMinusBuffers), oFormattedText.Height) ); oTranslucentRectangle.Offset( -oTranslucentRectangle.Width / 2.0, 0); } // The text and rectangle should be vertically centered on the edge. oDrawingContext.PushTransform( new TranslateTransform(0, -oFormattedText.Height / 2.0)); // Draw the translucent rectangle, then the text. // // Note: Don't make the rectangle any more opaque than the edge, which // might be translucent itself. oDrawingContext.DrawRectangle(GetBrush( WpfGraphicsUtil.SetWpfColorAlpha(oGraphDrawingContext.BackColor, Math.Min(LabelBackgroundAlpha, oColor.A)) ), null, oTranslucentRectangle); oDrawingContext.DrawText(oFormattedText, oLabelOrigin); oDrawingContext.Pop(); oDrawingContext.Pop(); }
TransferToGraphDrawer ( GraphDrawer graphDrawer ) { Debug.Assert(graphDrawer != null); AssertValid(); System.Windows.Media.Typeface oTypeface; Double dFontSize; //*********** // Vertex //*********** VertexDrawer oVertexDrawer = graphDrawer.VertexDrawer; FontToTypefaceAndFontSize(this.VertexFont, out oTypeface, out dFontSize); oVertexDrawer.SetFont(oTypeface, dFontSize); oVertexDrawer.LabelFillColor = WpfGraphicsUtil.ColorToWpfColor(this.VertexLabelFillColor); oVertexDrawer.LabelPosition = this.VertexLabelPosition; oVertexDrawer.MaximumLabelLength = this.VertexLabelMaximumLength; oVertexDrawer.LabelWrapText = this.VertexLabelWrapText; oVertexDrawer.LabelWrapMaxTextWidth = this.VertexLabelWrapMaxTextWidth; //*********** // Edge //*********** EdgeDrawer oEdgeDrawer = graphDrawer.EdgeDrawer; FontToTypefaceAndFontSize(this.EdgeFont, out oTypeface, out dFontSize); oEdgeDrawer.SetFont(oTypeface, dFontSize); oEdgeDrawer.LabelTextColor = WpfGraphicsUtil.ColorToWpfColor(this.EdgeLabelTextColor); oEdgeDrawer.MaximumLabelLength = this.EdgeLabelMaximumLength; //*********** // Group //*********** GroupDrawer oGroupDrawer = graphDrawer.GroupDrawer; FontToTypefaceAndFontSize(this.GroupFont, out oTypeface, out dFontSize); oGroupDrawer.SetFont(oTypeface, dFontSize); oGroupDrawer.LabelTextColor = WpfGraphicsUtil.ColorToWpfColor( Color.FromArgb((new AlphaConverter()).WorkbookToGraphAsByte( this.GroupLabelTextAlpha), this.GroupLabelTextColor) ); oGroupDrawer.LabelPosition = this.GroupLabelPosition; }
SaveGraphImageFile ( NodeXLControl oNodeXLControl, IEnumerable <LegendControlBase> oLegendControls, String sWorkbookFilePath ) { Debug.Assert(oNodeXLControl != null); Debug.Assert(oLegendControls != null); Debug.Assert(!String.IsNullOrEmpty(sWorkbookFilePath)); AutomatedGraphImageUserSettings oAutomatedGraphImageUserSettings = new AutomatedGraphImageUserSettings(); System.Drawing.Size oImageSizePx = oAutomatedGraphImageUserSettings.ImageSizePx; Int32 iWidth = oImageSizePx.Width; Int32 iHeight = oImageSizePx.Height; Boolean bIncludeHeader = oAutomatedGraphImageUserSettings.IncludeHeader; Boolean bIncludeFooter = oAutomatedGraphImageUserSettings.IncludeFooter; Debug.Assert(!bIncludeHeader || oAutomatedGraphImageUserSettings.HeaderText != null); Debug.Assert(!bIncludeFooter || oAutomatedGraphImageUserSettings.FooterText != null); GraphImageCompositor oGraphImageCompositor = new GraphImageCompositor(oNodeXLControl); UIElement oCompositeElement = oGraphImageCompositor.Composite( iWidth, iHeight, bIncludeHeader ? oAutomatedGraphImageUserSettings.HeaderText : null, bIncludeFooter ? oAutomatedGraphImageUserSettings.FooterText : null, oAutomatedGraphImageUserSettings.HeaderFooterFont, oLegendControls ); System.Drawing.Bitmap oBitmap = WpfGraphicsUtil.VisualToBitmap( oCompositeElement, iWidth, iHeight); ImageFormat eImageFormat = oAutomatedGraphImageUserSettings.ImageFormat; String sImageFilePath = Path.ChangeExtension(sWorkbookFilePath, SaveableImageFormats.GetFileExtension(eImageFormat)); try { oBitmap.Save(sImageFilePath, eImageFormat); } catch (System.Runtime.InteropServices.ExternalException) { // When an image file already exists and is read-only, an // ExternalException is thrown. // // Note that this method is called from the // ThisWorkbook.GraphLaidOut event handler, so this exception can't // be handled by a TaskAutomator.AutomateOneWorkbook() exception // handler. FormUtil.ShowWarning(String.Format( "The image file \"{0}\" couldn't be saved. Does a read-only" + " file with the same name already exist?" , sImageFilePath )); } finally { oBitmap.Dispose(); oGraphImageCompositor.RestoreNodeXLControl(); } }