⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 graph.cpp

📁 利用VC++开发的OCX控件
💻 CPP
📖 第 1 页 / 共 5 页
字号:
//Graph.cpp - Version 3.0 (Brian Convery, May, 2001)

#include "stdafx.h"
#include "afxtempl.h"
#include "GraphSeries.h"
#include "GraphLegend.h"
#include "math.h"
#include "Graph.h"
#include "GraphDataColor.h"
#include "GraphPieLabel.h"	//for pie labels

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

/////////////////////////////////////////////////////////////////////////////
// CGraph

CGraph::CGraph()
{
	graphSeries = new CObList();
	seriesSize = 0;
	minTick = 0;
	maxTick = 100;
	numTicks = 10;
	tickSpace = 10;

	graphHasLegend = FALSE;
	legendWidth = 0;
	legendMaxText= 0;
	graphAlignment = VERTICAL_ALIGN;  

	graphType = 0;

	xAxisAlign = 0;  //horizontal
	xAxisLabelLength = 0;

	xTickFontSize = 12;
	yTickFontSize = 12;
	legendFontSize = 12;

	depth = 0;
	depthRatio = 0.05;

	line3DXBase = 0;
	line3DYBase = 0;

	SetGridLines(FALSE);

	graphQuadType = 1;
	quadSetManually = FALSE;
}

CGraph::CGraph(int type)
{
	graphSeries = new CObList();
	colorList = new CObList();
	seriesSize = 0;
	minTick = 0;
	maxTick = 100;
	numTicks = 10;
	tickSpace = 10;

	graphHasLegend = FALSE;
	legendWidth = 0;
	legendMaxText= 0;
	graphAlignment = VERTICAL_ALIGN;  

	graphType = type;

	xAxisAlign = 0;  //in degrees == horizontal
	xAxisLabelLength = 0;

	xTickFontSize = 12;
	yTickFontSize = 12;
	legendFontSize = 12;

	depth = 0;
	depthRatio = 0.05;

	line3DXBase = 0;
	line3DYBase = 0;

	SetGridLines(FALSE);

	graphQuadType = 1;
	if(type != BAR_GRAPH)
		quadSetManually = TRUE;
	else
		quadSetManually = FALSE;
}

CGraph::~CGraph()
{
	POSITION pos;
	CGraphSeries* pSeries;

	for( pos = graphSeries->GetHeadPosition(); pos != NULL; )
	{
		pSeries = (CGraphSeries*) graphSeries->GetNext( pos );
		//graphSeries->RemoveAt(pos);
		delete pSeries;
	}

	graphSeries->RemoveAll();
	delete graphSeries;

	CGraphDataColor* dataColor;
	for( pos = colorList->GetHeadPosition(); pos != NULL; )
	{
		dataColor = (CGraphDataColor*) colorList->GetNext( pos );
		//colorList->RemoveAt(pos);
		delete dataColor;
	}

	colorList->RemoveAll();
	delete colorList;
	
}


BEGIN_MESSAGE_MAP(CGraph, CStatic)
	//{{AFX_MSG_MAP(CGraph)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CGraph message handlers

void CGraph::SetGraphType(int gType)
{
	graphType = gType;
}

void CGraph::SetXAxisAlignment(int alignValue)
{
	xAxisAlign = alignValue;
}

int CGraph::GetXAxisAlignment()
{
	return xAxisAlign;
}

void CGraph::SetColor(int dataGroup, COLORREF groupColor)
{
	CGraphDataColor *dataColor = new CGraphDataColor(dataGroup, groupColor);
	colorList->AddTail(dataColor);
}

COLORREF CGraph::GetColor(int dataGroup)
{
	POSITION pos;
	if((colorList->GetCount() <= dataGroup) || (colorList->GetCount() == 0))
		return BLACK;
	
	CGraphDataColor* dataColor;
	pos = colorList->GetHeadPosition();
	for(int i = 0; i < dataGroup; i++)
		colorList->GetNext(pos);

	dataColor = (CGraphDataColor*) colorList->GetAt( pos );
	return dataColor->GetColor();	
}

void CGraph::DrawGraph(CDC* pDC)
{
	CString tickLabel;
	CWnd* graphWnd = pDC->GetWindow();
	CRect graphRect;
	graphWnd->GetClientRect(&graphRect);
	TEXTMETRIC	tm;

	//reset graph to be clear background
	COLORREF backColor;
	backColor = RGB(255,255,255);  //replace with desired background color
	CBrush backBrush (backColor);
	CBrush* pOldBackBrush;
	pOldBackBrush = pDC->SelectObject(&backBrush);
	pDC->Rectangle(0, 0, graphRect.Width(), graphRect.Height());
	pDC->SelectObject(pOldBackBrush);

	maxHeight = graphRect.Height() - 20;  //for frame window and status bar
	maxWidth = graphRect.Width() - 5;  //for frame window


	if((graphType == PIE_GRAPH) || (graphType == PIE_GRAPH_3D))
	{

		//since pie does not have axis lines, set to full size minus 5 on each side
		//these are needed for legend to plot itself
		xAxisWidth = maxWidth - 10;
		yAxisHeight = maxHeight - 50;  //10 buffer, 20 for title, and 20 for series label
		xApexPoint = 5;
		yApexPoint = maxHeight - 5;
	}
	else
	{
		//compute label size for axis alignment
		CFont sideFont, axisFont;
		int tFontSize = 16;
		if(maxWidth > maxHeight)
		{
			while((axisYLabel.GetLength() * (tFontSize / 2)) > maxHeight)
			{
				tFontSize -= 2;
			}
		}
		else
		{
			while((axisXLabel.GetLength() * (tFontSize / 2)) > maxWidth)
			{
				tFontSize -= 2;
			}
		}
		axisFont.CreateFont(tFontSize, 0, 0, 0, 700, FALSE, FALSE, 0,
			ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
			DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
		sideFont.CreateFont(tFontSize, 0, 900, 0, 700, FALSE, FALSE, 0,
			ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
			DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");

		CFont* pOldFont = (CFont*) pDC->SelectObject(&sideFont);
		pDC->GetTextMetrics(&tm);
		int charWidth = tm.tmAveCharWidth;
		int labelHeight = tm.tmHeight + 10;
		if(graphAlignment)
		{
			if(axisYLabel.GetLength() == 0)
				labelHeight = 0;
		}
		else
		{
			if(axisXLabel.GetLength() == 0)
				labelHeight = 0;
		}
		pDC->SelectObject(pOldFont);

		tickLabel.Format("%d", maxTick);

		//determine axis specifications 
		if(graphAlignment)
		{
			if(graphType == SCATTER_GRAPH)
			{
				xApexPoint = 5 + (xAxisLabelLength * charWidth) + labelHeight; //labelHeight added for y-axis label height
				yApexPoint = (maxHeight - 15) - tm.tmHeight;
				yAxisHeight = yApexPoint - 40;
				xAxisWidth = (maxWidth - 5) - xApexPoint;
			}
			else
			{
				xApexPoint = 5 + (tickLabel.GetLength() * (yTickFontSize / 2)) + 45; 
				if(!xAxisAlign)  //horizontal
					yApexPoint = (maxHeight - 5) - 45;		//apex points are the cross section of axis lines
				else
					yApexPoint = (maxHeight - 5) - (xAxisLabelLength * (xTickFontSize / 2)) - 10;
				yAxisHeight = yApexPoint - 40;
				xAxisWidth = (maxWidth - 5) - xApexPoint;
			}
		}
		else
		{
			xApexPoint = 5 + (xAxisLabelLength * charWidth) + labelHeight; //labelHeight added for y-axis label height
			yApexPoint = (maxHeight - 15) - tm.tmHeight;
			yAxisHeight = yApexPoint - 40;
			xAxisWidth = (maxWidth - 5) - xApexPoint;
		}
	}

	//draw legend
	if(graphHasLegend)
	{
		int legendLeft = DrawLegend(pDC);
		xAxisWidth = legendLeft - 10 - xApexPoint;
	}

	if((!quadSetManually) && (graphType == BAR_GRAPH))
	{
		//computer number of quadrants needed based on data
		POSITION pos;
		pos = graphSeries->GetHeadPosition();
		CGraphSeries* tmpSeries;
		int minXValue = 0;
		int minYValue = 0;
		for(int x = 1; x <= graphSeries->GetCount(); x++)
		{
			tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
			for(int s = 0; s < seriesSize; s++)
			{
				//to allow scalability (height may be less than tickRange)
				int curXValue = tmpSeries->GetXDataValue();
				int curYValue = tmpSeries->GetYDataValue();
				if(curXValue < minXValue)
					minXValue = curXValue;
				if(curYValue < minYValue)
					minYValue = curYValue;
			}
		}
		graphQuadType = 1;
		if((minXValue < 0) && (minYValue < 0))
			graphQuadType = 4;
		if((minXValue < 0) && (minYValue >= 0))
			graphQuadType = 2;
		if((minXValue >= 0) && (minYValue < 0))
			graphQuadType = 3;
	}

	if(graphType == BAR_GRAPH)
	{
		switch(graphQuadType)
		{
			case 2 :
				xApexPoint += xAxisWidth / 2;
				break;
			case 3 :
				yApexPoint -= yAxisHeight / 2;
				break;
			case 4 :
				xApexPoint += xAxisWidth / 2;
				yApexPoint -= yAxisHeight / 2;
				break;
		}
	}

	if((graphType != 2) && (graphType != 32))  //pie & 3d pie
	{
		inRedraw = FALSE;
		//draw axis lines
		DrawAxis(pDC);
	}

	//draw series data and labels
	DrawSeries(pDC);

	//lines below are commented for doing redraw.  If you
	//want the axis lines on top of the other graph elements
	//uncomment this functionality...I may add it back later
	//but there were some bugs doing it this way.

	//redraw axis lines in case graph elements overwrote the axis lines
//	if((graphType != 2) && (graphType != 32) && (graphQuadType > 1))  //pie & 3d pie
//	{
//		inRedraw = TRUE;
		//draw axis lines
//		DrawAxis(pDC);
//	}
}

void CGraph::DrawAxis(CDC* pDC)
{
	TEXTMETRIC	tm;
	pDC->SetTextColor(BLACK);
	CFont sideFont, axisFont, dummyFont;
	int charWidth, labelHeight;
	double tickScale;
	int tickXLocation, tickYLocation;
	int seriesSpace;
	CFont* pOldFont;
	int x, y;

	COLORREF axisLineColor;
	axisLineColor = BLACK;
	CPen axisPen (PS_SOLID, 2, axisLineColor);
	dummyFont.CreateFont(12, 0, 0, 0, 700, FALSE, FALSE, 0,
		ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
	pOldFont = (CFont*)pDC->SelectObject(&dummyFont);
	switch(graphType)
	{
		case BAR_GRAPH :
		case LINE_GRAPH :
		case SCATTER_GRAPH :
		case BOX_WHISKER_GRAPH :
//		case RADAR_GRAPH :
		case STACKED_BAR_GRAPH :
		case XY_LINE_GRAPH :
				CPen* pOldAxisPen;
				pOldAxisPen = pDC->SelectObject(&axisPen);
				switch(graphQuadType)
				{
					case 1 :
						//draw y axis
						pDC->MoveTo(xApexPoint, yApexPoint);  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -