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

2D Graph ActiveX Control

, 5 Aug 2003
An ActiveX control for 2D data visualisation
ntgraph_activex_demo.zip
NTGraph_demo
NTGraph
Debug
Demo
Debug
res
Test.ico
Test.aps
Test.clw
Test.dsp
Test.plg
NTGraph.aps
NTGraph.clw
NTGraph.def
NTGraph.dsp
NTGraph.dsw
NTGraph.ico
NTGraph.ncb
NTGraph.odl
NTGraph.opt
NTGraph.plg
NTGraphCtl.bmp
Test.exe
ntgraph_activex_src.zip
NTGraph.ocx
NTGraph.lib
NTGraph.exp
ntgraph_bin.zip
NTGRAPH.HLP
NTGraph.ocx
ntgraph_bin1.zip
NTGraph.ocx
ntgraph_bin2.zip
NTGraph.ocx
ntgraph_bin3.zip
NTGraph.ocx
ntgraph_ctrl.zip
NTGraph_Ctrl
NTGraph.aps
NTGraph.clw
NTGraph.def
NTGraph.dsp
NTGraph.dsw
NTGraph.ico
NTGraph.ncb
NTGraph.odl
NTGraph.opt
NTGraph.plg
NTGraphCtl.bmp
Release
ntgraph_ctrl1.zip
NTGraph.aps
NTGraph.clw
NTGraph.def
NTGraph.dsp
NTGraph.dsw
NTGraph.ico
NTGraph.ncb
NTGraph.odl
NTGraph.opt
NTGraph.plg
NTGraphCtl.bmp
ntgraph_ctrl2.zip
NTGraph_Ctrl2
Debug
MAGNIFY.CUR
NTGraph.aps
NTGraph.clw
NTGraph.def
NTGraph.dsp
NTGraph.dsw
NTGraph.ico
NTGraph.ncb
NTGraph.odl
NTGraph.opt
NTGraph.plg
NTGraphCtl.bmp
Release
Test.dsm
ntgraph_ctrl3.zip
NTGraph_Ctrl3
Debug
hmove.cur
MAGNIFY.CUR
NTGraph.aps
NTGraph.clw
NTGraph.def
NTGraph.dsp
NTGraph.dsw
NTGraph.ico
NTGraph.odl
NTGraph.opt
NTGraph.plg
NTGraphCtl.bmp
Release
Test.dsm
ntgraph_demo.zip
Demo.ppt
Demo.xls
DlgDemo
Demo.aps
Demo.clw
Demo.dsp
Demo.dsw
Demo.exe
Demo.ncb
Demo.opt
Demo.plg
res
Demo.ico
MDIDemo
MDIDemo.aps
MDIDemo.clw
MDIDemo.dsp
MDIDemo.dsw
MDIDemo.exe
MDIDemo.ncb
MDIDemo.opt
MDIDemo.plg
res
MDIDemo.ico
MDIDemoDoc.ico
Toolbar.bmp
ntgraph_demo1.zip
Debug
Demo.aps
Demo.clw
Demo.dsp
Demo.dsw
Demo.ncb
Demo.opt
Demo.plg
res
Demo.ico
ntgraph_demo2.zip
NTGraph_demo2
Debug
Demo.aps
Demo.clw
Demo.dsp
Demo.dsw
Demo.ncb
Demo.opt
Demo.plg
res
Demo.ico
ntgraph_demo3.zip
NTGraph_demo3
Debug
Demo.dsp
Demo.dsw
res
Demo.ico
test.pdf
ntgraph_ppt.zip
NTGraph.ppt
ntgraph_ppt1.zip
NTGraph.ppt
ntgraph_src.zip
NTGraph_src
Frame.bmp
Hlp
Bullet.bmp
NTGraph.hm
NTGraph.RTF
Margritte.bmp
Margritte.jpg
NTGraph.aps
NTGraph.clw
NTGraph.def
NTGraph.dsp
NTGraph.dsw
NTGRAPH.GID
NTGRAPH.HLP
NTGraph.hpj
NTGraph.ico
NTGraph.log
NTGraph.ncb
NTGraph.odl
NTGraph.opt
NTGraph.ph
NTGraph.plg
NTGraph.suo
NTGraphCtl.bmp
Release
Test.dsm
// NTGraphCtl.cpp : Implementation of the CNTGraphCtrl ActiveX Control class.


#include "stdafx.h"
#include "NTGraph.h"
#include "NTGraphCtl.h"
#include "NTGraphPpg.h"

#include <math.h>

#define STATIC

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


IMPLEMENT_DYNCREATE(CNTGraphCtrl, COleControl)


/////////////////////////////////////////////////////////////////////////////
// Message map

BEGIN_MESSAGE_MAP(CNTGraphCtrl, COleControl)
	//{{AFX_MSG_MAP(CNTGraphCtrl)
	ON_WM_LBUTTONDOWN()
	//}}AFX_MSG_MAP
#ifdef STATIC
	ON_MESSAGE(OCM_COMMAND, OnOcmCommand)
#endif
	ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// Dispatch map

BEGIN_DISPATCH_MAP(CNTGraphCtrl, COleControl)
	//{{AFX_DISPATCH_MAP(CNTGraphCtrl)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "ShowGrid", m_showGrid, OnShowGridChanged, VT_BOOL)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "XLabel", m_strLabelX, OnXLabelChanged, VT_BSTR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "YLabel", m_strLabelY, OnYLabelChanged, VT_BSTR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "GridColor", m_gridColor, OnGridColorChanged, VT_COLOR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "LabelColor", m_labelColor, OnLabelColorChanged, VT_COLOR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "AxisColor", m_axisColor, OnAxisColorChanged, VT_COLOR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "NGridX", m_nGridX, OnNGridXChanged, VT_I2)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "NGridY", m_nGridY, OnNGridYChanged, VT_I2)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "MinX", m_minX, OnMinXChanged, VT_R8)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "MaxX", m_maxX, OnMaxXChanged, VT_R8)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "MinY", m_minY, OnMinYChanged, VT_R8)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "MaxY", m_maxY, OnMaxYChanged, VT_R8)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "GraphTitle", m_strGraphTitle, OnGraphTitleChanged, VT_BSTR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "CursorColor", m_cursorColor, OnCursorColorChanged, VT_COLOR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "ElementColor", m_elementColor, OnElementColorChanged, VT_COLOR)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "ZoomMode", m_zoomMode, OnZoomModeChanged, VT_BOOL)
	DISP_PROPERTY_NOTIFY(CNTGraphCtrl, "CursorMode", m_cursorMode, OnCursorModeChanged, VT_BOOL)
	DISP_PROPERTY_EX(CNTGraphCtrl, "Element", GetElement, SetElement, VT_I2)
	DISP_PROPERTY_EX(CNTGraphCtrl, "ElementCount", GetElementCount, SetElementCount, VT_I2)
	DISP_PROPERTY_EX(CNTGraphCtrl, "TickFont", GetTickFont, SetTickFont, VT_DISPATCH)
	DISP_PROPERTY_EX(CNTGraphCtrl, "TitleFont", GetTitleFont, SetTitleFont, VT_DISPATCH)
	DISP_PROPERTY_EX(CNTGraphCtrl, "LabelFont", GetLabelFont, SetLabelFont, VT_DISPATCH)
	DISP_FUNCTION(CNTGraphCtrl, "ClearGraph", ClearGraph, VT_EMPTY, VTS_NONE)
	DISP_FUNCTION(CNTGraphCtrl, "CreateElement", CreateElement, VT_BOOL, VTS_I4)
	DISP_FUNCTION(CNTGraphCtrl, "SetRange", SetRange, VT_BOOL, VTS_R8 VTS_R8 VTS_R8 VTS_R8)
	DISP_FUNCTION(CNTGraphCtrl, "SetXYValue", SetXYValue, VT_BOOL, VTS_R8 VTS_R8 VTS_I4 VTS_I2)
	DISP_FUNCTION(CNTGraphCtrl, "SetShowElement", SetShowElement, VT_EMPTY, VTS_BOOL)
	DISP_FUNCTION(CNTGraphCtrl, "Copy2Clipboard", Copy2Clipboard, VT_EMPTY, VTS_NONE)
	DISP_STOCKPROP_APPEARANCE()
	DISP_STOCKPROP_BACKCOLOR()
	DISP_STOCKPROP_BORDERSTYLE()
	DISP_STOCKPROP_ENABLED()
	DISP_STOCKPROP_CAPTION()
	//}}AFX_DISPATCH_MAP
	DISP_FUNCTION_ID(CNTGraphCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
END_DISPATCH_MAP()


/////////////////////////////////////////////////////////////////////////////
// Event map

BEGIN_EVENT_MAP(CNTGraphCtrl, COleControl)
	//{{AFX_EVENT_MAP(CNTGraphCtrl)
	EVENT_CUSTOM("CursorEvent", FireCursorEvent, VTS_R8  VTS_R8)
	//}}AFX_EVENT_MAP
END_EVENT_MAP()


/////////////////////////////////////////////////////////////////////////////
// Property pages

// TODO: Add more property pages as needed.  Remember to increase the count!
BEGIN_PROPPAGEIDS(CNTGraphCtrl, 3)
	PROPPAGEID(CNTGraphPropPage::guid)
	PROPPAGEID(CLSID_CColorPropPage)
	PROPPAGEID(CLSID_CFontPropPage)
END_PROPPAGEIDS(CNTGraphCtrl)


/////////////////////////////////////////////////////////////////////////////
// Initialize class factory and guid

IMPLEMENT_OLECREATE_EX(CNTGraphCtrl, "NTGRAPH.NTGraphCtrl.1",
	0x14f24365, 0x6c9d, 0x419e, 0x89, 0x94, 0xe7, 0xc9, 0x17, 0x9c, 0xa3, 0x4f)


/////////////////////////////////////////////////////////////////////////////
// Type library ID and version

IMPLEMENT_OLETYPELIB(CNTGraphCtrl, _tlid, _wVerMajor, _wVerMinor)


/////////////////////////////////////////////////////////////////////////////
// Interface IDs

const IID BASED_CODE IID_DNTGraph =
		{ 0x3b090608, 0x7603, 0x486d, { 0x9e, 0x9c, 0x9f, 0x26, 0x86, 0x4e, 0x13, 0xa0 } };
const IID BASED_CODE IID_DNTGraphEvents =
		{ 0x35000290, 0x97bd, 0x4b15, { 0xba, 0x89, 0xf4, 0xd, 0x82, 0x24, 0xdd, 0xd9 } };


/////////////////////////////////////////////////////////////////////////////
// Control type information

static const DWORD BASED_CODE _dwNTGraphOleMisc =
	OLEMISC_ACTIVATEWHENVISIBLE |
	OLEMISC_SETCLIENTSITEFIRST |
	OLEMISC_INSIDEOUT |
	OLEMISC_CANTLINKINSIDE |
	OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CNTGraphCtrl, IDS_NTGRAPH, _dwNTGraphOleMisc)


