mirror of
https://bitbucket.org/anguist/ntpa
synced 2026-10-02 08:19:12 +00:00
Initial commit
This commit is contained in:
Executable
+439
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
* NPlot - A charting library for .NET
|
||||
*
|
||||
* LegendBase.cs
|
||||
* Copyright (C) 2003-2006 Matt Howlett and others.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of NPlot nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Drawing;
|
||||
|
||||
namespace NPlot
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Provides functionality for drawing legends.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The class is quite closely tied to PlotSurface2D.
|
||||
/// </remarks>
|
||||
public class LegendBase
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public LegendBase()
|
||||
{
|
||||
this.Font = new Font( new FontFamily("Arial"), 10, FontStyle.Regular, GraphicsUnit.Pixel );
|
||||
this.BackgroundColor = Color.White;
|
||||
this.BorderColor = Color.Black;
|
||||
this.TextColor = Color.Black;
|
||||
this.borderStyle_ = BorderType.Shadow;
|
||||
this.autoScaleText_ = false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the bounding box of the rectangle.
|
||||
/// </summary>
|
||||
/// <param name="position">the position of the top left of the legend.</param>
|
||||
/// <param name="plots">Array of plot objects to appear in the legend.</param>
|
||||
/// <param name="scale">if the legend is set to scale, the amount to scale by.</param>>
|
||||
/// <returns></returns>
|
||||
/// <remarks>do implementation that doesn't call draw. Change xPos, yPos to PointF</remarks>
|
||||
public Rectangle GetBoundingBox( Point position, ArrayList plots, float scale )
|
||||
{
|
||||
System.Drawing.Bitmap b = new System.Drawing.Bitmap(1,1);
|
||||
Graphics g = Graphics.FromImage(b);
|
||||
return this.Draw( g, position, plots, scale );
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Draw The legend
|
||||
/// </summary>
|
||||
/// <param name="g">The graphics surface on which to draw</param>
|
||||
/// <param name="position">The position of the top left of the axis.</param>
|
||||
/// <param name="plots">Array of plot objects to appear in the legend.</param>
|
||||
/// <param name="scale">if the legend is set to scale, the amount to scale by.</param>
|
||||
/// <returns>bounding box</returns>
|
||||
public Rectangle Draw( Graphics g, Point position, ArrayList plots, float scale )
|
||||
{
|
||||
|
||||
// first of all determine the Font to use in the legend.
|
||||
Font textFont;
|
||||
if (this.AutoScaleText)
|
||||
{
|
||||
textFont = Utils.ScaleFont( this.font_, scale );
|
||||
}
|
||||
else
|
||||
{
|
||||
textFont = this.font_;
|
||||
}
|
||||
|
||||
// determine max width and max height of label strings and
|
||||
// count the labels.
|
||||
int labelCount = 0;
|
||||
int maxHt = 0;
|
||||
int maxWd = 0;
|
||||
int unnamedCount = 0;
|
||||
for (int i=0; i<plots.Count; ++i)
|
||||
{
|
||||
if (!(plots[i] is IPlot))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IPlot p = (IPlot)plots[i];
|
||||
|
||||
if (!p.ShowInLegend)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string label = p.Label;
|
||||
if (label == "")
|
||||
{
|
||||
unnamedCount += 1;
|
||||
label = "Series " + unnamedCount.ToString();
|
||||
}
|
||||
SizeF labelSize = g.MeasureString( label, textFont );
|
||||
if ( labelSize.Height > maxHt )
|
||||
{
|
||||
maxHt = (int)labelSize.Height;
|
||||
}
|
||||
if ( labelSize.Width > maxWd )
|
||||
{
|
||||
maxWd = (int)labelSize.Width;
|
||||
}
|
||||
|
||||
++labelCount;
|
||||
}
|
||||
|
||||
bool extendingHorizontally = numberItemsHorizontally_ == -1;
|
||||
bool extendingVertically = numberItemsVertically_ == -1;
|
||||
|
||||
|
||||
// determine width in legend items count units.
|
||||
int widthInItemCount = 0;
|
||||
if (extendingVertically)
|
||||
{
|
||||
if (labelCount >= numberItemsHorizontally_)
|
||||
{
|
||||
widthInItemCount = numberItemsHorizontally_;
|
||||
}
|
||||
else
|
||||
{
|
||||
widthInItemCount = labelCount;
|
||||
}
|
||||
}
|
||||
else if (extendingHorizontally)
|
||||
{
|
||||
widthInItemCount = labelCount / numberItemsVertically_;
|
||||
if (labelCount % numberItemsVertically_ != 0)
|
||||
widthInItemCount += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NPlotException( "logic error in legend base" );
|
||||
}
|
||||
|
||||
|
||||
// determine height of legend in items count units.
|
||||
int heightInItemCount = 0;
|
||||
if (extendingHorizontally)
|
||||
{
|
||||
if (labelCount >= numberItemsVertically_)
|
||||
{
|
||||
heightInItemCount = numberItemsVertically_;
|
||||
}
|
||||
else
|
||||
{
|
||||
heightInItemCount = labelCount;
|
||||
}
|
||||
}
|
||||
else // extendingVertically
|
||||
{
|
||||
heightInItemCount = labelCount / numberItemsHorizontally_;
|
||||
if (labelCount % numberItemsHorizontally_ != 0)
|
||||
heightInItemCount += 1;
|
||||
}
|
||||
|
||||
int lineLength = 20;
|
||||
int hSpacing = (int)(5.0f * scale);
|
||||
int vSpacing = (int)(3.0f * scale);
|
||||
int boxWidth = (int) ((float)widthInItemCount * (lineLength + maxWd + hSpacing * 2.0f ) + hSpacing);
|
||||
int boxHeight = (int)((float)heightInItemCount * (maxHt + vSpacing) + vSpacing);
|
||||
|
||||
int totalWidth = boxWidth;
|
||||
int totalHeight = boxHeight;
|
||||
|
||||
// draw box around the legend.
|
||||
|
||||
if ( this.BorderStyle == BorderType.Line )
|
||||
{
|
||||
g.FillRectangle( new SolidBrush( this.bgColor_ ), position.X, position.Y, boxWidth, boxHeight );
|
||||
g.DrawRectangle( new Pen( this.borderColor_ ), position.X, position.Y, boxWidth, boxHeight );
|
||||
}
|
||||
else if ( this.BorderStyle == BorderType.Shadow )
|
||||
{
|
||||
int offset = (int)(4.0f * scale);
|
||||
g.FillRectangle( new SolidBrush( Color.FromArgb(128, Color.Gray) ), position.X+offset, position.Y+offset, boxWidth, boxHeight );
|
||||
g.FillRectangle( new SolidBrush( this.bgColor_ ), position.X, position.Y, boxWidth, boxHeight );
|
||||
g.DrawRectangle( new Pen( this.borderColor_ ), position.X, position.Y, boxWidth, boxHeight );
|
||||
|
||||
totalWidth += offset;
|
||||
totalHeight += offset;
|
||||
}
|
||||
|
||||
/*
|
||||
else if ( this.BorderStyle == BorderType.Curved )
|
||||
{
|
||||
// TODO. make this nice.
|
||||
}
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
// do nothing.
|
||||
}
|
||||
|
||||
// now draw entries in box..
|
||||
labelCount = 0;
|
||||
unnamedCount = 0;
|
||||
|
||||
int plotCount = -1;
|
||||
for (int i=0; i<plots.Count; ++i)
|
||||
{
|
||||
if (!(plots[i] is IPlot))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IPlot p = (IPlot)plots[i];
|
||||
|
||||
if (!p.ShowInLegend)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
plotCount += 1;
|
||||
|
||||
int xpos, ypos;
|
||||
if (extendingVertically)
|
||||
{
|
||||
xpos = plotCount % numberItemsHorizontally_;
|
||||
ypos = plotCount / numberItemsHorizontally_;
|
||||
}
|
||||
else
|
||||
{
|
||||
xpos = plotCount / numberItemsVertically_;
|
||||
ypos = plotCount % numberItemsVertically_;
|
||||
}
|
||||
|
||||
int lineXPos = (int)(position.X + hSpacing + xpos * (lineLength + maxWd + hSpacing * 2.0f));
|
||||
int lineYPos = (int)(position.Y + vSpacing + ypos * (vSpacing + maxHt));
|
||||
p.DrawInLegend( g, new Rectangle( lineXPos, lineYPos, lineLength, maxHt ) );
|
||||
|
||||
int textXPos = lineXPos + hSpacing + lineLength;
|
||||
int textYPos = lineYPos;
|
||||
string label = p.Label;
|
||||
if (label == "")
|
||||
{
|
||||
unnamedCount += 1;
|
||||
label = "Series " + unnamedCount.ToString();
|
||||
}
|
||||
|
||||
g.DrawString( label, textFont,
|
||||
new SolidBrush( this.textColor_ ), textXPos, textYPos );
|
||||
|
||||
++labelCount;
|
||||
}
|
||||
return new Rectangle( position.X, position.Y, totalWidth, totalHeight );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The font used to draw text in the legend.
|
||||
/// </summary>
|
||||
public Font Font
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.font_;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.font_ = value;
|
||||
}
|
||||
}
|
||||
private Font font_;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The color used to draw text in the legend.
|
||||
/// </summary>
|
||||
public Color TextColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.textColor_;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.textColor_ = value;
|
||||
}
|
||||
}
|
||||
Color textColor_;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The background color of the legend.
|
||||
/// </summary>
|
||||
public Color BackgroundColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return bgColor_;
|
||||
}
|
||||
set
|
||||
{
|
||||
bgColor_ = value;
|
||||
}
|
||||
}
|
||||
Color bgColor_;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The color of the legend border.
|
||||
/// </summary>
|
||||
public Color BorderColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return borderColor_;
|
||||
}
|
||||
set
|
||||
{
|
||||
borderColor_ = value;
|
||||
}
|
||||
}
|
||||
Color borderColor_;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The types of legend borders (enum).
|
||||
/// </summary>
|
||||
public enum BorderType
|
||||
{
|
||||
/// <summary>
|
||||
/// No border.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// Line border.
|
||||
/// </summary>
|
||||
Line = 1,
|
||||
/// <summary>
|
||||
/// Shaded border.
|
||||
/// </summary>
|
||||
Shadow = 2
|
||||
//Curved = 3
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The border style to use for the legend.
|
||||
/// </summary>
|
||||
public Legend.BorderType BorderStyle
|
||||
{
|
||||
get
|
||||
{
|
||||
return borderStyle_;
|
||||
}
|
||||
set
|
||||
{
|
||||
borderStyle_ = value;
|
||||
}
|
||||
}
|
||||
private NPlot.Legend.BorderType borderStyle_;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to auto scale text in the legend according the physical
|
||||
/// dimensions of the plot surface.
|
||||
/// </summary>
|
||||
public bool AutoScaleText
|
||||
{
|
||||
get
|
||||
{
|
||||
return autoScaleText_;
|
||||
}
|
||||
set
|
||||
{
|
||||
autoScaleText_ = value;
|
||||
}
|
||||
}
|
||||
bool autoScaleText_;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Setting this does two things. First of all, it sets the maximum number of
|
||||
/// items in the legend vertically. Second of all, it makes the legend grow
|
||||
/// horizontally (as it must given this constraint).
|
||||
/// </summary>
|
||||
public int NumberItemsVertically
|
||||
{
|
||||
set
|
||||
{
|
||||
this.numberItemsVertically_ = value;
|
||||
this.numberItemsHorizontally_ = -1;
|
||||
}
|
||||
}
|
||||
int numberItemsVertically_ = -1;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Setting this does two things. First of all, it sets the maximum number of
|
||||
/// items in the legend horizontally. Second of all, it makes the legend grow
|
||||
/// vertically (as it must given this constraint).
|
||||
/// </summary>
|
||||
public int NumberItemsHorizontally
|
||||
{
|
||||
set
|
||||
{
|
||||
this.numberItemsHorizontally_ = value;
|
||||
this.numberItemsVertically_ = -1;
|
||||
}
|
||||
}
|
||||
int numberItemsHorizontally_ = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user