📄 graph.cpp
字号:
{
//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;//图块区占.6
pos = graphSeries->GetHeadPosition();
for(int x = 1; x <= graphSeries->GetCount(); x++)
{
tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace/2));
for(int s = 0; s < seriesSize; s++)
{
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);
else dataScale = 1;
if(tickRange > tmpSeries->GetData(s))
barHeight = (tmpSeries->GetData(s) * 1.00) * dataScale;
else barHeight = tickRange * dataScale;
if(m_DrawMode==RELATIVEMODE)
{
barHeight =(tmpSeries->GetData(s)*1.00)*m_nUnits/(tickSpace * 1.00);
if(tmpSeries->GetData(s)>=tickRange)
barHeight=yAxisHeight;//警告,此时数据可能越界,截断越界高度
}
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;
BOOL samsaratag=FALSE;//用于绘制线段标题时其位置的轮换
int Count=graphSeries->GetCount();
POINT linepoints[10][50];//储存所有顶点
for (int i=0;i<10;i++)
for(int j=0;j<50;j++)
{
linepoints[i][j].x=0;
linepoints[i][j].y=0;
}
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);
else dataScale = 1;
barHeight = (tmpSeries->GetData(s) * 1.00) * dataScale;
if(m_DrawMode==RELATIVEMODE)
{
barHeight = (tmpSeries->GetData(s)*1.00)*m_nUnits/(tickSpace * 1.00);
if(tmpSeries->GetData(s)>=tickRange)
barHeight=yAxisHeight;//警告,此时数据可能越界,截断越界高度
}
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 + 2, lastYLoc - 1);
pDC->LineTo(tickXLocation - 3, yDataLocation - 1);
linepoints[s][x-1].x =tickXLocation;
linepoints[s][x-1].y =yDataLocation;
if(x==graphSeries->GetCount())
{//以下为调整linetitle,避免它们互相重叠
CString title;
if (s>0)
{
for(int i=0;i<=s-1;i++)
{
if( abs(tickXLocation -linepoints[i][graphSeries->GetCount()-1].x)<30&&abs(yDataLocation -linepoints[i][graphSeries->GetCount()-1].y)<30)//标题间区域至少(30,30)
{
samsaratag=TRUE;//需要调整
break;
}
}
}
if(samsaratag==FALSE)//默认绘在线段的末尾
{
title=CGraphSeries::GetLineTitle(s);
pDC->SetTextColor(barColor);
if( CGraphSeries::GetTitleFlag()!=FALSE)
pDC->TextOut(tickXLocation + 6, yDataLocation - 8,title);
}
else
{
POINT ptext;
ptext.x =linepoints[s][graphSeries->GetCount()-2].x;
ptext.y =linepoints[s][graphSeries->GetCount()-2].y;
linepoints[s][graphSeries->GetCount()-1].x=ptext.x;
linepoints[s][graphSeries->GetCount()-1].y=ptext.y;
for(int i=0;i<=s-1;i++)
{
if( abs(ptext.x -linepoints[i][graphSeries->GetCount()-1].x)<30&&abs(ptext.y -linepoints[i][graphSeries->GetCount()-1].y)<30)
{
BOOL exitflag=TRUE;
ptext.x =linepoints[s][graphSeries->GetCount()-3-i].x;
ptext.y =linepoints[s][graphSeries->GetCount()-3-i].y;
linepoints[s][graphSeries->GetCount()-1].x=ptext.x;
linepoints[s][graphSeries->GetCount()-1].y=ptext.y;
for(int j=0;j<s;j++)
{
if( abs(ptext.x -linepoints[j][graphSeries->GetCount()-1].x)<30&&abs(ptext.y -linepoints[j][graphSeries->GetCount()-1].y)<30)
exitflag=FALSE;
}
if(exitflag)
break;
}
}
title=CGraphSeries::GetLineTitle(s);
pDC->SetTextColor(barColor);
if( CGraphSeries::GetTitleFlag()!=FALSE)
pDC->TextOut(ptext.x + 6, ptext.y - 8,title);
samsaratag=FALSE;
}//调整完毕
}
pDC->SelectObject(pOldPen);
}
//now draw ellipse...
pDC->Ellipse(tickXLocation - 3, yDataLocation - 3,
tickXLocation + 3, yDataLocation + 3);
linepoints[s][x-2].x= lastXLoc = tickXLocation;
linepoints[s][x-2].y=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 - legendWidth/* - 10*/) / graphSeries->GetCount())
> (yAxisHeight - 10))
seriesSpace = (yAxisHeight - 10)/* / graphSeries->GetCount()*/;
else
seriesSpace = (xAxisWidth - legendWidth/* - 10*/) / graphSeries->GetCount();
else
if(xAxisWidth > yAxisHeight)
seriesSpace = yAxisHeight / graphSeries->GetCount();
else
seriesSpace = xAxisWidth / graphSeries->GetCount();
double tmpD = (seriesSpace - /*60*/20)* .8; //max width of any pie
radius = tmpD / 2;
int centerYPie = (yAxisHeight + 60) / 2;
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 - legendWidth - 10) / 2) - radius/* - 25*/;
}
else
{
pieLeft = xApexPoint + 15 + (x * /*50*/20) + ((x - 1) * (2 * radius));
}
pieRight = pieLeft + (2 * radius);
CRect pieRect (pieLeft,
centerYPie - radius,
pieRight,
centerYPie + radius);
int centerXPie = pieLeft + radius;
//plot series label
pDC->TextOut(centerXPie - ((tmpSeries->GetLabel().GetLength() * 8) / 2),
centerYPie + radius + 15, tmpSeries->GetLabel());
lastXLocation = pieLeft;
lastYLocation = centerYPie;
dataSum = 0;
for(s = 0; s < 10; 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;
// newYLocation = centerYPie + radius - (deltaXY - radius);
break;
case 2 : newXLocation = pieLeft + (4 * radius) - deltaXY;
// newXLocation = pieLeft + (2 * radius) - (deltaXY - (2 * radius));
newYLocation = centerYPie + (2 * radius) - deltaXY;
// newYLocation = centerYPie - (deltaXY - (2 * radius));
break;
case 3 : newXLocation = pieLeft + (4 * radius) - deltaXY;
// newXLocation = pieLeft + radius - (deltaXY - (3 * radius));
newYLocation = centerYPie - (4 * radius) + deltaXY;
// newYLocation = centerYPie - radius + (deltaXY - (3 * radius));
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::SetLegend(int datagroup, CString label)
{
graphLegend.SetLegendText(datagroup, label);
graphHasLegend = TRUE;
}
void CGraph::DrawLegend(CDC* pDC)
{
//determine size of legend
//12 chars per seriesSize + 6 for spacing (3 top and bottom)
//+ 1 set for label title(3+12+6) + rectangle (2 chars) + 3 for final bottom buffer
int legendHeight = 23 + (seriesSize * 18) + 3;
int legendL, legendT, legendR, legendB;
int barL, barT, barR, barB;
legendT = (maxHeight / 2) - (legendHeight / 2);
legendB = legendT + legendHeight;
legendR = maxWidth - 5;
legendL = legendR - ((graphLegend.GetLegendLength() * (legendFontSize * .66)) + 25);
//allows 50 pixels for display of legend bar 45 + 5 space.
legendWidth = legendR - legendL;
pDC->Rectangle(legendL, legendT, legendR, legendB);
pDC->TextOut(legendL + (legendWidth / 2) - 24,
legendT + 3, "图例");//Legend
for(int i = 0; i < seriesSize; i++)
{
//top "Legend" text will use 12 + 3 top + 6 bottom (21 total)
//each legend label will need 3 chars on top, so the 24 in the offset
//each label than uses 12 + 3 below + 3 above next label, so 18
// in the i * offset.
CFont legendFont;
legendFont.CreateFont(legendFontSize, 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(&legendFont);
pDC->TextOut(legendL + 5, legendT + 24 + (i * 18), graphLegend.GetLegendText(i));
pDC->SelectObject(pOldFont);
//draw bar
COLORREF barColor;
barColor = GetColor(i);
CBrush brush (barColor);
CBrush* pOldBrush;
pOldBrush = pDC->SelectObject(&brush);
barL = legendL + 5 + (graphLegend.GetLegendText(i).GetLength() * 6) + 5;
barT = legendT + 24 + (i * 18) + 1, graphLegend.GetLegendText(i);
barR = legendR - 5;
barB = barT + 12;
pDC->Rectangle(barL, barT, barR, barB);
pDC->SelectObject(pOldBrush);
}
}
void CGraph::SetGraphTitle(CString title)
{
graphTitle = title;
}
void CGraph::SetXTickFontSize(int size)
{
xTickFontSize = size;
}
void CGraph::SetYTickFontSize(int size)
{
yTickFontSize = size;
}
void CGraph::SetLegendFontSize(int size)
{
legendFontSize = size;
}
int CGraph::PrintGraph(CDC* pDC, CPrintInfo* pInfo)
{
CString str;
char tmpStr[10];
CFont graphTitleFont, textFont;
TEXTMETRIC tm;
CString tickLabel;
//titleFont is 24 point, bold
graphTitleFont.CreateFont(-480, 0, 0, 0, 700, FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH || FF_ROMAN,
"Times New Roman");
//textFont is 12 point
textFont.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->SetMapMode(MM_TWIPS);
if(pInfo->m_nCurPage == 1)
{
CFont* pOldFont = (CFont*) pDC->SelectObject(&graphTitleFont);
pDC->GetTextMetrics(&tm);
int charWidth = tm.tmMaxCharWidth;
//next line is centered....trust me !!
pDC->TextOut(((graphTitle.GetLength() / 2) * charWidth) - (leftMargin / 2), pGraphT, graphTitle);
pDC->SelectObject(pOldFont);
//draw legend
if(graphHasLegend)
PrintLegend(pDC);
maxHeight = pGraphT - pGraphB;
maxWidth = pGraphR - pGraphL - 2200;
if(graphType == 2) //pie
{
//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 = pGraphR - pGraphL - legendWidth - 200;
yAxisHeight = maxHeight - 200; //100 buffer and 200 for title
xApexPoint = pGraphL + 1500;
yApexPoint = pGraphB + maxHeight + 500;
}
else
{
tickLabel.Format("%d", tickRange);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -