public virtual void Rotate(Xwt.Drawing.Context ctx, double x, double y) { ctx.Save(); ctx.Translate(x + 30, y + 30); ctx.SetLineWidth(3); // Rotation double end = 270; for (double n = 0; n <= end; n += 5) { ctx.Save(); ctx.Rotate(n); ctx.MoveTo(0, 0); ctx.RelLineTo(30, 0); double c = n / end; ctx.SetColor(new Color(c, c, c)); ctx.Stroke(); ctx.Restore(); } //ctx.ResetTransform(); ctx.Restore(); }
public virtual void Rotate(Xwt.Drawing.Context ctx, double x, double y) { // draws a line along the x-axis from (0,0) to (r,0) with a constant translation and an increasing // rotational component. This composite transform is then applied to a vertical line, with inverse // color, and an additional x-offset, to form a mirror image figure for easy visual comparison. // These transformed points must be drawn with the identity CTM, hence the Restore() each time. ctx.Save(); // save caller's context (assumed to be the Identity CTM) ctx.SetLineWidth(3); // should align exactly if drawn with half-pixel coordinates // Vector length (pixels) and rotation limit (degrees) double r = 30; double end = 270; for (double n = 0; n <= end; n += 5) { ctx.Save(); // save context and identity CTM for each line // Set up translation to centre point of first figure, ensuring pixel alignment ctx.Translate(x + 30.5, y + 30.5); ctx.Rotate(n); ctx.MoveTo(0, 0); ctx.RelLineTo(r, 0); double c = n / end; ctx.SetColor(new Color(c, c, c)); ctx.Stroke(); // stroke first figure with composite Translation and Rotation CTM // Generate mirror image figure as a visual test of TransformPoints Point p0 = new Point(0, 0); Point p1 = new Point(0, -r); Point[] p = new Point[] { p0, p1 }; ctx.TransformPoints(p); // using composite transformation ctx.Restore(); // restore identity CTM ctx.Save(); // save again (to restore after additional Translation) ctx.Translate(2 * r + 1, 0); // extra x-offset to clear first figure ctx.MoveTo(p[0]); ctx.LineTo(p[1]); c = 1 - c; ctx.SetColor(new Color(c, c, c)); ctx.Stroke(); // stroke transformed points with offset in CTM ctx.Restore(); // restore identity CTM for next line } ctx.Restore(); // restore caller's context }
protected override void OnDraw(Xwt.Drawing.Context ctx) { base.OnDraw(ctx); ctx.Translate(30, 30); double end = 270; for (double n = 0; n <= end; n += 5) { ctx.Save(); ctx.Rotate(n); ctx.MoveTo(0, 0); ctx.RelLineTo(30, 0); double c = n / end; ctx.SetColor(new Color(c, c, c)); ctx.Stroke(); ctx.Restore(); } }
public virtual void Rotate(Xwt.Drawing.Context ctx, double x, double y) { ctx.Save(); ctx.Translate(x + 30, y + 30); ctx.SetLineWidth(3); // Rotation double end = 270; double r = 30; for (double n = 0; n <= end; n += 5) { ctx.Save(); ctx.Rotate(n); ctx.MoveTo(0, 0); ctx.RelLineTo(r, 0); double c = n / end; ctx.SetColor(new Color(c, c, c)); ctx.Stroke(); // Visual test for TransformPoints Point p0 = new Point(0, 0); Point p1 = new Point(0, -r); Point[] p = new Point[] { p0, p1 }; ctx.TransformPoints(p); ctx.ResetTransform(); ctx.Translate(2 * r + 1, 0); ctx.MoveTo(p[0]); ctx.LineTo(p[1]); c = 1 - c; ctx.SetColor(new Color(c, c, c)); ctx.Stroke(); ctx.Restore(); } ctx.Restore(); }
public virtual void Texts(Xwt.Drawing.Context ctx, double x, double y) { ctx.Save(); ctx.Translate(x, y); ctx.SetColor(Colors.Black); var col1 = new Rectangle(); var col2 = new Rectangle(); var text = new TextLayout(); text.Font = this.Font.WithSize(24); Console.WriteLine(text.Font.Size); // first text text.Text = "Lorem ipsum dolor sit amet,"; var size1 = text.GetSize(); col1.Width = size1.Width; col1.Height += size1.Height + 10; ctx.DrawTextLayout(text, 0, 0); // proofing width; test should align with text above ctx.SetColor(Colors.DarkMagenta); text.Text = "consetetur sadipscing elitr, sed diam nonumy"; text.Width = col1.Width; var size2 = text.GetSize(); ctx.DrawTextLayout(text, 0, col1.Bottom); col1.Height += size2.Height + 10; ctx.SetColor(Colors.Black); // proofing scale, on second col ctx.Save(); ctx.SetColor(Colors.Red); col2.Left = col1.Right + 10; text.Text = "eirmod tempor invidunt ut."; var scale = 1.2; text.Width = text.Width / scale; var size3 = text.GetSize(); col2.Height = size3.Height * scale; col2.Width = size3.Width * scale + 5; ctx.Scale(scale, scale); ctx.DrawTextLayout(text, col2.Left / scale, col2.Top / scale); ctx.Restore(); // proofing heigth, on second col ctx.Save(); ctx.SetColor(Colors.DarkCyan); text.Text = "Praesent ac lacus nec dolor pulvinar feugiat a id elit."; var size4 = text.GetSize(); text.Height = size4.Height / 2; text.Trimming = TextTrimming.WordElipsis; ctx.DrawTextLayout(text, col2.Left, col2.Bottom + 5); ctx.SetLineWidth(1); ctx.SetColor(Colors.Blue); ctx.Rectangle(new Rectangle(col2.Left, col2.Bottom + 5, text.Width, text.Height)); ctx.Stroke(); ctx.Restore(); // drawing col line ctx.SetLineWidth(1); ctx.SetColor(Colors.Black.WithAlpha(.5)); ctx.MoveTo(col1.Right + 5, col1.Top); ctx.LineTo(col1.Right + 5, col1.Bottom); ctx.Stroke(); ctx.MoveTo(col2.Right + 5, col2.Top); ctx.LineTo(col2.Right + 5, col2.Bottom); ctx.Stroke(); ctx.SetColor(Colors.Black); // proofing rotate, and printing size to see the values ctx.Save(); text.Font = this.Font.WithSize(10); text.Text = string.Format("Size 1 {0}\r\nSize 2 {1}\r\nSize 3 {2} Scale {3}", size1, size2, size3, scale); text.Width = -1; // this clears textsize text.Height = -1; ctx.Rotate(5); // maybe someone knows a formula with angle and textsize to calculyte ty var ty = 30; ctx.DrawTextLayout(text, ty, col1.Bottom + 10); ctx.Restore(); // scale example here: ctx.Restore(); TextLayout tl0 = new TextLayout(this); tl0.Font = this.Font.WithSize(10); tl0.Text = "This text contains attributes."; tl0.SetUnderline(0, "This".Length); tl0.SetForeground(new Color(0, 1.0, 1.0), "This ".Length, "text".Length); tl0.SetBackground(new Color(0, 0, 0), "This ".Length, "text".Length); tl0.SetFontWeight(FontWeight.Bold, "This text ".Length, "contains".Length); tl0.SetFontStyle(FontStyle.Italic, "This text ".Length, "contains".Length); tl0.SetStrikethrough("This text contains ".Length, "attributes".Length); ctx.DrawTextLayout(tl0, col2.Left, col2.Bottom + 100); // Text boces y = 180; // Without wrapping TextLayout tl = new TextLayout(this); tl.Text = "Stright text"; DrawText(ctx, tl, ref y); // With wrapping tl = new TextLayout(this); tl.Text = "The quick brown fox jumps over the lazy dog"; tl.Width = 100; DrawText(ctx, tl, ref y); // With blank lines tl = new TextLayout(this); tl.Text = "\nEmpty line above\nLine break above\n\nEmpty line above\n\n\nTwo empty lines above\nEmpty line below\n"; tl.Width = 200; DrawText(ctx, tl, ref y); }
/// <summary> /// Draw a tick on the axis. /// </summary> /// <param name="ctx">The Drawing Context with on which to draw.</param> /// <param name="w">The tick position in world coordinates.</param> /// <param name="size">The size of the tick (in pixels)</param> /// <param name="text">The text associated with the tick</param> /// <param name="textOffset">The Offset to draw from the auto calculated position</param> /// <param name="axisPhysMin">The minimum physical extent of the axis</param> /// <param name="axisPhysMax">The maximum physical extent of the axis</param> /// <param name="boundingBox">out: The bounding rectangle for the tick and tickLabel drawn</param> /// <param name="labelOffset">out: offset from the axies required for axis label</param> public virtual void DrawTick( Context ctx, double w, double size, string text, Point textOffset, Point axisPhysMin, Point axisPhysMax, out Point labelOffset, out Rectangle boundingBox ) { // determine physical location where tick touches axis. Point tickStart = WorldToPhysical (w, axisPhysMin, axisPhysMax, true); // determine offset from start point. Point axisDir = Utils.UnitVector (axisPhysMin, axisPhysMax); // rotate axisDir anti-clockwise by TicksAngle radians to get tick direction. Note that because // the physical (pixel) origin is at the top left, a RotationTransform by a positive angle will // be clockwise. Consequently, for anti-clockwise rotations, use cos(A-B), sin(A-B) formulae double x1 = Math.Cos (TicksAngle) * axisDir.X + Math.Sin (TicksAngle) * axisDir.Y; double y1 = Math.Cos (TicksAngle) * axisDir.Y - Math.Sin (TicksAngle) * axisDir.X; // now get the scaled tick vector. Point tickVector = new Point (TickScale * size * x1, TickScale * size * y1); if (TicksCrossAxis) { tickStart.X -= tickVector.X / 2; tickStart.Y -= tickVector.Y / 2; } // and the end point [point off axis] of tick mark. Point tickEnd = new Point (tickStart.X + tickVector.X, tickStart.Y + tickVector.Y); // and draw it ctx.SetLineWidth (1); ctx.SetColor (LineColor); ctx.MoveTo (tickStart.X+0.5, tickStart.Y+0.5); ctx.LineTo (tickEnd.X+0.5, tickEnd.Y+0.5); ctx.Stroke (); // calculate bounds of tick. double minX = Math.Min (tickStart.X, tickEnd.X); double minY = Math.Min (tickStart.Y, tickEnd.Y); double maxX = Math.Max (tickStart.X, tickEnd.X); double maxY = Math.Max (tickStart.Y, tickEnd.Y); boundingBox = new Rectangle (minX, minY, maxX-minX, maxY-minY); // by default, label offset from axis is 0. TODO: revise this. labelOffset = new Point (-tickVector.X, -tickVector.Y); // ------------------------ // now draw associated text. // **** TODO **** // The following code needs revising. A few things are hard coded when // they should not be. Also, angled tick text currently just works for // the bottom x-axis. Also, it's a bit hacky. if (text != "" && !HideTickText) { TextLayout layout = new TextLayout (); layout.Font = tickTextFontScaled; layout.Text = text; Size textSize = layout.GetSize (); // determine the center point of the tick text. double textCenterX; double textCenterY; // if text is at pointy end of tick. if (!TickTextNextToAxis) { // offset due to tick. textCenterX = tickStart.X + tickVector.X*1.2; textCenterY = tickStart.Y + tickVector.Y*1.2; // offset due to text box size. textCenterX += 0.5 * x1 * textSize.Width; textCenterY += 0.5 * y1 * textSize.Height; } // else it's next to the axis. else { // start location. textCenterX = tickStart.X; textCenterY = tickStart.Y; // offset due to text box size. textCenterX -= 0.5 * x1 * textSize.Width; textCenterY -= 0.5 * y1 * textSize.Height; // bring text away from the axis a little bit. textCenterX -= x1*(2.0+FontScale); textCenterY -= y1*(2.0+FontScale); } // If tick text is angled.. if (TickTextAngle != 0) { // determine the point we want to rotate text about. Point textScaledTickVector = new Point ( TickScale * x1 * (textSize.Height/2), TickScale * y1 * (textSize.Height/2) ); Point rotatePoint; if (TickTextNextToAxis) { rotatePoint = new Point ( tickStart.X - textScaledTickVector.X, tickStart.Y - textScaledTickVector.Y); } else { rotatePoint = new Point ( tickEnd.X + textScaledTickVector.X, tickEnd.Y + textScaledTickVector.Y); } double actualAngle; if (FlipTickText) { double radAngle = TickTextAngle * Math.PI / 180; rotatePoint.X += textSize.Width * Math.Cos (radAngle); rotatePoint.Y += textSize.Width * Math.Sin (radAngle); actualAngle = TickTextAngle + 180; } else { actualAngle = TickTextAngle; } ctx.Save (); ctx.Translate (rotatePoint.X, rotatePoint.Y); ctx.Rotate (actualAngle); Point [] recPoints = new Point [2]; recPoints[0] = new Point (0.0, -textSize.Height/2); recPoints[1] = new Point (textSize.Width, textSize.Height); ctx.TransformPoints (recPoints); double t_x1 = Math.Min (recPoints[0].X, recPoints[1].X); double t_x2 = Math.Max (recPoints[0].X, recPoints[1].X); double t_y1 = Math.Min (recPoints[0].Y, recPoints[1].Y); double t_y2 = Math.Max (recPoints[0].Y, recPoints[1].Y); boundingBox = Rectangle.Union (boundingBox, new Rectangle (t_x1, t_y1, (t_x2-t_x1), (t_y2-t_y1))); ctx.DrawTextLayout (layout, 0, -textSize.Height/2); t_x2 -= tickStart.X; t_y2 -= tickStart.Y; t_x2 *= 1.25; t_y2 *= 1.25; labelOffset = new Point (t_x2, t_y2); ctx.Restore (); //ctx.Rectangle (boundingBox.X, boundingBox.Y, boundingBox.Width, boundingBox.Height); //ctx.Stroke (); } else { double bx1 = (textCenterX - textSize.Width/2); double by1 = (textCenterY - textSize.Height/2); double bx2 = textSize.Width; double by2 = textSize.Height; Rectangle drawRect = new Rectangle (bx1, by1, bx2, by2); // ctx.Rectangle (drawRect); boundingBox = Rectangle.Union (boundingBox, drawRect); // ctx.Rectangle (boundingBox); ctx.DrawTextLayout (layout, bx1, by1); textCenterX -= tickStart.X; textCenterY -= tickStart.Y; textCenterX *= 2.3; textCenterY *= 2.3; labelOffset = new Point (textCenterX, textCenterY); } } }
/// <summary> /// Draw the Axis Label /// </summary> /// <param name="ctx>The Drawing Context with which to draw.</param> /// <param name="offset">offset from axis. Should be calculated so as to make sure axis label misses tick labels.</param> /// <param name="axisPhysicalMin">The physical position corresponding to the world minimum of the axis.</param> /// <param name="axisPhysicalMax">The physical position corresponding to the world maximum of the axis.</param> /// <returns>boxed Rectangle indicating bounding box of label. null if no label printed.</returns> public object DrawLabel(Context ctx, Point offset, Point axisPhysicalMin, Point axisPhysicalMax) { if (Label != "") { // first calculate any extra offset for axis label spacing. double extraOffsetAmount = LabelOffset; extraOffsetAmount += 2; // empirically determed - text was too close to axis before this. if (AutoScaleText && LabelOffsetScaled) { extraOffsetAmount *= FontScale; } // now extend offset. double offsetLength = Math.Sqrt (offset.X*offset.X + offset.Y*offset.Y); if (offsetLength > 0.01) { double x_component = offset.X / offsetLength; double y_component = offset.Y / offsetLength; x_component *= extraOffsetAmount; y_component *= extraOffsetAmount; if (LabelOffsetAbsolute) { offset.X = x_component; offset.Y = y_component; } else { offset.X += x_component; offset.Y += y_component; } } // determine angle of axis in degrees double theta = Math.Atan2 ( axisPhysicalMax.Y - axisPhysicalMin.Y, axisPhysicalMax.X - axisPhysicalMin.X); theta = theta * 180.0 / Math.PI; Point average = new Point ( (axisPhysicalMax.X + axisPhysicalMin.X)/2, (axisPhysicalMax.Y + axisPhysicalMin.Y)/2); ctx.Save (); ctx.Translate (average.X + offset.X , average.Y + offset.Y); // this is done last. ctx.Rotate (theta); // this is done first. TextLayout layout = new TextLayout (); layout.Font = labelFontScaled; layout.Text = Label; Size labelSize = layout.GetSize (); //Draw label centered around zero. ctx.DrawTextLayout (layout, -labelSize.Width/2, -labelSize.Height/2); // now work out physical bounds of Rotated and Translated label. Point [] recPoints = new Point [2]; recPoints[0] = new Point (-labelSize.Width/2, -labelSize.Height/2); recPoints[1] = new Point ( labelSize.Width/2, labelSize.Height/2); ctx.TransformPoints (recPoints); double x1 = Math.Min (recPoints[0].X, recPoints[1].X); double x2 = Math.Max (recPoints[0].X, recPoints[1].X); double y1 = Math.Min (recPoints[0].Y, recPoints[1].Y); double y2 = Math.Max (recPoints[0].Y, recPoints[1].Y); ctx.Restore (); // and return label bounding box. return new Rectangle (x1, y1, (x2-x1), (y2-y1)); } return null; }
public void Path (Context ctx, double px, double py) { ctx.Save (); ctx.Translate (px, py); var path = new DrawingPath (); path.MoveTo (0.44, 18); path.LineTo (-1, 18); path.LineTo (-1, 26); path.LineTo (0.44, 26); path.LineTo (0, 42); path.LineTo (29, 21.98); path.LineTo (29, 21.98); path.LineTo (0, 2); path.LineTo (0.44, 18); ctx.AppendPath (path); ctx.SetColor (Colors.Black); ctx.SetLineWidth (2); ctx.Stroke (); var path2 = path.CopyPath (); path2.LineTo (15, 8); path2.ClosePath (); ctx.Rotate (180); ctx.AppendPath (path2); ctx.SetColor (Colors.Red); ctx.SetLineDash (0, 5); ctx.Stroke (); ctx.Restore (); }
protected override void OnDraw(Xwt.Drawing.Context ctx) { base.OnDraw(ctx); // Simple rectangles ctx.SetLineWidth(1); ctx.Rectangle(100, 5, 10, 10); ctx.SetColor(Color.Black); ctx.Fill(); ctx.Rectangle(115, 5, 10, 10); ctx.SetColor(Color.Black); ctx.Stroke(); // ctx.SetLineWidth(3); ctx.Rectangle(100, 20, 10, 10); ctx.SetColor(Color.Black); ctx.Fill(); ctx.Rectangle(115, 20, 10, 10); ctx.SetColor(Color.Black); ctx.Stroke(); // Rectangle with hole ctx.Rectangle(10, 100, 40, 40); ctx.MoveTo(45, 135); ctx.RelLineTo(0, -20); ctx.RelLineTo(-20, 0); ctx.RelLineTo(0, 20); ctx.ClosePath(); ctx.SetColor(Color.Black); ctx.Fill(); // Dashed lines ctx.SetLineDash(15, 10, 10, 5, 5); ctx.Rectangle(100, 100, 100, 100); ctx.Stroke(); ctx.SetLineDash(0); ImageBuilder ib = new ImageBuilder(30, 30, ImageFormat.ARGB32); ib.Context.Arc(15, 15, 15, 0, 360); ib.Context.SetColor(new Color(1, 0, 1)); ib.Context.Rectangle(0, 0, 5, 5); ib.Context.Fill(); var img = ib.ToImage(); ctx.DrawImage(img, 90, 90); ctx.DrawImage(img, 90, 140, 50, 10); ctx.Arc(190, 190, 15, 0, 360); ctx.SetColor(new Color(1, 0, 1, 0.4)); ctx.Fill(); ctx.Save(); ctx.Translate(90, 220); ctx.Pattern = new ImagePattern(img); ctx.Rectangle(0, 0, 100, 70); ctx.Fill(); ctx.Restore(); ctx.Translate(30, 30); double end = 270; for (double n = 0; n <= end; n += 5) { ctx.Save(); ctx.Rotate(n); ctx.MoveTo(0, 0); ctx.RelLineTo(30, 0); double c = n / end; ctx.SetColor(new Color(c, c, c)); ctx.Stroke(); ctx.Restore(); } ctx.ResetTransform(); }
void DrawFocus(Context ctx, Point p) { // Draw a 'zoom'-style Focus at specified point double focusRadius = 32; double r = 12, w = focusRadius - 1; Point o = Point.Zero; // Drawing origin // Align single-thickness lines on 0.5 pixel coords o.X += 0.5; o.Y += 0.5; ctx.Save (); ctx.Translate (p); // Final translation // Hairlines in X-direction ctx.MoveTo (o.X + r, o.Y); ctx.LineTo (o.X + w, o.Y); ctx.MoveTo (o.X - r, o.Y); ctx.LineTo (o.X - w, o.Y); // Hairlines in Y-direction ctx.MoveTo (o.X, o.Y + r); ctx.LineTo (o.X, o.Y + w); ctx.MoveTo (o.X, o.Y - r); ctx.LineTo (o.X, o.Y - w); // Inner single-thickness circle ctx.MoveTo (o.X + r, o.Y); ctx.Arc (o.X, o.Y, r, 0, 360); ctx.SetColor (Colors.Black); ctx.SetLineWidth (1); ctx.Stroke (); // Double thickness outer arcs. Draw at (0,0) and rotate o = Point.Zero; r = 22; ctx.Rotate (5); ctx.MoveTo (r, 0); ctx.Arc (o.X, o.Y, r, 0, 80); ctx.MoveTo (o.X, r); ctx.Arc (o.X, o.Y, r, 90, 170); ctx.MoveTo (-r, o.Y); ctx.Arc (o.X, o.Y, r, 180, 260); ctx.MoveTo (o.X, -r); ctx.Arc (o.X, o.Y, r, 270, 350); ctx.SetLineWidth (2); ctx.Stroke (); ctx.Restore (); }
void DrawFocus(Context ctx, Point p) { // Draw a 'zoom'-style Focus at specified point. // Following values draw at (0,0) with Size (64,64) double r1 = 12, r2 = 22, w = 31; Point o = Point.Zero; // Drawing origin // Align single-thickness lines on 0.5 pixel coords o.X += 0.5; o.Y += 0.5; ctx.Save (); ctx.SetColor (Colors.Black); ctx.SetLineWidth (1); ctx.Translate (p); // Final translation to point p // draw as 4 quadrants, each rotated by +90 degrees for (double theta = 0; theta < 300; theta += 90) { ctx.Rotate (theta); // Hairline in X-direction, ending at x=r1 ctx.MoveTo (o.X + w, o.Y); ctx.LineTo (o.X + r1, o.Y); // Inner single-thickness arc ctx.Arc (o.X, o.Y, r1, 0, 90); ctx.Stroke (); // Double thickness outer arc, 10 - 80 degrees. Draw at (0,0) and rotate ctx.Save (); ctx.Rotate (10); ctx.MoveTo (r2, 0); ctx.Arc (0, 0, r2, 0, 70); ctx.SetLineWidth (2); ctx.Stroke (); ctx.Restore (); } ctx.Restore (); }