📄 graph.cpp
字号:
//determine axis specifications
xApexPoint = pGraphL + 350 + (tickLabel.GetLength() * 240);
yApexPoint = pGraphB + 500;
yAxisHeight = maxHeight + (pGraphB - yApexPoint) - 1000;
xAxisWidth = pGraphR - legendWidth - xApexPoint;
}
if(graphType != 2) //pie
{
//draw axis lines
PrintAxis(pDC);
}
//draw series data and labels
PrintSeries(pDC);
} //end printing for Page 1
//update pGraphB value to pad some space below the graph
pGraphB -= 90;
return pGraphB;
}
void CGraph::PrintLegend(CDC *pDC)
{
CFont legendLabelFont, legendTitleFont;
TEXTMETRIC tm;
int legendL, legendT, legendR, legendB;
int barL, barT, barR, barB;
//legendLabelFont is 10 point
legendLabelFont.CreateFont(-200, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH || FF_ROMAN,
"Times New Roman");
//legendTitleFont is 12 point
legendTitleFont.CreateFont(-240, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH || FF_ROMAN,
"Times New Roman");
// pDC->Rectangle(pGraphL, pGraphT, pGraphR, pGraphB);
legendT = (((pGraphB - pGraphT) / 2) + pGraphT) + (((seriesSize + 1) / 2) * 240 + 300);
legendB = (((pGraphB - pGraphT) / 2) + pGraphT) - (((seriesSize + 1) / 2) * 240 + 300);
legendR = pGraphR - 50;
legendL = legendR - ((legendR - pGraphL) * .15);
legendWidth = legendR - legendL;
pDC->Rectangle(legendL, legendT, legendR, legendB);
CFont* pOldFont = (CFont*) pDC->SelectObject(&legendTitleFont);
pDC->GetTextMetrics(&tm);
pDC->TextOut(legendL + (legendWidth / 2) - 360,
legendT - 160, "图例");//Legend
pDC->SelectObject(pOldFont);
for(int i = 0; i < seriesSize; i++)
{
pOldFont = (CFont*) pDC->SelectObject(&legendLabelFont);
pDC->GetTextMetrics(&tm);
int charWidth = tm.tmMaxCharWidth;
int charHeight = tm.tmHeight;
CString valuStr;
valuStr.Format("value %d", i + 1);
pDC->TextOut(legendL + 50, legendT - (2 * charHeight) - 120 - (i * charHeight), valuStr);
pDC->SelectObject(pOldFont);
//draw bar
COLORREF barColor;
barColor = GetColor(i);
CBrush brush (barColor);
CBrush* pOldBrush;
pOldBrush = pDC->SelectObject(&brush);
barL = legendL + (9 * 120);
barT = legendT - (2 * charHeight) - 120 - (i * charHeight) - 60;
barR = legendR - 50;
barB = barT - 120;
pDC->Rectangle(barL, barT, barR, barB);
pDC->SelectObject(pOldBrush);
}
}
void CGraph::PrintAxis(CDC *pDC)
{
pDC->SetTextColor(RGB(0,0,0));
//draw y axis
pDC->MoveTo(xApexPoint, yApexPoint);
pDC->LineTo(xApexPoint, yApexPoint + yAxisHeight - 250);
//draw x axis
pDC->MoveTo(xApexPoint, yApexPoint);
if(graphHasLegend)
pDC->LineTo(xApexPoint + (xAxisWidth - 500), yApexPoint);
else
pDC->LineTo(xApexPoint + xAxisWidth - 500, yApexPoint);
//draw labels
CFont sideFont;
sideFont.CreateFont(320, 0, 2700, 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(pGraphL + 10, pGraphT - (maxHeight / 2) - ((axisYLabel.GetLength() / 2) * 160), axisYLabel);
pDC->SelectObject(pOldFont);
pDC->TextOut(xApexPoint + (xAxisWidth / 2) - ((axisXLabel.GetLength() / 2) * 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 * 20);
else tickScale = tickSpace * 15;
//draw y axis ticks
for(int y = 1; y <= tickRange / tickSpace; y++) //no tick at 0
{
int tickYLocation = yApexPoint + (y * tickScale);
pDC->MoveTo(xApexPoint - 75, tickYLocation);
pDC->LineTo(xApexPoint + 75, tickYLocation);
//draw tick label
CString tickLabel;
tickLabel.Format("%d", y * tickSpace);
CFont yFont;
yFont.CreateFont(yTickFontSize * 20, 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(&yFont);
pDC->TextOut(xApexPoint - 150 - (tickLabel.GetLength() * (yTickFontSize / 2) * 20), tickYLocation + 120, tickLabel);
pDC->SelectObject(pOldFont);
}
//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 - 75);
pDC->LineTo(tickXLocation,yApexPoint + 75);
//draw tick label
CString tickLabel;
tickLabel = tmpSeries->GetLabel();
CFont sideFont2;
sideFont2.CreateFont(xTickFontSize * 20, 0, ((360 - 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) //horizontal
pDC->TextOut(tickXLocation - ((tickLabel.GetLength() / 2) * (xTickFontSize * 10)), yApexPoint - 160, tickLabel);
else
{
if(xAxisAlign < 180)
pDC->TextOut(tickXLocation - ((xTickFontSize * 20) / 2), yApexPoint - (xTickFontSize * 20) - (xAxisLabelLength * ((xTickFontSize * 20) / 2)), tickLabel);
else
pDC->TextOut(tickXLocation + ((xTickFontSize * 20) / 2), yApexPoint - 160, tickLabel);
}
pDC->SelectObject(pOldFont);
}
}
void CGraph::PrintSeries(CDC *pDC)
{
int barWidth;
int dataPlotSize; //used to plot rects of data
int barL, barT, barR, barB;
int tickXLocation;
int seriesSpace;
double barHeight; //for scalability
POSITION pos;
CGraphSeries* tmpSeries;
if(graphType == 0) //bar
{
//determine width of barchart data blocks
if(graphHasLegend)
seriesSpace = (xAxisWidth - legendWidth - 10) / graphSeries->GetCount();
else
seriesSpace = xAxisWidth / graphSeries->GetCount();
barWidth = (seriesSpace * .6) / seriesSize;
dataPlotSize = seriesSize * barWidth;
pos = graphSeries->GetHeadPosition();
for(int x = 1; x <= graphSeries->GetCount(); x++)
{
tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
double tickScale = 0.00;
if(tickRange > yAxisHeight)
tickScale = ((yAxisHeight * 1.00) / (tickRange * 1.00)) * (tickSpace * 20);
else tickScale = tickSpace * 15;
tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
for(int s = 0; s < seriesSize; s++)
{
barHeight = 0.00;
int axisHeight = tickScale * (tickRange / tickSpace);
double barPercent = 0.00;
barPercent = (tmpSeries->GetData(s) * 1.00) / (tickRange * 1.00);
barHeight = barPercent * axisHeight;
barL = tickXLocation - (dataPlotSize / 2) + (s * barWidth);
barT = yApexPoint + barHeight;
barR = barL + barWidth;
barB = yApexPoint;
COLORREF barColor;
barColor = GetColor(s);
CBrush brush (barColor);
CBrush* pOldBrush;
pOldBrush = pDC->SelectObject(&brush);
pDC->Rectangle(barL, barT, barR, barB);
pDC->SelectObject(pOldBrush);
}
}
}
if(graphType == 1) //line
{
int lastXLoc, lastYLoc;
for(int s = 0; s < seriesSize; s++)
{
//determine width of barchart data blocks
if(graphHasLegend)
seriesSpace = (xAxisWidth - legendWidth - 10) / graphSeries->GetCount();
else
seriesSpace = xAxisWidth / graphSeries->GetCount();
barWidth = (seriesSpace * .6) / seriesSize;
dataPlotSize = seriesSize * barWidth;
pos = graphSeries->GetHeadPosition();
for(int x = 1; x <= graphSeries->GetCount(); x++)
{
tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
barHeight = 0.00;
//to allow scalability (height may be less than tickRange)
double dataScale = 0.00;
if(tickRange > yAxisHeight)
dataScale = ((yAxisHeight * 1.00) / (tickRange * 1.00)) * (tickSpace * 20);
else dataScale = tickSpace * 15.00;
int axisHeight = dataScale * (tickRange / tickSpace);
double barPercent = 0.00;
barPercent = (tmpSeries->GetData(s) * 1.00) / (tickRange * 1.00);
barHeight = barPercent * axisHeight;
int yDataLocation = yApexPoint + barHeight;
//now have x and y location of center of ellipse
COLORREF barColor;
barColor = GetColor(s);
CBrush brush (barColor);
CBrush* pOldBrush;
pOldBrush = pDC->SelectObject(&brush);
//draw line back to last data member
if(x > 1)
{
CPen* pOldPen;
CPen linePen (PS_SOLID, 1, barColor);
pOldPen = pDC->SelectObject(&linePen);
pDC->MoveTo(lastXLoc/* - 40*/, lastYLoc/* + 20*/);
pDC->LineTo(tickXLocation/* + 60*/, yDataLocation/* + 20*/);
pDC->SelectObject(pOldPen);
}
//now draw ellipse...
pDC->Ellipse(tickXLocation + 60, yDataLocation + 60,
tickXLocation - 60, yDataLocation - 60);
lastXLoc = tickXLocation;
lastYLoc = yDataLocation;
pDC->SelectObject(pOldBrush);
}
}
}
if(graphType == 2) //pie
{
double dataSum = 0.00; //for storing cumulative sum
int lastXLocation, lastYLocation;
int newXLocation, newYLocation;
double percent = 0.00;
int degrees;
double totalSum = 0.00;
int deltaXY;
int radius;
lastXLocation = 0;
lastYLocation = 0;
//determine width of pie display area
if(graphHasLegend)
if((xAxisWidth / graphSeries->GetCount())
> (yAxisHeight - 200))
seriesSpace = (yAxisHeight - 200)/* / graphSeries->GetCount()*/;
else
seriesSpace = xAxisWidth / graphSeries->GetCount();
else
if(xAxisWidth > yAxisHeight)
seriesSpace = yAxisHeight / graphSeries->GetCount();
else
seriesSpace = xAxisWidth / graphSeries->GetCount();
double tmpD = (seriesSpace - 100) * .9; //max width of any pie
radius = tmpD / 2;
int centerYPie = pGraphT - (yAxisHeight / 2) - 300;
pos = graphSeries->GetHeadPosition();
for(int x = 1; x <= graphSeries->GetCount(); x++)
{
tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
totalSum = 0;
for(int s = 0; s < 10; s++)
totalSum += tmpSeries->GetData(s);
int pieLeft, pieRight;
if(graphSeries->GetCount() == 1)
{
pieLeft = ((xAxisWidth - 200) / 2) - radius;
}
else
{
pieLeft = pGraphL + 15 + (x * 200) + ((x - 1) * (2 * radius));
}
pieRight = pieLeft + (2 * radius);
CRect pieRect (pieLeft,
centerYPie + radius,
pieRight,
centerYPie - radius);
int centerXPie = pieLeft + radius;
CFont pieFont;
pieFont.CreateFont(xTickFontSize * 20, 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(&pieFont);
//plot series label
pDC->TextOut(centerXPie - ((tmpSeries->GetLabel().GetLength() / 2) * ((xTickFontSize / 2) * 20)),
centerYPie - radius - 300, tmpSeries->GetLabel());
pDC->SelectObject(pOldFont);
lastXLocation = pieLeft;
lastYLocation = centerYPie;
dataSum = 0;
for(s = 0; s < seriesSize; s++)
{
if(tmpSeries->GetData(s) > 0)
{
dataSum += tmpSeries->GetData(s);
percent = (dataSum * 100) / totalSum;
degrees = (360 * percent) / 100;
//degress / 90 will never exceed 4.
//this can tell us the quadrant of destination
deltaXY = (degrees * radius) / 90;
//deltaXY is change from start point of pie 0
//this value is total change. so if radius is 300
//and degrees is 270, delta is 300. The change
//would move both x and y 300 pixels. For x, 100
//to right is center, another 100 to right edge,
//100 back to center. For y, 100 to bottom, 100
//back to center, 100 to top. thus gives 270 degree
//rotation.
//determine destination quadrant...
//and set newXLocation and newYLocation values...
int quadrant = degrees / 90; //truncates decimal
switch(quadrant)
{
//in the computations below, the remarked line is
//the original computation. The line above it, for
//actual use, is the simplified line, and gives the
//exact same result
case 0 : newXLocation = pieLeft + deltaXY;
newYLocation = centerYPie - deltaXY;
break;
case 1 : newXLocation = pieLeft + deltaXY;
newYLocation = centerYPie - (2 * radius) + deltaXY;
break;
case 2 : newXLocation = pieLeft + (4 * radius) - deltaXY;
newYLocation = centerYPie - (2 * radius) + deltaXY;
break;
case 3 : newXLocation = pieLeft + (4 * radius) - deltaXY;
newYLocation = centerYPie + (4 * radius) - deltaXY;
break;
case 4 : newXLocation = pieLeft;
newYLocation = centerYPie + 1;
break;
}
if(s == 0)
lastYLocation -= 1;
CPoint p1 (lastXLocation, lastYLocation);
CPoint p2 (newXLocation, newYLocation);
COLORREF barColor;
barColor = GetColor(s);
CBrush brush (barColor);
CBrush* pOldBrush;
pOldBrush = pDC->SelectObject(&brush);
pDC->Pie(pieRect, p1, p2);
pDC->SelectObject(pOldBrush);
lastXLocation = newXLocation;
lastYLocation = newYLocation;
}
}
}
}
}
void CGraph::SetMargins(int top, int bottom, int left, int right, int graphTop)
{
//page margins for portrait or landscape distinction
topMargin = top;
bottomMargin = bottom;
leftMargin = left;
rightMargin = right;
//set up rectangle area for showing the graph
pGraphL = leftMargin;
pGraphT = graphTop;
pGraphB = pGraphT - 7200;
pGraphR = rightMargin;
if(pGraphB < bottomMargin)
pGraphB = bottomMargin;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -