336 lines
8.5 KiB
C++
336 lines
8.5 KiB
C++
|
/*
|
|||
|
*
|
|||
|
* ChartPointsSerie.cpp
|
|||
|
*
|
|||
|
* Written by C<EFBFBD>dric 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.
|
|||
|
*
|
|||
|
*
|
|||
|
* History:
|
|||
|
* - 07/07/2008: Last point of the series was not displayed. Fixed.
|
|||
|
*/
|
|||
|
|
|||
|
#include "stdafx.h"
|
|||
|
#include "ChartPointsSerie.h"
|
|||
|
#include "ChartCtrl.h"
|
|||
|
#include "Math.h"
|
|||
|
|
|||
|
#ifdef _DEBUG
|
|||
|
#undef THIS_FILE
|
|||
|
static char THIS_FILE[]=__FILE__;
|
|||
|
#define new DEBUG_NEW
|
|||
|
#endif
|
|||
|
|
|||
|
//////////////////////////////////////////////////////////////////////
|
|||
|
// Construction/Destruction
|
|||
|
//////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
CChartPointsSerie::CChartPointsSerie(CChartCtrl* pParent)
|
|||
|
: CChartXYSerie(pParent), m_iPointType(ptEllipse), m_iXPointSize(5),
|
|||
|
m_iYPointSize(5), m_colBorder(RGB(0,0,0))
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
CChartPointsSerie::~CChartPointsSerie()
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
void CChartPointsSerie::SetPointSize(int XSize, int YSize)
|
|||
|
{
|
|||
|
m_iXPointSize = XSize;
|
|||
|
m_iYPointSize = YSize;
|
|||
|
m_pParentCtrl->RefreshCtrl();
|
|||
|
}
|
|||
|
|
|||
|
void CChartPointsSerie::SetPointType(PointType Type)
|
|||
|
{
|
|||
|
m_iPointType = Type;
|
|||
|
m_pParentCtrl->RefreshCtrl();
|
|||
|
}
|
|||
|
|
|||
|
void CChartPointsSerie::SetBorderColor(COLORREF Color)
|
|||
|
{
|
|||
|
m_colBorder = Color;
|
|||
|
m_pParentCtrl->RefreshCtrl();
|
|||
|
}
|
|||
|
|
|||
|
void CChartPointsSerie::Draw(CDC *pDC)
|
|||
|
{
|
|||
|
if (!m_bIsVisible)
|
|||
|
return;
|
|||
|
if (!pDC->GetSafeHdc())
|
|||
|
return;
|
|||
|
|
|||
|
CBrush NewBrush(m_SerieColor);
|
|||
|
CPen BorderPen(PS_SOLID, 1, m_colBorder);
|
|||
|
CBrush ShadowBrush(m_ShadowColor);
|
|||
|
CPen ShadowPen(PS_SOLID, 1, m_ShadowColor);
|
|||
|
CPen* pOldPen = pDC->SelectObject(&BorderPen);
|
|||
|
CBrush* pOldBrush = pDC->SelectObject(&NewBrush);
|
|||
|
|
|||
|
pDC->SetBkMode(TRANSPARENT);
|
|||
|
//To have lines limited in the drawing rectangle :
|
|||
|
pDC->IntersectClipRect(m_PlottingRect);
|
|||
|
|
|||
|
//Draw all points that haven't been drawn yet
|
|||
|
for (m_uLastDrawnPoint;m_uLastDrawnPoint<(int)GetPointsCount();m_uLastDrawnPoint++)
|
|||
|
{
|
|||
|
SChartXYPoint Point = GetPoint(m_uLastDrawnPoint);
|
|||
|
CPoint ScreenPoint;
|
|||
|
ValueToScreen(Point.X, Point.Y, ScreenPoint);
|
|||
|
|
|||
|
CRect PointRect;
|
|||
|
PointRect.SetRect(ScreenPoint.x-m_iXPointSize/2,ScreenPoint.y-m_iYPointSize/2,ScreenPoint.x+m_iXPointSize/2,ScreenPoint.y+m_iYPointSize/2);
|
|||
|
CRect ShadowRect = PointRect + CSize(m_iShadowDepth,m_iShadowDepth);
|
|||
|
|
|||
|
switch(m_iPointType)
|
|||
|
{
|
|||
|
case ptEllipse:
|
|||
|
if (m_bShadow)
|
|||
|
{
|
|||
|
pOldPen = pDC->SelectObject(&ShadowPen);
|
|||
|
pDC->SelectObject(&ShadowBrush);
|
|||
|
pDC->Ellipse(ShadowRect);
|
|||
|
pDC->SelectObject(&NewBrush);
|
|||
|
pDC->SelectObject(&BorderPen);
|
|||
|
}
|
|||
|
pDC->Ellipse(PointRect);
|
|||
|
break;
|
|||
|
|
|||
|
case ptRectangle:
|
|||
|
if (m_bShadow)
|
|||
|
{
|
|||
|
pOldPen = pDC->SelectObject(&ShadowPen);
|
|||
|
pDC->SelectObject(&ShadowBrush);
|
|||
|
pDC->Rectangle(ShadowRect);
|
|||
|
pDC->SelectObject(&NewBrush);
|
|||
|
pDC->SelectObject(&BorderPen);
|
|||
|
}
|
|||
|
pDC->Rectangle(PointRect);
|
|||
|
break;
|
|||
|
|
|||
|
case ptTriangle:
|
|||
|
{
|
|||
|
CPoint TrPoints[3];
|
|||
|
TrPoints[0].x = PointRect.left;
|
|||
|
TrPoints[0].y = PointRect.bottom;
|
|||
|
TrPoints[1].x = PointRect.right;
|
|||
|
TrPoints[1].y = PointRect.bottom;
|
|||
|
TrPoints[2].x = PointRect.left + (int)fabs((PointRect.left-PointRect.right)/2.0);
|
|||
|
TrPoints[2].y = PointRect.top;
|
|||
|
|
|||
|
if (m_bShadow)
|
|||
|
{
|
|||
|
CPoint ShadowPoints[3];
|
|||
|
for (int i=0;i<3;i++)
|
|||
|
{
|
|||
|
ShadowPoints[i] = TrPoints[i] + CSize(m_iShadowDepth,m_iShadowDepth);
|
|||
|
}
|
|||
|
|
|||
|
pOldPen = pDC->SelectObject(&ShadowPen);
|
|||
|
pDC->SelectObject(&ShadowBrush);
|
|||
|
pDC->Polygon(ShadowPoints,3);
|
|||
|
pDC->SelectObject(&NewBrush);
|
|||
|
pDC->SelectObject(&BorderPen);
|
|||
|
}
|
|||
|
pDC->Polygon(TrPoints,3);
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
pDC->SelectClipRgn(NULL);
|
|||
|
pDC->SelectObject(pOldPen);
|
|||
|
pDC->SelectObject(pOldBrush);
|
|||
|
DeleteObject(BorderPen);
|
|||
|
DeleteObject(NewBrush);
|
|||
|
DeleteObject(ShadowBrush);
|
|||
|
DeleteObject(ShadowPen);
|
|||
|
}
|
|||
|
|
|||
|
void CChartPointsSerie::DrawAll(CDC *pDC)
|
|||
|
{
|
|||
|
if (!m_bIsVisible)
|
|||
|
return;
|
|||
|
if (!pDC->GetSafeHdc())
|
|||
|
return;
|
|||
|
|
|||
|
CBrush NewBrush(m_SerieColor);
|
|||
|
CPen BorderPen(PS_SOLID, 1, m_colBorder);
|
|||
|
CBrush ShadowBrush(m_ShadowColor);
|
|||
|
CPen ShadowPen(PS_SOLID, 1, m_ShadowColor);
|
|||
|
CPen* pOldPen = pDC->SelectObject(&BorderPen);
|
|||
|
CBrush* pOldBrush = pDC->SelectObject(&NewBrush);
|
|||
|
|
|||
|
unsigned uFirst=0, uLast=0;
|
|||
|
if (!GetVisiblePoints(uFirst,uLast))
|
|||
|
return;
|
|||
|
|
|||
|
pDC->SetBkMode(TRANSPARENT);
|
|||
|
//To have lines limited in the drawing rectangle :
|
|||
|
pDC->IntersectClipRect(m_PlottingRect);
|
|||
|
|
|||
|
for (m_uLastDrawnPoint=uFirst;m_uLastDrawnPoint<=uLast;m_uLastDrawnPoint++)
|
|||
|
{
|
|||
|
SChartXYPoint Point = GetPoint(m_uLastDrawnPoint);
|
|||
|
CPoint ScreenPoint;
|
|||
|
ValueToScreen(Point.X, Point.Y, ScreenPoint);
|
|||
|
|
|||
|
CRect PointRect;
|
|||
|
PointRect.SetRect(ScreenPoint.x-m_iXPointSize/2,ScreenPoint.y-m_iYPointSize/2,ScreenPoint.x+m_iXPointSize/2,ScreenPoint.y+m_iYPointSize/2);
|
|||
|
CRect ShadowRect = PointRect + CSize(m_iShadowDepth,m_iShadowDepth);
|
|||
|
|
|||
|
switch(m_iPointType)
|
|||
|
{
|
|||
|
case ptEllipse:
|
|||
|
if (m_bShadow)
|
|||
|
{
|
|||
|
pOldPen = pDC->SelectObject(&ShadowPen);
|
|||
|
pDC->SelectObject(&ShadowBrush);
|
|||
|
pDC->Ellipse(ShadowRect);
|
|||
|
pDC->SelectObject(&NewBrush);
|
|||
|
pDC->SelectObject(&BorderPen);
|
|||
|
}
|
|||
|
pDC->Ellipse(PointRect);
|
|||
|
break;
|
|||
|
|
|||
|
case ptRectangle:
|
|||
|
if (m_bShadow)
|
|||
|
{
|
|||
|
pOldPen = pDC->SelectObject(&ShadowPen);
|
|||
|
pDC->SelectObject(&ShadowBrush);
|
|||
|
pDC->Rectangle(ShadowRect);
|
|||
|
pDC->SelectObject(&NewBrush);
|
|||
|
pDC->SelectObject(&BorderPen);
|
|||
|
}
|
|||
|
pDC->Rectangle(PointRect);
|
|||
|
break;
|
|||
|
|
|||
|
case ptTriangle:
|
|||
|
{
|
|||
|
CPoint TrPoints[3];
|
|||
|
TrPoints[0].x = PointRect.left;
|
|||
|
TrPoints[0].y = PointRect.bottom;
|
|||
|
TrPoints[1].x = PointRect.right;
|
|||
|
TrPoints[1].y = PointRect.bottom;
|
|||
|
TrPoints[2].x = PointRect.left + (int)fabs((PointRect.left-PointRect.right)/2.0);
|
|||
|
TrPoints[2].y = PointRect.top;
|
|||
|
|
|||
|
if (m_bShadow)
|
|||
|
{
|
|||
|
CPoint ShadowPoints[3];
|
|||
|
for (int i=0;i<3;i++)
|
|||
|
{
|
|||
|
ShadowPoints[i] = TrPoints[i] + CSize(m_iShadowDepth,m_iShadowDepth);
|
|||
|
}
|
|||
|
|
|||
|
pOldPen = pDC->SelectObject(&ShadowPen);
|
|||
|
pDC->SelectObject(&ShadowBrush);
|
|||
|
pDC->Polygon(ShadowPoints,3);
|
|||
|
pDC->SelectObject(&NewBrush);
|
|||
|
pDC->SelectObject(&BorderPen);
|
|||
|
}
|
|||
|
pDC->Polygon(TrPoints,3);
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
pDC->SelectClipRgn(NULL);
|
|||
|
pDC->SelectObject(pOldPen);
|
|||
|
pDC->SelectObject(pOldBrush);
|
|||
|
DeleteObject(BorderPen);
|
|||
|
DeleteObject(NewBrush);
|
|||
|
DeleteObject(ShadowBrush);
|
|||
|
DeleteObject(ShadowPen);
|
|||
|
}
|
|||
|
|
|||
|
void CChartPointsSerie::DrawLegend(CDC *pDC, const CRect& rectBitmap) const
|
|||
|
{
|
|||
|
if (m_strSerieName== _T(""))
|
|||
|
return;
|
|||
|
|
|||
|
CRect PointRect(0,0,m_iXPointSize,m_iYPointSize);
|
|||
|
if ( (rectBitmap.Height()>m_iYPointSize) && (rectBitmap.Width()>m_iXPointSize) )
|
|||
|
{
|
|||
|
int XOffset = rectBitmap.left + rectBitmap.Width()/2 - m_iXPointSize/2;
|
|||
|
int YOffset = rectBitmap.top + rectBitmap.Height()/2 - m_iYPointSize/2;
|
|||
|
PointRect.OffsetRect(XOffset,YOffset);
|
|||
|
}
|
|||
|
else
|
|||
|
PointRect = rectBitmap;
|
|||
|
|
|||
|
CBrush NewBrush(m_SerieColor);
|
|||
|
CBrush* pOldBrush = pDC->SelectObject(&NewBrush);
|
|||
|
|
|||
|
switch(m_iPointType)
|
|||
|
{
|
|||
|
case ptEllipse:
|
|||
|
pDC->Ellipse(PointRect);
|
|||
|
break;
|
|||
|
|
|||
|
case ptRectangle:
|
|||
|
pDC->Rectangle(PointRect);
|
|||
|
break;
|
|||
|
|
|||
|
case ptTriangle:
|
|||
|
{
|
|||
|
CPoint TrPoints[3];
|
|||
|
TrPoints[0].x = PointRect.left;
|
|||
|
TrPoints[0].y = PointRect.bottom;
|
|||
|
TrPoints[1].x = PointRect.right;
|
|||
|
TrPoints[1].y = PointRect.bottom;
|
|||
|
TrPoints[2].x = PointRect.left + (int)fabs((PointRect.left-PointRect.right)/2.0);
|
|||
|
TrPoints[2].y = PointRect.top;
|
|||
|
|
|||
|
pDC->Polygon(TrPoints,3);
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
pDC->SelectObject(pOldBrush);
|
|||
|
DeleteObject(NewBrush);
|
|||
|
}
|
|||
|
|
|||
|
bool CChartPointsSerie::IsPointOnSerie(const CPoint& screenPoint, unsigned& uIndex) const
|
|||
|
{
|
|||
|
uIndex = INVALID_POINT;
|
|||
|
if (!m_bIsVisible)
|
|||
|
return false;
|
|||
|
|
|||
|
unsigned uFirst=0, uLast=0;
|
|||
|
if (!GetVisiblePoints(uFirst, uLast))
|
|||
|
return false;
|
|||
|
|
|||
|
bool bResult = false;
|
|||
|
for (unsigned i=uFirst ; i < uLast ; i++)
|
|||
|
{
|
|||
|
SChartXYPoint Point = GetPoint(i);
|
|||
|
CPoint ValuePoint;
|
|||
|
ValueToScreen(Point.X, Point.Y, ValuePoint);
|
|||
|
|
|||
|
int xDist = abs(screenPoint.x - ValuePoint.x);
|
|||
|
int yDist = abs(screenPoint.y - ValuePoint.y);
|
|||
|
if (xDist<=5 && yDist<=5)
|
|||
|
{
|
|||
|
uIndex = i;
|
|||
|
bResult = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
return bResult;
|
|||
|
}
|
|||
|
|