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

📄 graph.cpp

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

			//determine axis specifications 
			xApexPoint = pGraphL + 350 + (tickLabel.GetLength() * 240); 

			yApexPoint = pGraphB + 500;		
			yAxisHeight = maxHeight + (pGraphB - yApexPoint) - 1000;
			xAxisWidth = pGraphR - legendWidth - xApexPoint;
		}

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

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

	}  //end printing for Page 1    
	
	//update pGraphB value to pad some space below the graph
	pGraphB -= 90;
	return pGraphB;
}


void CGraph::PrintLegend(CDC *pDC)
{
	CFont		legendLabelFont, legendTitleFont;
	TEXTMETRIC	tm;

	int legendL, legendT, legendR, legendB;
	int barL, barT, barR, barB;

	//legendLabelFont is 10 point
	legendLabelFont.CreateFont(-200, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET,
			OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
			DEFAULT_QUALITY, DEFAULT_PITCH || FF_ROMAN,
			"Times New Roman");

	//legendTitleFont is 12 point
	legendTitleFont.CreateFont(-240, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET,
			OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
			DEFAULT_QUALITY, DEFAULT_PITCH || FF_ROMAN,
			"Times New Roman");

//	pDC->Rectangle(pGraphL, pGraphT, pGraphR, pGraphB);
	legendT = (((pGraphB - pGraphT) / 2) + pGraphT) + (((seriesSize + 1) / 2) * 240 + 300);
	legendB = (((pGraphB - pGraphT) / 2) + pGraphT) - (((seriesSize + 1) / 2) * 240 + 300);
	legendR = pGraphR - 50;
	legendL = legendR - ((legendR - pGraphL) * .15);
	legendWidth = legendR - legendL;

	pDC->Rectangle(legendL, legendT, legendR, legendB);
	CFont* pOldFont = (CFont*) pDC->SelectObject(&legendTitleFont);
	pDC->GetTextMetrics(&tm);
	pDC->TextOut(legendL + (legendWidth / 2) - 360, 
					legendT - 160, "图例");//Legend
	pDC->SelectObject(pOldFont);
	for(int i = 0; i < seriesSize; i++)
	{
		pOldFont = (CFont*) pDC->SelectObject(&legendLabelFont);
		pDC->GetTextMetrics(&tm);

		int charWidth = tm.tmMaxCharWidth;
		int charHeight = tm.tmHeight;

		CString valuStr;
		valuStr.Format("value %d", i + 1);
		pDC->TextOut(legendL + 50, legendT - (2 * charHeight) - 120 - (i * charHeight), valuStr);
		pDC->SelectObject(pOldFont);

		//draw bar
		COLORREF barColor;
		barColor = GetColor(i);
		CBrush brush (barColor);
		CBrush* pOldBrush;
		pOldBrush = pDC->SelectObject(&brush);

		barL = legendL + (9 * 120);
		barT = legendT - (2 * charHeight) - 120 - (i * charHeight) - 60;
		barR = legendR - 50;
		barB = barT - 120;
		pDC->Rectangle(barL, barT, barR, barB);

		pDC->SelectObject(pOldBrush);
	
	}

}

