VERIFY(dc.TextOut(m_ptOrigin.x - GAP_PIXELS - sizTickLabel.cx - TICK_PIXELS, nTickYLocation - sizTickLabel.cy, sTickLabel)); } // Draw X axis tick s. POSITION pos(m_olElysiumChartSeries.GetHeadPosition()); int nSeries(0); while (pos) {
CElysiumChartSeries* pSeries = static_cast<CElysiumChartSeries*> (m_olElysiumChartSeries.GetNext(pos)); ASSERT_VALID(pSeries); // Ignore unpopulated series if bar chart. if (m_eGraphType != CElysiumChart::Bar || 0 < pSeries->GetNonZeroElementCount()) { // Get the spacing of the series. _ASSERTE(GetNonZeroSeriesCount() && "Div by zero coming"); // int nSeriesSpace(0); DWORD nSeriesSpace(0); if (m_saLegendLabels.GetSize()) { nSeriesSpace = (m_nXAxisWidth - m_rcLegend.Width() - (GAP_PIXELS * 2)) / (m_eGraphType == CElysiumChart::Bar ? GetNonZeroSeriesCount() : m_olElysiumChartSeries.GetCount());//hyh } else { nSeriesSpace = m_nXAxisWidth / (m_eGraphType == CElysiumChart::Bar ? GetNonZeroSeriesCount() : m_olElysiumChartSeries.GetCount());//hyh }// int nTickXLocation(m_ptOrigin.x + ((nSeries + 1) * nSeriesSpace) - DWORD nTickXLocation(m_ptOrigin.x + ((nSeries + 1) * nSeriesSpace) - (nSeriesSpace / 2)); dc.MoveTo(nTickXLocation, m_ptOrigin.y - TICK_PIXELS); VERIFY(dc.LineTo(nTickXLocation, m_ptOrigin.y + TICK_PIXELS)); // Draw x-axis tick label. CString sTickLabel(pSeries->GetLabel()); CSize sizTickLabel(dc.GetTextExtent(sTickLabel)); VERIFY(dc.TextOut(nTickXLocation - (sizTickLabel.cx / 2), m_ptOrigin.y + sizTickLabel.cy, sTickLabel)); ++nSeries; } } VERIFY(dc.SelectObject(pFontOld)); }
// void CElysiumChart::DrawSeriesBar(CDC& dc) const { VALIDATE; ASSERT_VALID(&dc); // How much space does each series get (includes interseries space)? // We ignore series whose members are all zero. int nSeriesSpace(0); if (m_saLegendLabels.GetSize()) { nSeriesSpace = (m_nXAxisWidth - m_rcLegend.Width() - (GAP_PIXELS * 2)) / GetNonZeroSeriesCount(); } else { nSeriesSpace = m_nXAxisWidth / GetNonZeroSeriesCount(); } // Determine width of bars. Data points with a value of zero are assumed // to be empty. This is a bad assumption. int nBarWidth(nSeriesSpace / GetMaxNonZeroSeriesSize()); if (1 < GetNonZeroSeriesCount()) { nBarWidth = (int) ((double) nBarWidth * INTERSERIES_PERCENT_USED); } // This is the width of the largest series (no interseries space). int nMaxSeriesPlotSize(GetMaxNonZeroSeriesSize() * nBarWidth); // Iterate the series. POSITION pos(m_olElysiumChartSeries.GetHeadPosition()); int nSeries(0); while (pos) {
CElysiumChartSeries* pSeries = static_cast<CElysiumChartSeries*> (m_olElysiumChartSeries.GetNext(pos)); ASSERT_VALID(pSeries); // Ignore unpopulated series. if (0 < pSeries->GetNonZeroElementCount()) { // Draw each bar; empty bars are not drawn. int nRunningLeft(m_ptOrigin.x + ((nSeries + 1) * nSeriesSpace) - nMaxSeriesPlotSize); for (int nGroup = 0; nGroup < GetMaxSeriesSize(); ++nGroup) { if (pSeries->GetData(nGroup)) { CRect rcBar; rcBar.left = nRunningLeft; rcBar.top = m_ptOrigin.y - (m_nYAxisHeight * // pSeries->GetData(nGroup)) / (GetMaxDataValue()+1); pSeries->GetData(nGroup)) / (GetMaxDataValue()); rcBar.right = rcBar.left + nBarWidth; rcBar.bottom = m_ptOrigin.y; pSeries->SetTipRegion(nGroup, rcBar); COLORREF crBar(m_dwaColors.GetAt(nGroup)); CBrush br(crBar); CBrush* pBrushOld = dc.SelectObject(&br); ASSERT_VALID(pBrushOld); VERIFY(dc.Rectangle(rcBar)); dc.SelectObject(&pBrushOld); nRunningLeft += nBarWidth; } } ++nSeries; } } }// void CElysiumChart::DrawSeriesLine(CDC& dc) const { VALIDATE; ASSERT_VALID(&dc); // Iterate the groups. CPoint ptLastLoc(0,0); for (int nGroup = 0; nGroup < GetMaxSeriesSize(); nGroup++) { // How much space does each series get (includes interseries space)? int nSeriesSpace(0); if (m_saLegendLabels.GetSize()) { nSeriesSpace = (m_nXAxisWidth - m_rcLegend.Width() - (GAP_PIXELS * 2)) / m_olElysiumChartSeries.GetCount(); } else { nSeriesSpace = m_nXAxisWidth / m_olElysiumChartSeries.GetCount(); } // Determine width of bars. int nBarWidth(nSeriesSpace / GetMaxSeriesSize()); if (1 < m_olElysiumChartSeries.GetCount()) { nBarWidth = (int) ((double) nBarWidth * INTERSERIES_PERCENT_USED); } // This is the width of the largest series (no interseries space). int nMaxSeriesPlotSize(GetMaxSeriesSize() * nBarWidth); // Iterate the series. POSITION pos(m_olElysiumChartSeries.GetHeadPosition());
如果是后者就更简单了 用CListCtrl控件插入两列,将坐标数据插入显示就行了。
/////////////////////////////////
void CElysiumChart::DrawAxes(CDC& dc) const
{
VALIDATE;
ASSERT_VALID(&dc);
_ASSERTE(CElysiumChart::Pie != m_eGraphType); dc.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)); // Draw y axis.
dc.MoveTo(m_ptOrigin);
VERIFY(dc.LineTo(m_ptOrigin.x, m_ptOrigin.y - m_nYAxisHeight)); // Draw x axis.
dc.MoveTo(m_ptOrigin); if (m_saLegendLabels.GetSize()) { VERIFY(dc.LineTo(m_ptOrigin.x +
(m_nXAxisWidth - m_rcLegend.Width() - (GAP_PIXELS * 2)),
m_ptOrigin.y));
}
else {
VERIFY(dc.LineTo(m_ptOrigin.x + m_nXAxisWidth, m_ptOrigin.y));
} // Create the y-axis label font and draw it.
CFont fontYAxes; VERIFY(fontYAxes.CreateFont(
/* nHeight */ m_rectArea.Width() / 10 / Y_AXIS_LABEL_DIVISOR,
/* nWidth */ 0, /* nEscapement */ 90 * 10, /* nOrientation */ 0,
/* nWeight */ FW_DONTCARE, /* bItalic */ false, /* bUnderline */ false,
/* cStrikeOut */ 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | FF_DONTCARE,
"Arial")); CFont* pFontOld = static_cast<CFont*> (dc.SelectObject(&fontYAxes));
ASSERT_VALID(pFontOld);
CSize sizYLabel(dc.GetTextExtent(m_sYAxisLabel));
VERIFY(dc.TextOut(GAP_PIXELS, (m_rectArea.Height() - sizYLabel.cy) / 2,
m_sYAxisLabel)); // Create the x-axis label font and draw it.
CFont fontXAxes;
VERIFY(fontXAxes.CreatePointFont(m_rectArea.Width() / X_AXIS_LABEL_DIVISOR,
"Arial", &dc));
VERIFY(dc.SelectObject(&fontXAxes));
CSize sizXLabel(dc.GetTextExtent(m_sXAxisLabel)); VERIFY(dc.TextOut(m_ptOrigin.x + (m_nXAxisWidth - sizXLabel.cx) / 2,
m_rectArea.Height() - GAP_PIXELS - sizXLabel.cy, m_sXAxisLabel)); // We hardwire TITLE_DIVISOR y-axis ticks here for simplicity.
int nTickCount(min(Y_AXIS_MAX_TICK_COUNT, GetMaxDataValue()));
int nTickSpace(m_nYAxisHeight / (nTickCount+1)); for (int nTick = 0; nTick < nTickCount; ++nTick) {
int nTickYLocation(m_ptOrigin.y - (nTickSpace * (nTick + 1)));
dc.MoveTo(m_ptOrigin.x - TICK_PIXELS, nTickYLocation);
VERIFY(dc.LineTo(m_ptOrigin.x + TICK_PIXELS, nTickYLocation)); // Draw tick label.
CString sTickLabel;
sTickLabel.Format("%d", (GetMaxDataValue() * (nTick + 1)) / nTickCount);
CSize sizTickLabel(dc.GetTextExtent(sTickLabel));
VERIFY(dc.TextOut(m_ptOrigin.x - GAP_PIXELS - sizTickLabel.cx - TICK_PIXELS,
nTickYLocation - sizTickLabel.cy, sTickLabel));
} // Draw X axis tick s.
POSITION pos(m_olElysiumChartSeries.GetHeadPosition());
int nSeries(0); while (pos) {
CElysiumChartSeries* pSeries =
static_cast<CElysiumChartSeries*> (m_olElysiumChartSeries.GetNext(pos));
ASSERT_VALID(pSeries); // Ignore unpopulated series if bar chart.
if (m_eGraphType != CElysiumChart::Bar ||
0 < pSeries->GetNonZeroElementCount()) { // Get the spacing of the series.
_ASSERTE(GetNonZeroSeriesCount() && "Div by zero coming");
// int nSeriesSpace(0);
DWORD nSeriesSpace(0); if (m_saLegendLabels.GetSize()) { nSeriesSpace =
(m_nXAxisWidth - m_rcLegend.Width() - (GAP_PIXELS * 2)) /
(m_eGraphType == CElysiumChart::Bar ?
GetNonZeroSeriesCount() : m_olElysiumChartSeries.GetCount());//hyh
}
else {
nSeriesSpace = m_nXAxisWidth / (m_eGraphType == CElysiumChart::Bar ?
GetNonZeroSeriesCount() : m_olElysiumChartSeries.GetCount());//hyh
}// int nTickXLocation(m_ptOrigin.x + ((nSeries + 1) * nSeriesSpace) -
DWORD nTickXLocation(m_ptOrigin.x + ((nSeries + 1) * nSeriesSpace) -
(nSeriesSpace / 2)); dc.MoveTo(nTickXLocation, m_ptOrigin.y - TICK_PIXELS);
VERIFY(dc.LineTo(nTickXLocation, m_ptOrigin.y + TICK_PIXELS)); // Draw x-axis tick label.
CString sTickLabel(pSeries->GetLabel());
CSize sizTickLabel(dc.GetTextExtent(sTickLabel)); VERIFY(dc.TextOut(nTickXLocation - (sizTickLabel.cx / 2),
m_ptOrigin.y + sizTickLabel.cy, sTickLabel)); ++nSeries;
}
} VERIFY(dc.SelectObject(pFontOld));
}
//
void CElysiumChart::DrawSeriesBar(CDC& dc) const
{
VALIDATE;
ASSERT_VALID(&dc); // How much space does each series get (includes interseries space)?
// We ignore series whose members are all zero.
int nSeriesSpace(0); if (m_saLegendLabels.GetSize()) { nSeriesSpace = (m_nXAxisWidth - m_rcLegend.Width() - (GAP_PIXELS * 2)) /
GetNonZeroSeriesCount();
}
else {
nSeriesSpace = m_nXAxisWidth / GetNonZeroSeriesCount();
} // Determine width of bars. Data points with a value of zero are assumed
// to be empty. This is a bad assumption.
int nBarWidth(nSeriesSpace / GetMaxNonZeroSeriesSize()); if (1 < GetNonZeroSeriesCount()) {
nBarWidth = (int) ((double) nBarWidth * INTERSERIES_PERCENT_USED);
} // This is the width of the largest series (no interseries space).
int nMaxSeriesPlotSize(GetMaxNonZeroSeriesSize() * nBarWidth); // Iterate the series.
POSITION pos(m_olElysiumChartSeries.GetHeadPosition());
int nSeries(0); while (pos) {
CElysiumChartSeries* pSeries =
static_cast<CElysiumChartSeries*> (m_olElysiumChartSeries.GetNext(pos));
ASSERT_VALID(pSeries); // Ignore unpopulated series.
if (0 < pSeries->GetNonZeroElementCount()) { // Draw each bar; empty bars are not drawn.
int nRunningLeft(m_ptOrigin.x + ((nSeries + 1) * nSeriesSpace) -
nMaxSeriesPlotSize); for (int nGroup = 0; nGroup < GetMaxSeriesSize(); ++nGroup) { if (pSeries->GetData(nGroup)) { CRect rcBar;
rcBar.left = nRunningLeft;
rcBar.top = m_ptOrigin.y - (m_nYAxisHeight *
// pSeries->GetData(nGroup)) / (GetMaxDataValue()+1);
pSeries->GetData(nGroup)) / (GetMaxDataValue());
rcBar.right = rcBar.left + nBarWidth;
rcBar.bottom = m_ptOrigin.y; pSeries->SetTipRegion(nGroup, rcBar); COLORREF crBar(m_dwaColors.GetAt(nGroup));
CBrush br(crBar);
CBrush* pBrushOld = dc.SelectObject(&br);
ASSERT_VALID(pBrushOld); VERIFY(dc.Rectangle(rcBar));
dc.SelectObject(&pBrushOld); nRunningLeft += nBarWidth;
}
} ++nSeries;
}
}
}//
void CElysiumChart::DrawSeriesLine(CDC& dc) const
{
VALIDATE;
ASSERT_VALID(&dc); // Iterate the groups.
CPoint ptLastLoc(0,0); for (int nGroup = 0; nGroup < GetMaxSeriesSize(); nGroup++) { // How much space does each series get (includes interseries space)?
int nSeriesSpace(0); if (m_saLegendLabels.GetSize()) { nSeriesSpace = (m_nXAxisWidth - m_rcLegend.Width() - (GAP_PIXELS * 2)) /
m_olElysiumChartSeries.GetCount();
}
else {
nSeriesSpace = m_nXAxisWidth / m_olElysiumChartSeries.GetCount();
} // Determine width of bars.
int nBarWidth(nSeriesSpace / GetMaxSeriesSize()); if (1 < m_olElysiumChartSeries.GetCount()) {
nBarWidth = (int) ((double) nBarWidth * INTERSERIES_PERCENT_USED);
} // This is the width of the largest series (no interseries space).
int nMaxSeriesPlotSize(GetMaxSeriesSize() * nBarWidth); // Iterate the series.
POSITION pos(m_olElysiumChartSeries.GetHeadPosition());
for (int nSeries = 0; nSeries < m_olElysiumChartSeries.GetCount(); ++nSeries) { CElysiumChartSeries* pSeries =
static_cast<CElysiumChartSeries*> (m_olElysiumChartSeries.GetNext(pos));
ASSERT_VALID(pSeries);
// Get x and y location of center of ellipse.
CPoint ptLoc(0,0);
ptLoc.x = m_ptOrigin.x + (((nSeries + 1) * nSeriesSpace) -
(nSeriesSpace / 2));
double dLineHeight(pSeries->GetData(nGroup) * m_nYAxisHeight /
// (GetMaxDataValue()+1));//lijt
(GetMaxDataValue()));
ptLoc.y = (int) ((double) m_ptOrigin.y - dLineHeight);
// Build objects.
COLORREF crLine(m_dwaColors.GetAt(nGroup));
CBrush br(crLine);
CBrush* pBrushOld = dc.SelectObject(&br);
ASSERT_VALID(pBrushOld); // Draw line back to last data member.
if (nSeries > 0) {
CPen penLine(PS_SOLID, 1, crLine);
CPen* pPenOld = dc.SelectObject(&penLine);
ASSERT_VALID(pPenOld); dc.MoveTo(ptLastLoc.x + 2, ptLastLoc.y - 1);
VERIFY(dc.LineTo(ptLoc.x - 3, ptLoc.y - 1));
VERIFY(dc.SelectObject(pPenOld));
} // Now draw ellipse.
CRect rcEllipse(ptLoc.x - 3, ptLoc.y - 3, ptLoc.x + 3, ptLoc.y + 3);
VERIFY(dc.Ellipse(rcEllipse)); pSeries->SetTipRegion(nGroup, rcEllipse);
dc.SelectObject(&pBrushOld);
ptLastLoc = ptLoc;
}
}
}