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

📄 graph.cpp

📁 经过扩展的CGraph类及示例工程源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// Graph.cpp : implementation file


#include "stdafx.h"
#include "CDrawLine.h"//应改为对应应用程序的头文件
#include "GraphSeries.h"
#include "GraphLegend.h"
#include "math.h"
#include "Graph.h"

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

#define GREEN		RGB(0,255,0)
#define BLUE		RGB(0,0,255)
#define RED			RGB(255,0,0)
#define YELLOW		RGB(255,255,0)
#define ORANGE		RGB(255,153,51)
#define HOT_PINK	RGB(255,51,153)
#define PURPLE		RGB(153,0,204)
#define CYAN		RGB(0,255,255)
#define BLACK		RGB(0,0,0)
#define WHITE		RGB(255,255,255)


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

CGraph::CGraph()
{
	graphSeries = new CObList();
	tickRange = 100;
	seriesSize = 0;

	graphHasLegend = FALSE;
	legendWidth = 0;

	graphType = 0;
//以下为设置图例的背景色
	dataColor[0] = GREEN;  //green
	dataColor[1] = BLUE;  //blue
	dataColor[2] = RED;  //red
	dataColor[3] = YELLOW;  //yellow
	dataColor[4] = ORANGE;  //orange
	dataColor[5] = HOT_PINK;  //hot pink
	dataColor[6] = PURPLE;  //purple
	dataColor[7] = CYAN;  //cyan
	dataColor[8] = BLACK;  //black
	dataColor[9] = WHITE;  //white
//以上为图例的背景色
	xAxisAlign = 0;  //horizontal
	xAxisLabelLength = 0;

	xTickFontSize = 12;//x轴的单元格字体大小
	yTickFontSize = 12;//y轴的单元格字体
	legendFontSize = 12;//图例中的字体大小
	m_DrawMode=DEFAULTMODE;
}

CGraph::CGraph(int type,int drawmode)
{
	graphSeries = new CObList();
	tickRange = 100;
	seriesSize = 0;

	graphHasLegend = FALSE;
	legendWidth = 0;

	m_DrawMode=drawmode;
	graphType = type;
//以下为设置图例的背景色
	dataColor[0] = GREEN;  //green
	dataColor[1] = BLUE;  //blue
	dataColor[2] = RED;  //red
	dataColor[3] = YELLOW;  //yellow
	dataColor[4] = ORANGE;  //orange
	dataColor[5] = HOT_PINK;  //hot pink
	dataColor[6] = PURPLE;  //purple
	dataColor[7] = CYAN;  //cyan
	dataColor[8] = BLACK;  //black
	dataColor[9] = WHITE;  //white
//以上为图例的背景色
	xAxisAlign = 0;  //horizontal
	xAxisLabelLength = 0;

	xTickFontSize = 12;//x轴的单元格字体大小
	yTickFontSize = 12;//y轴的单元格字体大小
	legendFontSize =16;//图例中的字体大小
}

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

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

	graphSeries->RemoveAll();
	delete graphSeries;
}


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::SetTickSpace(int yDist)
{
	tickSpace = yDist;
}

void CGraph::SetTickRange(int maxTick)
{
	tickRange = maxTick;
}

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

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

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

void CGraph::DrawGraph(CDC* pDC)
{
	CString tickLabel;
	CWnd* graphWnd = pDC->GetWindow();//此调用得到pDC对应的窗口,即此绘图的区域
	CRect graphRect;
	graphWnd->GetClientRect(&graphRect);

	//reset graph to be clear background
	COLORREF backColor;
	backColor = RGB(255,255,255);  //设置你所希望的背景色
	m_background=backColor;
	CBrush backBrush (backColor);
	CBrush* pOldBackBrush;
	pOldBackBrush = pDC->SelectObject(&backBrush);
	pDC->Rectangle(0, 0, graphRect.Width(), graphRect.Height());
	pDC->SelectObject(pOldBackBrush);
    pDC->SetBkMode(TRANSPARENT);
	maxHeight = graphRect.Height() - 20;  //for frame window and status bar
	maxWidth = graphRect.Width() - 5;  //for frame window
	//We will leave 5 pixels blank on all sides of the graph.  So
	//top-left side of graph is at 5,5 and the bottom-right side of
	//graph is at ((maxHeight - 5), (maxWidth - 5))
	//these settings are altered by axis labels and legends.

	//draw graph title
	CFont titleFont;//设置标题的自体
	titleFont.CreateFont(28, 0, 0, 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(&titleFont);

	pDC->TextOut((maxWidth / 2) - ((graphTitle.GetLength() * 12) / 2),
				10, graphTitle);//绘制标题的位置
	pDC->SelectObject(pOldFont);
    
	if(graphType == 2)  //pie
	{

		//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 - 20;  //10 buffer and 20 for title
		xApexPoint = 5;
		yApexPoint = maxHeight - 5;
	}
	else
	{
		//X-axis will be raised by 20 pixels for tick-labels
		//Y-axis will be shifted by (max(tick-label size) * 10) + label * 10
		
		tickLabel.Format("%d", tickRange);

		//determine axis specifications 
			//tick label offset is 4 (for the tick) + 6 (total 10) from axis line
		xApexPoint = 5 + (tickLabel.GetLength() * (yTickFontSize/ 2 )) + 10 + 30/*(axisYLabel.GetLength() * 8)*/ + 5; //allowing 8 pixels per char in tick label
			//y apex based on 5 + 15 (x label) + 4 (for the tick) + 4 (text below tick) + 12 (tick label) + 10
		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;//从客户区往下40个像素
		xAxisWidth = (maxWidth - 5) - xApexPoint;//实际长度为maxwidth-5
	}

	//draw legend
	if(graphHasLegend)
		DrawLegend(pDC);

	if(graphType != 2)  //pie
	{
		//draw axis lines
		DrawAxis(pDC);
	}

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

}

void CGraph::DrawAxis(CDC* pDC)
{
	pDC->SetTextColor(RGB(0,0,0));
    BOOL  drawarrow=FALSE;
	//draw y axis
	double tickScale = 0.00;//tickScale按比例缩小y轴单元
	if(tickRange > yAxisHeight)
		tickScale = ((yAxisHeight * 1.00) / (tickRange * 1.00)) * tickSpace;
	else tickScale = tickSpace;
	int ymutiple;
	ymutiple = tickRange / tickSpace; 
	m_nUnits=yAxisHeight/ymutiple;//设置每个逻辑单元的像素数目
	int ylength = yApexPoint - (ymutiple* tickScale);
	

  if(m_DrawMode==DEFAULTMODE)
  {
	  pDC->MoveTo(xApexPoint, yApexPoint);  
	
	 pDC->LineTo(xApexPoint, ylength);//(yApexPoint - yAxisHeight)被ylength替换
  }
  else

  {
      pDC->MoveTo(xApexPoint, yApexPoint); 
      pDC->LineTo(xApexPoint, yApexPoint - yAxisHeight);
  }


	//draw x axis
  POINT xaxisRight;
	pDC->MoveTo(xApexPoint, yApexPoint);  
	if(graphHasLegend)
	{
		pDC->LineTo(xApexPoint + (xAxisWidth - legendWidth - 10), yApexPoint);
	    xaxisRight.x=xApexPoint+ (xAxisWidth - legendWidth - 10);
		
	}
	else
	{
		pDC->LineTo(xApexPoint + xAxisWidth, yApexPoint);
		xaxisRight.x=xApexPoint + xAxisWidth;
        
	}
    xaxisRight.y =yApexPoint;
	//绘制x轴的箭头

    POINT   pointx4[4];
			pointx4[0].x=xaxisRight.x;
			pointx4[0].y=xaxisRight.y;
			pointx4[1].x=xaxisRight.x-10;
            pointx4[1].y=xaxisRight.y+4;
		    pointx4[2].x=xaxisRight.x-8;
		    pointx4[2].y=xaxisRight.y;
            pointx4[3].x=xaxisRight.x-10;
		    pointx4[3].y=xaxisRight.y-4;
		    HRGN arrowrgnx;
			arrowrgnx=::CreatePolygonRgn(pointx4,4,WINDING);
			
	       ::Polygon(pDC->m_hDC,pointx4,4);
	       ::InvertRgn(pDC->m_hDC,arrowrgnx);


//以上绘制x轴的箭头

	//draw labels
	CFont sideFont;
	sideFont.CreateFont(16, 0, 900, 0, 700, FALSE, FALSE, 0,
		ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");//创建y轴标签字体
	CFont* pOldFont = (CFont*) pDC->SelectObject(&sideFont);

	pDC->TextOut(10, (maxHeight / 2) + ((axisYLabel.GetLength() / 2) * 4), axisYLabel);
	pDC->SelectObject(pOldFont);

	pDC->TextOut(xApexPoint + (xAxisWidth / 2) - ((axisXLabel.GetLength() / 2) * 19), maxHeight - 5 - 6, axisXLabel);

	
	

	//draw y axis ticks
	for(int y = 1; y <= tickRange / tickSpace; y++)  //no tick at 0
	{
		int tickYLocation = yApexPoint - (y * tickScale);
      
		if(y < tickRange / tickSpace&&m_DrawMode==DEFAULTMODE)
		{
		   
		   pDC->MoveTo(xApexPoint - 4, tickYLocation);
		   pDC->LineTo(xApexPoint + 4, tickYLocation);
		}
		else if(m_DrawMode==DEFAULTMODE)//绘制y轴顶端的箭头(其中点为坐标值)
		{
			
			POINT point4[4];
			point4[0].x=xApexPoint;
			point4[0].y=tickYLocation-6;
			point4[1].x=xApexPoint-4;
            point4[1].y=tickYLocation+6;
		    point4[2].x=xApexPoint;
		    point4[2].y=tickYLocation+2;
            point4[3].x=xApexPoint+4;
		    point4[3].y=tickYLocation+6;
		    HRGN arrowrgn;
			arrowrgn=::CreatePolygonRgn(point4,4,WINDING);
			
	       ::Polygon(pDC->m_hDC,point4,4);
	       ::InvertRgn(pDC->m_hDC,arrowrgn);
			
		}
		else
		{
			tickYLocation = yApexPoint - (y *m_nUnits);
			if(drawarrow==FALSE)
			{
               	POINT point4[4];
			    point4[0].x=xApexPoint;
				point4[0].y=yApexPoint -yAxisHeight-6;
				point4[1].x=xApexPoint-4;
				point4[1].y=yApexPoint -yAxisHeight+6;
				point4[2].x=xApexPoint;
				point4[2].y=yApexPoint -yAxisHeight+2;
				point4[3].x=xApexPoint+4;
				point4[3].y=yApexPoint -yAxisHeight+6;
				HRGN arrowrgn;
				arrowrgn=::CreatePolygonRgn(point4,4,WINDING);
			
				::Polygon(pDC->m_hDC,point4,4);
				::InvertRgn(pDC->m_hDC,arrowrgn);
				drawarrow=TRUE;
			
			}
			   

				pDC->MoveTo(xApexPoint - 4, tickYLocation);
		        pDC->LineTo(xApexPoint + 4, tickYLocation);

		}

		//draw tick label
		CString tickLabel;
		tickLabel.Format("%d", y * tickSpace);

		CFont yFont;
		yFont.CreateFont(yTickFontSize, 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(&yFont);

		pDC->TextOut(xApexPoint - 10 - (tickLabel.GetLength() * (yTickFontSize / 2)), tickYLocation - 6, tickLabel);

		pDC->SelectObject(pOldFont);

	}

	//draw X axis tick marks
	POSITION pos;
	pos = graphSeries->GetHeadPosition();
	CGraphSeries* tmpSeries;
	for(int x = 1; x <= graphSeries->GetCount(); x++)
	{
		tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);

		int seriesSpace;
		int tickXLocation;
		if(graphHasLegend)
			seriesSpace= (xAxisWidth - legendWidth - 10) / graphSeries->GetCount();
		else
			seriesSpace= xAxisWidth / graphSeries->GetCount();
		tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));

		pDC->MoveTo(tickXLocation,yApexPoint - 4);
		pDC->LineTo(tickXLocation,yApexPoint + 4);

		//draw tick label
		CString tickLabel;
		tickLabel = tmpSeries->GetLabel();
		if(!xAxisAlign)  //horizontal
			pDC->TextOut(tickXLocation - ((tickLabel.GetLength() * 8) / 2), yApexPoint + 8, tickLabel);
		else
		{
			CFont sideFont2;
			sideFont2.CreateFont(xTickFontSize, 0, (xAxisAlign * 10), 0, 700, FALSE, FALSE, 0,
				ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
				DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
			pOldFont = (CFont*) pDC->SelectObject(&sideFont2);
			if(xAxisAlign < 180)
				pDC->TextOut(tickXLocation - 8, yApexPoint + 8 + (xAxisLabelLength * (xTickFontSize / 2)), tickLabel);
			else
				pDC->TextOut(tickXLocation + 2, yApexPoint + 8, tickLabel);

			pDC->SelectObject(pOldFont);
		}
	}


}

void CGraph::AddSeries(CGraphSeries* dataSet)
{
	int numData = 0;
	for(int i = 0; i < 10; i++)
	{
		if(dataSet->GetData(i) > 0)
			numData++;
		if(dataSet->GetLabel().GetLength() > xAxisLabelLength)
			xAxisLabelLength = dataSet->GetLabel().GetLength();
	}
	if(numData > seriesSize)
		seriesSize = numData;

	graphSeries->AddTail(dataSet);
}

void CGraph::SetXAxisLabel(CString label)
{
	axisXLabel = label;
}
void CGraph::SetYAxisLabel(CString label)
{
	axisYLabel = label;
}

void CGraph::SetColor(int group, COLORREF groupColor)
{
	dataColor[group] = groupColor;
}

COLORREF CGraph::GetColor(int group)
{
	return dataColor[group];
}

void CGraph::DrawSeries(CDC* pDC)
{
	int barWidth;
	int dataPlotSize;   //used to plot rects of data
	int barL, barT, barR, barB;
	int tickXLocation;
	int seriesSpace;
	double barHeight;  //for scalability
	POSITION pos;
	CGraphSeries* tmpSeries;

	if(graphType == 0) //bar

⌨️ 快捷键说明

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