📄 xgraph.cpp
字号:
// XGRAPH.cpp : Definiert den Einsprungpunkt f黵 die DLL-Anwendung.
//
#include "stdafx.h"
#include "XGRAPH.h"
#include "XGraphLabel.h"
#ifndef _WIN32_WCE
#include "AxisDlg.h"
#include "ChartPage.h"
#include "CurveDlg.h"
#include "ChartDlg.h"
#endif
#include <afxpriv.h>
#include "float.h"
#include "GfxUtils.h"
#include "math.h"
#include "MemDC.h"
#include "WinGDI.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// XGraph.cpp: Implementation
//
/////////////////////////////////////////////////////////////////////////////
// CXGraph
IMPLEMENT_SERIAL( CXGraph, CWnd, 1 )
#pragma warning (disable : 4244)
#pragma warning (disable : 4800)
CXGraph::NM_POINTMOVING CXGraph::m_nmCurrentPointMoving;
CXGraph::CXGraph()
{
WNDCLASS wndcls;
// setup drawing function pointers
m_pDrawFn[0] = DrawRect;
m_pDrawFn[1] = DrawCircle;
m_pDrawFn[2] = DrawCross;
m_pDrawFn[3] = DrawRhombus;
m_pDrawFn[4] = DrawLeftTriangle;
m_pDrawFn[5] = DrawUpTriangle;
m_pDrawFn[6] = DrawRightTriangle;
m_pDrawFn[7] = DrawDownTriangle;
HINSTANCE hInst = AfxGetInstanceHandle();
m_crBackColor = RGB(255,255,255);
m_crGraphColor = RGB(255,255,255);
m_crInnerColor = RGB(240,240,240);
m_nLeftMargin =
m_nTopMargin =
m_nRightMargin =
m_nBottomMargin = 5;
m_LegendAlignment = right;
m_bLButtonDown = false;
m_bRButtonDown = false;
m_bObjectSelected = false;
m_bTmpDC = false;
m_bDoubleBuffer = true;
m_bShowLegend = true;
m_bInteraction = true;
m_bDataPointMoving= false;
m_nSelectedSerie = -1;
m_pTracker = NULL;
m_pCurrentObject = NULL;
m_pPrintDC = NULL;
m_pDrawDC = NULL;
m_nAxisSpace = 5;
m_nCursorFlags = XGC_LEGEND | XGC_VERT | XGC_HORIZ;
m_OldPoint = CPoint(0,0);
m_opOperation = opNone;
m_bSnapCursor = true;
m_nSnapRange = 10;
m_cPrintHeader = _T("");
m_cPrintFooter = _T("");
m_pCurrentObject = NULL;
m_nForcedSnapCurve = -1;
m_nSnappedCurve1 = 0;
m_fCurrentEditValue = 0.0;
m_OldCursorRect.SetRectEmpty();
// Create one legend for the cursor
m_CursorLabel.m_bVisible = false;
m_CursorLabel.m_bCanEdit = false;
m_CursorLabel.m_bBorder = true;
m_CursorLabel.m_clRect.SetRect(100,100,200,175);
m_Objects.AddHead (&m_CursorLabel);
// Register window class
if (!(::GetClassInfo(hInst, _T("XGraph"), &wndcls)))
{
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = _T("XGraph");
if (!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return ;
}
}
}
CXGraph::~CXGraph()
{
ResetAll();
}
BEGIN_MESSAGE_MAP(CXGraph, CWnd)
//{{AFX_MSG_MAP(CXGraph)
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_LBUTTONDOWN()
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDBLCLK()
ON_WM_SETCURSOR()
#ifndef _WIN32_WCE
ON_WM_RBUTTONUP()
ON_WM_RBUTTONDOWN()
ON_WM_MOUSEWHEEL()
#endif
ON_WM_KEYUP()
ON_COMMAND(IDM_ZOOM, Zoom )
ON_COMMAND(IDM_PAN, Pan )
ON_COMMAND(IDM_CURSOR, Cursor )
ON_COMMAND(IDM_MEASURE, Measure)
ON_COMMAND(IDM_SELECT, NoOp )
ON_COMMAND(IDM_RESET, ResetZoom )
ON_COMMAND(IDM_INSERTLABEL, InsertEmptyLabel)
ON_COMMAND(IDM_PROPERTIES, OnProperties)
#ifndef _WIN32_WCE
ON_COMMAND(IDM_PRINT, OnPrint)
#endif
ON_COMMAND(IDM_LINEARTREND, LinearTrend)
ON_COMMAND(IDM_CUBICTREND, CubicTrend)
ON_COMMAND(IDM_PARENTCALLBACK, ParentCallback)
ON_COMMAND(IDM_ZOOM_BACK, RestoreLastZoom)
ON_COMMAND(IDM_EDITCURVE, Edit)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
bool CXGraph::DeleteXAxis(int nAxis)
{
if (nAxis < 0 || nAxis >= static_cast<int>(m_XAxis.size()))
return false;
m_XAxis.erase (&m_XAxis[nAxis]);
return true;
}
bool CXGraph::DeleteYAxis(int nAxis)
{
if (nAxis < 0 || nAxis >= static_cast<int>(m_YAxis.size()))
return false;
m_YAxis.erase (&m_YAxis[nAxis]);
return true;
}
bool CXGraph::DeleteCurve(int nCurve)
{
if (nCurve < 0 || nCurve >= static_cast<int>(m_Data.size()))
return false;
m_Data.erase (&m_Data[nCurve]);
return true;
}
CXGraphDataSerie& CXGraph::SetData(TDataPoint* pValues, long nCount, int nCurve, int nXAxis, int nYAxis, bool bAutoDelete)
{
ASSERT (nCurve <= static_cast<int>(m_Data.size()));
ASSERT (nXAxis <= static_cast<int>(m_XAxis.size()));
ASSERT (nYAxis <= static_cast<int>(m_YAxis.size()));
if (pValues == NULL || nCount == 0)
return (CXGraphDataSerie&)*((CXGraphDataSerie*)NULL);
if (nCurve == m_Data.size ())
{
// New data serie
CXGraphDataSerie serie;
serie.m_bAutoDelete = bAutoDelete;
serie.m_nXAxis = nXAxis;
serie.m_nYAxis = nYAxis;
serie.m_nCount = nCount;
serie.m_nIndex = nCurve;
if (bAutoDelete)
{
serie.m_pData = (TDataPoint*) new TDataPoint[nCount];
memcpy(serie.m_pData, pValues, sizeof(TDataPoint) * nCount);
}
else
serie.m_pData = pValues;
serie.m_crColor = BASECOLORTABLE[m_Data.size () % 12];
m_Data.push_back (serie);
}
else
{
// existing data serie, just update
m_Data[nCurve].m_nXAxis = nXAxis;
m_Data[nCurve].m_nYAxis = nYAxis;
m_Data[nCurve].m_pData = pValues;
m_Data[nCurve].m_nCount = nCount;
m_Data[nCurve].m_bAutoDelete = bAutoDelete;
}
// Need additional X-Axis
if (nXAxis == m_XAxis.size())
{
CXGraphAxis axis;
axis.m_pGraph = this;
axis.m_AxisKind = CXGraphAxis::xAxis;
m_XAxis.push_back (axis);
}
// Need additional Y-Axis
if (nYAxis == m_YAxis.size())
{
CXGraphAxis axis;
axis.m_pGraph = this;
axis.m_AxisKind = CXGraphAxis::yAxis;
m_YAxis.push_back (axis);
}
m_Data[nCurve].m_pGraph = this;
Autoscale(nXAxis, nYAxis, nCurve);
Invalidate(TRUE);
return m_Data[nCurve];
}
void CXGraph::Autoscale(int nXAxis, int nYAxis, int nCurve)
{
// Get min/max for data serie
double fxMin = m_XAxis[nXAxis].m_fMin;
double fxMax = m_XAxis[nXAxis].m_fMax;
double fyMin = m_YAxis[nYAxis].m_fMin;
double fyMax = m_YAxis[nYAxis].m_fMax;
GetMinMaxForData(m_Data[nCurve], fxMin,
fxMax,
fyMin,
fyMax);
// Set axis ranges
VERIFY(m_XAxis[nXAxis].SetRange(fxMin, fxMax));
VERIFY(m_YAxis[nYAxis].SetRange(fyMin, fyMax));
}
CXGraphAxis& CXGraph::GetXAxis(int nAxis)
{
ASSERT(nAxis >= 0 && nAxis < static_cast<int>(m_XAxis.size()));
return m_XAxis[nAxis];
}
CXGraphAxis& CXGraph::GetYAxis(int nAxis)
{
ASSERT(nAxis >= 0 && nAxis < static_cast<int>(m_YAxis.size()));
return m_YAxis[nAxis];
}
CXGraphDataSerie& CXGraph::GetCurve(int nCurve)
{
ASSERT(nCurve >= 0 && nCurve < static_cast<int>(m_Data.size()));
return m_Data[nCurve];
}
TDataPoint CXGraph::GetCursorAbsolute(int nCurve)
{
TDataPoint vPoint = { 0.0, 0.0};
long nIndex;
vPoint.fXVal = m_XAxis[m_Data[nCurve].m_nXAxis].GetValueForPos (m_CurrentPoint.x);
double fSnappedXVal = m_XAxis[m_Data[nCurve].m_nXAxis].GetValueForPos (m_CurrentPoint.x);
// Find index for this value
m_XAxis[m_Data[nCurve].m_nXAxis].GetIndexByXVal(nIndex, fSnappedXVal, nCurve);
// get yval for index
vPoint.fYVal = m_Data[nCurve].m_pData[nIndex].fYVal;
return vPoint;
}
void CXGraph::SetCursorAbsolute(int nCurve, TDataPoint vPoint, bool bForceVisible )
{
long nIndex;
m_CurrentPoint = m_XAxis[m_Data[nCurve].m_nXAxis].GetPointForValue (&vPoint);
m_XAxis[m_Data[nCurve].m_nXAxis].GetIndexByXVal(nIndex, vPoint.fXVal, nCurve);
vPoint.fYVal = m_Data[nCurve].m_pData[nIndex].fYVal;
if (m_nCursorFlags & XGC_ADJUSTSMOOTH && bForceVisible)
{
double fRange = m_XAxis[m_Data[nCurve].m_nXAxis].m_fCurMax - m_XAxis[m_Data[nCurve].m_nXAxis].m_fCurMin;
m_XAxis[m_Data[nCurve].m_nXAxis].SetCurrentRange(vPoint.fXVal - fRange / 2, vPoint.fXVal + fRange / 2);
}
else
if ( (vPoint.fXVal < m_XAxis[m_Data[nCurve].m_nXAxis].m_fCurMin ||
vPoint.fXVal > m_XAxis[m_Data[nCurve].m_nXAxis].m_fCurMax ) &&
bForceVisible)
{
double fRange = m_XAxis[m_Data[nCurve].m_nXAxis].m_fCurMax - m_XAxis[m_Data[nCurve].m_nXAxis].m_fCurMin;
m_XAxis[m_Data[nCurve].m_nXAxis].SetCurrentRange(vPoint.fXVal - (fRange / 2.0), vPoint.fXVal + (fRange / 2.0));
}
if (m_nCursorFlags & XGC_ADJUSTSMOOTH && bForceVisible)
{
double fRange = m_YAxis[m_Data[nCurve].m_nYAxis].m_fCurMax - m_YAxis[m_Data[nCurve].m_nYAxis].m_fCurMin;
m_YAxis[m_Data[nCurve].m_nYAxis].SetCurrentRange(vPoint.fYVal - (fRange / 2.0), vPoint.fYVal + (fRange / 2.0));
}
else
if ( (vPoint.fYVal < m_YAxis[m_Data[nCurve].m_nYAxis].m_fCurMin ||
vPoint.fYVal > m_YAxis[m_Data[nCurve].m_nYAxis].m_fCurMax ) &&
bForceVisible)
{
double fRange = m_YAxis[m_Data[nCurve].m_nYAxis].m_fCurMax - m_YAxis[m_Data[nCurve].m_nYAxis].m_fCurMin;
m_YAxis[m_Data[nCurve].m_nYAxis].SetCurrentRange(vPoint.fYVal - (fRange / 2.0), vPoint.fYVal + (fRange / 2.0));
}
Invalidate();
}
void CXGraph::GetMinMaxForData (CXGraphDataSerie& serie, double& fXMin, double& fXMax, double& fYMin, double& fYMax)
{
// check mins and maxs
for (long i = 0; i < serie.m_nCount; i++)
{
if (serie.m_pData[i].fXVal > fXMax)
fXMax = serie.m_pData[i].fXVal;
if (serie.m_pData[i].fXVal < fXMin)
fXMin = serie.m_pData[i].fXVal;
if (serie.m_pData[i].fYVal > fYMax)
fYMax = serie.m_pData[i].fYVal;
if (serie.m_pData[i].fYVal < fYMin)
fYMin = serie.m_pData[i].fYVal;
}
}
// Returns the index for the given axis
int CXGraph::GetAxisIndex(CXGraphAxis* pAxis)
{
for (int x = 0; x < static_cast<int>(m_XAxis.size()); x++)
if (pAxis == &m_XAxis[x])
return x;
for (int y = 0; y < static_cast<int>(m_YAxis.size()); y++)
if (pAxis == &m_YAxis[y])
return y;
return -1;
}
// Returns the index for the given curve
int CXGraph::GetCurveIndex(CXGraphDataSerie* pSerie)
{
for (int i = 0; i < static_cast<int>(m_Data.size()); i++)
if (pSerie == &m_Data[i])
return i;
return -1;
}
void CXGraph::SetGraphMargins(int nLeft, int nTop, int nRight, int nBottom)
{
m_nLeftMargin = nLeft;
m_nTopMargin = nTop;
m_nRightMargin = nRight;
m_nBottomMargin = nBottom;
}
void CXGraph::DrawMeasures (CDCEx* pDC)
{
for (UINT i = 0; i < m_Measures.size(); i++)
{
CRect measureRect;
measureRect.left = m_XAxis[m_Data[m_Measures[i].nCurve1].m_nXAxis].GetPointForValue(&m_Data[m_Measures[i].nCurve1].m_pData[m_Measures[i].nIndex1]).x;
measureRect.right= m_XAxis[m_Data[m_Measures[i].nCurve2].m_nXAxis].GetPointForValue(&m_Data[m_Measures[i].nCurve2].m_pData[m_Measures[i].nIndex2]).x;
measureRect.top = m_YAxis[m_Data[m_Measures[i].nCurve1].m_nYAxis].GetPointForValue(&m_Data[m_Measures[i].nCurve1].m_pData[m_Measures[i].nIndex1]).y;
measureRect.bottom = m_YAxis[m_Data[m_Measures[i].nCurve2].m_nYAxis].GetPointForValue(&m_Data[m_Measures[i].nCurve2].m_pData[m_Measures[i].nIndex2]).y;
DrawMeasure(pDC, measureRect);
}
}
void CXGraph::DrawMeasure (CDCEx* pDC, CRect measureRect)
{
COLORREF crColor = RGB(255,0,0);
COLORREF crColorGray = RGB(200, 200, 200);
int nArrowSize = 6;
CString cMarker;
long nIndex1, nIndex2;
UINT nOldBkColor = pDC->SetBkColor(m_crInnerColor);
CQuickFont font("Arial", -11, FW_BOLD);
CFontSelector fs(&font, pDC, false);
if (measureRect.IsRectEmpty () && m_opOperation == opMeasure)
{
measureRect.SetRect(m_MouseDownPoint.x, m_MouseDownPoint.y, m_CurrentPoint.x, m_CurrentPoint.y);
measureRect.left = max(measureRect.left, m_clInnerRect.left);
measureRect.top = max(measureRect.top, m_clInnerRect.top);
measureRect.right = min(measureRect.right, m_clInnerRect.right);
measureRect.bottom = min(measureRect.bottom, m_clInnerRect.bottom);
m_clCurrentMeasure = measureRect;
}
{
CPenSelector ps(crColorGray, 1, pDC, PS_DOT);
pDC->MoveTo (m_clInnerRect.left, measureRect.top);
pDC->LineTo (m_clInnerRect.right, measureRect.top);
pDC->MoveTo (measureRect.right, m_clInnerRect.top);
pDC->LineTo (measureRect.right, m_clInnerRect.bottom);
}
{
CPenSelector ps(crColor, 1, pDC, PS_DOT);
pDC->MoveTo (measureRect.left, measureRect.top);
pDC->LineTo (measureRect.right, measureRect.top);
pDC->LineTo (measureRect.right, measureRect.bottom);
if (abs(measureRect.Width()) > nArrowSize )
DrawLeftTriangle(CPoint(measureRect.left, measureRect.top - (nArrowSize/2)), nArrowSize, crColor, false, pDC);
else
DrawUpTriangle(CPoint(measureRect.right - (nArrowSize/2), measureRect.top + (nArrowSize/2)), nArrowSize, crColor, false, pDC);
if (abs(measureRect.Height()) > nArrowSize )
DrawDownTriangle(CPoint(measureRect.right - (nArrowSize/2), measureRect.bottom - nArrowSize), nArrowSize, crColor, false, pDC);
else
DrawRightTriangle(CPoint(measureRect.right - nArrowSize, measureRect.bottom - nArrowSize), nArrowSize, crColor, false, pDC);
}
double fSnappedX1 = m_XAxis[m_Data[m_nSnappedCurve].m_nXAxis].GetValueForPos (measureRect.left);
double fSnappedX2 = m_XAxis[m_Data[m_nSnappedCurve1].m_nXAxis].GetValueForPos (measureRect.right);
double fX = fSnappedX2 - fSnappedX1;
if (m_XAxis[m_Data[m_nSnappedCurve].m_nXAxis].GetDateTime())
#ifndef _WIN32_WCE
cMarker = COleDateTime(fX).Format(m_XAxis[m_Data[m_nSnappedCurve].m_nXAxis].GetDisplayFmt());
#else
cMarker = COleDateTime(fX).Format();
#endif
else
cMarker.Format(m_XAxis[m_Data[m_nSnappedCurve].m_nXAxis].GetDisplayFmt(), fX);
pDC->SetBkMode(TRANSPARENT);
if (abs(measureRect.Width()) > pDC->GetTextExtent(cMarker).cx)
pDC->DrawText(cMarker, measureRect, DT_CENTER | DT_SINGLELINE | DT_TOP | DT_NOCLIP);
m_XAxis[m_Data[m_nSnappedCurve].m_nXAxis].GetIndexByXVal(nIndex1, fSnappedX1, m_nSnappedCurve);
m_XAxis[m_Data[m_nSnappedCurve1].m_nXAxis].GetIndexByXVal(nIndex2, fSnappedX2, m_nSnappedCurve1);
double fSnappedY1 = m_Data[m_nSnappedCurve].m_pData[nIndex1].fYVal;
double fSnappedY2 = m_Data[m_nSnappedCurve1].m_pData[nIndex2].fYVal;
double fY = fabs(fSnappedY2 - fSnappedY1);
cMarker.Format(m_YAxis[m_Data[m_nSnappedCurve].m_nYAxis].GetDisplayFmt(), fY);
cMarker += (" " + m_YAxis[m_Data[m_nSnappedCurve].m_nYAxis].GetLabel());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -