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

A 2D Graph Component With Zoom Capability

, 21 Dec 2004 CPOL
A 2D graph component with zoom capability.
smartgraphdemo_src.zip
res
cur1.cur
cur2.cur
SmartGraphDemo.ico
SmartGraphDemo.manifest
SmartGraphDemoDoc.ico
Toolbar.bmp
smartgraph_dll_exe.zip
msvcr71.dll
Graph.dll
SmartGraphDemo.exe
smartgraph_src.zip
SmartGraph.bmp
_Graph.tlb
bitmap1.bmp
Graph.rgs
Graphps.def
smart_graph_dll_exe.zip
msvcr71.dll
SmartGraphDemo.exe
SmartGraph.dll
// SmartGraph.h : Declaration of the SmartGraph
#pragma once
#include "resource.h"       // main symbols
#include <atlctl.h>
#include "comutil.h"
#pragma comment(lib,"comsupp.lib")
#include <Math.h>
#include <atlcoll.h>
#include "GraphDataSet.h"
const static double PI = 3.1415926535897932384626433832795;

#define GRAPH_RESIZED	1
#define DATA_CHANGED	2
#define SEL_CHANGED		3
#define GRID_CHANGED	4


// ISmartGraph
[
	object,
	uuid(1EECA078-14D3-427D-AEA5-F9342ABBFC7C),
	dual,
	helpstring("ISmartGraph Interface"),
	pointer_default(unique)
]
__interface ISmartGraph : public IDispatch
{
	[propput, bindable, requestedit, id(DISPID_BACKCOLOR)]
	HRESULT BackColor([in]OLE_COLOR clr);
	[propget, bindable, requestedit, id(DISPID_BACKCOLOR)]
	HRESULT BackColor([out,retval]OLE_COLOR* pclr);
	[propput, bindable, requestedit, id(DISPID_BORDERCOLOR)]
	HRESULT BorderColor([in]OLE_COLOR clr);
	[propget, bindable, requestedit, id(DISPID_BORDERCOLOR)]
	HRESULT BorderColor([out, retval]OLE_COLOR* pclr);
	[propput, bindable, requestedit, id(DISPID_FORECOLOR)]
	HRESULT ForeColor([in]OLE_COLOR clr);
	[propget, bindable, requestedit, id(DISPID_FORECOLOR)]
	HRESULT ForeColor([out,retval]OLE_COLOR* pclr);
	[propget, id(1), helpstring("property Title")] HRESULT Title([out, retval] BSTR* pVal);
	[propput, id(1), helpstring("property Title")] HRESULT Title([in] BSTR newVal);
	[propget, id(2), helpstring("property xLable")] HRESULT xLable([out, retval] BSTR* pVal);
	[propput, id(2), helpstring("property xLable")] HRESULT xLable([in] BSTR newVal);
	[propget, id(3), helpstring("property yLable")] HRESULT yLable([out, retval] BSTR* pVal);
	[propput, id(3), helpstring("property yLable")] HRESULT yLable([in] BSTR newVal);
	[propget, id(4), helpstring("property Columns")] HRESULT Columns([out, retval] LONG* pVal);
	[propput, id(4), helpstring("property Columns")] HRESULT Columns([in] LONG newVal);
	[propget, id(5), helpstring("property Rows")] HRESULT Rows([out, retval] LONG* pVal);
	[propput, id(5), helpstring("property Rows")] HRESULT Rows([in] LONG newVal);
	[propget, id(6), helpstring("property MarginBottom")] HRESULT MarginBottom([out, retval] LONG* pVal);
	[propput, id(6), helpstring("property MarginBottom")] HRESULT MarginBottom([in] LONG newVal);
	[propget, id(7), helpstring("property MarginTop")] HRESULT MarginTop([out, retval] LONG* pVal);
	[propput, id(7), helpstring("property MarginTop")] HRESULT MarginTop([in] LONG newVal);
	[propget, id(8), helpstring("property MarginRight")] HRESULT MarginRight([out, retval] LONG* pVal);
	[propput, id(8), helpstring("property MarginRight")] HRESULT MarginRight([in] LONG newVal);
	[propget, id(9), helpstring("property MarginLeft")] HRESULT MarginLeft([out, retval] LONG* pVal);
	[propput, id(9), helpstring("property MarginLeft")] HRESULT MarginLeft([in] LONG newVal);
	[id( 10), helpstring("method SetData")] HRESULT SetData([in] DOUBLE* xData, [in] DOUBLE* yData, [in] LONG NumOfPoints, [in] VARIANT_BOOL bResample);
	[id(11), helpstring("method SetDataWithDetail")] HRESULT SetData2([in] DOUBLE* xData, [in] DOUBLE* yData, [in] LONG NumOfPoints, 
		[in] DOUBLE xMin, [in] DOUBLE xMax, [in] DOUBLE yMin, [in] DOUBLE yMax, [in] VARIANT_BOOL bResample);
	[id(12), helpstring("method ShowGrid")] HRESULT ShowGrid([in] VARIANT_BOOL bShow);
	[id(13), helpstring("method UpdateGraph")] HRESULT UpdateGraph(void);
	[id(14), helpstring("method SetPlotType")] HRESULT SetPlotType([in] LONG nType);
	[id(15), helpstring("method GetPlotRect")] HRESULT GetPlotRect([out] LONG* left, [out] LONG* top, [out] LONG* right,[out] LONG* bottom);
	[id(16), helpstring("method GetClientRect")] HRESULT GetClientRect([out] LONG* left, [out] LONG* top, [out] LONG* right,[out] LONG* bottom);
	[id(17), helpstring("method ZoomIn")] HRESULT ZoomIn([in] LONG FromSample, [in] LONG ToSample);
	[id(18), helpstring("method ZoomInByPercent")] HRESULT ZoomInByPercent([in] DOUBLE FromPercent, [in] DOUBLE ToPercent);
	[id(19), helpstring("method ZoomOut")] HRESULT ZoomOut(void);
	[id(20), helpstring("Resets graph view to original view"), helpcontext(20)] HRESULT Reset(void);
	[id(21), helpstring("method GetDisplayedRange")] HRESULT GetDisplayedRange([out] LONGLONG* nStartSample, [out] LONGLONG* nEndSample);
	[id(22), helpstring("method SetLegendText")] HRESULT SetLegendText([in] BSTR strText, LONG top, LONG left, LONG bottom, LONG right);
	[id(23), helpstring("method SetParentWnd")] HRESULT SetParentWnd([in] OLE_HANDLE hWnd);
	[id(24), helpstring("method GetPlotType")] HRESULT GetPlotType(LONG* PlotType);
};


// _ISmartGraphEvents
[
	uuid("1F12078D-03B2-4C25-84CA-3191E7DF3FFB"),
	dispinterface,
	helpstring("_ISmartGraphEvents Interface")
]
__interface _ISmartGraphEvents
{
	[id(1), helpstring("method LButtonDown")] HRESULT LButtonDown([in] LONG xPos, LONG yPos, LONGLONG wParam);
	[id(2), helpstring("method LButtonUp")] HRESULT LButtonUp([in] LONG xPos, LONG yPos, LONGLONG wParam);
	[id(3), helpstring("method MouseMove")] HRESULT MouseMove([in] LONG xPos, LONG yPos, LONGLONG wParam);
};

// SmartGraph
[
	coclass,
	threading("apartment"),
	vi_progid("Graph.SmartGraph"),
	progid("Graph.SmartGraph.1"),
	version(1.0),
	uuid("A2919A75-B379-4BBD-8D95-15BEB3BAA140"),
	helpstring("SmartGraph Class"),
	event_source("com"),
	support_error_info(ISmartGraph),
	registration_script("control.rgs")
]
class ATL_NO_VTABLE SmartGraph : 
	public CStockPropImpl<SmartGraph, ISmartGraph>,
	public IPersistStreamInitImpl<SmartGraph>,
	public IOleControlImpl<SmartGraph>,
	public IOleObjectImpl<SmartGraph>,
	public IOleInPlaceActiveObjectImpl<SmartGraph>,
	public IViewObjectExImpl<SmartGraph>,
	public IOleInPlaceObjectWindowlessImpl<SmartGraph>,
	public IPersistStorageImpl<SmartGraph>,
	public ISpecifyPropertyPagesImpl<SmartGraph>,
	public IQuickActivateImpl<SmartGraph>,
	public IDataObjectImpl<SmartGraph>,
	public CComControl<SmartGraph>
{
public:

	SmartGraph()
		: m_nRow(5)
		, m_nCol(5)
	{
	}

DECLARE_OLEMISC_STATUS(OLEMISC_RECOMPOSEONRESIZE | 
	OLEMISC_CANTLINKINSIDE | 
	OLEMISC_INSIDEOUT | 
	OLEMISC_ACTIVATEWHENVISIBLE | 
	OLEMISC_SETCLIENTSITEFIRST
)


BEGIN_PROP_MAP(SmartGraph)
	PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
	PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
	PROP_ENTRY("BackColor", DISPID_BACKCOLOR, CLSID_StockColorPage)
	PROP_ENTRY("BorderColor", DISPID_BORDERCOLOR, CLSID_StockColorPage)
	PROP_ENTRY("ForeColor", DISPID_FORECOLOR, CLSID_StockColorPage)
	// Example entries
	// PROP_ENTRY("Property Description", dispid, clsid)
	// PROP_PAGE(CLSID_StockColorPage)
END_PROP_MAP()


BEGIN_MSG_MAP(SmartGraph)
	CHAIN_MSG_MAP(CComControl<SmartGraph>)
	MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
	MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
	MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
	DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
// Handler prototypes:
//  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);

	__event __interface _ISmartGraphEvents;
// IViewObjectEx
	DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE)

