📄 graph.cpp
字号:
//Graph.cpp - Version 3.0 (Brian Convery, May, 2001)
#include "stdafx.h"
#include "afxtempl.h"
#include "GraphSeries.h"
#include "GraphLegend.h"
#include "math.h"
#include "Graph.h"
#include "GraphDataColor.h"
#include "GraphPieLabel.h" //for pie labels
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CGraph
CGraph::CGraph()
{
graphSeries = new CObList();
seriesSize = 0;
minTick = 0;
maxTick = 100;
numTicks = 10;
tickSpace = 10;
graphHasLegend = FALSE;
legendWidth = 0;
legendMaxText= 0;
graphAlignment = VERTICAL_ALIGN;
graphType = 0;
xAxisAlign = 0; //horizontal
xAxisLabelLength = 0;
xTickFontSize = 12;
yTickFontSize = 12;
legendFontSize = 12;
depth = 0;
depthRatio = 0.05;
line3DXBase = 0;
line3DYBase = 0;
SetGridLines(FALSE);
graphQuadType = 1;
quadSetManually = FALSE;
}
CGraph::CGraph(int type)
{
graphSeries = new CObList();
colorList = new CObList();
seriesSize = 0;
minTick = 0;
maxTick = 100;
numTicks = 10;
tickSpace = 10;
graphHasLegend = FALSE;
legendWidth = 0;
legendMaxText= 0;
graphAlignment = VERTICAL_ALIGN;
graphType = type;
xAxisAlign = 0; //in degrees == horizontal
xAxisLabelLength = 0;
xTickFontSize = 12;
yTickFontSize = 12;
legendFontSize = 12;
depth = 0;
depthRatio = 0.05;
line3DXBase = 0;
line3DYBase = 0;
SetGridLines(FALSE);
graphQuadType = 1;
if(type != BAR_GRAPH)
quadSetManually = TRUE;
else
quadSetManually = FALSE;
}
CGraph::~CGraph()
{
POSITION pos;
CGraphSeries* pSeries;
for( pos = graphSeries->GetHeadPosition(); pos != NULL; )
{
pSeries = (CGraphSeries*) graphSeries->GetNext( pos );
//graphSeries->RemoveAt(pos);
delete pSeries;
}
graphSeries->RemoveAll();
delete graphSeries;
CGraphDataColor* dataColor;
for( pos = colorList->GetHeadPosition(); pos != NULL; )
{
dataColor = (CGraphDataColor*) colorList->GetNext( pos );
//colorList->RemoveAt(pos);
delete dataColor;
}
colorList->RemoveAll();
delete colorList;
}
BEGIN_MESSAGE_MAP(CGraph, CStatic)
//{{AFX_MSG_MAP(CGraph)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CGraph message handlers
void CGraph::SetGraphType(int gType)
{
graphType = gType;
}
void CGraph::SetXAxisAlignment(int alignValue)
{
xAxisAlign = alignValue;
}
int CGraph::GetXAxisAlignment()
{
return xAxisAlign;
}
void CGraph::SetColor(int dataGroup, COLORREF groupColor)
{
CGraphDataColor *dataColor = new CGraphDataColor(dataGroup, groupColor);
colorList->AddTail(dataColor);
}
COLORREF CGraph::GetColor(int dataGroup)
{
POSITION pos;
if((colorList->GetCount() <= dataGroup) || (colorList->GetCount() == 0))
return BLACK;
CGraphDataColor* dataColor;
pos = colorList->GetHeadPosition();
for(int i = 0; i < dataGroup; i++)
colorList->GetNext(pos);
dataColor = (CGraphDataColor*) colorList->GetAt( pos );
return dataColor->GetColor();
}
void CGraph::DrawGraph(CDC* pDC)
{
CString tickLabel;
CWnd* graphWnd = pDC->GetWindow();
CRect graphRect;
graphWnd->GetClientRect(&graphRect);
TEXTMETRIC tm;
//reset graph to be clear background
COLORREF backColor;
backColor = RGB(255,255,255); //replace with desired background color
CBrush backBrush (backColor);
CBrush* pOldBackBrush;
pOldBackBrush = pDC->SelectObject(&backBrush);
pDC->Rectangle(0, 0, graphRect.Width(), graphRect.Height());
pDC->SelectObject(pOldBackBrush);
maxHeight = graphRect.Height() - 20; //for frame window and status bar
maxWidth = graphRect.Width() - 5; //for frame window
if((graphType == PIE_GRAPH) || (graphType == PIE_GRAPH_3D))
{
//since pie does not have axis lines, set to full size minus 5 on each side
//these are needed for legend to plot itself
xAxisWidth = maxWidth - 10;
yAxisHeight = maxHeight - 50; //10 buffer, 20 for title, and 20 for series label
xApexPoint = 5;
yApexPoint = maxHeight - 5;
}
else
{
//compute label size for axis alignment
CFont sideFont, axisFont;
int tFontSize = 16;
if(maxWidth > maxHeight)
{
while((axisYLabel.GetLength() * (tFontSize / 2)) > maxHeight)
{
tFontSize -= 2;
}
}
else
{
while((axisXLabel.GetLength() * (tFontSize / 2)) > maxWidth)
{
tFontSize -= 2;
}
}
axisFont.CreateFont(tFontSize, 0, 0, 0, 700, FALSE, FALSE, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
sideFont.CreateFont(tFontSize, 0, 900, 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->GetTextMetrics(&tm);
int charWidth = tm.tmAveCharWidth;
int labelHeight = tm.tmHeight + 10;
if(graphAlignment)
{
if(axisYLabel.GetLength() == 0)
labelHeight = 0;
}
else
{
if(axisXLabel.GetLength() == 0)
labelHeight = 0;
}
pDC->SelectObject(pOldFont);
tickLabel.Format("%d", maxTick);
//determine axis specifications
if(graphAlignment)
{
if(graphType == SCATTER_GRAPH)
{
xApexPoint = 5 + (xAxisLabelLength * charWidth) + labelHeight; //labelHeight added for y-axis label height
yApexPoint = (maxHeight - 15) - tm.tmHeight;
yAxisHeight = yApexPoint - 40;
xAxisWidth = (maxWidth - 5) - xApexPoint;
}
else
{
xApexPoint = 5 + (tickLabel.GetLength() * (yTickFontSize / 2)) + 45;
if(!xAxisAlign) //horizontal
yApexPoint = (maxHeight - 5) - 45; //apex points are the cross section of axis lines
else
yApexPoint = (maxHeight - 5) - (xAxisLabelLength * (xTickFontSize / 2)) - 10;
yAxisHeight = yApexPoint - 40;
xAxisWidth = (maxWidth - 5) - xApexPoint;
}
}
else
{
xApexPoint = 5 + (xAxisLabelLength * charWidth) + labelHeight; //labelHeight added for y-axis label height
yApexPoint = (maxHeight - 15) - tm.tmHeight;
yAxisHeight = yApexPoint - 40;
xAxisWidth = (maxWidth - 5) - xApexPoint;
}
}
//draw legend
if(graphHasLegend)
{
int legendLeft = DrawLegend(pDC);
xAxisWidth = legendLeft - 10 - xApexPoint;
}
if((!quadSetManually) && (graphType == BAR_GRAPH))
{
//computer number of quadrants needed based on data
POSITION pos;
pos = graphSeries->GetHeadPosition();
CGraphSeries* tmpSeries;
int minXValue = 0;
int minYValue = 0;
for(int x = 1; x <= graphSeries->GetCount(); x++)
{
tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
for(int s = 0; s < seriesSize; s++)
{
//to allow scalability (height may be less than tickRange)
int curXValue = tmpSeries->GetXDataValue();
int curYValue = tmpSeries->GetYDataValue();
if(curXValue < minXValue)
minXValue = curXValue;
if(curYValue < minYValue)
minYValue = curYValue;
}
}
graphQuadType = 1;
if((minXValue < 0) && (minYValue < 0))
graphQuadType = 4;
if((minXValue < 0) && (minYValue >= 0))
graphQuadType = 2;
if((minXValue >= 0) && (minYValue < 0))
graphQuadType = 3;
}
if(graphType == BAR_GRAPH)
{
switch(graphQuadType)
{
case 2 :
xApexPoint += xAxisWidth / 2;
break;
case 3 :
yApexPoint -= yAxisHeight / 2;
break;
case 4 :
xApexPoint += xAxisWidth / 2;
yApexPoint -= yAxisHeight / 2;
break;
}
}
if((graphType != 2) && (graphType != 32)) //pie & 3d pie
{
inRedraw = FALSE;
//draw axis lines
DrawAxis(pDC);
}
//draw series data and labels
DrawSeries(pDC);
//lines below are commented for doing redraw. If you
//want the axis lines on top of the other graph elements
//uncomment this functionality...I may add it back later
//but there were some bugs doing it this way.
//redraw axis lines in case graph elements overwrote the axis lines
// if((graphType != 2) && (graphType != 32) && (graphQuadType > 1)) //pie & 3d pie
// {
// inRedraw = TRUE;
//draw axis lines
// DrawAxis(pDC);
// }
}
void CGraph::DrawAxis(CDC* pDC)
{
TEXTMETRIC tm;
pDC->SetTextColor(BLACK);
CFont sideFont, axisFont, dummyFont;
int charWidth, labelHeight;
double tickScale;
int tickXLocation, tickYLocation;
int seriesSpace;
CFont* pOldFont;
int x, y;
COLORREF axisLineColor;
axisLineColor = BLACK;
CPen axisPen (PS_SOLID, 2, axisLineColor);
dummyFont.CreateFont(12, 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(&dummyFont);
switch(graphType)
{
case BAR_GRAPH :
case LINE_GRAPH :
case SCATTER_GRAPH :
case BOX_WHISKER_GRAPH :
// case RADAR_GRAPH :
case STACKED_BAR_GRAPH :
case XY_LINE_GRAPH :
CPen* pOldAxisPen;
pOldAxisPen = pDC->SelectObject(&axisPen);
switch(graphQuadType)
{
case 1 :
//draw y axis
pDC->MoveTo(xApexPoint, yApexPoint);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -