www.gusucode.com > VC++自定义图表控件及使用例子源码程序 > VC++自定义图表控件及使用例子源码程序\code\ChartCtrl_demo\ChartDemo\ChartCtrl\ChartBarSerie.cpp

    //Download by http://www.NewXing.com
/*
 *
 *	ChartBarSerie.cpp
 *
 *	Written by C閐ric Moonen (cedric_moonen@hotmail.com)
 *
 *
 *
 *	This code may be used for any non-commercial and commercial purposes in a compiled form.
 *	The code may be redistributed as long as it remains unmodified and providing that the 
 *	author name and this disclaimer remain intact. The sources can be modified WITH the author 
 *	consent only.
 *	
 *	This code is provided without any garanties. I cannot be held responsible for the damage or
 *	the loss of time it causes. Use it at your own risks
 *
 *	An e-mail to notify me that you are using this code is appreciated also.
 *
 *
 */

#include "stdafx.h"
#include "ChartBarSerie.h"
#include "ChartCtrl.h"
#include <algorithm>

using namespace std;

int CChartBarSerie::m_iInterSpace = 0;
std::list<CChartBarSerie*> CChartBarSerie::m_lstBarSeries;

CChartBarSerie::CChartBarSerie(CChartCtrl* pParent) 
 : CChartXYSerie(pParent), m_iBarWidth(20), m_iBorderWidth(1),
   m_BorderColor(RGB(0,0,0)), m_uGroupId(0), m_bGradient(true), 
   m_GradientColor(RGB(255,255,255)), m_GradientType(gtHorizontalDouble),
   m_bHorizontal(false), m_dBaseLine(0), m_bAutoBaseLine(true), m_bStacked(false)
{
	m_lstBarSeries.push_back(this);
	m_iShadowDepth = 3;
	m_bShadow = false;
}

CChartBarSerie::~CChartBarSerie()
{
	TBarSeriesList::iterator iter = m_lstBarSeries.begin();
	while (iter!=m_lstBarSeries.end())
	{
		if ((*iter) == this)
			iter = m_lstBarSeries.erase(iter);
		else
			iter++;
	}
}

void CChartBarSerie::SetHorizontal(bool bHorizontal)  
{ 
	m_bHorizontal = bHorizontal; 
	if (m_bHorizontal)
		SetSeriesOrdering(poYOrdering);
	else
		SetSeriesOrdering(poXOrdering);
	m_pParentCtrl->RefreshCtrl();
}

void CChartBarSerie::SetBorderColor(COLORREF BorderColor)  
{ 
	m_BorderColor = BorderColor; 
	m_pParentCtrl->RefreshCtrl();
}
void CChartBarSerie::SetBorderWidth(int Width)  
{ 
	m_iBorderWidth = Width; 
	m_pParentCtrl->RefreshCtrl();
}

void CChartBarSerie::SetBarWidth(int Width)		
{ 
	m_iBarWidth = Width;
	m_pParentCtrl->RefreshCtrl();
}

void CChartBarSerie::SetGroupId(unsigned GroupId)	
{ 
	m_uGroupId = GroupId; 
	m_pParentCtrl->RefreshCtrl();
}

void CChartBarSerie::ShowGradient(bool bShow)		
{ 
	m_bGradient = bShow; 
	m_pParentCtrl->RefreshCtrl();
}

void CChartBarSerie::SetGradient(COLORREF GradientColor, EGradientType GradientType)
{
	m_GradientColor = GradientColor;
	m_GradientType = GradientType;
	m_pParentCtrl->RefreshCtrl();
}

void CChartBarSerie::SetStacked(bool bStacked)
{
	m_bStacked = bStacked;
	m_pParentCtrl->RefreshCtrl();
}

bool CChartBarSerie::IsStacked()
{
	return m_bStacked;
}

void CChartBarSerie::DrawBar(CDC* pDC, CBrush* pFillBrush, CBrush* pBorderBrush, 
							 CRect BarRect)
{
	if (m_bShadow)
	{
		CBrush ShadowBrush(m_ShadowColor);
		CRect ShadowRect(BarRect);
		ShadowRect.OffsetRect(m_iShadowDepth,m_iShadowDepth);
		pDC->FillRect(ShadowRect,&ShadowBrush);
	}
	pDC->FillRect(BarRect,pBorderBrush);

	CRect FillRect(BarRect);
	FillRect.DeflateRect(m_iBorderWidth,m_iBorderWidth);
	if (m_bGradient)
	{
		CChartGradient::DrawGradient(pDC,FillRect,m_SerieColor,m_GradientColor,
									 m_GradientType);
	}
	else
	{
		pDC->FillRect(FillRect,pFillBrush);
	}
}

void CChartBarSerie::Draw(CDC* pDC)
{
	if (!m_bIsVisible)
		return;
	if (!pDC->GetSafeHdc())
		return;

	RefreshStackedCache();
	int iMinorOffset = GetMinorOffset();

	CRect TempClipRect(m_PlottingRect);
	TempClipRect.DeflateRect(1,1);
	pDC->SetBkMode(TRANSPARENT);
	pDC->IntersectClipRect(TempClipRect);

	CBrush BorderBrush(m_BorderColor);
	CBrush FillBrush(m_SerieColor);
	//Draw all points that haven't been drawn yet
	for (m_uLastDrawnPoint;m_uLastDrawnPoint<(int)GetPointsCount();m_uLastDrawnPoint++)
	{
		CRect BarRect = GetBarRectangle(m_uLastDrawnPoint,iMinorOffset);
		DrawBar(pDC, &FillBrush, &BorderBrush, BarRect);
	}

	pDC->SelectClipRgn(NULL);
	DeleteObject(BorderBrush);
	DeleteObject(FillBrush);
}

void CChartBarSerie::DrawAll(CDC *pDC)
{
	if (!m_bIsVisible)
		return;
	if (!pDC->GetSafeHdc())
		return;

	RefreshStackedCache();
	int iMinorOffset = GetMinorOffset();

	unsigned uFirst=0, uLast=0;
	if (!GetVisiblePoints(uFirst,uLast))
		return;

	CRect TempClipRect(m_PlottingRect);
	TempClipRect.DeflateRect(1,1);
	if (uFirst>0)
		uFirst--;
	if (uLast<GetPointsCount()-1)
		uLast++;

	pDC->SetBkMode(TRANSPARENT);
	pDC->IntersectClipRect(TempClipRect);

	CBrush BorderBrush(m_BorderColor);
	CBrush FillBrush(m_SerieColor);
	for (m_uLastDrawnPoint=uFirst;m_uLastDrawnPoint<=uLast;m_uLastDrawnPoint++)
	{
		CRect BarRect = GetBarRectangle(m_uLastDrawnPoint,iMinorOffset);
		DrawBar(pDC, &FillBrush, &BorderBrush, BarRect);
	}

	pDC->SelectClipRgn(NULL);
	DeleteObject(BorderBrush);
	DeleteObject(FillBrush);
}

void CChartBarSerie::DrawLegend(CDC* pDC, const CRect& rectBitmap) const
{
	if (m_strSerieName== _T(""))
		return;

	//Draw bar:
	CBrush BorderBrush(m_BorderColor);
	pDC->FillRect(rectBitmap,&BorderBrush);

	CRect FillRect(rectBitmap);
	CBrush FillBrush(m_SerieColor);
	FillRect.DeflateRect(m_iBorderWidth,m_iBorderWidth);
	if (m_bGradient)
	{
		CChartGradient::DrawGradient(pDC,FillRect,m_SerieColor,m_GradientColor,m_GradientType);
	}
	else
	{
		pDC->FillRect(FillRect,&FillBrush);
	}
}

bool CChartBarSerie::IsPointOnSerie(const CPoint& screenPoint, unsigned& uIndex) const 
{ 
	uIndex = INVALID_POINT;
	if (!m_bIsVisible)
		return false;

	RefreshStackedCache();
	int iMinorOffset = GetMinorOffset();
	
	unsigned uFirst=0, uLast=0;
	if (!GetVisiblePoints(uFirst,uLast))
		return false;

	bool bResult = false;
	for (unsigned i=uFirst ; i < uLast ; i++)
	{
		CRect BarRect = GetBarRectangle(i,iMinorOffset);
		if (BarRect.PtInRect(screenPoint))
		{
			bResult = true;
			uIndex = i;
			break;
		}
	}
	return bResult; 
}

int CChartBarSerie::GetMinorOffset() const
{
	int iOffset = 0;
	int iTotalWidth = 0;
	int iLargestStacked = 0;
	bool bFound = false;

	TBarSeriesList::const_iterator iter = m_lstBarSeries.begin();
	for (iter; iter!=m_lstBarSeries.end(); iter++)
	{
		// Skip the series with a different group Id
		if ((*iter)->GetGroupId() != m_uGroupId)
			continue;

		if ((*iter)->IsStacked() )
		{
			if ((*iter)->GetBarWidth() > iLargestStacked)
				iLargestStacked = (*iter)->GetBarWidth();
		} 
		else
		{
			if (!bFound)
			{
				if ((*iter)==this)
					bFound = true;
				else 
					iOffset += (*iter)->GetBarWidth() + m_iInterSpace;
			}
			iTotalWidth += (*iter)->GetBarWidth() + m_iInterSpace;
		}
	}
	// Remove the interspace because it has been counted once too much.
	iTotalWidth -= m_iInterSpace;

	if (iLargestStacked > 0)
		iTotalWidth += iLargestStacked + m_iInterSpace;

	// If this series is a stacked series, it is put at the start
	if (m_bStacked)
		iOffset = 0;
	else if (iLargestStacked > 0)
	{
		iOffset += iLargestStacked + m_iInterSpace;
	}
	return (iOffset - iTotalWidth/2);  
}

CRect CChartBarSerie::GetBarRectangle(unsigned uPointIndex, int minorOffset) const
{
	SChartXYPoint point = GetPoint(uPointIndex);
	TBarSeriesList::const_iterator iter = m_lstStackedSeries.begin();

	bool bCalcOffset = false;
	if (m_bStacked && (*iter)!=this)
		bCalcOffset = true;

	double dXOffset = 0;
	double dYOffset = 0;
	if (bCalcOffset)
	{
		for (iter; iter!=m_lstStackedSeries.end(); iter++)
		{
			if ( (*iter)->GetPointsCount() <= uPointIndex)
				continue;

			if ( (*iter) == this)
				break;

			dXOffset += (*iter)->GetPoint(uPointIndex).GetX();
			dYOffset += (*iter)->GetPoint(uPointIndex).GetY();
		}
	}

	int barXStart, barXEnd, barYStart, barYEnd;
	if (m_bHorizontal)
	{
		if (bCalcOffset)
		{
			barXStart = m_pHorizontalAxis->ValueToScreen(dXOffset);
			barXEnd = m_pHorizontalAxis->ValueToScreen(dXOffset+point.X);
		}
		else 
		{
			barXEnd = m_pHorizontalAxis->ValueToScreen(point.X);
			if (!m_bAutoBaseLine)
				barXStart = m_pHorizontalAxis->ValueToScreen(m_dBaseLine);
			else
			{
				double Position = m_pVerticalAxis->GetPosition()/100.00;
				barXStart = m_PlottingRect.left + (int)(Position * (m_PlottingRect.right-m_PlottingRect.left));
			}
		}
		barYStart = m_pVerticalAxis->ValueToScreen(point.Y) + minorOffset;
		barYEnd = m_pVerticalAxis->ValueToScreen(point.Y) + minorOffset + m_iBarWidth;
	}
	else
	{
		if (bCalcOffset)
		{
			barYStart = m_pVerticalAxis->ValueToScreen(dYOffset);
			barYEnd = m_pVerticalAxis->ValueToScreen(dYOffset+point.Y);
		}
		else 
		{
			barYEnd = m_pVerticalAxis->ValueToScreen(point.Y);
			if (!m_bAutoBaseLine)
				barYStart = m_pVerticalAxis->ValueToScreen(m_dBaseLine);
			else
			{
				double Position = m_pHorizontalAxis->GetPosition()/100.00;
				barYStart = m_PlottingRect.left + (int)(Position * (m_PlottingRect.bottom-m_PlottingRect.top));
			}
		}
		barXStart = m_pHorizontalAxis->ValueToScreen(point.X) + minorOffset;
		barXEnd = m_pHorizontalAxis->ValueToScreen(point.X) + minorOffset + m_iBarWidth;
	}
	
	CRect barRect(min(barXStart, barXEnd), min(barYStart, barYEnd),
				  max(barXStart, barXEnd), max(barYStart, barYEnd) );
	return barRect;
}

void CChartBarSerie::RefreshStackedCache() const
{
	m_lstStackedSeries.clear();
	if (!m_bStacked)
		return;

	TBarSeriesList::const_iterator iter = m_lstBarSeries.begin();
	for (iter; iter!=m_lstBarSeries.end(); iter++)
	{
		// Skip the series with a different group Id
		if ((*iter)->GetGroupId() != m_uGroupId)
			continue;

		if ((*iter)->IsStacked() )
		{
			m_lstStackedSeries.push_back(*iter);
		}
	}
}