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

📄 graph.cpp

📁 EZ-USB 开发板完整资料
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	while (pos) {
		CGraphSeries* pSeries = (CGraphSeries*)m_olCGraphSeries.GetNext(pos);
		ASSERT_VALID(pSeries);

		nMax = max(nMax, pSeries->GetNonZeroElementCount());
	}

	return nMax;
}

// Get the largest data value in all series.
int CGraph::GetMaxDataValue() 
{
	VALIDATE;

	int nMax(-32768);
	POSITION pos(m_olCGraphSeries.GetHeadPosition());

	while (pos) {
		CGraphSeries* pSeries = (CGraphSeries*)m_olCGraphSeries.GetNext(pos);
		ASSERT_VALID(pSeries);

		nMax = max(nMax, pSeries->GetMaxDataValue());
	}

	return nMax;
}

// How many series are populated?
int CGraph::GetNonZeroSeriesCount() 
{
	VALIDATE;

	int nCount(0);
	POSITION pos(m_olCGraphSeries.GetHeadPosition());

	while (pos) {
		CGraphSeries* pSeries = (CGraphSeries*)m_olCGraphSeries.GetNext(pos);
		ASSERT_VALID(pSeries);

		if (0 < pSeries->GetNonZeroElementCount()) {
			++nCount;
		}
	}

	return nCount;
}

// Returns the group number for the sent label; -1 if not found.
int CGraph::LookupLabel(CString sLabel) 
{
	VALIDATE;
	_ASSERTE(! sLabel.IsEmpty());
	
	for (int nGroup = 0; nGroup < m_paLegend.GetSize(); ++nGroup) {

		if (0 == sLabel.CompareNoCase(((PGRAPHICLEGEND)(m_paLegend.GetAt(nGroup)))->sLabel)) {
			return nGroup;
		}
	}

	return -1;
}

//
void CGraph::AddSeries(CGraphSeries* pCGraphSeries)
{
	VALIDATE;
	ASSERT_VALID(pCGraphSeries);
	
	m_olCGraphSeries.AddTail(pCGraphSeries);
	//TRACE("CGraph::AddSeries. Added Series.\n");
}

//
void CGraph::SetXAxisLabel(CString sLabel)
{
	VALIDATE;
	_ASSERTE(! sLabel.IsEmpty());

	m_sXAxisLabel = sLabel;
}

//
void CGraph::SetYAxisLabel(CString sLabel)
{
	VALIDATE;
	_ASSERTE(! sLabel.IsEmpty());

	m_sYAxisLabel = sLabel;
}

// Returns the group number added.  Also, makes sure that all the series have 
// this many elements.
int CGraph::AppendGroup(CString sLabel)
{
	VALIDATE;
	_ASSERTE(! sLabel.IsEmpty());

	// Add the group.
	int nGroup((int)m_paLegend.GetSize());

	if (nGroup < MAX_GROUPS_ALLOWED)
	{
		AddLegend(nGroup, sLabel);

		// Make sure that all series have this element.
		POSITION pos(m_olCGraphSeries.GetHeadPosition());

		while (pos) {

			CGraphSeries* pSeries = (CGraphSeries*)m_olCGraphSeries.GetNext(pos);
			ASSERT_VALID(pSeries);

			if (nGroup >= pSeries->m_dwaValues.GetSize()) {
				pSeries->m_dwaValues.SetAtGrow(nGroup, 0);
			}
		}
	}
	else
	{
		nGroup = -1;
	}

	return nGroup;
}

// Set this value to the legend.
void CGraph::AddLegend(int nGroup, CString sLabel)
{
	VALIDATE;
	_ASSERTE(nGroup <= m_paLegend.GetSize());
	_ASSERTE(nGroup < MAX_GROUPS_ALLOWED);
	_ASSERTE(! sLabel.IsEmpty());

	PGRAPHICLEGEND pLegend = new GRAPHICLEGEND;

	if(pLegend == NULL) return;

	pLegend->sLabel = sLabel;
	if (m_dwaColors.GetCount()) {
		pLegend->dwColor = m_dwaColors.GetAt(0);
		m_dwaColors.RemoveAt(0);
	} else {
		delete pLegend;
		return;
	}

	m_paLegend.SetAtGrow(nGroup, (void*)pLegend);
}

void CGraph::RenameLegend(int nGroup, CString sLabel)
{
	VALIDATE;
	_ASSERTE(nGroup < m_paLegend.GetSize());
	_ASSERTE(nGroup < MAX_GROUPS_ALLOWED);
	_ASSERTE(! sLabel.IsEmpty());


	PGRAPHICLEGEND pLegend = (PGRAPHICLEGEND)m_paLegend.GetAt(nGroup);
	pLegend->sLabel = sLabel;
}

void CGraph::SetGraphTitle(CString sTitle)
{
	VALIDATE;
	_ASSERTE(! sTitle.IsEmpty());

	m_sTitle = sTitle;
}

void CGraph::DrawGraph(CDC* pDc)
{
	VALIDATE;
	ASSERT_VALID(pDc);


	pDc->SetBkMode(TRANSPARENT);

	CWnd* graphWnd = pDc->GetWindow();
	CRect rcWnd;
	graphWnd->GetClientRect(&rcWnd);

	// Reduce the graphable area by the frame window and status bar.  We will
	// leave GAP_PIXELS pixels blank on all sides of the graph.  So top-left 
	// side of graph is at GAP_PIXELS,GAP_PIXELS and the bottom-right side 
	// of graph is at (m_rcGraph.Height() - GAP_PIXELS), (m_rcGraph.Width() -
	// GAP_PIXELS).  These settings are altered by axis labels and legends.

	m_rcGraph.left = GAP_PIXELS;
	m_rcGraph.top = GAP_PIXELS;
	m_rcGraph.right = rcWnd.Width() - GAP_PIXELS;
	m_rcGraph.bottom = rcWnd.Height() - GAP_PIXELS;

	CBrush br;
	VERIFY(br.CreateSolidBrush(::GetSysColor(COLOR_WINDOW)));
	pDc->FillRect(rcWnd, &br);

	// Draw graph title.
	DrawTitle(pDc);

	// Set the axes and origin values.
	SetupAxes(pDc);

	// Draw axes unless it's a pie.
	if (m_eGraphType != CGraph::Pie) {
		DrawAxes(pDc);
	}
	
	try {
		// Draw legend if there is one.
		if (m_paLegend.GetSize()) {
			DrawLegend(pDc);
		}

		// Draw series data and labels.
		switch (m_eGraphType) {
			case CGraph::Bar:  DrawSeriesBar(pDc);  break;
			case CGraph::Line: DrawSeriesLine(pDc); break;
			case CGraph::Pie:  DrawSeriesPie(pDc);  break;
			default: _ASSERTE(! "Bad default case"); break;
		}
	}
	catch(...) {TRACE("Handled Exception\n");}
}

// Draw graph title; size is proportionate to width.
void CGraph::DrawTitle(CDC* pDc)
{
	VALIDATE;
	ASSERT_VALID(pDc);

	// Create the title font.
	CFont fontTitle;
	VERIFY(fontTitle.CreatePointFont(m_rcGraph.Width() / TITLE_DIVISOR,
		"Arial", pDc));
	CFont* pFontOld = static_cast<CFont*> (pDc->SelectObject(&fontTitle));
	ASSERT_VALID(pFontOld);

	// Draw the title.
	m_rcTitle.SetRect(GAP_PIXELS, GAP_PIXELS, m_rcGraph.Width() + GAP_PIXELS,
		m_rcGraph.Height() + GAP_PIXELS);

	pDc->DrawText(m_sTitle, m_rcTitle, DT_CENTER | DT_NOPREFIX | DT_SINGLELINE |
		DT_TOP | DT_CALCRECT);

	m_rcTitle.right = m_rcGraph.Width() + GAP_PIXELS;

	pDc->DrawText(m_sTitle, m_rcTitle, DT_CENTER | DT_NOPREFIX | DT_SINGLELINE | 
		DT_TOP);

	VERIFY(pDc->SelectObject(pFontOld));
}

// Set the axes and origin values.
void CGraph::SetupAxes(CDC* pDc)
{
	VALIDATE;
	ASSERT_VALID(pDc);

	// Since pie has no axis lines, set to full size minus GAP_PIXELS on each 
	// side.  These are needed for legend to plot itself.
	if (CGraph::Pie == m_eGraphType) {
		m_nXAxisWidth = m_rcGraph.Width() - (GAP_PIXELS * 2);
		m_nYAxisHeight = m_rcGraph.Height() - m_rcTitle.bottom;
		m_ptOrigin.x = GAP_PIXELS;
		m_ptOrigin.y = m_rcGraph.Height() - GAP_PIXELS;
	}
	else {
		// Bar and Line graphs.
		CString sTickLabel;
		sTickLabel.Format("-%d", GetMaxDataValue());

		if (m_nMaxDataValueAllowed == INVALID_MAX_VALUE) {// no Max data value
			sTickLabel.Format("-%d", GetMaxDataValue());
		} 
		else {
			sTickLabel.Format("-%d", m_nMaxDataValueAllowed);
		}

		CSize sizTickLabel(pDc->GetTextExtent(sTickLabel));

		// Determine axis specifications.  Assume tick label and axes label 
		// fonts are about the same size.
		m_ptOrigin.x = GAP_PIXELS + sizTickLabel.cx + GAP_PIXELS + 
			sizTickLabel.cy + GAP_PIXELS + TICK_PIXELS;
		m_ptOrigin.y = m_rcGraph.Height() - sizTickLabel.cy - GAP_PIXELS - 
			sizTickLabel.cy - GAP_PIXELS - TICK_PIXELS;
		m_nYAxisHeight = m_ptOrigin.y - m_rcTitle.bottom - (2 * GAP_PIXELS);
		m_nXAxisWidth = (m_rcGraph.Width() - GAP_PIXELS) - m_ptOrigin.x;
	}
}

//
void CGraph::DrawLegend(CDC* pDc)
{
	VALIDATE;
	ASSERT_VALID(pDc);

	// Create the legend font.
	CFont fontLegend;
	VERIFY(fontLegend.CreatePointFont(m_rcGraph.Height() / LEGEND_DIVISOR, 
		"Arial", pDc));
	CFont* pFontOld = static_cast<CFont*> (pDc->SelectObject(&fontLegend));
	ASSERT_VALID(pFontOld);

	// Get the height of each label.
	LOGFONT lf;
	::ZeroMemory(&lf, sizeof(lf));
	VERIFY(fontLegend.GetLogFont(&lf));
	int nLabelHeight(abs(lf.lfHeight));

	// Determine size of legend.  A buffer of (GAP_PIXELS / 2) on each side, 
	// plus the height of each label based on the pint size of the font.
	int nLegendHeight((GAP_PIXELS / 2) + ((int)m_paLegend.GetSize() * nLabelHeight) +
		(GAP_PIXELS / 2));
	
	// Draw the legend border.  Allow LEGEND_COLOR_BAR_PIXELS pixels for
	// display of label bars.
	m_rcLegend.top = (m_rcGraph.Height() / 2) - (nLegendHeight / 2);
	m_rcLegend.bottom = m_rcLegend.top + nLegendHeight;
	m_rcLegend.right = m_rcGraph.Width() - GAP_PIXELS;
	m_rcLegend.left = m_rcLegend.right - GetMaxLegendLabelLength(pDc) - 
		LEGEND_COLOR_BAR_WIDTH_PIXELS;
	VERIFY(pDc->Rectangle(m_rcLegend));


	// Draw each group's label and bar.
	for (int nGroup = 0; nGroup < m_paLegend.GetSize(); ++nGroup) 
	{
		int nLabelTop(m_rcLegend.top + (nGroup * nLabelHeight) +
			(GAP_PIXELS / 2));

		// Draw the label.
		VERIFY(pDc->TextOut(m_rcLegend.left + GAP_PIXELS, nLabelTop,
			((PGRAPHICLEGEND)(m_paLegend.GetAt(nGroup)))->sLabel));

		// Determine the bar.
		CRect rcBar;
		rcBar.left = m_rcLegend.left + GAP_PIXELS + GetMaxLegendLabelLength(pDc) +
			GAP_PIXELS;
		rcBar.top = nLabelTop + LEGEND_COLOR_BAR_GAP_PIXELS;
		rcBar.right = m_rcLegend.right - GAP_PIXELS;
		rcBar.bottom = rcBar.top + nLabelHeight - LEGEND_COLOR_BAR_GAP_PIXELS;
		VERIFY(pDc->Rectangle(rcBar));

		// Draw bar for group.
		//COLORREF crBar(m_dwaColors.GetAt(nGroup));
		COLORREF crBar(((PGRAPHICLEGEND)(m_paLegend.GetAt(nGroup)))->dwColor);

		CBrush br(crBar);

		CBrush* pBrushOld = pDc->SelectObject(&br);
		ASSERT_VALID(pBrushOld);

		pDc->SelectObject(&pBrushOld);
		rcBar.DeflateRect(LEGEND_COLOR_BAR_GAP_PIXELS, LEGEND_COLOR_BAR_GAP_PIXELS);
		pDc->FillRect(rcBar, &br);
	}

	VERIFY(pDc->SelectObject(pFontOld));
}

