Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

High-speed Charting Control

, 13 Jul 2010 CPOL
A flexible charting control to display 2D data
chartcrtl_src.zip
ChartCtrl_demo.zip
ChartDemo
ChartCtrl
.svn
all-wcprops
entries
format
prop-base
props
text-base
ChartAxis.cpp.svn-base
ChartAxis.h.svn-base
ChartAxisLabel.cpp.svn-base
ChartAxisLabel.h.svn-base
ChartBalloonLabel.h.svn-base
ChartBalloonLabel.inl.svn-base
ChartBarSerie.cpp.svn-base
ChartBarSerie.h.svn-base
ChartCandlestickSerie.cpp.svn-base
ChartCandlestickSerie.h.svn-base
ChartCrossHairCursor.cpp.svn-base
ChartCrossHairCursor.h.svn-base
ChartCtrl.cpp.svn-base
ChartCtrl.h.svn-base
ChartCursor.cpp.svn-base
ChartCursor.h.svn-base
ChartDateTimeAxis.cpp.svn-base
ChartDateTimeAxis.h.svn-base
ChartDragLineCursor.cpp.svn-base
ChartDragLineCursor.h.svn-base
ChartFont.cpp.svn-base
ChartFont.h.svn-base
ChartGanttSerie.cpp.svn-base
ChartGanttSerie.h.svn-base
ChartGradient.cpp.svn-base
ChartGradient.h.svn-base
ChartGrid.cpp.svn-base
ChartGrid.h.svn-base
ChartLabel.h.svn-base
ChartLabel.inl.svn-base
ChartLegend.cpp.svn-base
ChartLegend.h.svn-base
ChartLineSerie.cpp.svn-base
ChartLineSerie.h.svn-base
ChartLogarithmicAxis.cpp.svn-base
ChartLogarithmicAxis.h.svn-base
ChartMouseListener.h.svn-base
ChartPointsArray.h.svn-base
ChartPointsArray.inl.svn-base
ChartPointsSerie.cpp.svn-base
ChartPointsSerie.h.svn-base
ChartScrollBar.cpp.svn-base
ChartScrollBar.h.svn-base
ChartSerie.cpp.svn-base
ChartSerie.h.svn-base
ChartSerieBase.h.svn-base
ChartSerieBase.inl.svn-base
ChartSeriesMouseListener.h.svn-base
ChartStandardAxis.cpp.svn-base
ChartStandardAxis.h.svn-base
ChartString.h.svn-base
ChartSurfaceSerie.cpp.svn-base
ChartSurfaceSerie.h.svn-base
ChartTitle.cpp.svn-base
ChartTitle.h.svn-base
ChartXYSerie.cpp.svn-base
ChartXYSerie.h.svn-base
PointsOrdering.h.svn-base
tmp
prop-base
props
text-base
ChartBalloonLabel.inl
ChartCtrl_source.zip
ChartLabel.inl
ChartPointsArray.inl
ChartSerieBase.inl
ChartDemo.dsp
ChartDemo.dsw
ColourPicker
.svn
entries
format
prop-base
props
text-base
ColourPicker.cpp.svn-base
ColourPicker.h.svn-base
ColourPopup.cpp.svn-base
ColourPopup.h.svn-base
tmp
prop-base
props
text-base
Doc
html
class_c_chart_axis.png
class_c_chart_balloon_label.png
class_c_chart_bar_serie.png
class_c_chart_candlestick_serie.png
class_c_chart_cross_hair_cursor.png
class_c_chart_cursor.png
class_c_chart_date_time_axis.png
class_c_chart_drag_line_cursor.png
class_c_chart_gantt_serie.png
class_c_chart_label.png
class_c_chart_line_serie.png
class_c_chart_logarithmic_axis.png
class_c_chart_points_serie.png
class_c_chart_serie.png
class_c_chart_serie_base.png
class_c_chart_standard_axis.png
class_c_chart_surface_serie.png
class_c_chart_x_y_serie.png
doxygen.png
tab_b.gif
tab_l.gif
tab_r.gif
res
ChartDemo.ico
ChartCtrl_doxygen.zip
html
class_c_chart_axis.png
class_c_chart_balloon_label.png
class_c_chart_bar_serie.png
class_c_chart_candlestick_serie.png
class_c_chart_cross_hair_cursor.png
class_c_chart_cursor.png
class_c_chart_date_time_axis.png
class_c_chart_drag_line_cursor.png
class_c_chart_gantt_serie.png
class_c_chart_label.png
class_c_chart_line_serie.png
class_c_chart_logarithmic_axis.png
class_c_chart_points_serie.png
class_c_chart_serie.png
class_c_chart_serie_base.png
class_c_chart_standard_axis.png
class_c_chart_surface_serie.png
class_c_chart_x_y_serie.png
doxygen.png
tab_b.gif
tab_l.gif
tab_r.gif
ChartCtrl_source.zip
ChartLabel.inl
ChartPointsArray.inl
ChartSerieBase.inl
ChartBalloonLabel.inl
chartctrl_src.zip
chartctr_demo.zip
ChartDemo.clw
ChartDemo.dsp
ChartDemo.dsw
res
ChartDemo.ico
/*
 *
 *	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_

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Cedric Moonen
Engineer
Belgium Belgium
I am a 29 years old guy and I live with my girlfriend in Hoegaarden, little city from Belgium well known for its white beer Smile | :) .
I studied as an industrial engineer in electronics but I oriented myself more towards software development when I started to work.
Currently I am working in a research centre in mechatronica. I mainly develop in C++ but I also do a bit of Java.
When I have so spare time, I like to read (mainly fantasy) and play electric guitar.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411023.1 | Last Updated 13 Jul 2010
Article Copyright 2006 by Cedric Moonen
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid