Click here to Skip to main content
15,886,799 members
Articles / Desktop Programming / MFC

Scientific charting control

Rate me:
Please Sign up or sign in to vote.
4.84/5 (122 votes)
17 Jan 20055 min read 1.3M   42.6K   405  
Multi-purpose scientific charting control.
///////////////////////////////////////////////////////////////////////////////////////
// XGraph.h
//
// Main header file for the CXGraph charting control
//
// You are free to use, modify and distribute this source, as long as
// there is no charge, and this HEADER stays intact. This source is
// supplied "AS-IS", without WARRANTY OF ANY KIND, and the user
// holds me blameless for any or all problems that may arise
// from the use of this code.
//
// Expect bugs.
//
// Gunnar Bolle (webmaster@beatmonsters.com)
// 
// 
// History
// 
// 21 Mar 2002    1.00    First release
// 26 Mar 2002    1.01    Fixed DateTime-bug in cursor mode
//						  (thanks to Pavel Klocek for providing the fix)
//						  Fixed crash when adding trend or moving average
// 11 Apr 2002    1.02    Panning in cursor mode added
//						  Added support for very large and very small numbers
//						  Values greater/less 10E6/10E-6 are now automatically shown in 
//                        exponential format
//                        Completely redesigned autoscaling (only for normal axes, 
//                        DateTime types follow) 
//                        Added data notation marks
//                        Added Get/Set member functions
//                        Added nth-order-polynomial trend
// 25. Sep 2002   1.03    Now compiles under VC7
//                        Load/Save for properties/data/object persistence
//						  Added zoom-history
// unreleased	  1.04    Added UNICODE support
//                        Added background bitmaps
//                        Added bitmap objects
//                        Added gradient colorranges
//						  Added axismarkers
// 02.12.2004     1.05    Added support for WINDOWS CE (needs improvement)
//						  Logarithmic axes (thanks to ...)
//						  Added polygonfilling between 2 curves
//   					  Several Bugs fixed by Joerg Blattner
//						  Added Cursor-Synchronisation
//						  Curve editing mode
//						  Measuring mode
// 
//						  					
// Known issues
// 
// - clipping in print preview doesn't work
//
// Additional credits
//
// - Ishay Sivan (Bugfixing) 
// - Pavel Klocek (Bugfixing)
// - James White (color button)
// - Chris Maunder (color popup)
// - Keith Rule (MemDC)
// - J.G. Hattingh (parts of Device Context Utilities)
// - J�rg Blattner (Bugfixing, improvements)
//
///////////////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_XGRAPH_H__6F244A3B_22E2_4F7F_802F_8FBA303058C1__INCLUDED_)
#define AFX_XGRAPH_H__6F244A3B_22E2_4F7F_802F_8FBA303058C1__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif 

#ifndef __AFXTEMPL_H__
#include <afxtempl.h>
#endif

#include "resource.h"

#include <vector>
#include <list>
#include <functional>

using namespace std;

class CXGraph;

#include "XGraphObjectBase.h"
#include "XGraphDataSerie.h"
#include "XGraphAxis.h"
#include "XGraphLabel.h"
#include "XGraphBitmap.h"
#include "XGraphDataNotation.h"

#define XG_YAXISCLICK	   WM_USER + 1
#define XG_XAXISCLICK	   WM_USER + 2
#define XG_CURVECLICK	   WM_USER + 3
#define XG_YAXISDBLCLICK   WM_USER + 4
#define XG_XAXISDBLCLICK   WM_USER + 5
#define XG_CURVEDBLCLICK   WM_USER + 6
#define XG_GRAPHDBLCLICK   WM_USER + 7
#define XG_RBUTTONUP       WM_USER + 8
#define XG_CURSORMOVED     WM_USER + 9
#define XG_ZOOMCHANGE      WM_USER + 10
#define XG_POINTCHANGED    WM_USER + 11

#define BITMAP_CHART	   0x01
#define BITMAP_INNER       0x02
#define BITMAP_NOSIZE      0x04
#define BITMAP_STRETCH     0x08
#define BITMAP_TILE        0x10

#define PERSIST_PROPERTIES 0x01  
#define PERSIST_DATA       0x02
#define PERSIST_OBJECTS    0x04