//
void CGraph::DrawAxes(CDC* pDc)
{
	VALIDATE;
	ASSERT_VALID(pDc);
	_ASSERTE(CGraph::Pie != m_eGraphType);

	pDc->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));

	// Draw y axis.
	pDc->MoveTo(m_ptOrigin);  
	VERIFY(pDc->LineTo(m_ptOrigin.x, m_ptOrigin.y - m_nYAxisHeight));

	// Draw x axis.
	pDc->MoveTo(m_ptOrigin);  

	if (m_paLegend.GetSize()) {

		VERIFY(pDc->LineTo(m_ptOrigin.x + 
			(m_nXAxisWidth - m_rcLegend.Width() - (GAP_PIXELS * 2)), 
			m_ptOrigin.y));
	}
	else {
		VERIFY(pDc->LineTo(m_ptOrigin.x + m_nXAxisWidth, m_ptOrigin.y));
	}

	// Create the y-axis label font and draw it.
	CFont fontYAxes;
	VERIFY(fontYAxes.CreateFont( 
		/* nHeight */ 15,
		/* nWidth */ 0, /* nEscapement */ 90 * 10, /* nOrientation */ 0,
		/* nWeight */ FW_DONTCARE,	/* bItalic */ false, /* bUnderline */ false,
		/* cStrikeOut */ 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
		CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | FF_DONTCARE, 
		"Arial"));

	CFont* pFontOld = static_cast<CFont*> (pDc->SelectObject(&fontYAxes));
	ASSERT_VALID(pFontOld);
	CSize sizYLabel(pDc->GetTextExtent(m_sYAxisLabel));
	VERIFY(pDc->TextOut(GAP_PIXELS, (m_rcGraph.Height() - sizYLabel.cy)*3/4,
		m_sYAxisLabel));

	// Create the x-axis label font and draw it.
	CFont fontXAxes;
	VERIFY(fontXAxes.CreatePointFont(100,
		"Arial", pDc));
	VERIFY(pDc->SelectObject(&fontXAxes));
	CSize sizXLabel(pDc->GetTextExtent(m_sXAxisLabel));

	VERIFY(pDc->TextOut(m_ptOrigin.x + (m_nXAxisWidth - sizXLabel.cx) / 2,
		m_rcGraph.Height() - (sizXLabel.cy/2), 
		m_sXAxisLabel));


	// Print the date and time.
	CTime logTime = CTime::GetCurrentTime();
	CString timeLabel= logTime.Format( "%m/%d/%Y,   %H:%M" );
	

	CFont fontTimeLabel;
	VERIFY(fontTimeLabel.CreatePointFont(100,
		"Arial", pDc));
	VERIFY(pDc->SelectObject(&fontTimeLabel));
	CSize sizTimeLabel(pDc->GetTextExtent(timeLabel));

	VERIFY(pDc->TextOut(m_ptOrigin.x ,
		m_rcGraph.Height() - (sizTimeLabel.cy/2), 
		timeLabel));


	// We hardwire TITLE_DIVISOR y-axis ticks here for simplicity.
	int nMaxValue;
	if (m_nMaxDataValueAllowed == INVALID_MAX_VALUE) {// no Max data value
		nMaxValue = GetMaxDataValue();
	} 
	else {
		nMaxValue = m_nMaxDataValueAllowed;	
	}

	int nTickCount(min(Y_AXIS_MAX_TICK_COUNT, ((nMaxValue-m_nYAxisShift) > 0) ? (nMaxValue-m_nYAxisShift) : 0));
	float nTickSpace(0);
	if (nTickCount)
		nTickSpace = (float)m_nYAxisHeight / (float)nTickCount;

	nMaxValue -= m_nYAxisShift;
	for (int nTick = 0; nTick <= nTickCount; ++nTick) {
		int nTickYLocation(m_ptOrigin.y - (int)(nTickSpace * nTick));
		pDc->MoveTo(m_ptOrigin.x - TICK_PIXELS, nTickYLocation);
		VERIFY(pDc->LineTo(m_ptOrigin.x + TICK_PIXELS, nTickYLocation));

		// Draw tick label.
		CString sTickLabel;
		sTickLabel.Format("%d", ((nMaxValue * nTick) / nTickCount)+m_nYAxisShift);
		CSize sizTickLabel(pDc->GetTextExtent(sTickLabel));
		
		VERIFY(pDc->TextOut(m_ptOrigin.x - GAP_PIXELS - sizTickLabel.cx - TICK_PIXELS,
			nTickYLocation - (sizTickLabel.cy/2), sTickLabel));
	}


	// Draw X axis tick marks.

	// Get the spacing of the series.
	float nSeriesSpace(0);

	nSeriesSpace = (float)((float)(m_nXAxisWidth - m_rcLegend.Width() - (GAP_PIXELS * 2)) / (float)(m_nXAxisScale+1));

	int jj = (m_nXAxisScale+20)/30;

	int kk;
	if (m_nXAxisScale == 10) 
		kk = 1;
	else if (m_nXAxisScale > 10 && m_nXAxisScale <= 20) 
		kk = 2;
	else
		kk = jj * 3;

	for (int ii=0; ii<=m_nXAxisScale; ii++) {

⌨️ 快捷键说明

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