void CGraph::PrintAxis(CDC *pDC)
{
	pDC->SetTextColor(RGB(0,0,0));

	//draw y axis
	pDC->MoveTo(xApexPoint, yApexPoint);  
	pDC->LineTo(xApexPoint, yApexPoint + yAxisHeight - 250);

	//draw x axis
	pDC->MoveTo(xApexPoint, yApexPoint);  
	if(graphHasLegend)
		pDC->LineTo(xApexPoint + (xAxisWidth - 500), yApexPoint);
	else
		pDC->LineTo(xApexPoint + xAxisWidth - 500, yApexPoint);

	//draw labels
	CFont sideFont;
	sideFont.CreateFont(320, 0, 2700, 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->TextOut(pGraphL + 10, pGraphT - (maxHeight / 2) - ((axisYLabel.GetLength() / 2) * 160), axisYLabel);
	pDC->SelectObject(pOldFont);

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

	//to allow scalability (height may be less than tickRange)
	double tickScale = 0.00;
	if(tickRange > yAxisHeight)
		tickScale = ((yAxisHeight * 1.00) / (tickRange * 1.00)) * (tickSpace * 20);
	else tickScale = tickSpace * 15;

	//draw y axis ticks
	for(int y = 1; y <= tickRange / tickSpace; y++)  //no tick at 0
	{
		int tickYLocation = yApexPoint + (y * tickScale);

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

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

		CFont yFont;
		yFont.CreateFont(yTickFontSize * 20, 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 - 150 - (tickLabel.GetLength() * (yTickFontSize / 2) * 20), tickYLocation + 120, 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 - 75);
		pDC->LineTo(tickXLocation,yApexPoint + 75);

		//draw tick label
		CString tickLabel;
		tickLabel = tmpSeries->GetLabel();
		CFont sideFont2;
		sideFont2.CreateFont(xTickFontSize * 20, 0, ((360 - 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)  //horizontal
			pDC->TextOut(tickXLocation - ((tickLabel.GetLength() / 2) * (xTickFontSize * 10)), yApexPoint - 160, tickLabel);
		else
		{
			if(xAxisAlign < 180)
				pDC->TextOut(tickXLocation - ((xTickFontSize * 20) / 2), yApexPoint - (xTickFontSize * 20) - (xAxisLabelLength * ((xTickFontSize * 20) / 2)), tickLabel);
			else
				pDC->TextOut(tickXLocation + ((xTickFontSize * 20) / 2), yApexPoint - 160, tickLabel);

		}
		pDC->SelectObject(pOldFont);
	}

}

void CGraph::PrintSeries(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
	{
		//determine width of barchart data blocks
		if(graphHasLegend)
			seriesSpace = (xAxisWidth - legendWidth - 10) / graphSeries->GetCount();
		else
			seriesSpace = xAxisWidth / graphSeries->GetCount();
		barWidth = (seriesSpace * .6) / seriesSize;
		dataPlotSize = seriesSize * barWidth;

		pos = graphSeries->GetHeadPosition();

		for(int x = 1; x <= graphSeries->GetCount(); x++)
		{
			tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);

			double tickScale = 0.00;
			if(tickRange > yAxisHeight)
				tickScale = ((yAxisHeight * 1.00) / (tickRange * 1.00)) * (tickSpace * 20);
			else tickScale = tickSpace * 15;
			tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));

			for(int s = 0; s < seriesSize; s++)
			{
				barHeight = 0.00;

				int axisHeight = tickScale * (tickRange / tickSpace);
				double barPercent = 0.00;
				barPercent = (tmpSeries->GetData(s) * 1.00) / (tickRange * 1.00);
				barHeight = barPercent * axisHeight;

				barL = tickXLocation - (dataPlotSize / 2) + (s * barWidth);
				barT = yApexPoint + barHeight;
				barR = barL + barWidth;
				barB = yApexPoint;
				
				COLORREF barColor;
				barColor = GetColor(s);
				CBrush brush (barColor);
				CBrush* pOldBrush;
				pOldBrush = pDC->SelectObject(&brush);
				pDC->Rectangle(barL, barT, barR, barB);
				pDC->SelectObject(pOldBrush);
			}
		}
	}

	if(graphType == 1)  //line
	{
		int lastXLoc, lastYLoc;
		for(int s = 0; s < seriesSize; s++)
		{
			//determine width of barchart data blocks
			if(graphHasLegend)
				seriesSpace = (xAxisWidth - legendWidth - 10) / graphSeries->GetCount();
			else
				seriesSpace = xAxisWidth / graphSeries->GetCount();
			barWidth = (seriesSpace * .6) / seriesSize;
			dataPlotSize = seriesSize * barWidth;

			pos = graphSeries->GetHeadPosition();

			for(int x = 1; x <= graphSeries->GetCount(); x++)
			{
				tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);

				tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
				
				barHeight = 0.00;
				//to allow scalability (height may be less than tickRange)
				double dataScale = 0.00;
				if(tickRange > yAxisHeight)
					dataScale = ((yAxisHeight * 1.00) / (tickRange * 1.00)) * (tickSpace * 20);
				else dataScale = tickSpace * 15.00;

				int axisHeight = dataScale * (tickRange / tickSpace);
				double barPercent = 0.00;
				barPercent = (tmpSeries->GetData(s) * 1.00) / (tickRange * 1.00);
				barHeight = barPercent * axisHeight;

				int yDataLocation = yApexPoint + barHeight;
				
				//now have x and y location of center of ellipse
				COLORREF barColor;
				barColor = GetColor(s);
				CBrush brush (barColor);
				CBrush* pOldBrush;
				pOldBrush = pDC->SelectObject(&brush);
				//draw line back to last data member
				if(x > 1)
				{
					CPen* pOldPen;
					CPen linePen (PS_SOLID, 1, barColor);
					pOldPen = pDC->SelectObject(&linePen);
					pDC->MoveTo(lastXLoc/* - 40*/, lastYLoc/* + 20*/);
					pDC->LineTo(tickXLocation/* + 60*/, yDataLocation/* + 20*/);
					pDC->SelectObject(pOldPen);
				}
				//now draw ellipse...
				pDC->Ellipse(tickXLocation + 60, yDataLocation + 60,
					tickXLocation - 60, yDataLocation - 60);
				lastXLoc = tickXLocation;
				lastYLoc = yDataLocation;
				pDC->SelectObject(pOldBrush);
			}
		}
	}

	if(graphType == 2)  //pie
	{
		double dataSum = 0.00;  //for storing cumulative sum
		int lastXLocation, lastYLocation;
		int newXLocation, newYLocation;
		double percent = 0.00;
		int degrees;
		double totalSum = 0.00;
		int deltaXY;
		int radius;
			
		lastXLocation = 0;
		lastYLocation = 0;

		//determine width of pie display area
		if(graphHasLegend)
			if((xAxisWidth / graphSeries->GetCount())
					> (yAxisHeight - 200))
				seriesSpace = (yAxisHeight - 200)/* / graphSeries->GetCount()*/;
			else
				seriesSpace = xAxisWidth / graphSeries->GetCount();
		else
			if(xAxisWidth > yAxisHeight)
				seriesSpace = yAxisHeight / graphSeries->GetCount();
			else
				seriesSpace = xAxisWidth / graphSeries->GetCount();
		double tmpD = (seriesSpace - 100) * .9;  //max width of any pie
		radius = tmpD / 2;  

		int centerYPie = pGraphT - (yAxisHeight / 2) - 300;
		
		pos = graphSeries->GetHeadPosition();
		for(int x = 1; x <= graphSeries->GetCount(); x++)
		{
			tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
			totalSum = 0;
			for(int s = 0; s < 10; s++)
				totalSum += tmpSeries->GetData(s);
			int pieLeft, pieRight;
			if(graphSeries->GetCount() == 1)
			{
				pieLeft = ((xAxisWidth - 200) / 2) - radius;
			}
			else
			{
				pieLeft = pGraphL + 15 + (x * 200) + ((x - 1) * (2 * radius));
			}
			pieRight = pieLeft + (2 * radius);
			CRect pieRect (pieLeft, 
					centerYPie + radius,
					pieRight, 
					centerYPie - radius);
			int centerXPie = pieLeft + radius;

			CFont pieFont;
			pieFont.CreateFont(xTickFontSize * 20, 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(&pieFont);

			//plot series label
			pDC->TextOut(centerXPie - ((tmpSeries->GetLabel().GetLength() / 2) * ((xTickFontSize / 2) * 20)),
						centerYPie - radius - 300, tmpSeries->GetLabel());
			pDC->SelectObject(pOldFont);

			lastXLocation = pieLeft;
			lastYLocation = centerYPie;
			
			dataSum = 0;
			for(s = 0; s < seriesSize; s++)
			{
				if(tmpSeries->GetData(s) > 0)
				{
					dataSum += tmpSeries->GetData(s);
					percent = (dataSum * 100) / totalSum;
					degrees = (360 * percent) / 100;

						//degress / 90 will never exceed 4.
						//this can tell us the quadrant of destination
					deltaXY = (degrees * radius) / 90;
						//deltaXY is change from start point of pie 0
						//this value is total change.  so if radius is 300
						//and degrees is 270, delta is 300.  The change 
						//would move both x and y 300 pixels.  For x, 100
						//to right is center, another 100 to right edge,
						//100 back to center.  For y, 100 to bottom, 100
						//back to center, 100 to top. thus gives 270 degree
						//rotation.

					//determine destination quadrant...
						//and set newXLocation and newYLocation values...
					int quadrant = degrees / 90;  //truncates decimal
					switch(quadrant)
					{
						//in the computations below, the remarked line is
						//the original computation.  The line above it, for
						//actual use, is the simplified line, and gives the
						//exact same result
						case 0 : newXLocation = pieLeft + deltaXY;
								 newYLocation = centerYPie - deltaXY;
								 break;
						case 1 : newXLocation = pieLeft + deltaXY;
								 newYLocation = centerYPie - (2 * radius) + deltaXY;
								 break;
						case 2 : newXLocation = pieLeft + (4 * radius) - deltaXY;
								 newYLocation = centerYPie - (2 * radius) + deltaXY;
								 break;
						case 3 : newXLocation = pieLeft + (4 * radius) - deltaXY;
								 newYLocation = centerYPie + (4 * radius) - deltaXY;
								 break;
						case 4 : newXLocation = pieLeft;
								 newYLocation = centerYPie + 1;
								 break;
					}
					
					if(s == 0)
						lastYLocation -= 1;

					CPoint p1 (lastXLocation, lastYLocation);
					CPoint p2 (newXLocation, newYLocation);
					COLORREF barColor;
					barColor = GetColor(s);
					CBrush brush (barColor);
					CBrush* pOldBrush;
					pOldBrush = pDC->SelectObject(&brush);
					pDC->Pie(pieRect, p1, p2); 
					pDC->SelectObject(pOldBrush);

					lastXLocation = newXLocation;
					lastYLocation = newYLocation;
				}
			}
			
		}
	}
}

void CGraph::SetMargins(int top, int bottom, int left, int right, int graphTop)
{
	//page margins for portrait or landscape distinction
	topMargin = top;
	bottomMargin = bottom;
	leftMargin = left;
	rightMargin = right;

	//set up rectangle area for showing the graph
	pGraphL = leftMargin;
	pGraphT = graphTop;
	pGraphB = pGraphT - 7200;
	pGraphR = rightMargin;

	if(pGraphB < bottomMargin)
		pGraphB = bottomMargin; 

}

⌨️ 快捷键说明

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