/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::CNTGraphCtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CNTGraphCtrl

BOOL CNTGraphCtrl::CNTGraphCtrlFactory::UpdateRegistry(BOOL bRegister)
{
	// TODO: Verify that your control follows apartment-model threading rules.
	// Refer to MFC TechNote 64 for more information.
	// If your control does not conform to the apartment-model rules, then
	// you must modify the code below, changing the 6th parameter from
	// afxRegApartmentThreading to 0.

	if (bRegister)
		return AfxOleRegisterControlClass(
			AfxGetInstanceHandle(),
			m_clsid,
			m_lpszProgID,
			IDS_NTGRAPH,
			IDB_NTGRAPH,
			afxRegApartmentThreading,
			_dwNTGraphOleMisc,
			_tlid,
			_wVerMajor,
			_wVerMinor);
	else
		return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}

//////////////////////////////////////////////////////////////////////////////
// static FONTDESC structure containing default attributes of the fonts

static const FONTDESC _fontdescTick =
  { sizeof(FONTDESC), OLESTR("Arial"), FONTSIZE( 8 ), FW_NORMAL, 
     ANSI_CHARSET, FALSE, FALSE, FALSE };

static const FONTDESC _fontdescTitle =
  { sizeof(FONTDESC), OLESTR("Arial"), FONTSIZE( 12 ), FW_BOLD, 
     ANSI_CHARSET, FALSE, FALSE, FALSE };

static const FONTDESC _fontdescLabel =
  { sizeof(FONTDESC), OLESTR("Arial"), FONTSIZE( 12 ), FW_NORMAL, 
     ANSI_CHARSET, FALSE, FALSE, FALSE };

/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::CNTGraphCtrl - Constructor

CNTGraphCtrl::CNTGraphCtrl() : m_fontTick( &m_xFontNotification ), 
                               m_fontTitle( &m_xFontNotification ), 
							   m_fontLabel( &m_xFontNotification )
{
	InitializeIIDs(&IID_DNTGraph, &IID_DNTGraphEvents);

	// Initialize the control's instance data.
	m_minX=m_minY=0;
	m_maxX=m_maxY=10;
	SetRange(0,1,0,1);
 	m_strLabelX = "X Axis" ;
	m_strLabelY = "Y Axis" ;
	m_strGraphTitle = "XY Graph";
	m_nGridX = 5 ;
	m_nGridY = 5;
	
	bIsElementAllocated = FALSE ;
	bFontIsCreated = FALSE ;

	nPlotIndex = 0 ;
	nPointCount = 2000 ;
	nElementCount = 2 ;
	m_ElementId=0;
    
	m_BGColor    = RGB(255,255,255);
	m_axisColor  = RGB(0,0,0);
	m_labelColor = RGB(0,0,0);
	m_gridColor  = RGB(0,0,0);
    m_cursorColor = RGB(255,0,0);
}

/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::~CNTGraphCtrl - Destructor

CNTGraphCtrl::~CNTGraphCtrl()
{
	// TODO: Cleanup your control's instance data here.
	for( int i = 0  ; i < nElementCount ; i++){
		mpElement[i].DeleteElement() ;
	}

	if( bFontIsCreated ) {
		delete pTickFont ;
		delete pXLabelFont;
		delete pYLabelFont;
		delete pTitleFont ;
	}
}


/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::OnDraw - Drawing function

void CNTGraphCtrl::OnDraw(
			CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
   
    DoSuperclassPaint(pdc, rcBounds);

		  
    m_pDC = pdc;
    m_ctlRect = rcBounds;

 	PrepareForDrawing(&rcBounds);

 	CBrush hbrBackground(TranslateColor(GetBackColor()));
	pdc->FillRect (m_ctlRect,&hbrBackground);

    DrawAxis() ;
    DrawGraphTitle();
	DrawAxisLabel();

	if (m_showGrid)
			DrawGrid();
	else 
			DrawTicks();

	DrawGraphTitle();

	PlotElement() ;

	if (m_cursorMode)
		DrawCursor();
}


/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::DoPropExchange - Persistence support

void CNTGraphCtrl::DoPropExchange(CPropExchange* pPX)
{
	ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
	COleControl::DoPropExchange(pPX);

	// TODO: Call PX_ functions for each persistent custom property.
    PX_Bool(pPX,_T("ShowGrid"),m_showGrid,FALSE);
	PX_Bool(pPX,_T("CursorMode"),m_cursorMode,FALSE);
	PX_Bool(pPX,_T("ZoomMode"),m_zoomMode,FALSE);
	PX_Font(pPX, _T("TickFont"), m_fontTick, &_fontdescTick);
	PX_Font(pPX, _T("TitleFont"), m_fontTitle, &_fontdescTitle);
	PX_Font(pPX, _T("LabelFont"), m_fontLabel, &_fontdescLabel);
}