#define XGC_HORIZ		   0x01
#define XGC_VERT		   0x02
#define XGC_LEGEND		   0x04
#define XGC_ADJUSTSMOOTH   0x08

#define MIN_ZOOM_PIXELS    15


// Custom clipboard formats

#define CF_XBITMAP		   _T("XGRAPHBITMAP")
#define CF_XLABEL		   _T("XGRAPHLABEL")

const COLORREF BASECOLORTABLE[12] = 
{
	RGB(128,0,0),
	RGB(255,0,0),
	RGB(128,128,0),
	RGB(255,255,0),
	RGB(0,128,0),
	RGB(0,255,0),
	RGB(0,128,128),
	RGB(0,255,255),
	RGB(0,0,128),
	RGB(0,0,255),
	RGB(128,0,128),
	RGB(255,0,255)
};

#define MAX_MARKERS 8

#ifdef _AFXDLL
class __declspec(dllexport)  CXGraph : public CWnd
#else
class __declspec(dllimport)  CXGraph : public CWnd
#endif
{

	DECLARE_SERIAL( CXGraph )

	friend class CXGraphAxis;
	friend class CXGraphLogAxis;
	friend class CXGraphDataSerie;
	friend class CXGraphLabel;

public:

	enum { VERSION = 105 };

	CXGraph();

public:

	enum EOperation {

		opNone,
		opZoom,
		opReset,
		opPan,
		opCursor,
		opMoveObject,
		opEditObject,
		opEditCurve,
		opMeasure
	};

	enum EAlignment
	{
		left,
		right,
		top,
		bottom
	};

	typedef struct tagNM_POINTMOVING
	{
		long    nCurve;
		long	nIndex;
		double  dOldVal;
		double  dNewVal;
	} NM_POINTMOVING;

	typedef struct tagMeasureDef
	{
		long nCurve1;
		long nIndex1;
		long nCurve2;
		long nIndex2;
	} MeasureDef;




public:

	//{{AFX_VIRTUAL(CXGraph)
	public:
	virtual BOOL PreTranslateMessage(MSG* pMsg);
	virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
	//}}AFX_VIRTUAL

public:
	virtual ~CXGraph();

	CXGraphDataSerie& SetData(TDataPoint* pValues, long nCount, int nCurve = 0, int nXAxis = 0, int nYAxis = 0, bool bAutoDelete = false);
	
	CXGraphAxis& GetXAxis(int nAxis);
	CXGraphAxis& GetYAxis(int nAxis);
	CXGraphDataSerie& GetCurve(int nCurve);

	bool DeleteCurve(int nCurve);
	bool DeleteXAxis(int nAxis);
	bool DeleteYAxis(int nAxis);
	
	void InsertDataNotation(int nCurve, int nIndex);
	void AddLinearTrend(CXGraphDataSerie& serie);
	void AddCubicTrend(CXGraphDataSerie& serie);

	int  GetXAxisCount() { return m_XAxis.size(); };
	int  GetYAxisCount() { return m_YAxis.size(); };
	int  GetCurveCount() { return m_Data.size(); };

	bool SelectCurve(int nCurve);
	bool SelectXAxis(int nAxis);
	bool SelectYAxis(int nAxis);

	void SetGraphMargins(int nLeft, int nTop, int nRight, int nBottom);

#ifndef _WIN32_WCE
	BOOL SaveBitmap(const CString cFile);
#endif

	// Graph operations
	void Edit();
	void Zoom();
	void ResetZoom();
	void Pan();
	void NoOp();
	void Cursor();
	void Measure();
	

	void OnDraw(CDC *pDC);

#ifndef _WIN32_WCE
	void PrintGraph(CDC *pDC);
	void PrintGraph(CDC *pDC, CRect printRect);
#endif

	int  GetZoomDepth();
	
	void ResetAll();

	bool SetBackgroundBitmap(CBitmap* pBitmap, UINT nFlags = BITMAP_CHART | BITMAP_STRETCH);

	CXGraphLabel&  InsertLabel(CString cText = _T(""));
	CXGraphLabel&  InsertLabel(CRect rect, CString cText = _T(""));
	CXGraphBitmap& InsertBitmap(CRect rect, CBitmapEx* pBitmap);

	inline void SetBackColor(COLORREF color)		 { m_crBackColor = color; };
	inline void SetGraphColor(COLORREF color)		 { m_crGraphColor = color; };
	inline void SetInnerColor(COLORREF color)		 { m_crInnerColor = color; };
	inline void SetDoubleBuffer(bool bValue)		 { m_bDoubleBuffer = bValue; };
	inline void SetShowLegend(bool bValue)			 { m_bShowLegend = bValue; };
	inline void SetInteraction(bool bValue)		     { m_bInteraction = bValue; };
	inline void SetLegendAlignment(EAlignment align) { m_LegendAlignment = align; };
	inline void SetSnapCursor(bool bValue)			 { m_bSnapCursor = bValue; };
	inline void SetSnapRange(int nValue)			 { m_nSnapRange = nValue; };
	inline void SetPrintHeader(CString cHeader)      { m_cPrintHeader = cHeader; };
	inline void SetPrintFooter(CString cFooter)      { m_cPrintFooter = cFooter; };
	inline void SetCursor(CPoint point)              { m_CurrentPoint = point; };
	inline void SetCursorFlags(UINT nFlags)			 { m_nCursorFlags = nFlags; };
	
	void		Autoscale(int nXAxis, int nYAxis, int nCurve);

	inline void DeleteMeasures()                     { m_Measures.clear(); };

	inline void ForceSnap (UINT nCurve)              { m_nForcedSnapCurve = nCurve; };


	inline COLORREF   GetBackColor()		{ return m_crBackColor; };
	inline COLORREF   GetGraphColor()		{ return m_crGraphColor; };
	inline COLORREF   GetInnerColor()		{ return m_crInnerColor; };
	inline bool		  GetDoubleBuffer()		{ return m_bDoubleBuffer; };
	inline bool		  GetShowLegend()		{ return m_bShowLegend; };
	inline bool       GetInteraction()      { return m_bInteraction; };
	inline EAlignment GetLegendAlignment()	{ return m_LegendAlignment; };
	inline bool		  GetSnapCursor()		{ return m_bSnapCursor; };
	inline int		  GetSnapRange()		{ return m_nSnapRange; };
	inline CPoint     GetCursor()           { return m_CurrentPoint; };
	inline EOperation GetOperation()        { return m_opOperation; };
	
	TDataPoint GetCursorAbsolute(int nCurve);
	void	 SetCursorAbsolute(int nCurve, TDataPoint vPoint, bool bForceVisible = false);


	bool   Save(const CString cFile, UINT nFlags = PERSIST_PROPERTIES | PERSIST_DATA | PERSIST_OBJECTS);
	bool   Load(const CString cFile);

	lpDrawFunc  m_pDrawFn[MAX_MARKERS];

protected:

#ifndef _WIN32_WCE
	BOOL   WriteDIB( LPTSTR szFile, HANDLE hDIB);
	HANDLE DDBToDIB( CBitmap& bitmap, DWORD dwCompression, CPalette* pPal );
#endif

	void   Serialize( CArchive& archive, UINT nFlags);

	//{{AFX_MSG(CXGraph)
	afx_msg void OnPaint();
	afx_msg void OnSize(UINT nType, int cx, int cy);
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
#if _MFC_VER >= 0x0700
	afx_msg BOOL OnMouseWheel( UINT nFlags, short zDelta, CPoint pt );
#else
	afx_msg void OnMouseWheel( UINT nFlags, short zDelta, CPoint pt );
#endif
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
	afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
#ifndef _WIN32_WCE
	afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
#endif
	afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
#ifndef _WIN32_WCE
	afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
#endif
	afx_msg void ParentCallback();
	afx_msg void RestoreLastZoom();

#ifndef _WIN32_WCE
	afx_msg void OnCopy();
	afx_msg void OnPaste();
#endif

	//}}AFX_MSG

	DECLARE_MESSAGE_MAP()

private:


	typedef struct tagSelectByMarker {

		CRect markerRect;
		CXGraphObject* pObject;

	} SelectByMarker;

	static NM_POINTMOVING		m_nmCurrentPointMoving;
	COLORREF					m_crBackColor;
	COLORREF					m_crGraphColor;
	COLORREF					m_crInnerColor;
	bool						m_bDoubleBuffer;
	bool						m_bShowLegend;
	bool						m_bInteraction;
	bool						m_bTmpDC;
	EAlignment					m_LegendAlignment;
	bool						m_bSnapCursor;
	int							m_nSnapRange;
	UINT						m_nCursorFlags;

	CDCEx*                      m_pPrintDC;
	CDCEx*                      m_pDrawDC;
	CRectTracker*               m_pTracker;
	CRect                       m_clInnerRect;
	CRect                       m_clCurrentMeasure;
	CRect                       m_OldCursorRect;
	CRect                       m_clPrintRect;
	CPoint                      m_OldPoint;
	EOperation                  m_opOperation;
	int                         m_nSnappedCurve;
	int                         m_nSnappedCurve1;
	int                         m_nLeftMargin,
								m_nTopMargin,
								m_nRightMargin,
								m_nBottomMargin;
	int                         m_nAxisSpace;
	int                         m_nBitmapFlags;
	int							m_nForcedSnapCurve;
	CRect                       m_clCurrentZoom;
	CBitmap*                    m_pBitmap;
	CPoint						m_MouseDownPoint,
								m_oldCursorPoint,
								m_MouseUpPoint,
								m_CurrentPoint;
	bool 						m_bLButtonDown;
	bool 						m_bRButtonDown;
	bool						m_bObjectSelected;
	double						m_fCurrentEditValue;
	bool						m_bDataPointMoving;
	int				            m_nSelectedSerie;
	double                      m_fSnappedXVal,
		                        m_fSnappedYVal;
	CString                     m_cPrintHeader;
	CString                     m_cPrintFooter;
	CXGraphLabel                m_CursorLabel;
	MeasureDef                  m_MeasureDef;

	vector <MeasureDef>         m_Measures;
	vector <SelectByMarker>     m_SelectByMarker;
	vector <CXGraphDataSerie>	m_Data;
	vector <CXGraphAxis>		m_XAxis;
	vector <CXGraphAxis>		m_YAxis;
	CObList				        m_Objects;
	CXGraphObject*              m_pCurrentObject;
	UINT                        m_nCFBitmap;
		

	
	void AdjustPointToData(CPoint& point);
	void InsertEmptyLabel();
	bool CheckObjectSelection(bool bEditAction = false, bool bCheckFocusOnly = false);
	void GetMinMaxForData (CXGraphDataSerie& serie, double& fXMin, double& fXMax, double& fYMin, double& fYMax);
	int  GetAxisIndex(CXGraphAxis* pAxis);
	int  GetCurveIndex(CXGraphDataSerie* pSerie);
	void DrawLegend(CDCEx *pDC, CRect& ChartRect);
	void DrawCursorLegend (CDCEx* pDC);
	void DrawBackgroundBitmap(CDCEx* pDC, CRect clChartRect);
	void DoZoom();
	void DoPan(CPoint point);
	void DrawZoom(CDCEx* pDC);
	void DrawMeasure(CDCEx* pDC, CRect measureRect);
	void DrawMeasures(CDCEx* pDC);
	void DrawCursor(CDCEx* pDC);
	void LinearTrend();
	void CubicTrend();
	void OnProperties();
#ifndef _WIN32_WCE
	void OnPrint();
#endif
};

#if _MSC_VER < 1300

	// CArchive operators for C++ bool, guess the guys at microsoft have forgotten this
	// after introducing the "bool" type
	inline CArchive& operator <<(CArchive& ar, bool b) 
	{
		ar << (b ? TRUE : FALSE);
		return ar;
	};

	inline CArchive& operator >>(CArchive& ar, bool& b) 
	{
		BOOL old_b;
		ar >> old_b;
		(old_b ? b = true : b = false);
		return ar;
	};

#endif


//{{AFX_INSERT_LOCATION}}


#endif // AFX_XGRAPH_H__6F244A3B_22E2_4F7F_802F_8FBA303058C1__INCLUDED_



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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions