in Clients/Xamarin.Interactive.Client.Mac/MacHtmlResultRenderer.cs [188:379]
static string RenderRectangle(XIR.Rect rectangle)
{
var base64 = string.Empty;
var size = new CGSize (rectangle.Width, rectangle.Height);
var origin = new CGPoint (rectangle.X, rectangle.Y);
// We want the absolute values of the size
var workSize = new CGSize(Math.Abs (size.Width), Math.Abs (size.Height));
// This is our scale factor for output
var dstSize = new CGSize (100, 100);
// Define our Height label variables
var numHeightLabelBounds = CGSize.Empty;
var heightLabelBounds = CGSize.Empty;
var heightBounds = CGSize.Empty;
// Obtain our label lines and bounding boxes of the labels
var numHeightLine = GetLabel (string.Format ("{0:0.########}", size.Height), out numHeightLabelBounds);
var heightLine = GetSubLabel ("Height", out heightLabelBounds);
heightBounds.Width = NMath.Max (numHeightLabelBounds.Width, heightLabelBounds.Width);
heightBounds.Height = NMath.Max (numHeightLabelBounds.Height, heightLabelBounds.Height);
// Define our Width label variables
var numWidthLabelBounds = CGSize.Empty;
var widthLabelBounds = CGSize.Empty;
var widthBounds = CGSize.Empty;
// Obtain our label lines and bound boxes of the labels
var numWidthLine = GetLabel (string.Format ("{0:0.########}", size.Width), out numWidthLabelBounds);
var widthLine = GetSubLabel ("Width", out widthLabelBounds);
widthBounds.Width = NMath.Max (numWidthLabelBounds.Width, widthLabelBounds.Width);
widthBounds.Height = NMath.Max (numWidthLabelBounds.Height, widthLabelBounds.Height);
// Define our Width label variables
var originLabelBounds = CGSize.Empty;
var xyLabelBounds = CGSize.Empty;
var originBounds = CGSize.Empty;
// Obtain our label lines and bound boxes of the labels
var originLine = GetLabel (string.Format ("({0:0.########}, {1:0.########})", origin.X, origin.Y), out originLabelBounds);
var xyLine = GetSubLabel ("x, y", out xyLabelBounds);
originBounds.Width = NMath.Max (originLabelBounds.Width, xyLabelBounds.Width);
originBounds.Height = NMath.Max (originLabelBounds.Height, xyLabelBounds.Height);
// Calculate our scale based on our destination size
var ratio = 1f;
if (!workSize.IsEmpty)
{
if (workSize.Width > workSize.Height) {
ratio = (float)workSize.Height / (float)workSize.Width;
dstSize.Height = (int)(dstSize.Height * ratio);
} else {
ratio = (float)workSize.Width / (float)workSize.Height;
dstSize.Width = (int)(dstSize.Width * ratio);
}
// Make sure we at least have something to draw if the values are very small
dstSize.Width = NMath.Max (dstSize.Width, 4f);
dstSize.Height = NMath.Max (dstSize.Height, 4f);
}
else
{
dstSize = CGSize.Empty;
}
// Define graphic element sizes and offsets
var lineWidth = 2;
var capSize = 8f;
var vCapIndent = 3f;
var separationSpace = 2f;
var dotSize = new CGSize (6, 6);
var extraBoundingSpaceWidth = (widthBounds.Width + separationSpace) * 2;
var extraBoundingSpaceHeight = (heightBounds.Height + separationSpace) * 2;
int width = (int)(dstSize.Width + lineWidth + capSize + vCapIndent + extraBoundingSpaceWidth);
int height = (int)(dstSize.Height + lineWidth + capSize + extraBoundingSpaceHeight + originBounds.Height * 2);
var bytesPerRow = 4 * width;
using (var context = new CGBitmapContext (
IntPtr.Zero, width, height,
8, bytesPerRow, CGColorSpace.CreateDeviceRGB (),
CGImageAlphaInfo.PremultipliedFirst))
{
// Clear the context with our background color
context.SetFillColor (BackgroundColor.CGColor);
context.FillRect (new CGRect(0,0,width,height));
// Setup our matrices so our 0,0 is top left corner. Just makes it easier to layout
context.ConcatCTM (context.GetCTM().Invert());
var matrix = new CGAffineTransform (
1, 0, 0, -1, 0, height);
context.ConcatCTM (matrix);
context.SetStrokeColor (pen.CGColor);
context.SetFillColor (pen.CGColor);
context.SetLineWidth (lineWidth);
context.SaveState ();
// We need to offset the drawing of our size segment rulers leaving room for labels
var xOffSet = heightBounds.Width;
var yOffset = ((height + originBounds.Height * 2) - extraBoundingSpaceHeight) / 2f - dstSize.Height / 2f;
context.TranslateCTM (xOffSet, yOffset);
context.AddEllipseInRect (new CGRect (vCapIndent - dotSize.Width / 2f, vCapIndent - dotSize.Height / 2f, dotSize.Width, dotSize.Height));
context.FillPath ();
context.AddRect (new CGRect (vCapIndent, vCapIndent, dstSize.Width, dstSize.Height));
context.StrokePath ();
context.RestoreState ();
// Setup our text matrix
var textMatrix = new CGAffineTransform (
1, 0, 0, -1, 0, 0);
context.TextMatrix = textMatrix;
// Draw the Origin labels
context.TextPosition = new CGPoint ((xOffSet + vCapIndent) - originLabelBounds.Width / 2, originLabelBounds.Height);
originLine.Draw (context);
context.TextPosition = new CGPoint ((xOffSet + vCapIndent) - xyLabelBounds.Width / 2, originLabelBounds.Height * 2);
xyLine.Draw (context);
// Draw the Height label
var heightCenter = yOffset + ((dstSize.Height / 2) + ((vCapIndent + lineWidth) * 2));
context.TextPosition = new CGPoint (heightBounds.Width / 2 - numHeightLabelBounds.Width / 2, heightCenter - heightBounds.Height / 2f);
numHeightLine.Draw (context);
context.TextPosition = new CGPoint (heightBounds.Width / 2 - heightLabelBounds.Width / 2, heightCenter + heightBounds.Height / 2f);
heightLine.Draw (context);
// Draw the Width label
var widthOffsetX = heightBounds.Width + ((dstSize.Width / 2) - ((lineWidth + vCapIndent) * 2));// xOffSet - vCapIndent - lineWidth + dstSize.Width / 2f;
context.TextPosition = new CGPoint (widthOffsetX + (widthBounds.Width / 2 - numWidthLabelBounds.Width / 2), height - widthBounds.Height - 2f);
numWidthLine.Draw (context);
context.TextPosition = new CGPoint (widthOffsetX + (widthBounds.Width / 2 - widthLabelBounds.Width / 2), height - widthLabelBounds.Height / 2f);
widthLine.Draw (context);
// Get rid of our lines
numHeightLine.Dispose ();
heightLine.Dispose ();
numWidthLine.Dispose ();
widthLine.Dispose ();
originLine.Dispose ();
xyLine.Dispose ();
// Convert to base64 for display
var bitmap = new NSBitmapImageRep (context.ToImage());
var data = bitmap.RepresentationUsingTypeProperties (NSBitmapImageFileType.Png);
base64 = data.GetBase64EncodedString (NSDataBase64EncodingOptions.None);
}
return String.Format (
"<figure>" +
"<figcatpion>" +
"Rectangle: " +
"<span class='var'>X</span> = <span class='value'>{0:0.########}</span>, " +
"<span class='var'>Y</span> = <span class='value'>{1:0.########}</span>, " +
"<span class='var'>Width</span> = <span class='value'>{2:0.########}</span>, " +
"<span class='var'>Height</span> = <span class='value'>{3:0.########}</span>" +
"</figcaption>" +
"<img width='{4}' height='{5}' src='data:image/png;base64,{6}' />" +
"</figure>",
origin.X, origin.Y,
size.Width, size.Height,
(int)width,
(int)height,
base64
);
}