// ISmartGraph
public:
		HRESULT OnDraw(ATL_DRAWINFO& di)
		{
			static bool bLock = false;
			if(bLock)
				return S_FALSE;
			bLock = true;
			RECT& rc = *(RECT*)di.prcBounds;
			static RECT rcOld = rc;
			if( ( (rc.right - rc.left) != (rcOld.right - rcOld.left) )||
				( (rc.bottom - rc.top) != (rcOld.bottom - rcOld.top) )
				)
				m_bDirty = true;
			rcOld.top = rc.top;
			rcOld.bottom = rc.bottom;
			rcOld.right = rc.right;
			rcOld.left = rc.left;

			// Set Clip region to the rectangle specified by di.prcBounds
			HRGN hRgnOld = NULL;
			if (GetClipRgn(di.hdcDraw, hRgnOld) != 1)
				hRgnOld = NULL;
			bool bSelectOldRgn = false;

			if(m_RgnClient)
				DeleteObject(m_RgnClient);
			m_RgnClient = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);

			if (m_RgnClient != NULL)
			{
				bSelectOldRgn = (SelectClipRgn(di.hdcDraw, m_RgnClient) != ERROR);
			}

			m_rcClient = rc;
			m_rcPlot.left = rc.left + m_nLMargin;
			m_rcPlot.top	= rc.top  + m_nTMargin;
			m_rcPlot.bottom	= rc.bottom - m_nBMargin;
			m_rcPlot.right	= rc.right - m_nRMargin;

			UpdateGraph(di.hdcDraw);

			if (bSelectOldRgn)
				SelectClipRgn(di.hdcDraw, hRgnOld);
			bLock = false;
			return S_OK;
		}

	OLE_COLOR m_clrBackColor;
	void OnBackColorChanged()
	{
		ATLTRACE(_T("OnBackColorChanged\n"));
		if(m_brBackColor)
			DeleteObject(m_brBackColor);
		m_brBackColor = CreateSolidBrush(m_clrBackColor);
		UpdateGraph();
	}
	
	OLE_COLOR m_clrBorderColor;
	void OnBorderColorChanged()
	{
		ATLTRACE(_T("OnBorderColorChanged\n"));
		if(m_brMarginColor)
			DeleteObject(m_brMarginColor);
		if(m_penBorder)
			DeleteObject(m_penBorder);
		m_brMarginColor = CreateSolidBrush(m_clrBorderColor);
		m_penBorder = CreatePen(PS_SOLID,1,m_clrBorderColor);
		UpdateGraph();
	}
	OLE_COLOR m_clrForeColor;
	void OnForeColorChanged()
	{
		ATLTRACE(_T("OnForeColorChanged\n"));
		if(m_penGraph)
			DeleteObject(m_penGraph);
		m_penGraph = CreatePen(PS_SOLID,1,m_clrForeColor);
		m_cDataSet->m_clr = m_clrForeColor;
		UpdateGraph();
	}

	DECLARE_PROTECT_FINAL_CONSTRUCT()

	HRESULT FinalConstruct()
	{
		m_hWndParent = NULL;
		m_RgnClient = NULL;
		m_nDataLength = 0;
		m_rcPlot.left = 0;
		m_rcPlot.right = 512;
		m_rcLegend.left = m_rcLegend.right = 0;
		m_pxData = m_pyData = 0;
		m_dFactor = 1.0;
		m_bResample = true;
		m_nPlotType = 0;//Normal
		m_bGrid = true;
		//m_nReason = 1;
		m_bDirty = true;
		//m_clrBackColor = RGB(175,200,255);
		m_clrBackColor = RGB(0,0,0);
		m_clrBorderColor = RGB(200,200,200);
		m_clrSelection =  RGB(200,0,0);
		m_clrForeColor = RGB(0,255,0);
		m_nSelStart = m_nSelEnd = 0;
		m_strTitle = _T("Smart Graph");
		m_strxLable = _T("X");
		m_stryLable = _T("Y");
		m_strLegend = _T("");
		m_nBMargin = 30;
		m_nLMargin = 50;
		m_nTMargin = 30;
		m_nRMargin = 20;
		int nLen = 360*12;
		m_brMarginColor = CreateSolidBrush(m_clrBorderColor);
		m_brBackColor = CreateSolidBrush(m_clrBackColor);
		m_brSelectionColor = CreateSolidBrush(m_clrSelection);
		m_penGraph = CreatePen(PS_SOLID,1,m_clrForeColor);
		m_penBorder = CreatePen(PS_SOLID,1,m_clrBorderColor);

		double *xData = new double[nLen];
		double *yData= new double[nLen];
		memset(xData,0,nLen*sizeof(double));
		memset(yData,0,nLen*sizeof(double));
		int x = -1;
		for(int i = -nLen/2; i < nLen/2; i++)
		{
			x++;
			xData[x] = i*PI/180;
			//xData[x] = i;
			if(xData[x] == 0)
				yData[x] = 1;
			else
				yData[x] = sin(xData[x])/xData[x];
			//yData[x] = -xData[x]*xData[x];
		}

/*		double yData[] =
		{
			0.475941,
			0.475935,
			0.475929,
			0.475924,
			0.475918,
			0.475912,
			0.475907,
			0.475901,
			0.475896,
			0.475891,
			0.475885,
			0.475880,
			0.475875,
			0.475870,
			0.475864,
			0.475859,
			0.475854,
			0.475849,
			0.475844,
			0.475839,
			0.475834,
			0.475829,
			0.475824,
			0.475820,
			0.475815,
			0.475810,
			0.475805,
			0.475801,
			0.475796,
			0.475791,
			0.475787,
			0.475782,
			0.475778,
			0.475773,
			0.475769,
			0.475764,
			0.475760,
			0.475756,
			0.475751,
			0.475747,
			0.475743,
			0.475739,
			0.475734,
			0.475730,
			0.475726,
			0.475722,
			0.475718,
			0.475714,
			0.475710,
			0.475706,
			0.475702,
			0.475698,
			0.475694,
			0.475690,
			0.475686,
			0.475683,
			0.475679,
			0.475675,
			0.475671,
			0.475668,
			0.475664,
			0.475660,
			0.475657,
			0.475653,
			0.475649,
			0.475646,
			0.475642,
			0.475639,
			0.475635,
			0.475632,
			0.475628,
			0.475625,
			0.475622,
			0.475618,
			0.475615,
			0.475611,
			0.475608,
			0.475605,
			0.475602,
			0.475598,
			0.475595,
			0.475592,
			0.475589,
			0.475586,
			0.475582,
			0.475579,
			0.475576,
			0.475573,
			0.475570,
			0.475567,
			0.475564,
			0.475561,
			0.475558,
			0.475555,
			0.475552,
			0.475549,
			0.475546,
			0.475543,
			0.475540,
			0.475537
};*/
		m_cDataSet = new CGraphDataSet<double>;
		SetData(xData,yData,nLen, (VARIANT_BOOL)false);
		//SetData(0,yData,100, (VARIANT_BOOL)false);

		//SetData(xData,yData,nLen);
		CreateFonts();
		SAFE_DELETE(xData);
		SAFE_DELETE(yData);
		return S_OK;
	}
	
	void FinalRelease() 
	{
		delete m_cDataSet;
		DeleteObject(m_brBackColor);
		DeleteObject(m_brMarginColor);
		DeleteObject(m_brSelectionColor);
		DeleteObject(m_penBorder);
		DeleteObject(m_penGraph);
		DeleteObject(m_penGrids);
		DeleteObject(m_FontX);
		DeleteObject(m_FontY);
		DeleteObject(m_RgnClient);
	}
	int m_nDataLength;
	double *m_pxData, *m_pyData;
	struct ZoomParam{
		int nFrom,nTo,nLen;//Current Zoom Parameters
	};
	CAtlList<ZoomParam> m_lstZoom;

	double m_dFactor;//Resample Factor
	bool m_bResample;

	HWND m_hWndParent;
	HRGN m_RgnClient;
	int m_nSelStart,m_nSelEnd;//Start and End Of Selection in Graph
	int m_nPlotType;	// Type of plot 0,1,2-->Normal,dot,Bar
	int m_nRow;			// Number of rows in smart graph
	int m_nCol;			// Number of columns in smart graph
	int m_nBMargin;		// Margin for xLable
	int m_nLMargin;		// Margin for yLable
	int m_nTMargin;		// Margin for title
	int m_nRMargin;		// Right Margin
	CString m_strTitle;		// Title
	CString m_strxLable;	// xLable
	CString m_stryLable;	// yLable
	CString m_strLegend;	// Text in graph
	RECT m_rcPlot,		// Graph Area
		m_rcClient,		// Graph and all its lables area
		m_rcSelected,	//
		m_rcLegend;		// Legend text area
	HFONT m_FontX, m_FontY;
	HBRUSH m_brBackColor,m_brMarginColor,m_brSelectionColor;
	HPEN m_penGraph,m_penBorder,m_penGrids;
	bool m_bGrid;
	CGraphDataSet<double> *m_cDataSet;
	HBITMAP m_bmTemp;
	HBITMAP m_bmOld;
	HDC m_dcMem;
	bool m_bDirty;
	//int m_nReason;//Reason Of Being Dirty (Graph Resized, Selection Changed, ...)

	OLE_COLOR m_clrSelection;

	void CreateFonts(void);
	void UpdateGraph(HDC dc);
	int DrawGrids(HDC dc);
	int DrawLabes(HDC dc, RECT rc);
	int Zoom(void);
	void SetData(double* xData, double* yData, long NumOfPoints,
		double xMin = LONG_MAX, double xMax = LONG_MIN, 
		double yMin = LONG_MAX, double yMax = LONG_MIN);

	STDMETHOD(get_Columns)(LONG* pVal);
	STDMETHOD(put_Columns)(LONG newVal);
	STDMETHOD(get_Rows)(LONG* pVal);
	STDMETHOD(put_Rows)(LONG newVal);
	STDMETHOD(get_MarginBottom)(LONG* pVal);
	STDMETHOD(put_MarginBottom)(LONG newVal);
	STDMETHOD(get_MarginLeft)(LONG* pVal);
	STDMETHOD(put_MarginLeft)(LONG newVal);
	STDMETHOD(get_Title)(BSTR* pVal);
	STDMETHOD(put_Title)(BSTR newVal);
	STDMETHOD(get_xLable)(BSTR* pVal);
	STDMETHOD(put_xLable)(BSTR newVal);
	STDMETHOD(get_yLable)(BSTR* pVal);
	STDMETHOD(put_yLable)(BSTR newVal);
	STDMETHOD(get_MarginTop)(LONG* pVal);
	STDMETHOD(put_MarginTop)(LONG newVal);
	STDMETHOD(get_MarginRight)(LONG* pVal);
	STDMETHOD(put_MarginRight)(LONG newVal);
	STDMETHOD(SetData)(DOUBLE* xData, DOUBLE* yData, LONG NumOfPoints, VARIANT_BOOL bResample);
	STDMETHOD(SetData2)(DOUBLE* xData, DOUBLE* yData, LONG NumOfPoints, DOUBLE xMin, DOUBLE xMax, DOUBLE yMin, DOUBLE yMax, VARIANT_BOOL bResample);
	STDMETHOD(ShowGrid)(VARIANT_BOOL bShow);
	STDMETHOD(UpdateGraph)(void);
	STDMETHOD(SetPlotType)(LONG nType);
	LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
	LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
	LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
	STDMETHOD(GetPlotRect)(LONG* left, LONG* top, LONG* right, LONG* bottom);
	STDMETHOD(GetClientRect)(LONG* left, LONG* top, LONG* right, LONG* bottom);
	STDMETHOD(ZoomIn)(LONG FromSample, LONG ToSample);
	STDMETHOD(ZoomInByPercent)(DOUBLE FromPercent, DOUBLE ToPercent);
	STDMETHOD(ZoomOut)(void);
	STDMETHOD(Reset)(void);
	STDMETHOD(GetDisplayedRange)(LONGLONG* nStartSample, LONGLONG* nEndSample);
	STDMETHOD(SetLegendText)(BSTR strText, LONG top, LONG left, LONG bottom, LONG right);
	STDMETHOD(SetParentWnd)(OLE_HANDLE hWnd);
	STDMETHOD(GetPlotType)(LONG* PlotType);
};

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

Hossein Khosravi
Software Developer (Senior) FarsiOCR.ir
Iran (Islamic Republic Of) Iran (Islamic Republic Of)
Currently I'm working at Dept. of Electrical Engineering in University of Shahrood.
Pattern Recognition (specially OCR), Neural Networks, Image Processing and Machine Vision are my interests. However I'm a PROGRAMMER as well.
BSc: Sharif University of technology @ 2002
MSc. and PhD: Tarbiat Modarres University @ 2006 & 2010 respectively
 
Personal Blog: Andisheh Online

Religious Blogs: Shia Muslims , Ashura , Islamic Quotes

Commercial Site: Farsi OCR
Follow on   Twitter   Google+

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141220.1 | Last Updated 22 Dec 2004
Article Copyright 2004 by Hossein Khosravi
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid