High-speed-Charting-Control/ChartDemo/ChartCtrl/ChartAxis.h

526 lines
17 KiB
C++

/*
*
* ChartAxis.h
*
* Written by Cédric Moonen (cedric_moonen@hotmail.com)
*
*
*
* This code may be used for any non-commercial and commercial purposes in a compiled form.
* The code may be redistributed as long as it remains unmodified and providing that the
* author name and this disclaimer remain intact. The sources can be modified WITH the author
* consent only.
*
* This code is provided without any garanties. I cannot be held responsible for the damage or
* the loss of time it causes. Use it at your own risks
*
* An e-mail to notify me that you are using this code is appreciated also.
*
*
*/
#ifndef _CHARTAXIS_H_
#define _CHARTAXIS_H_
#include "ChartScrollBar.h"
#include "ChartString.h"
#include <afx.h>
#include <list>
class CChartCtrl;
class CChartGrid;
class CChartSerie;
class CChartAxisLabel;
//! Base class that takes care of the management of a chart axis.
/**
This class cannot be instanciated but should be overriden in order
to provide the required functionality (this is already done for
standard axis, date/time axis and logarithmic axis).<br>
The class provides already a lot of functionalities but delegate the
ticks positioning and labeling to the child classes.<br>
By default, the class manages a continues range of double values (which
is the case for standard axis and date/time axis) but in some cases, this
is not valid (for instance, a logarithmic scale). In that case, you should
in addition override some specific functions (e.g. those handling the scrollbar).
Take a look at the CChartLogarithmicAxis class for more details.
**/
class CChartAxis
{
friend CChartCtrl;
friend CChartGrid;
friend CChartSerie;
friend CChartScrollBar;
public:
//! Default constructor
CChartAxis();
//! Default destructor
virtual ~CChartAxis();
//! Retrieves the position (in %) of the axis.
int GetPosition();
//! Sets the axis in reverse.
/**
For an inverted axis, the values on the axis are
in decreasing order.
@param bInverted
true if the axis has to be inverted.
**/
void SetInverted(bool bInverted);
//! Retrieves if the axis is inverted or not.
bool IsInverted() const { return m_bIsInverted; }
//! Sets the axis in automatic or manual mode.
/**
In automatic mode, the axis min and max will be updated
depending on the series related to this axis.
@param bAutomatic
true if the axis should be automatic.
@deprecated You should use the SetAutomaticType instead.
**/
void SetAutomatic(bool bAutomatic);
//! Returns true if an automatic mode has been set on this axis.
/**
@deprecated You should use the GetAutomaticType instead.
**/
bool IsAutomatic() const { return m_AutoMode != NotAutomatic; }
//! The different modes of automatic modes for an axis.
enum EAxisAutoModes
{
//! The axis min and max values are set manually
NotAutomatic,
//! The axis min and max values of the axis are the min and max values of all series associated with this axis. This corresponds to the "standard" automatic mode that was implemented before version 3.0.
FullAutomatic,
//! The axis min and max values of the axis are the <b>visible</b> min and max values of all series associated with this axis. The end result will then depends on how the other axes are configured.
ScreenAutomatic
};
//! Sets the automatic mode of the axis
void SetAutomaticMode(EAxisAutoModes AutoMode);
//! Gets the automatic type of the axis
EAxisAutoModes GetAutomaticMode() const { return m_AutoMode; }
//! Sets the axis visible/invisible.
void SetVisible(bool bVisible);
//! Retrieves the axis automatic mode.
bool IsVisible() const { return m_bIsVisible; }
//! Sets the axis min and max values.
/**
This doesn't take into account the real type of the axis,
so double values should be provided.
@param Minimum
The min value of the axis
@param Maximum
The max value of the axis.
**/
void SetMinMax(double Minimum, double Maximum);
//! Gets the min anx max values of the axis.
void GetMinMax(double& Minimum, double& Maximum) const
{
Minimum = m_MinValue;
Maximum = m_MaxValue;
}
//! Sets the axis color.
void SetAxisColor(COLORREF NewColor);
//! Sets the tick labels color.
void SetTextColor(COLORREF NewColor);
//! Gets the tick labels color.
COLORREF GetTextColor() const { return m_TextColor; }
//! Sets the tick labels font
/**
@param nPointSize
The font point size
@param strFaceName
The font face name
**/
void SetFont(int nPointSize, const TChartString& strFaceName);
//! Retrieves the chart axis label object
CChartAxisLabel* GetLabel() const { return m_pAxisLabel; }
//! Retrieves the chart axis grid object
CChartGrid* GetGrid() const { return m_pAxisGrid; }
//! Sets the margin size
/**
@param bAuto
Specifies if the margin size is automatic or not.
In automatic mode, the iNewSize parameter is ignored
and the margin size is calculated automatically.
@param iNewSize
The new size of the margin, in manual mode.
**/
void SetMarginSize(bool bAuto, int iNewSize);
//! Enable the pan and zoom for this axis.
void SetPanZoomEnabled(bool bEnabled) { m_bZoomEnabled = bEnabled; }
//! Sets the zoom limit.
/**
The zoom limit is the minimum lenght (in values) of the axis.
**/
void SetZoomLimit(double dLimit) { m_dZoomLimit = dLimit; }
//! Enables/disables the scroll bar.
void EnableScrollBar(bool bEnabled);
//! Retrieves if the scroll bar is enabled or not.
bool ScrollBarEnabled() const
{
if (m_pScrollBar)
return (m_pScrollBar->GetEnabled());
else
return false;
}
//! Specifies if the scroll bar is in auto-hide mode.
/**
In auto-hide mode, the scroll bar will be hidden until
you hover the mouse over it.
**/
void SetAutoHideScrollBar(bool bAutoHide);
//! Retrieves if the scroll bar is in auto-hide mode.
bool GetAutoHideScrollBar() const;
//! Sets the axis in discrete mode
/**
@param bDiscrete
true if the axis has to be discrete, false otherwise.
In discrete mode, the axis doesn't have a continuous range of values
but only steps which are defined by the tick interval. In this mode,
you won't be able to plot points at a different location that in the
middle of two ticks. For instance, if you have a tick interval of 1.0,
trying to plot a value of 0.9 will display the point at the same position
as if the value was 0.3: it will be displayed in the middle of tick 0.0 and
tick 1.0.
<br>It is mainly used to display the tick label in the middle of two ticks.
This is for instance nice with date/time axis.
**/
virtual void SetDiscrete(bool bDiscrete);
//! Converts a value on the axis to a screen position
/**
The functions takes care of the discrete mode (internally,
it calls ValueToScreenStandard or ValueToScreenDiscrete
depending on the discrete mode).
@param Value
The value to convert
@return the screen position of the value
**/
long ValueToScreen(double Value) const;
//! Converts a screen position to a value on the axis
/**
The function is implemented for an axis with a standard
behavior (the axis shows a continuous range of doubles).
It is the case for standard axis and date/time axis (date
are converted to doubles internally). Axis that needs a different
behavior should override this function (e.g. a logarithmic axis).
The function does not take care of the discrete mode.
@param ScreenVal
The screen value to convert
@return the double value
**/
virtual double ScreenToValue(long ScreenVal) const;
//! Returns true if the axis is horizontal
bool IsHorizontal() const { return m_bIsHorizontal; }
//! Returns true if a screen point is in the region of the axis.
BOOL IsPointInside(const CPoint& screenPoint) const;
protected:
//! Returns the first tick value.
/**
This pure virtual function must be implemented for specific
axes type.
**/
virtual double GetFirstTickValue() const = 0;
//! Retrieves the next tick value after a given tick.
/**
This pure virtual function must be implemented for specific
axes type.
@param dCurrentTick
The value of the current tick
@param dNextTick
The value of the next tick will be stored in this parameter
@return true if there is a next or false when the current tick is the last one.
**/
virtual bool GetNextTickValue(double dCurrentTick, double& dNextTick) const = 0;
//! Retrieves the screen position of a certain tick.
/**
This pure virtual function must be implemented for specific
axes type.
@param Value
The value of the tick for which we want to retrieve the position
@return
the screen position of the tick
**/
virtual long GetTickPos(double Value) const = 0;
//! Converts a value on the axis to a screen position.
/**
This function is called internally only when the axis is in
discrete mode. This pure virtual function must be implemented for specific
axes type.
@param Value
The value to convert
@return the screen position of the value
**/
virtual long ValueToScreenDiscrete(double Value) const = 0;
//! Converts a value on the axis to a screen position.
/**
This function is called internally only when the axis is in
standard mode. This virtual function can be overriden when the
axis doesn't display a continuous range of values (e.g. log axis).
@param Value
The value to convert
@return the screen position of the value
**/
virtual long ValueToScreenStandard(double Value) const;
//! Retrieves the label for a specific tick.
/**
This pure virtual function must be implemented for specific
axes type.
@param TickValue
The tick value for which we need to get the label.
@return A TChartString containing the label for the tick.
**/
virtual TChartString GetTickLabel(double TickValue) const = 0;
//! Forces a recalculation of the tick increment.
virtual void RefreshTickIncrement() = 0;
//! Forces a recalculation of the first tick value.
virtual void RefreshFirstTick() = 0;
//! Retrieves the step information related to the scrollbar.
/**
This function can be implemented for specific axis types which
should provide a behavior different than the standard behavior
(for instance log axis).
@param iTotalSteps
Stores the total number of steps for the scrollbar
@param iCurrentStep
Stores the current step index for the scrollbar
**/
virtual void GetScrollbarSteps(int& iTotalSteps, int& iCurrentStep);
//! Sets the axis to the specified scrollbar step.
/**
This function can be implemented for specific axis types which
should provide a behavior different than the standard behavior
(for instance log axis).
@param iPreviousStep
The previous scroll step.
@param iCurrentStep
The current scroll step to which the axis should be moved.
@param bScrollInverted
Specifies if the scroll is inverted or not.
**/
virtual void SetAxisToScrollStep(int iPreviousStep, int iCurrentStep, bool bScrollInverted);
//! Pan the axis
/**
This function can be overriden in case the axis doesn't display
a continuous range of values (e.g. log axis).
@param PanStart
The position of the start of the pan
@param PanEnd
The position of the end of the pan
**/
virtual void PanAxis(long PanStart, long PanEnd);
//! Sets the min and max values of the axis due to a zoom operation.
virtual void SetZoomMinMax(double Minimum, double Maximum);
//! Reverts the zoom and pan settings.
void UndoZoom();
//! Retrieves the lenght (in pixels) of the axis
long GetAxisLenght() const;
//! Retrieves the min and max values for all the series related to this axis
void GetSeriesMinMax(double& Minimum, double& Maximum);
//! Retrieves the screen min and max values for all the series related to this axis
void GetSeriesScreenMinMax(double& Minimum, double& Maximum);
private:
//! Refresh the axis if it is automatic
/**
@return true if the axis has changed
**/
bool RefreshAutoAxis();
//! Refresh the axis if it is automatic for the screen only
/**
@return true if the axis has changed
**/
bool RefreshScreenAutoAxis();
//! Returns the largest tick width and the largest tick heigh.
/**
The function returns a CSize object for which the x value
is the largest width and the y value is the largest height.
They do not necessarily belong to the same tick.
**/
CSize GetLargestTick(CDC* pDC);
//! Sets the axis as a secondary axis.
/**
A secondary axis is on top for horizontal axis and on the
right for vertical axis.
**/
void SetSecondary(bool bSecondary) { m_bIsSecondary = bSecondary; }
//! Returns true if the axis is secondary.
bool IsSecondary() const { return m_bIsSecondary; }
//! Sets the axis to horizontal/vertical
void SetHorizontal(bool bHorizontal);
//! Draw the axis on the chart
/**
@param pDC
The DC used to draw the axis.
**/
void Draw(CDC* pDC);
//! Draw the axis label
/**
@param pDC
The DC used to draw the axis.
**/
void DrawLabel(CDC* pDC);
//! Draw a specific tick on the axis.
/**
@param pDC
The DC used to draw the axis.
@param dTickVal
The tick value.
The tick label will be drawn on the tick or between two ticks
depending if the axis is set as standard or discrete.
**/
void DrawTick(CDC* pDC, double dTickVal);
//! Check whether a specific label is still on the axis.
/**
@param dTickVal
The tick value.
The function returns false if the label is outside
the axis range (and thus, should not be drawn).
**/
bool IsLabelOnAxis(double TickVal);
//! Register a series that is associated with this axis.
/**
This is used when the axis is in automatic mode.
**/
void RegisterSeries(CChartSerie* pSeries);
//! Unregister a series with this axis.
void UnregisterSeries(CChartSerie* pSeries);
//! Creates and attach a new scroll bar to the axis
void CreateScrollBar();
//! Update the scroll bar position depending on the plotting rect.
void UpdateScrollBarPos();
//! Refreshes the scroll bar.
void RefreshScrollBar();
//! Sets the parent charting control.
void SetParent(CChartCtrl* pParent);
//! Sets the axis size
/**
@param ControlRect
The rectangle of the control
@param MarginRect
The rectangle in which the axis should be contained
**/
void SetAxisSize(const CRect& ControlRect, const CRect& MarginRect);
//! Removes the margin needed for the axis from the full control rect.
/**
@param ControlRect
The rectangle of the control
@param MarginRect
The rectangle in which the axis should be contained
@param pDC
The CDC used to draw the axis.
**/
int ClipMargin(CRect ControlRect,CRect& MarginRect,CDC* pDC);
//! Recalculate the axis properties.
/**
This function simply calls RefreshTickIncrement and
RefreshFirstTick.
**/
void Recalculate();
protected:
//! The parent chart control.
CChartCtrl* m_pParentCtrl;
//! Indicates if this is an horizontal or vertical axis
bool m_bIsHorizontal;
//! Indicates if the axis is inverted
bool m_bIsInverted;
//! Indicates if the axis is automatic
// bool m_bIsAutomatic;
//! Indicates the automatic mode of the axis
EAxisAutoModes m_AutoMode;
//! Indicates if the axis is visible or not
bool m_bIsVisible;
//! Specifies if the axis is secondary
/**
The secondary axis is either on the top (for horizontal
axis) or on the right (for vertical axis) of the chart.
**/
bool m_bIsSecondary;
//! The axis max value
double m_MaxValue;
//! The axis min value
double m_MinValue;
//! Min value of the axis before it has been zoomed
double m_UnzoomMin;
//! Max value of the axis before it has been zoomed
double m_UnzoomMax;
//! Specify if the tick increment is manual or automatic
bool m_bAutoTicks;
//! Specify if the axis has to be in discrete mode or not
bool m_bDiscrete;
//! Start position of the axis (in pixels)
int m_StartPos;
//! End position of the axis (in pixels)
int m_EndPos;
//! The rectangle in which the axis is contained.
CRect m_AxisRect;
private:
//! The font size used for the axis labels
int m_nFontSize;
//! The font face name used for the axis labels
TChartString m_strFontName;
//! The color used for the axis labels
COLORREF m_TextColor;
//! The color used for the axis line
COLORREF m_AxisColor;
//! The grid related to this axis
CChartGrid* m_pAxisGrid;
//! The axis label associated with this axis
CChartAxisLabel* m_pAxisLabel;
typedef std::list<CChartSerie*> SeriesList;
//! List containing pointers to series related to this axis
SeriesList m_pRelatedSeries;
//! Specify if the margin size is calculated automatically
bool m_bAutoMargin;
//! The margin size, used in manual mode
int m_iMarginSize;
//! Specifies if the zoom is enabled for this axis
bool m_bZoomEnabled;
//! The zoom limit (axis can't be zoomed under this limit)
double m_dZoomLimit;
//! The axis scrollbar
CChartScrollBar* m_pScrollBar;
};
#endif // _CHARTAXIS_H_