protected override void OnDraw(Context ctx, Rectangle dirtyRect) { base.OnDraw(ctx, dirtyRect); if (image != null) { if (Heighlighted && IsThumbnail) { ctx.RoundRectangle(new Rectangle(Point.Zero, image.Size), 3); ctx.SetColor(Colors.LightSteelBlue); ctx.Fill(); } ctx.DrawImage(image, (new Rectangle(Point.Zero, image.Size)).Inflate(-3, -3)); if (mask != null && ShowMask) { ctx.DrawImage(MaskBitmap, (new Rectangle(Point.Zero, image.Size)).Inflate(-3, -3), 0.6); } } if (isEditMode) { Point scaleFactor = new Point( scan.Size.Width / image.Size.Width, scan.Size.Height / image.Size.Height); ctx.SetColor(Mask.maskColor); foreach (MaskEntry p in scan.Mask.MaskPositions) { switch (p.type) { case MaskEntryType.Point: ctx.SetLineWidth(p.pointerSize / scaleFactor.Y * 2); ctx.LineTo(p.position.X / scaleFactor.X, p.position.Y / scaleFactor.Y); ctx.Stroke(); ctx.Arc( p.position.X / scaleFactor.X, p.position.Y / scaleFactor.Y, p.pointerSize / scaleFactor.Y, 0, 360); ctx.Fill(); ctx.MoveTo(p.position.X / scaleFactor.X, p.position.Y / scaleFactor.Y); break; case MaskEntryType.Space: ctx.Stroke(); ctx.ClosePath(); break; case MaskEntryType.Delete: ctx.Arc( p.position.X / scaleFactor.X, p.position.Y / scaleFactor.Y, p.pointerSize / scaleFactor.Y, 0, 360); ctx.Save(); ctx.Clip(); int newX = (int) Math.Min(Math.Max( p.position.X / scaleFactor.X - pointerSize / scaleFactor.Y, 0), scan.Size.Width); int newY = (int) Math.Min(Math.Max( p.position.Y / scaleFactor.Y - pointerSize / scaleFactor.Y, 0), scan.Size.Height); using (ImageBuilder ib = new ImageBuilder((pointerSize / scaleFactor.Y * 2), (pointerSize / scaleFactor.Y * 2))) { BitmapImage bi = ib.ToBitmap(); image.WithBoxSize(image.Size).ToBitmap().CopyArea( newX, newY, (int) (pointerSize / scaleFactor.Y * 2), (int) (pointerSize / scaleFactor.Y * 2), bi, 0, 0); ctx.DrawImage(bi, new Point(newX, newY)); } ctx.Restore(); ctx.ClosePath(); break; } } ctx.Stroke(); if (mousePosition != Point.Zero) { ctx.Arc(mousePosition.X, mousePosition.Y, pointerSize / Math.Max(scaleFactor.X, scaleFactor.Y), 0, 360); ctx.Fill(); if (mousePositionStart != Point.Zero) { ctx.SetLineWidth((pointerSize / Math.Max(scaleFactor.X, scaleFactor.Y)) * 2); ctx.SetColor(Mask.maskColor); ctx.Arc(mousePositionStart.X, mousePositionStart.Y, pointerSize / Math.Max(scaleFactor.X, scaleFactor.Y), 0, 360); ctx.Fill(); ctx.MoveTo(mousePosition); ctx.LineTo(mousePositionStart); ctx.Stroke(); } } } }
/// <summary> /// Draw the the PlotSurface and contents (axes, drawables, and legend) using the /// Drawing Context supplied and the bounding rectangle for the PlotSurface to cover /// </summary> /// <param name="ctx">The Drawing Context with which to draw.</param> /// <param name="bounds">The rectangle within which to draw</param> public void Draw(Context ctx, Rectangle bounds) { Point titleOrigin = Point.Zero; ctx.Save (); // determine font sizes and tick scale factor. double scale = DetermineScaleFactor (bounds.Width, bounds.Height); // if there is nothing to plot, draw title and return. if (drawables.Count == 0) { // draw title //TODO: Title should be centred here - not its origin Point origin = Point.Zero; titleOrigin.X = bounds.Width/2; titleOrigin.Y = bounds.Height/2; DrawTitle (ctx, titleOrigin, scale); ctx.Restore (); return; } // determine the [non physical] axes to draw based on the axis properties set. Axis XAxis1 = null; Axis XAxis2 = null; Axis YAxis1 = null; Axis YAxis2 = null; DetermineAxesToDraw (out XAxis1, out XAxis2, out YAxis1, out YAxis2); // apply scale factor to axes as desired. if (XAxis1.AutoScaleTicks) { XAxis1.TickScale = scale; } if (XAxis1.AutoScaleText) { XAxis1.FontScale = scale; } if (YAxis1.AutoScaleTicks) { YAxis1.TickScale = scale; } if (YAxis1.AutoScaleText) { YAxis1.FontScale = scale; } if (XAxis2.AutoScaleTicks) { XAxis2.TickScale = scale; } if (XAxis2.AutoScaleText) { XAxis2.FontScale = scale; } if (YAxis2.AutoScaleTicks) { YAxis2.TickScale = scale; } if (YAxis2.AutoScaleText) { YAxis2.FontScale = scale; } // determine the default physical positioning of those axes. PhysicalAxis pXAxis1 = null; PhysicalAxis pYAxis1 = null; PhysicalAxis pXAxis2 = null; PhysicalAxis pYAxis2 = null; DeterminePhysicalAxesToDraw ( bounds, XAxis1, XAxis2, YAxis1, YAxis2, out pXAxis1, out pXAxis2, out pYAxis1, out pYAxis2 ); double oldXAxis2Height = pXAxis2.PhysicalMin.Y; // Apply axes constraints for (int i=0; i<axesConstraints.Count; ++i) { ((AxesConstraint)axesConstraints[i]).ApplyConstraint( pXAxis1, pYAxis1, pXAxis2, pYAxis2 ); } // draw legend if have one. // Note: this will update axes if necessary. Point legendPosition = new Point(0,0); if (legend != null) { legend.UpdateAxesPositions ( pXAxis1, pYAxis1, pXAxis2, pYAxis2, drawables, scale, Padding, bounds, out legendPosition ); } double newXAxis2Height = pXAxis2.PhysicalMin.Y; double titleExtraOffset = oldXAxis2Height - newXAxis2Height; // now we are ready to define the clipping region plotAreaBoundingBoxCache = new Rectangle ( Math.Min (pXAxis1.PhysicalMin.X, pXAxis1.PhysicalMax.X), Math.Min (pYAxis1.PhysicalMax.Y, pYAxis1.PhysicalMin.Y), Math.Abs (pXAxis1.PhysicalMax.X - pXAxis1.PhysicalMin.X + 1), Math.Abs (pYAxis1.PhysicalMin.Y - pYAxis1.PhysicalMax.Y + 1) ); bbXAxis1Cache = pXAxis1.GetBoundingBox (); bbXAxis2Cache = pXAxis2.GetBoundingBox (); bbYAxis1Cache = pYAxis1.GetBoundingBox (); bbYAxis2Cache = pYAxis2.GetBoundingBox (); Rectangle plotBounds = (Rectangle)plotAreaBoundingBoxCache; // set the clipping region.. (necessary for zoom) // Note: although clipping is enforced by the clip region, it is probably more efficient // for each Drawable to check against the plotBounds and not draw if points are outside. // This hasn't yet been implemented ctx.Save (); ctx.Rectangle (plotBounds); ctx.Clip (); // Fill in the plot background. if (plotBackImage != null) { // Ensure plotBounds has integer size for correct tiling/drawing plotBounds.Width = Math.Truncate (plotBounds.Width); plotBounds.Height = Math.Truncate (plotBounds.Height); ctx.DrawImage (Utils.TiledImage (plotBackImage , plotBounds.Size), plotBounds); } else if (plotBackGradient != null) { // Scale plotBackGradient to plotBounds double startX = plotBounds.X + (plotBackGradient.StartPoint.X * plotBounds.Width); double startY = plotBounds.Y + (plotBackGradient.StartPoint.Y * plotBounds.Height); double endX = plotBounds.X + (plotBackGradient.EndPoint.X * plotBounds.Width); double endY = plotBounds.Y + (plotBackGradient.EndPoint.Y * plotBounds.Height); LinearGradient g = new LinearGradient (startX, startY, endX, endY); g.AddColorStop (0, plotBackGradient.StartColor); g.AddColorStop (1, plotBackGradient.EndColor); ctx.Rectangle (plotBounds); ctx.Pattern = g; ctx.Fill (); } else { ctx.Rectangle (plotBounds); ctx.SetColor (plotBackColor); ctx.Fill (); } // draw title at centre of Physical X-axis and at top of plot titleOrigin.X = (pXAxis2.PhysicalMax.X + pXAxis2.PhysicalMin.X)/2.0; titleOrigin.Y = bounds.Top + Padding - titleExtraOffset; Size s = DrawTitle (ctx, titleOrigin, scale); bbTitleCache = new Rectangle (titleOrigin.X-s.Width/2, titleOrigin.Y, s.Width, s.Height); // draw drawables.. bool legendDrawn = false; for (int i_o = 0; i_o < ordering.Count; ++i_o) { int i = (int)ordering.GetByIndex (i_o); double zOrder = (double)ordering.GetKey (i_o); if (zOrder > legendZOrder) { // draw legend. if (!legendDrawn && legend != null) { legend.Draw (ctx, legendPosition, drawables, scale); legendDrawn = true; } } IDrawable drawable = (IDrawable)drawables[i]; XAxisPosition xap = (XAxisPosition)xAxisPositions[i]; YAxisPosition yap = (YAxisPosition)yAxisPositions[i]; PhysicalAxis drawXAxis; PhysicalAxis drawYAxis; if (xap == XAxisPosition.Bottom) { drawXAxis = pXAxis1; } else { drawXAxis = pXAxis2; } if (yap == YAxisPosition.Left) { drawYAxis = pYAxis1; } else { drawYAxis = pYAxis2; } drawable.Draw (ctx, drawXAxis, drawYAxis); } if (!legendDrawn && legend != null) { legend.Draw (ctx, legendPosition, drawables, scale); } ctx.Restore (); // end of clipping region // cache the physical axes we used on this draw; pXAxis1Cache = pXAxis1; pYAxis1Cache = pYAxis1; pXAxis2Cache = pXAxis2; pYAxis2Cache = pYAxis2; // now draw axes. Rectangle axisBounds; pXAxis1.Draw (ctx, out axisBounds); pXAxis2.Draw (ctx, out axisBounds); pYAxis1.Draw (ctx, out axisBounds); pYAxis2.Draw (ctx, out axisBounds); #if DEBUG_BOUNDING_BOXES ctx.SetColor (Colors.Orange); ctx.Rectangle ((Rectangle)bbXAxis1Cache); ctx.Rectangle ((Rectangle)bbXAxis2Cache); ctx.Rectangle ((Rectangle)bbYAxis1Cache); ctx.Rectangle ((Rectangle)bbYAxis2Cache); ctx.Stroke (); ctx.SetColor (Colors.Red); ctx.Rectangle ((Rectangle)plotAreaBoundingBoxCache); ctx.Rectangle ((Rectangle)bbTitleCache); ctx.Stroke (); #endif ctx.Restore (); }
void DrawSerie (Context ctx, Serie serie) { ctx.NewPath (); ctx.Rectangle (left, top, width + 1, height + 1); ctx.Clip (); ctx.NewPath (); ctx.SetColor (serie.Color); ctx.SetLineWidth (serie.LineWidth); bool first = true; bool blockMode = serie.DisplayMode == DisplayMode.BlockLine; double lastY = 0; foreach (Data d in serie.GetData (startX, endX)) { double x, y; GetPoint (d.X, d.Y, out x, out y); if (first) { ctx.MoveTo (x, y); lastY = y; first = false; } else { if (blockMode) { if (lastY != y) ctx.LineTo (x, lastY); ctx.LineTo (x, y); } else ctx.LineTo (x, y); } lastY = y; } ctx.Stroke (); }
void DrawProgress(Context ctx) { int threadsRunning = progress.Keys.Count; Rectangle clipBound = bound.Inflate(-1, -1); clipBound.Bottom = clipBound.Top + contentOffset.Y; double height = threadsRunning == 0 ? clipBound.Height : clipBound.Height / threadsRunning; double width = clipBound.Width; clipBound.Bottom = clipBound.Top + height; List<int> toRemove = new List<int>(); foreach (var singleProgress in progress) { int progressForThread = singleProgress.Value; ctx.Save(); clipBound.Width = width * (progressForThread / 100.0); ctx.Rectangle(clipBound); ctx.Clip(); ctx.RoundRectangle(bound.Inflate(-1, -1), NodeRadius); ctx.SetColor(NodeColorProgress); ctx.Fill(); ctx.Restore(); clipBound.Top += height; if (progressForThread >= 100 && progress.ContainsKey(singleProgress.Key)) { toRemove.Add(singleProgress.Key); } } foreach (int removeID in toRemove) { progress.Remove(removeID); } }