Exemple #1
0
        /// <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();
        }
Exemple #2
0
        void DeterminePhysicalAxesToDraw(Rectangle bounds, 
			Axis XAxis1, Axis XAxis2, Axis YAxis1, Axis YAxis2,
			out PhysicalAxis pXAxis1, out PhysicalAxis pXAxis2, 
			out PhysicalAxis pYAxis1, out PhysicalAxis pYAxis2 )
        {
            Rectangle cb = bounds;

            pXAxis1 = new PhysicalAxis (XAxis1,
                new Point (cb.Left, cb.Bottom), new Point (cb.Right, cb.Bottom) );
            pYAxis1 = new PhysicalAxis (YAxis1,
                new Point (cb.Left, cb.Bottom), new Point (cb.Left, cb.Top) );
            pXAxis2 = new PhysicalAxis (XAxis2,
                new Point (cb.Left, cb.Top), new Point (cb.Right, cb.Top) );
            pYAxis2 = new PhysicalAxis (YAxis2,
                new Point (cb.Right, cb.Bottom), new Point (cb.Right, cb.Top) );

            double bottomIndent = Padding;
            if (!pXAxis1.Axis.Hidden) {
                // evaluate its bounding box
                Rectangle bb = pXAxis1.GetBoundingBox ();
                // finally determine its indentation from the bottom
                bottomIndent = bottomIndent + bb.Bottom - cb.Bottom;
            }

            double leftIndent = Padding;
            if (!pYAxis1.Axis.Hidden) {
                // evaluate its bounding box
                Rectangle bb = pYAxis1.GetBoundingBox();
                // finally determine its indentation from the left
                leftIndent = leftIndent - bb.Left + cb.Left;
            }

            // determine title size
            double scale = DetermineScaleFactor (bounds.Width, bounds.Height);
            Font scaled_font;
            if (AutoScaleTitle) {
                scaled_font = TitleFont.WithScaledSize (scale);
            }
            else {
                scaled_font = TitleFont;
            }

            Size titleSize;
            using (TextLayout layout = new TextLayout ()) {
                layout.Font = scaled_font;
                layout.Text = Title;
                titleSize = layout.GetSize ();
            };
            double topIndent = Padding;

            if (!pXAxis2.Axis.Hidden) {
                // evaluate its bounding box
                Rectangle bb = pXAxis2.GetBoundingBox();
                topIndent = topIndent - bb.Top + cb.Top;

                // finally determine its indentation from the top
                // correct top indendation to take into account plot title
                if (Title != "" ) {
                    topIndent += titleSize.Height * 1.3;
                }
            }

            double rightIndent = Padding;
            if (!pYAxis2.Axis.Hidden) {
                // evaluate its bounding box
                Rectangle bb = pYAxis2.GetBoundingBox();

                // finally determine its indentation from the right
                rightIndent += (bb.Right-cb.Right);
            }

            // now we have all the default calculated positions and we can proceed to
            // "move" the axes to their right places

            // primary axes (bottom, left)
            pXAxis1.PhysicalMin = new Point (cb.Left+leftIndent, cb.Bottom-bottomIndent);
            pXAxis1.PhysicalMax = new Point (cb.Right-rightIndent, cb.Bottom-bottomIndent);
            pYAxis1.PhysicalMin = new Point (cb.Left+leftIndent, cb.Bottom-bottomIndent);
            pYAxis1.PhysicalMax = new Point (cb.Left+leftIndent, cb.Top+topIndent);

            // secondary axes (top, right)
            pXAxis2.PhysicalMin = new Point (cb.Left+leftIndent, cb.Top+topIndent);
            pXAxis2.PhysicalMax = new Point (cb.Right-rightIndent, cb.Top+topIndent);
            pYAxis2.PhysicalMin = new Point (cb.Right-rightIndent, cb.Bottom-bottomIndent);
            pYAxis2.PhysicalMax = new Point (cb.Right-rightIndent, cb.Top+topIndent);
        }
Exemple #3
0
        void DeterminePhysicalAxesToDraw(Rectangle bounds,
                                         Axis XAxis1, Axis XAxis2, Axis YAxis1, Axis YAxis2,
                                         out PhysicalAxis pXAxis1, out PhysicalAxis pXAxis2,
                                         out PhysicalAxis pYAxis1, out PhysicalAxis pYAxis2)
        {
            Rectangle cb = bounds;

            pXAxis1 = new PhysicalAxis(XAxis1,
                                       new Point(cb.Left, cb.Bottom), new Point(cb.Right, cb.Bottom));
            pYAxis1 = new PhysicalAxis(YAxis1,
                                       new Point(cb.Left, cb.Bottom), new Point(cb.Left, cb.Top));
            pXAxis2 = new PhysicalAxis(XAxis2,
                                       new Point(cb.Left, cb.Top), new Point(cb.Right, cb.Top));
            pYAxis2 = new PhysicalAxis(YAxis2,
                                       new Point(cb.Right, cb.Bottom), new Point(cb.Right, cb.Top));

            double bottomIndent = Padding;

            if (!pXAxis1.Axis.Hidden)
            {
                // evaluate its bounding box
                Rectangle bb = pXAxis1.GetBoundingBox();
                // finally determine its indentation from the bottom
                bottomIndent = bottomIndent + bb.Bottom - cb.Bottom;
            }

            double leftIndent = Padding;

            if (!pYAxis1.Axis.Hidden)
            {
                // evaluate its bounding box
                Rectangle bb = pYAxis1.GetBoundingBox();
                // finally determine its indentation from the left
                leftIndent = leftIndent - bb.Left + cb.Left;
            }

            // determine title size
            double scale = DetermineScaleFactor(bounds.Width, bounds.Height);
            Font   scaled_font;

            if (AutoScaleTitle)
            {
                scaled_font = TitleFont.WithScaledSize(scale);
            }
            else
            {
                scaled_font = TitleFont;
            }

            Size titleSize;

            using (TextLayout layout = new TextLayout()) {
                layout.Font = scaled_font;
                layout.Text = Title;
                titleSize   = layout.GetSize();
            };
            double topIndent = Padding;

            if (!pXAxis2.Axis.Hidden)
            {
                // evaluate its bounding box
                Rectangle bb = pXAxis2.GetBoundingBox();
                topIndent = topIndent - bb.Top + cb.Top;

                // finally determine its indentation from the top
                // correct top indendation to take into account plot title
                if (Title != "")
                {
                    topIndent += titleSize.Height * 1.3;
                }
            }

            double rightIndent = Padding;

            if (!pYAxis2.Axis.Hidden)
            {
                // evaluate its bounding box
                Rectangle bb = pYAxis2.GetBoundingBox();

                // finally determine its indentation from the right
                rightIndent += (bb.Right - cb.Right);
            }

            // now we have all the default calculated positions and we can proceed to
            // "move" the axes to their right places

            // primary axes (bottom, left)
            pXAxis1.PhysicalMin = new Point(cb.Left + leftIndent, cb.Bottom - bottomIndent);
            pXAxis1.PhysicalMax = new Point(cb.Right - rightIndent, cb.Bottom - bottomIndent);
            pYAxis1.PhysicalMin = new Point(cb.Left + leftIndent, cb.Bottom - bottomIndent);
            pYAxis1.PhysicalMax = new Point(cb.Left + leftIndent, cb.Top + topIndent);

            // secondary axes (top, right)
            pXAxis2.PhysicalMin = new Point(cb.Left + leftIndent, cb.Top + topIndent);
            pXAxis2.PhysicalMax = new Point(cb.Right - rightIndent, cb.Top + topIndent);
            pYAxis2.PhysicalMin = new Point(cb.Right - rightIndent, cb.Bottom - bottomIndent);
            pYAxis2.PhysicalMax = new Point(cb.Right - rightIndent, cb.Top + topIndent);
        }