/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::GetControlFlags -
// Flags to customize MFC's implementation of ActiveX controls.
//
// For information on using these flags, please see MFC technical note
// #nnn, "Optimizing an ActiveX Control".
DWORD CNTGraphCtrl::GetControlFlags()
{
	DWORD dwFlags = COleControl::GetControlFlags();


	// The control will not be redrawn when making the transition
	// between the active and inactivate state.
	dwFlags |= noFlickerActivate;
	return dwFlags;
}


/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::OnResetState - Reset control to default state

void CNTGraphCtrl::OnResetState()
{
	COleControl::OnResetState();  // Resets defaults found in DoPropExchange

	// TODO: Reset any other control state here.
}


/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::AboutBox - Display an "About" box to the user

void CNTGraphCtrl::AboutBox()
{
	CDialog dlgAbout(IDD_ABOUTBOX_NTGRAPH);
	dlgAbout.DoModal();
}


#ifdef STATIC
/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::PreCreateWindow - Modify parameters for CreateWindowEx
BOOL CNTGraphCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
	//cs.lpszClass = _T("STATIC");
	return COleControl::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::IsSubclassedControl - This is a subclassed control
BOOL CNTGraphCtrl::IsSubclassedControl()
{
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CNTGraphCtrl::OnOcmCommand - Handle command messages

LRESULT CNTGraphCtrl::OnOcmCommand(WPARAM wParam, LPARAM lParam)
{
#ifdef _WIN32
	WORD wNotifyCode = HIWORD(wParam);
#else
	WORD wNotifyCode = HIWORD(lParam);
#endif

	// TODO: Switch on wNotifyCode here.

	return 0;
}

#endif


/////////////////////////////////////////////////////////////////////////////
////////////////////////// Source of CGraphElement //////////////////////////
/////////////////////////////////////////////////////////////////////////////
CGraphElement::CGraphElement() 
{
	    dValueX = NULL ;
		dValueY = NULL ;
		bIsPlotAvailable = FALSE ;
		bBufferAllocated = FALSE ;
		m_Color = RGB(0,0,0);
		m_bShow = TRUE;      // Added by A. Hofmann
		m_nCount = 0;        // Added by A. Hofmann
}

BOOL CGraphElement::NewElement(UINT nPoint)
{

	dValueX = new double[nPoint] ; 
	dValueY = new double[nPoint] ;  
	if ( (!dValueX) || (!dValueY) ) 
		return FALSE ;
	bBufferAllocated = TRUE ;
	return TRUE ;
}

BOOL CGraphElement::DeleteElement()
{
	if ( bBufferAllocated ) {
		delete [] dValueX;
		delete [] dValueY ;		
	}
	bBufferAllocated = FALSE ;
	return TRUE ;
}

/////////////////////////////////////////////////////////////////////
void CNTGraphCtrl::PrepareForDrawing(CRect rect)
{

	m_BGColor=TranslateColor(GetBackColor());
 
    m_ctlRect = rect ;
	CreateFont(); // Get system font for label draw 
	bFontIsCreated = TRUE ;
	CalcRect() ; // Compute rectangle 
	ResCalc();   // Compute resolution per dot.

    m_pDC->SetViewportExt (rect.right , rect.bottom );
    m_pDC->DPtoLP(&m_ctlRect);
 
}

void CNTGraphCtrl::DrawAxis()
{

	m_axisRect.NormalizeRect ();
	m_pDC->FillSolidRect (m_axisRect,m_BGColor);

	CPen *old , pen(PS_SOLID, 2, m_axisColor);
	
	old = m_pDC->SelectObject(&pen) ;
		m_pDC->MoveTo(Corrdinate(dRangeX[MIN],dRangeY[MIN]));
		m_pDC->LineTo(Corrdinate(dRangeX[MAX],dRangeY[MIN]));
		m_pDC->MoveTo(Corrdinate(dRangeX[MIN],dRangeY[MIN]));
		m_pDC->LineTo(Corrdinate(dRangeX[MIN],dRangeY[MAX]));
        m_pDC->MoveTo(Corrdinate(dRangeX[MAX],dRangeY[MIN]));
		m_pDC->LineTo(Corrdinate(dRangeX[MAX],dRangeY[MAX]));
		m_pDC->MoveTo(Corrdinate(dRangeX[MIN],dRangeY[MAX]));
		m_pDC->LineTo(Corrdinate(dRangeX[MAX],dRangeY[MAX]));
	m_pDC->SelectObject(old) ;
}

void CNTGraphCtrl::DrawGraphTitle()
{

	CFont* pOldFont;
	TEXTMETRIC tm;

	pOldFont = SelectFontObject(m_pDC, m_fontTitle);
    m_pDC->GetTextMetrics(&tm);

	m_pDC->SetTextAlign(TA_TOP | TA_CENTER);
    m_pDC->ExtTextOut((m_ctlRect.left + m_ctlRect.right) / 2,
                 (m_ctlRect.top+m_axisRect.top - tm.tmHeight) / 2,
                  ETO_CLIPPED, m_ctlRect, m_strGraphTitle, m_strGraphTitle.GetLength(),NULL);

   m_pDC->SelectObject(pOldFont);


}

void CNTGraphCtrl::DrawGrid()
{
	CPen *old , pen(PS_SOLID, 0, m_gridColor);
	CPoint m_start, m_stop ;
	int i  ;
	double x ,y ;
	double step ;

	old = m_pDC->SelectObject(&pen);
	
	// Draw vertical grid 

	step = (dRangeX[MAX] - dRangeX[MIN]) / (double)m_nGridX ;
	for( i = 1 ; i < m_nGridX ; i++ )
	{
		x = dRangeX[MIN] + (step * (double)i) ;
		m_start = Corrdinate(x,dRangeY[MIN]);
		m_stop  = Corrdinate(x,dRangeY[MAX]);
		m_pDC->MoveTo(m_start);
		m_pDC->LineTo(m_stop);
	}
	
	// Draw horizontal grid.

	step = (dRangeY[MAX] - dRangeY[MIN]) / (double)m_nGridY ;
	for( i = 1 ; i < m_nGridY ; i++ )
	{
		y = dRangeY[MIN] + (step * (double)i) ;
		m_start = Corrdinate(dRangeX[MIN],y) ;
		m_stop  = Corrdinate(dRangeX[MAX],y) ;
		m_pDC->MoveTo(m_start);
		m_pDC->LineTo(m_stop);
	}
	
	m_pDC->SelectObject(old);
}

void CNTGraphCtrl::DrawAxisLabel()
{
	CFont *pOldFont;

	int i ;
	double res , x, y  ; 
	CPoint point ;
	CSize txtSize ;
	CString str ;

	pOldFont = m_pDC->SelectObject(pTickFont);
	m_pDC->SetTextColor (m_labelColor);

	res = (dRangeY[MAX] - dRangeY[MIN]) / m_nGridY ;
	m_pDC->SetTextAlign(TA_RIGHT);
	m_pDC->SetBkMode(TRANSPARENT);

	CSize sz;
	sz.cx=0;

	// Draw Y Tick Labels
	for ( i = 0 ; i <= m_nGridY ; i++)
	{
		y = dRangeY[MIN] + (res * (double)i) ;
		point = Corrdinate(dRangeX[MIN],y) ;
		str.Format("%g",y) ;

		txtSize = m_pDC->GetTextExtent(str) ;

		if (sz.cx < txtSize.cx) sz=txtSize;

		point.x -= 5 ;
		point.y -= txtSize.cy/2 ;

		m_pDC->TextOut(point.x,point.y,str) ;
	}

	m_pDC->SelectObject(pXLabelFont);

    // Draw X Axis Title
	txtSize = m_pDC->GetTextExtent(m_strLabelX);
    point.x = m_axisRect.CenterPoint().x + (txtSize.cx/2); 
	point.y = (m_ctlRect.bottom + m_axisRect.bottom)/2;
	point.y -= (txtSize.cy - sz.cy)/2;
    
	m_pDC->TextOut(point.x,point.y,m_strLabelX);

	// Draw X Tick Labels
	m_pDC->SelectObject(pTickFont);

	res = (dRangeX[MAX] - dRangeX[MIN]) / m_nGridX ;

	for ( i = 0 ; i <= m_nGridX ; i ++ )
	{
		x = dRangeX[MIN] + ( res * (double)i);
		point = Corrdinate(x,dRangeY[MIN]);
		
		str.Format("%g",x);

		txtSize = m_pDC->GetTextExtent(str) ;

		point.x += txtSize.cx/2;
		point.y += 5 ;

		m_pDC->TextOut(point.x,point.y,str);
	}
	 
 	m_pDC->SelectObject(pYLabelFont);

	// Draw Y Axis Title
	txtSize = m_pDC->GetTextExtent(m_strLabelY);
	point.x = (m_ctlRect.left+m_axisRect.left)/2;
	point.x -= ( txtSize.cy + sz.cx )/2 ;
	point.y = m_axisRect.CenterPoint().y  - (txtSize.cx/2);
	m_pDC->TextOut(point.x,point.y,m_strLabelY);

    m_pDC->SelectObject(pOldFont);
}

//////////////////////////////////
// Draw ticks in 1/5 fine scale 
void CNTGraphCtrl::DrawTicks()
{

	CPen *old , pen(PS_SOLID, 0, m_gridColor);
	CPoint m_start, m_stop ;
	int i  ;
	double x ,y ;
	double step ;

	old = m_pDC->SelectObject(&pen);
	
	// Draw vertical Major Ticks 

	step = (dRangeX[MAX] - dRangeX[MIN]) / (double)m_nGridX ;
	for( i = 1 ; i < m_nGridX ; i++ )
	{
		x = dRangeX[MIN] + (step * (double)i) ;
		m_start = Corrdinate(x,dRangeY[MIN]);
		m_stop = m_start; m_stop.y -= 5;	// Major Ticks on Botom
		m_pDC->MoveTo(m_start);
		m_pDC->LineTo(m_stop);
	}

	for( i = 1 ; i < m_nGridX ; i++ )
	{
		x = dRangeX[MIN] + (step * (double)i) ;
		m_start = Corrdinate(x,dRangeY[MAX]);
		m_stop = m_start; m_stop.y += 5;	// Major Ticks on Top
		m_pDC->MoveTo(m_start);
		m_pDC->LineTo(m_stop);
	}
	

	// Draw horizontal Major Ticks
	step = (dRangeY[MAX] - dRangeY[MIN]) / (double)m_nGridY ;
	for( i = 1 ; i < m_nGridY ; i++ )
	{
		y = dRangeY[MIN] + (step * (double)i) ;
		m_start = Corrdinate(dRangeX[MIN],y) ;
		m_stop  = m_start; m_stop.x += 5;	 // Major Ticks on Left
		m_pDC->MoveTo(m_start);
		m_pDC->LineTo(m_stop);
	}
	
	for( i = 1 ; i < m_nGridY ; i++ )
	{
		y = dRangeY[MIN] + (step * (double)i) ;
		m_start = Corrdinate(dRangeX[MAX],y) ;
		m_stop  = m_start; m_stop.x -= 5;	// Major Ticks on Right
		m_pDC->MoveTo(m_start);
		m_pDC->LineTo(m_stop);
	}

	m_pDC->SelectObject(old);
}

void CNTGraphCtrl::PlotElement()
{
	
	// If there is no data available for plot then return .
	if ( !nPlotIndex ) return ;
		
	CPen *old , *pen ;
	
	CPoint pt;
	int i;
	
	for( i = 0 ; i < nElementCount ; i++) {

        /////////////////////////////
		// Added by A.Hofmann
		/////////////////////////////
		// Check show state of serie
		if ( ! mpElement[i].m_bShow )
			continue;

		// Create the new pen as the color of serie 
		pen = new CPen(PS_SOLID /*mpElement[i].m_lineType*/,
			           1 /*mpElement[i].m_lineWidth*/,
					   mpElement[i].m_Color);

		old = m_pDC->SelectObject(pen);

		// Calculate the corrdinate of ploting point.
		pt = Corrdinate(mpElement[i].dValueX[0],mpElement[i].dValueY[0]) ;

		if (m_axisRect.PtInRect(pt))
						m_pDC->MoveTo(pt);
		else {

			if ( pt.y < m_axisRect.bottom) pt.y=m_axisRect.bottom;
			if ( pt.y > m_axisRect.top ) pt.y=m_axisRect.top;
			if ( pt.x < m_axisRect.left ) pt.x=m_axisRect.left;
			if ( pt.x > m_axisRect.right ) pt.x=m_axisRect.right;
			
			m_pDC->MoveTo(pt);
		}				
		
		// Start plot all available data .
		// Changed by A. Hofmann
		for(int index = 1 ; index <= mpElement[i].m_nCount;/*nPlotIndex;*/ index++){
			pt = Corrdinate(mpElement[i].dValueX[index], mpElement[i].dValueY[index]) ;

            // Clipping to Axis Rectangle
            if (m_axisRect.PtInRect(pt))
				               m_pDC->LineTo(pt) ;		
			else
				continue;

		}
		m_pDC->SelectObject(old);
		delete pen ;
	}
	
}

void CNTGraphCtrl::DrawCursor()
{

	if(bIsCursorInRange) {

		m_axisRect.NormalizeRect ();

		CPen *old , pen(PS_SOLID, 1, m_cursorColor);
	
		old = m_pDC->SelectObject(&pen) ;
			m_pDC->MoveTo(Corrdinate(m_dXCur,dRangeY[MIN]));
			m_pDC->LineTo(Corrdinate(m_dXCur,dRangeY[MAX]));
			m_pDC->MoveTo(Corrdinate(dRangeX[MIN],m_dYCur));
			m_pDC->LineTo(Corrdinate(dRangeX[MAX],m_dYCur));
  		m_pDC->SelectObject(old) ;
	}
}

void CNTGraphCtrl::ClearGraph()
{
	// Added by A. Hofmann
	for(int i = 0 ; i < nElementCount; i++ )
		mpElement[i].m_nCount = 0;

	nPlotIndex = 0 ;
	InvalidateRect(m_ctlRect);
}
/////////////////////////////////
// Allocate memory for plotting 
BOOL CNTGraphCtrl::CreateElement(long nElement)
{
	
	if( !bIsElementAllocated )
	{
		for(int i = 0 ; i < nElementCount ; i++ ) {
			if ( !mpElement[i].NewElement(nElement)) {
				AfxMessageBox("Can not allocate element!") ;
				return FALSE ;
			}
		}
	}
	
	nPointCount = nElement ;
	bIsElementAllocated = TRUE ;
	return TRUE ;

}

BOOL CNTGraphCtrl::SetRange(double MinX, double MaxX, double MinY, double MaxY) 
{
	dRangeY[MIN] = MinY ;
	dRangeY[MAX] = MaxY ;
	dRangeX[MAX] = MaxX ;
	dRangeX[MIN] = MinX ;
    ResCalc();
	InvalidateControl();
	return TRUE;
}

BOOL CNTGraphCtrl::SetXYValue(double X, double Y, long index, short iElementId) 
{
	if(!bIsElementAllocated ) return FALSE;
	if (iElementId > (nElementCount-1)) return FALSE;

	// Prevent writting to unallocated buffer 
	if(index >= nPointCount ) return FALSE;
	
	// Clip the ploting area if it exceed ranged .
	if(X > dRangeX[MAX] ) X = dRangeX[MAX] ;
	if(X < dRangeX[MIN] ) X = dRangeX[MIN] ;
	if(Y > dRangeY[MAX] ) Y = dRangeY[MAX] ;
	if(Y < dRangeY[MIN] ) Y = dRangeY[MIN];

	
	mpElement[iElementId].dValueX[index] = X ;
	mpElement[iElementId].dValueY[index] = Y ;
	mpElement[iElementId].bIsPlotAvailable = TRUE ;
	mpElement[iElementId].m_nCount = index; // Added by A. Hofmann

	nPlotIndex = index ;
	return TRUE;
}

CPoint CNTGraphCtrl::Corrdinate(double x, double y)
{
	double rx , ry ;
	int xPixel , yPixel ;
	CPoint retPt ;

	rx = x - dRangeX[MIN] ; // Calculate horizontal offset from origin
	ry = y - dRangeY[MIN] ; // Calculate vertical offset from origin .

	// Convert offset to be number of pixel on screen .
	xPixel = (int)(rx / dResX) ; 
	yPixel = (int)(ry / dResY) ;

	//Calulate point to be drawn .
	retPt.x= xPixel + m_axisRect.left ;
	retPt.y= m_axisRect.bottom - yPixel; 
	return retPt ;
}

void CNTGraphCtrl::CalcRect()
{
	int offset = 30;
    
	CSize txtXLabelSize,txtYLabelSize,txtTitleSize ;
	CString str ;
   	CPaintDC dc(this); // device context for painting
	CFont *pOldFont ;
	pOldFont = dc.SelectObject(pTickFont);

    int bigY = __max(abs((int)dRangeY[MAX]),abs((int)dRangeY[MIN]));
	str.Format("%g",(double)bigY);
	txtYLabelSize = dc.GetTextExtent(str);
	str.Format("%g",dRangeX[MAX]);
	txtXLabelSize = dc.GetTextExtent(str);
	
	dc.SelectObject (pTitleFont);
	txtTitleSize = dc.GetTextExtent (m_strLabelX);
	dc.SelectObject(pOldFont);

	m_axisRect.left  = m_ctlRect.left + txtTitleSize.cy+txtYLabelSize.cx + offset;
	m_axisRect.right = m_ctlRect.right - (txtXLabelSize.cx/2) - (offset/2);
	m_axisRect.top   = m_ctlRect.top + txtTitleSize.cy + (offset/2);
	m_axisRect.bottom= m_ctlRect.bottom - (txtTitleSize.cy+txtXLabelSize.cy) - (offset/2); 
}

////////////////////////////////
//Calculate resolution per dot
void CNTGraphCtrl::ResCalc()
{
	double dpixelx, dpixely ;

	dpixelx = (double)m_axisRect.Width() ;
	dpixely = (double)m_axisRect.Height() ;
	dResY = (dRangeY[MAX] - dRangeY[MIN]) / dpixely ;
	dResX = (dRangeX[MAX] - dRangeX[MIN]) / dpixelx ;

}
/////////////////////////////////////////////////////////////////////////////
// Create desired fonts for draw labels on x axis and y axis and graph title.
void CNTGraphCtrl::CreateFont()
{
		
	//Create system font ..
	LOGFONT lf;
	CFont *pStockFont, *pOldFont;

	pOldFont = SelectFontObject(m_pDC, m_fontTick);
	pStockFont = SelectFontObject(m_pDC, m_fontTick);
	
    // Retrieve a copy of the LOGFONT structure 
	// for a currently selected stock font.
	if (pStockFont)
        pStockFont->GetLogFont(&lf);

	// Create a new font for Ticks
	pTickFont = new CFont() ;
	pTickFont->CreateFontIndirect(&lf);

	pOldFont = SelectFontObject(m_pDC, m_fontTitle);
	pStockFont = SelectFontObject(m_pDC, m_fontTitle);
	
	// Retrieve a copy of the LOGFONT structure 
	// for a currently selected stock font.
	if (pStockFont)
        pStockFont->GetLogFont(&lf);
	
	// Create a new font for Title
	pTitleFont = new CFont();
	pTitleFont->CreateFontIndirect(&lf);

	pOldFont = SelectFontObject(m_pDC, m_fontLabel);
	pStockFont = SelectFontObject(m_pDC, m_fontLabel);
	    
	// Retrieve a copy of the LOGFONT structure 
	// for a currently selected stock font.
	if (pStockFont)
        pStockFont->GetLogFont(&lf);
	
	pXLabelFont = new CFont() ;
	pXLabelFont->CreateFontIndirect(&lf);

	// Rotate font 90 degree for Y axis label
	SetGraphicsMode( m_pDC->m_hDC, GM_ADVANCED );
	lf.lfOrientation = 900 ; 
	lf.lfEscapement = 900 ;
	
	pYLabelFont = new CFont() ;
	pYLabelFont->CreateFontIndirect(&lf);

    m_pDC->SelectObject(pOldFont);

}
void CNTGraphCtrl::CursorPosition(CPoint point) 
{
     double rx,ry;

	 rx = (double)((point.x - m_axisRect.left)*dResX)   + dRangeX[MIN];
	 ry = (double)((m_axisRect.bottom - point.y)*dResY) + dRangeY[MIN];


	if ( point.x < m_axisRect.right && point.x > m_axisRect.left && 
		 point.y > m_axisRect.top && point.y < m_axisRect.bottom )
	{
		m_dXCur = rx;
		m_dYCur = ry;
		
		//Fire Cursor Position Event
		FireCursorEvent(rx,ry);

		bIsCursorInRange=TRUE;
		return;
    }
    else
	{
		bIsCursorInRange=FALSE;
		return;
	}
}

void CNTGraphCtrl::OnShowGridChanged() 
{
    InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnXLabelChanged() 
{
    InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnYLabelChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnGridColorChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnLabelColorChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnAxisColorChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnNGridXChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnNGridYChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnMinXChanged() 
{
	SetRange(m_minX,m_maxX,m_minY,m_maxY);
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnMaxXChanged() 
{
   	SetRange(m_minX,m_maxX,m_minY,m_maxY);
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnMinYChanged() 
{
	SetRange(m_minX,m_maxX,m_minY,m_maxY);
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnMaxYChanged() 
{
	SetRange(m_minX,m_maxX,m_minY,m_maxY);
	InvalidateControl();
	SetModifiedFlag();
}


short CNTGraphCtrl::GetElement() { return m_ElementId; }

void CNTGraphCtrl::SetElement(short nNewValue) 
{
	m_ElementId = nNewValue;
	if (m_ElementId <0) 
		m_ElementId=0;
	SetModifiedFlag();
}

short CNTGraphCtrl::GetElementCount() {	return nElementCount;}

void CNTGraphCtrl::SetElementCount(short nNewValue) 
{
    nElementCount = nNewValue;
	if (nElementCount <0) 
		nElementCount=0;
	SetModifiedFlag();
}

void CNTGraphCtrl::OnCursorModeChanged() 
{
	InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnGraphTitleChanged() 
{
    InvalidateControl();
	SetModifiedFlag();
}

void CNTGraphCtrl::OnCursorColorChanged() 
{
    InvalidateControl();
	SetModifiedFlag();
}


void CNTGraphCtrl::OnZoomModeChanged() 
{
    AfxMessageBox("Not implemented yet, but reserved!");
	SetModifiedFlag();
}


void CNTGraphCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{

	CursorPosition(point);     // Fire CursorEvent
	InvalidateControl();
	SetModifiedFlag();

/*				
    if (::GetCapture() == m_hWnd) // in capture mode
	{
        POINT p=point;
		::ClientToScreen(m_hWnd, &p);
		CursorPosition(p);        // Fire CursorEvent
		InvalidateControl();
		SetModifiedFlag();		
		
    } else  // leave control area and start mouse leave event 
		TRACKMOUSEEVENT t = {sizeof(TRACKMOUSEEVENT),TME_LEAVE,m_hWnd,0} ;
*/ 
	
	COleControl::OnLButtonDown(nFlags, point);
}


void CNTGraphCtrl::OnElementColorChanged() 
{
	mpElement[m_ElementId].m_Color = m_elementColor;
    InvalidateControl();
	SetModifiedFlag();
}

////////////////////////////////////////////////////////
//  Implementation of the Custom Font Proprties
LPDISPATCH CNTGraphCtrl::GetTickFont() { return m_fontTick.GetFontDispatch( ); }

void CNTGraphCtrl::SetTickFont(LPDISPATCH newValue) 
{
	m_fontTick.InitializeFont( &_fontdescTick, newValue);
    OnFontChanged();    //notify any changes
    SetModifiedFlag( );
}

LPDISPATCH CNTGraphCtrl::GetTitleFont() { return m_fontTitle.GetFontDispatch( );}

void CNTGraphCtrl::SetTitleFont(LPDISPATCH newValue) 
{
	m_fontTitle.InitializeFont( &_fontdescTitle, newValue);
    OnFontChanged();    //notify any changes
    SetModifiedFlag( );
}

LPDISPATCH CNTGraphCtrl::GetLabelFont() { return m_fontLabel.GetFontDispatch( ); }

void CNTGraphCtrl::SetLabelFont(LPDISPATCH newValue) 
{
	m_fontLabel.InitializeFont( &_fontdescLabel, newValue);
    OnFontChanged();    //notify any changes
    SetModifiedFlag( );

}

void CNTGraphCtrl::OnFontChanged() 
{
	InvalidateControl();
	SetModifiedFlag( );
	COleControl::OnFontChanged();
}

////////////////////////////////////////////////////////
// New Method Show/Hide Graph Element
// Added by A.Hofmann
void CNTGraphCtrl::SetShowElement(BOOL bShow) 
{
	mpElement[m_ElementId].m_bShow = bShow;
	InvalidateControl();
	SetModifiedFlag();
}

////////////////////////////////////////////////////////
// New Method to copy a control bitmap to the clipboard
// Code Project Article: "Clipboard Copy in a Nutshell"
// by Keith Rule
void CNTGraphCtrl::Copy2Clipboard() 
{
    CRect rect;
    CClientDC dc(this);
    CDC memDC;
    CBitmap bitmap;
    GetClientRect(&rect);
    
	// Create memDC
    memDC.CreateCompatibleDC(&dc);
    bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
    CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
    
	// Fill in memDC
    memDC.FillSolidRect(rect, dc.GetBkColor());
    OnDraw(&memDC, rect, rect);
    
	// Copy contents of memDC to clipboard
    OpenClipboard();
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, bitmap.GetSafeHandle()); // CF_METAFILEPICT
    CloseClipboard();
    
	// Clean up
    memDC.SelectObject(pOldBitmap);
    bitmap.Detach();	

}

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

Share

About the Author

Nikolai Teofilov
Researcher
Germany Germany
No Biography provided

| Advertise | Privacy | Mobile
Web03 | 2.8.140916.1 | Last Updated 6 Aug 2003
Article Copyright 2002 by Nikolai Teofilov
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid