Пример #1
0
        /// <summary>
        /// Calculate the <see cref="Legend"/> rectangle (<see cref="Rect"/>),
        /// taking into account the number of required legend
        /// entries, and the legend drawing preferences.
        /// </summary>
        /// <remarks>Adjust the size of the
        /// <see cref="Chart.Rect"/> for the parent <see cref="GraphPane"/> to accomodate the
        /// space required by the legend.
        /// </remarks>
        /// <param name="g">
        /// A graphic device object to be drawn into.  This is normally e.Graphics from the
        /// PaintEventArgs argument to the Paint() method.
        /// </param>
        /// <param name="pane">
        /// A reference to the <see cref="PaneBase"/> object that is the parent or
        /// owner of this object.
        /// </param>
        /// <param name="scaleFactor">
        /// The scaling factor to be used for rendering objects.  This is calculated and
        /// passed down by the parent <see cref="GraphPane"/> object using the
        /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
        /// font sizes, etc. according to the actual size of the graph.
        /// </param>
        /// <param name="tChartRect">
        /// The rectangle that contains the area bounded by the axes, in pixel units.
        /// <seealso cref="Chart.Rect" />
        /// </param>
        public void CalcRect(Graphics g, PaneBase pane, float scaleFactor,
                             ref RectangleF tChartRect)
        {
            // Start with an empty rectangle
            _rect             = Rectangle.Empty;
            _numberOfColumns  = 1;
            _legendItemWidth  = 1;
            _legendItemHeight = 0;

            RectangleF clientRect = pane.CalcClientRect(g, scaleFactor);

            // If the legend is invisible, don't do anything
            if (!_isVisible)
            {
                return;
            }

            int numberOfCurvesToDraw = 0;

            PaneList paneList = GetPaneList(pane);

            _tmpSize = GetMaxHeight(paneList, g, scaleFactor);

            float halfGap  = _tmpSize / 2.0F,
                  maxWidth = 0,
                  tmpWidth = 0,
                  gapPix   = _gap * _tmpSize;

            bool showingSecondaryLabel = false;

            foreach (GraphPane tmpPane in paneList)
            {
                // Loop through each curve in the curve list
                // Find the maximum width of the legend labels
                //foreach ( CurveItem curve in tmpPane.CurveList )
                //foreach ( CurveItem curve in GetIterator( tmpPane.CurveList, _isReverse ) )
                int count = tmpPane.CurveList.Count;
                for (int i = 0; i < count; i++)
                {
                    CurveItem curve = tmpPane.CurveList[_isReverse ? count - i - 1 : i];
                    bool      atLeastOneLabelDrawn = false;
                    if (curve._label._text != string.Empty && curve._label._isVisible)
                    {
                        // Calculate the width of the label save the max width
                        FontSpec tmpFont = (curve._label._fontSpec != null) ?
                                           curve._label._fontSpec : this.FontSpec;

                        tmpWidth = tmpFont.GetWidth(g, curve._label._text, scaleFactor);

                        if (tmpWidth > maxWidth)
                        {
                            maxWidth = tmpWidth;
                        }

                        // Save the maximum symbol height for line-type curves
                        if (curve is LineItem && ((LineItem)curve).Symbol.Size > _legendItemHeight)
                        {
                            _legendItemHeight = ((LineItem)curve).Symbol.Size;
                        }

                        atLeastOneLabelDrawn = true;
                    }
                    if (curve.SecondaryLabel._text != string.Empty && curve.SecondaryLabel._isVisible)
                    {
                        // Calculate the width of the label save the max width
                        FontSpec tmpFont = (curve.SecondaryLabel._fontSpec != null) ?
                                           curve.SecondaryLabel._fontSpec : this.FontSpec;

                        tmpWidth = tmpFont.GetWidth(g, curve.SecondaryLabel._text, scaleFactor);

                        if (tmpWidth > maxWidth)
                        {
                            maxWidth = tmpWidth;
                        }

                        // Save the maximum symbol height for line-type curves
                        if (curve is LineItem && ((LineItem)curve).Symbol.Size > _legendItemHeight)
                        {
                            _legendItemHeight = ((LineItem)curve).Symbol.Size;
                        }

                        atLeastOneLabelDrawn  = true;
                        showingSecondaryLabel = true;
                    }

                    if (atLeastOneLabelDrawn)
                    {
                        ++numberOfCurvesToDraw;
                    }
                }

                if (pane is MasterPane && ((MasterPane)pane).IsUniformLegendEntries)
                {
                    break;
                }
            }

            float widthAvail;

            // Is this legend horizontally stacked?

            if (_isHStack)
            {
                // Determine the available space for horizontal stacking
                switch (_position)
                {
                // Never stack if the legend is to the right or left
                case LegendPos.Right:
                case LegendPos.Left:
                    widthAvail = 0;
                    break;

                // for the top & bottom, the axis border width is available
                case LegendPos.Top:
                case LegendPos.TopCenter:
                case LegendPos.Bottom:
                case LegendPos.BottomCenter:
                    widthAvail = tChartRect.Width;
                    break;

                // for the top & bottom flush left, the panerect less margins is available
                case LegendPos.TopFlushLeft:
                case LegendPos.BottomFlushLeft:
                    widthAvail = clientRect.Width;
                    break;

                // for inside the axis area or Float, use 1/2 of the axis border width
                case LegendPos.InsideTopRight:
                case LegendPos.InsideTopLeft:
                case LegendPos.InsideBotRight:
                case LegendPos.InsideBotLeft:
                case LegendPos.Float:
                    widthAvail = tChartRect.Width / 2;
                    break;

                // shouldn't ever happen
                default:
                    widthAvail = 0;
                    break;
                }

                // width of one legend entry
                if (_isShowLegendSymbols)
                {
                    if (showingSecondaryLabel)
                    {
                        _legendItemWidth = 3.0f * _tmpSize + maxWidth * 1.6f;
                    }
                    else
                    {
                        _legendItemWidth = 3.0f * _tmpSize + maxWidth;
                    }
                }
                else
                {
                    _legendItemWidth = 0.5f * _tmpSize + maxWidth;
                }

                // Calculate the number of columns in the legend
                // Normally, the legend is:
                //     available width / ( max width of any entry + space for line&symbol )
                if (maxWidth > 0)
                {
                    _numberOfColumns = (int)((widthAvail - halfGap) / _legendItemWidth);
                }

                // You can never have more columns than legend entries
                if (_numberOfColumns > numberOfCurvesToDraw)
                {
                    _numberOfColumns = numberOfCurvesToDraw;
                }

                // a saftey check
                if (_numberOfColumns == 0)
                {
                    _numberOfColumns = 1;
                }
            }
            else
            {
                if (_isShowLegendSymbols)
                {
                    _legendItemWidth = 4.0F * _tmpSize + maxWidth;
                }
                else
                {
                    _legendItemWidth = 0.5F * _tmpSize + maxWidth;
                }
            }

            // legend is:
            //   item:     space  line  space  text   space
            //   width:     wid  4*wid   wid  maxWid   wid
            // The symbol is centered on the line
            //
            // legend begins 3 * wid to the right of the plot rect
            //
            // The height of the legend is the actual height of the lines of text
            //   (nCurve * hite) plus wid on top and wid on the bottom

            // total legend width
            float totLegWidth = _numberOfColumns * _legendItemWidth;

            // The total legend height
            _legendItemHeight = _legendItemHeight * (float)scaleFactor + halfGap;
            if (_tmpSize > _legendItemHeight)
            {
                _legendItemHeight = _tmpSize;
            }
            float totLegHeight = (float)Math.Ceiling((double)numberOfCurvesToDraw / (double)_numberOfColumns)
                                 * _legendItemHeight;

            RectangleF newRect = new RectangleF();

            // Now calculate the legend rect based on the above determined parameters
            // Also, adjust the ChartRect to reflect the space for the legend
            if (numberOfCurvesToDraw > 0)
            {
                newRect = new RectangleF(0, 0, totLegWidth, totLegHeight);

                // The switch statement assigns the left and top edges, and adjusts the ChartRect
                // as required.  The right and bottom edges are calculated at the bottom of the switch.
                switch (_position)
                {
                case LegendPos.Right:
                    newRect.X = clientRect.Right - totLegWidth;
                    newRect.Y = tChartRect.Top;

                    tChartRect.Width -= totLegWidth + gapPix;
                    break;

                case LegendPos.Top:
                    newRect.X = tChartRect.Left;
                    newRect.Y = clientRect.Top;

                    tChartRect.Y      += totLegHeight + gapPix;
                    tChartRect.Height -= totLegHeight + gapPix;
                    break;

                case LegendPos.TopFlushLeft:
                    newRect.X = clientRect.Left;
                    newRect.Y = clientRect.Top;

                    tChartRect.Y      += totLegHeight + gapPix * 1.5f;
                    tChartRect.Height -= totLegHeight + gapPix * 1.5f;
                    break;

                case LegendPos.TopCenter:
                    newRect.X = tChartRect.Left + (tChartRect.Width - totLegWidth) / 2;
                    newRect.Y = tChartRect.Top;

                    tChartRect.Y      += totLegHeight + gapPix;
                    tChartRect.Height -= totLegHeight + gapPix;
                    break;

                case LegendPos.Bottom:
                    newRect.X = tChartRect.Left;
                    newRect.Y = clientRect.Bottom - totLegHeight;

                    tChartRect.Height -= totLegHeight + gapPix;
                    break;

                case LegendPos.BottomFlushLeft:
                    newRect.X = clientRect.Left;
                    newRect.Y = clientRect.Bottom - totLegHeight;

                    tChartRect.Height -= totLegHeight + gapPix;
                    break;

                case LegendPos.BottomCenter:
                    newRect.X = tChartRect.Left + (tChartRect.Width - totLegWidth) / 2;
                    newRect.Y = clientRect.Bottom - totLegHeight;

                    tChartRect.Height -= totLegHeight + gapPix;
                    break;

                case LegendPos.Left:
                    newRect.X = clientRect.Left;
                    newRect.Y = tChartRect.Top;

                    tChartRect.X     += totLegWidth + halfGap;
                    tChartRect.Width -= totLegWidth + gapPix;
                    break;

                case LegendPos.InsideTopRight:
                    newRect.X = tChartRect.Right - totLegWidth;
                    newRect.Y = tChartRect.Top;
                    break;

                case LegendPos.InsideTopLeft:
                    newRect.X = tChartRect.Left;
                    newRect.Y = tChartRect.Top;
                    break;

                case LegendPos.InsideBotRight:
                    newRect.X = tChartRect.Right - totLegWidth;
                    newRect.Y = tChartRect.Bottom - totLegHeight;
                    break;

                case LegendPos.InsideBotLeft:
                    newRect.X = tChartRect.Left;
                    newRect.Y = tChartRect.Bottom - totLegHeight;
                    break;

                case LegendPos.Float:
                    newRect.Location = this.Location.TransformTopLeft(pane, totLegWidth, totLegHeight);
                    break;
                }
            }

            _rect = newRect;
        }
Пример #2
0
        /// <summary>
        /// Calculate the <see cref="Legend"/> rectangle (<see cref="Rect"/>),
        /// taking into account the number of required legend
        /// entries, and the legend drawing preferences.
        /// </summary>
        /// <remarks>Adjust the size of the
        /// <see cref="GraphPane.AxisRect"/> for the parent <see cref="GraphPane"/> to accomodate the
        /// space required by the legend.
        /// </remarks>
        /// <param name="g">
        /// A graphic device object to be drawn into.  This is normally e.Graphics from the
        /// PaintEventArgs argument to the Paint() method.
        /// </param>
        /// <param name="pane">
        /// A reference to the <see cref="PaneBase"/> object that is the parent or
        /// owner of this object.
        /// </param>
        /// <param name="scaleFactor">
        /// The scaling factor to be used for rendering objects.  This is calculated and
        /// passed down by the parent <see cref="GraphPane"/> object using the
        /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
        /// font sizes, etc. according to the actual size of the graph.
        /// </param>
        /// <param name="tAxisRect">
        /// The rectangle that contains the area bounded by the axes, in pixel units.
        /// <seealso cref="GraphPane.AxisRect">AxisRect</seealso>
        /// </param>
        public void CalcRect(Graphics g, PaneBase pane, float scaleFactor,
                             ref RectangleF tAxisRect)
        {
            // Start with an empty rectangle
            this.rect             = Rectangle.Empty;
            this.hStack           = 1;
            this.legendItemWidth  = 1;
            this.legendItemHeight = 0;

            // If the legend is invisible, don't do anything
            if (!this.isVisible)
            {
                return;
            }

            int nCurve = 0;

            PaneList paneList = GetPaneList(pane);

            this.gap = GetMaxHeight(paneList, g, scaleFactor);

            float halfGap  = this.gap / 2.0F,
                  maxWidth = 0,
                  tmpWidth;

            foreach (GraphPane tmpPane in paneList)
            {
                // Loop through each curve in the curve list
                // Find the maximum width of the legend labels
                foreach (CurveItem curve in tmpPane.CurveList)
                {
                    if (curve.Label != "" && curve.IsLegendLabelVisible)
                    {
                        // Calculate the width of the label save the max width
                        FontSpec tmpFont = (curve.FontSpec != null) ? curve.FontSpec : this.FontSpec;

                        tmpWidth = tmpFont.GetWidth(g, curve.Label, scaleFactor);

                        if (tmpWidth > maxWidth)
                        {
                            maxWidth = tmpWidth;
                        }

                        // Save the maximum symbol height for line-type curves
                        if (curve is LineItem && ((LineItem)curve).Symbol.Size > this.legendItemHeight)
                        {
                            this.legendItemHeight = ((LineItem)curve).Symbol.Size;
                        }

                        nCurve++;
                    }
                }

                if (pane is MasterPane && ((MasterPane)pane).HasUniformLegendEntries)
                {
                    break;
                }
            }

            float widthAvail;

            // Is this legend horizontally stacked?

            if (this.isHStack)
            {
                // Determine the available space for horizontal stacking
                switch (this.position)
                {
                // Never stack if the legend is to the right or left
                case LegendPos.Right:
                case LegendPos.Left:
                    widthAvail = 0;
                    break;

                // for the top & bottom, the axis border width is available
                case LegendPos.Top:
                case LegendPos.TopCenter:
                case LegendPos.Bottom:
                case LegendPos.BottomCenter:
                    widthAvail = tAxisRect.Width;
                    break;

                // for inside the axis area or Float, use 1/2 of the axis border width
                case LegendPos.InsideTopRight:
                case LegendPos.InsideTopLeft:
                case LegendPos.InsideBotRight:
                case LegendPos.InsideBotLeft:
                case LegendPos.Float:
                    widthAvail = tAxisRect.Width / 2;
                    break;

                // shouldn't ever happen
                default:
                    widthAvail = 0;
                    break;
                }

                // width of one legend entry
                this.legendItemWidth = 3 * gap + maxWidth;

                // Calculate the number of columns in the legend
                // Normally, the legend is:
                //     available width / ( max width of any entry + space for line&symbol )
                if (maxWidth > 0)
                {
                    this.hStack = (int)((widthAvail - halfGap) / this.legendItemWidth);
                }

                // You can never have more columns than legend entries
                if (this.hStack > nCurve)
                {
                    this.hStack = nCurve;
                }

                // a saftey check
                if (this.hStack == 0)
                {
                    this.hStack = 1;
                }
            }
            else
            {
                this.legendItemWidth = 3.5F * gap + maxWidth;
            }

            // legend is:
            //   item:     space  line  space  text   space
            //   width:     wid  4*wid   wid  maxWid   wid
            // The symbol is centered on the line
            //
            // legend begins 3 * wid to the right of the plot rect
            //
            // The height of the legend is the actual height of the lines of text
            //   (nCurve * hite) plus wid on top and wid on the bottom

            // total legend width
            float totLegWidth = this.hStack * this.legendItemWidth;

            // The total legend height
            this.legendItemHeight = this.legendItemHeight * (float)scaleFactor + halfGap;
            if (gap > this.legendItemHeight)
            {
                this.legendItemHeight = gap;
            }
            float totLegHeight = (float)Math.Ceiling((double)nCurve / (double)hStack)
                                 * this.legendItemHeight;

            RectangleF newRect = new RectangleF();

            // Now calculate the legend rect based on the above determined parameters
            // Also, adjust the axisRect to reflect the space for the legend
            if (nCurve > 0)
            {
                newRect = new RectangleF(0, 0, totLegWidth, totLegHeight);

                RectangleF clientRect = pane.CalcClientRect(g, scaleFactor);

                // The switch statement assigns the left and top edges, and adjusts the axisRect
                // as required.  The right and bottom edges are calculated at the bottom of the switch.
                switch (this.position)
                {
                case LegendPos.Right:
                    newRect.X = clientRect.Right - totLegWidth;
                    newRect.Y = tAxisRect.Top;

                    tAxisRect.Width -= totLegWidth + halfGap;
                    break;

                case LegendPos.Top:
                    newRect.X = tAxisRect.Left;
                    newRect.Y = clientRect.Top;

                    tAxisRect.Y      += totLegHeight + halfGap;
                    tAxisRect.Height -= totLegHeight + halfGap;
                    break;

                case LegendPos.TopCenter:
                    newRect.X = tAxisRect.Left + (tAxisRect.Width - totLegWidth) / 2;
                    newRect.Y = tAxisRect.Top;

                    tAxisRect.Y      += totLegHeight + halfGap;
                    tAxisRect.Height -= totLegHeight + halfGap;
                    break;

                case LegendPos.Bottom:
                    newRect.X = tAxisRect.Left + (tAxisRect.Width - totLegWidth) / 2;
                    newRect.Y = clientRect.Bottom - totLegHeight;

                    tAxisRect.Height -= totLegHeight + halfGap;
                    break;

                case LegendPos.BottomCenter:
                    newRect.X = tAxisRect.Left + (tAxisRect.Width - totLegWidth) / 2;
                    newRect.Y = clientRect.Bottom - totLegHeight;

                    tAxisRect.Height -= totLegHeight + halfGap;
                    break;

                case LegendPos.Left:
                    newRect.X = clientRect.Left;
                    newRect.Y = tAxisRect.Top;

                    tAxisRect.X     += totLegWidth + halfGap;
                    tAxisRect.Width -= totLegWidth + halfGap;
                    break;

                case LegendPos.InsideTopRight:
                    newRect.X = tAxisRect.Right - totLegWidth;
                    newRect.Y = tAxisRect.Top;
                    break;

                case LegendPos.InsideTopLeft:
                    newRect.X = tAxisRect.Left;
                    newRect.Y = tAxisRect.Top;
                    break;

                case LegendPos.InsideBotRight:
                    newRect.X = tAxisRect.Right - totLegWidth;
                    newRect.Y = tAxisRect.Bottom - totLegHeight;
                    break;

                case LegendPos.InsideBotLeft:
                    newRect.X = tAxisRect.Left;
                    newRect.Y = tAxisRect.Bottom - totLegHeight;
                    break;

                case LegendPos.Float:
                    newRect.Location = this.Location.TransformTopLeft(pane, totLegWidth, totLegHeight);
                    break;
                }
            }

            this.rect = newRect;
        }