// Graph.cpp : implementation file
//
#include "stdafx.h"
//#include "testdraw.h"
#include "GraphSeries.h"
#include "GraphLegend.h"
#include "math.h"
#include "Graph.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CGraph
CGraph::CGraph()
{
graphSeries = new CObList();
tickRange = 100;
seriesSize = 0;
graphHasLegend = FALSE;
legendWidth = 0;
graphType = 0;
dataColor[0] = RGB(0,255,0); //green
dataColor[1] = RGB(0,0,255); //blue
dataColor[2] = RGB(255,0,0); //red
dataColor[3] = RGB(255,255,0); //yellow
dataColor[4] = RGB(255,153,51); //orange
dataColor[5] = RGB(255,51,153); //hot pink
dataColor[6] = RGB(153,0,204); //purple
dataColor[7] = RGB(0,255,255); //cyan
dataColor[8] = RGB(0,0,0); //black
dataColor[9] = RGB(255,255,255); //white
xAxisAlign = 0; //horizontal
xAxisLabelLength = 0;
}
CGraph::CGraph(int type)
{
graphSeries = new CObList();
tickRange = 100;
seriesSize = 0;
graphHasLegend = FALSE;
legendWidth = 0;
graphType = type;
dataColor[0] = RGB(0,255,0); //green
dataColor[1] = RGB(0,0,255); //blue
dataColor[2] = RGB(255,0,0); //red
dataColor[3] = RGB(255,255,0); //yellow
dataColor[4] = RGB(255,153,51); //orange
dataColor[5] = RGB(255,51,153); //hot pink
dataColor[6] = RGB(153,0,204); //purple
dataColor[7] = RGB(0,255,255); //cyan
dataColor[8] = RGB(0,0,0); //black
dataColor[9] = RGB(255,255,255); //white
xAxisAlign = 0; //horizontal
xAxisLabelLength = 0;
}
CGraph::~CGraph()
{
}
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::SetTickSpace(int yDist)
{
tickSpace = yDist;
}
void CGraph::SetTickRange(int maxTick)
{
tickRange = maxTick;
}
void CGraph::SetGraphType(int gType)
{
graphType = gType;
}
void CGraph::SetXAxisAlignment(int alignValue)
{
xAxisAlign = alignValue;
}
int CGraph::GetXAxisAlignment()
{
return xAxisAlign;
}
void CGraph::DrawGraph(CDC* pDC)
{
CString tickLabel;
CWnd* graphWnd = pDC->GetWindow();
CRect graphRect;
graphWnd->GetClientRect(&graphRect);
maxHeight = graphRect.Height() - 20; //for frame window and status bar
maxWidth = graphRect.Width() - 5; //for frame window
//We will leave 5 pixels blank on all sides of the graph. So
//top-left side of graph is at 5,5 and the bottom-right side of
//graph is at ((maxHeight - 5), (maxWidth - 5))
//these settings are altered by axis labels and legends.
//draw graph title
CFont titleFont;
titleFont.CreateFont(28, 0, 0, 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(&titleFont);
pDC->TextOut((maxWidth / 2) - ((graphTitle.GetLength() * 16) / 2),
10, graphTitle);
pDC->SelectObject(pOldFont);
if(graphType == 2) //pie
{
//since pie has not axis lines, set to full size minus 5 on each side
//these are needed for legend to plot itself
xAxisWidth = maxWidth - 10;
yAxisHeight = maxHeight - 20; //10 buffer and 20 for title
xApexPoint = 5;
yApexPoint = maxHeight - 5;
}
else
{
//X-axis will be raised by 20 pixels for tick-labels
//Y-axis will be shifted by (max(tick-label size) * 10) + label * 10
tickLabel.Format("%d", tickRange);
//determine axis specifications
//tick label offset is 4 (for the tick) + 6 (total 10) from axis line
xApexPoint = 5 + (tickLabel.GetLength() * 8) + 10 + 30/*(axisYLabel.GetLength() * 8)*/ + 5; //allowing 8 pixels per char in tick label
//y apex based on 5 + 15 (x label) + 4 (for the tick) + 4 (text below tick) + 12 (tick label) + 10
if(!xAxisAlign) //horizontal
yApexPoint = (maxHeight - 5) - 45; //apex points are the cross section of axis lines
else
yApexPoint = (maxHeight - 5) - (xAxisLabelLength * 12) - 10;
yAxisHeight = yApexPoint - 40;
xAxisWidth = (maxWidth - 5) - xApexPoint;
}
//draw legend
if(graphHasLegend)
DrawLegend(pDC);
if(graphType != 2) //pie
{
//draw axis lines
DrawAxis(pDC);
}
//draw series data and labels
DrawSeries(pDC);
}
void CGraph::DrawAxis(CDC* pDC)
{
pDC->SetTextColor(RGB(0,0,0));
//draw y axis
pDC->MoveTo(xApexPoint, yApexPoint);
pDC->LineTo(xApexPoint, yApexPoint - yAxisHeight);
//draw x axis
pDC->MoveTo(xApexPoint, yApexPoint);
if(graphHasLegend)
pDC->LineTo(xApexPoint + (xAxisWidth - legendWidth - 10), yApexPoint);
else
pDC->LineTo(xApexPoint + xAxisWidth, yApexPoint);
//draw labels
CFont sideFont;
sideFont.CreateFont(16, 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->TextOut(10, (maxHeight / 2) - 6, axisYLabel);
pDC->SelectObject(pOldFont);
pDC->TextOut(xApexPoint + (xAxisWidth / 2) - (axisXLabel.GetLength() * 19), maxHeight - 5 - 6, axisXLabel);
//to allow scalability (height may be less than tickRange)
double tickScale = 0.00;
if(tickRange > yAxisHeight)
tickScale = ((yAxisHeight * 1.00) / (tickRange * 1.00)) * tickSpace;
else tickScale = tickSpace;
//draw y axis ticks
for(int y = 1; y <= tickRange / tickSpace; y++) //no tick at 0
{
int tickYLocation = yApexPoint - (y * tickScale);
pDC->MoveTo(xApexPoint - 4, tickYLocation);
pDC->LineTo(xApexPoint + 4, tickYLocation);
//draw tick label
CString tickLabel;
tickLabel.Format("%d", y * tickSpace);
pDC->TextOut(xApexPoint - 10 - (tickLabel.GetLength() * 8), tickYLocation - 6, tickLabel);
}
//draw X axis tick marks
POSITION pos;
pos = graphSeries->GetHeadPosition();
CGraphSeries* tmpSeries;
for(int x = 1; x <= graphSeries->GetCount(); x++)
{
tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
int seriesSpace;
int tickXLocation;
if(graphHasLegend)
seriesSpace= (xAxisWidth - legendWidth - 10) / graphSeries->GetCount();
else
seriesSpace= xAxisWidth / graphSeries->GetCount();
tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
pDC->MoveTo(tickXLocation,yApexPoint - 4);
pDC->LineTo(tickXLocation,yApexPoint + 4);
//draw tick label
CString tickLabel;
tickLabel = tmpSeries->GetLabel();
if(!xAxisAlign) //horizontal
pDC->TextOut(tickXLocation - ((tickLabel.GetLength() * 8) / 2), yApexPoint + 8, tickLabel);
else
{
CFont sideFont2;
sideFont2.CreateFont(16, 0, (xAxisAlign * 10), 0, 700, FALSE, FALSE, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
pOldFont = (CFont*) pDC->SelectObject(&sideFont2);
if(xAxisAlign < 180)
pDC->TextOut(tickXLocation - 8, yApexPoint + 8 + (xAxisLabelLength * 8), tickLabel);
else
pDC->TextOut(tickXLocation + 8, yApexPoint + 8, tickLabel);
pDC->SelectObject(pOldFont);
}
}
}
void CGraph::AddSeries(CGraphSeries* dataSet)
{
int numData = 0;
for(int i = 0; i < 10; i++)
{
if(dataSet->GetData(i) > 0)
numData++;
if(dataSet->GetLabel().GetLength() > xAxisLabelLength)
xAxisLabelLength = dataSet->GetLabel().GetLength();
}
if(numData > seriesSize)
seriesSize = numData;
graphSeries->AddTail(dataSet);
}
void CGraph::SetXAxisLabel(CString label)
{
axisXLabel = label;
}
void CGraph::SetYAxisLabel(CString label)
{
axisYLabel = label;
}
void CGraph::SetColor(int group, COLORREF groupColor)
{
dataColor[group] = groupColor;
}
CO