Graph.cpp
上传用户:tianjwyx
上传日期:2007-01-13
资源大小:813k
文件大小:288k
源码类别:

操作系统开发

开发平台:

Visual C++

  1. //barT uses a 560 offset below,...why?
  2. //would be 500, but barB is only using 120 height,
  3. //when it should be 240 (but 240 puts bars too close
  4. //together, so I'm setting them to 1/2 size.
  5. //therefore, I want to adjust my barT by half of that
  6. //adjustment ( 1/2 of 120 is 60).  This basically centers
  7. //the bar 1/2 way in text, and makes it 1/2 the height
  8. //of text
  9. barL = legendL + 50 + (legendMaxText * charWidth / 2);
  10. barT = legendT - 560 - (i * charHeight);
  11. barR = legendR - 100;
  12. barB = barT - 120;
  13. pDC->Rectangle(barL, barT, barR, barB);
  14. pDC->SelectObject(pOldBrush);
  15. }
  16. return legendL;
  17. }
  18. void CGraph::PrintAxis(CDC *pDC)
  19. {
  20. TEXTMETRIC tm;
  21. pDC->SetTextColor(BLACK);
  22. CFont sideFont, axisFont;
  23. int charWidth;
  24. int charHeight;
  25. int tFontSize;
  26. double tickScale;
  27. int tickYLocation;
  28. int seriesSpace;
  29. int tickXLocation;
  30. switch(graphType)
  31. {
  32. case BAR_GRAPH :
  33. case LINE_GRAPH :
  34. case SCATTER_GRAPH :
  35. case BOX_WHISKER_GRAPH :
  36. // case RADAR_GRAPH :
  37. case STACKED_BAR_GRAPH :
  38. case XY_LINE_GRAPH :
  39. //draw y axis
  40. pDC->MoveTo(xApexPoint, yApexPoint);  
  41. //unlike drawAxis, the lineto below uses a + in the y
  42. //coordinate because printer uses negative locations
  43. //when going down a page, so use a + to move the line
  44. //upwards...
  45. pDC->LineTo(xApexPoint, yApexPoint + yAxisHeight);
  46. //draw x axis
  47. pDC->MoveTo(xApexPoint, yApexPoint);  
  48. pDC->LineTo(xApexPoint + xAxisWidth, yApexPoint);
  49. //draw labels
  50. tFontSize = 16;
  51. if(maxWidth > maxHeight)
  52. {
  53. while((axisYLabel.GetLength() * (tFontSize / 2)) > maxHeight)
  54. {
  55. tFontSize -= 2;
  56. }
  57. }
  58. else
  59. {
  60. while((axisXLabel.GetLength() * (tFontSize / 2)) > maxWidth)
  61. {
  62. tFontSize -= 2;
  63. }
  64. }
  65. tFontSize *= 20;
  66. axisFont.CreateFont(tFontSize, 0, 0, 0, 700, FALSE, FALSE, 0,
  67. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  68. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  69. sideFont.CreateFont(tFontSize, 0, 2700, 0, 700, FALSE, FALSE, 0,
  70. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  71. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  72. CFont* pOldFont;
  73. pOldFont = (CFont*) pDC->SelectObject(&sideFont);
  74. pDC->GetTextMetrics(&tm);
  75. charWidth = tm.tmAveCharWidth;
  76. charHeight = tm.tmHeight;
  77. if(graphAlignment)
  78. {
  79. pDC->TextOut(pGraphL + 10, pGraphT - (maxHeight / 2) - ((axisYLabel.GetLength() / 2) * charHeight), axisYLabel);
  80. pDC->SelectObject(&axisFont);
  81. pDC->GetTextMetrics(&tm);
  82. charWidth = tm.tmAveCharWidth;
  83. pDC->TextOut(xApexPoint + (xAxisWidth / 2) - ((axisXLabel.GetLength() / 2) * charWidth), pGraphB + 50 + charHeight, axisXLabel);
  84. pDC->SelectObject(pOldFont);
  85. tickScale = 0.00;
  86. tickScale = (yAxisHeight - 100) / numTicks;
  87. //draw y axis ticks
  88. for(int y = 1; y <= numTicks; y++)  
  89. {
  90. tickYLocation = yApexPoint + (int)(y * tickScale);
  91. //draw tick mark
  92. pDC->MoveTo(xApexPoint - 60, tickYLocation);
  93. pDC->LineTo(xApexPoint + 60, tickYLocation);
  94. if(graphHasGridLines)
  95. {
  96. //draw grid lines
  97. COLORREF gridLineColor;
  98. gridLineColor = DARK_GREY;
  99. CBrush gridBrush (gridLineColor);
  100. CBrush* pOldBrush;
  101. pOldBrush = pDC->SelectObject(&gridBrush);
  102. pDC->MoveTo(xApexPoint, tickYLocation);
  103. pDC->LineTo(xApexPoint + xAxisWidth, tickYLocation);
  104. pDC->SelectObject(pOldBrush);
  105. }
  106. //draw tick label
  107. CString tickLabel;
  108. tickLabel.Format("%d", minTick + (y * tickSpace));
  109. CFont yFont;
  110. yFont.CreateFont(yTickFontSize * 20, 0, 0, 0, 700, FALSE, FALSE, 0,
  111. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  112. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  113. pOldFont = (CFont*) pDC->SelectObject(&yFont);
  114. pDC->TextOut(xApexPoint - 200 - (tickLabel.GetLength() * (yTickFontSize / 2) * 20), tickYLocation + 120, tickLabel);
  115. p_topYTick = tickYLocation;
  116. pDC->SelectObject(pOldFont);
  117. }
  118. //draw X axis tick marks
  119. if(graphType != SCATTER_GRAPH)
  120. {
  121. POSITION pos;
  122. pos = graphSeries->GetHeadPosition();
  123. CGraphSeries* tmpSeries;
  124. for(int x = 1; x <= graphSeries->GetCount(); x++)
  125. {
  126. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  127. int seriesSpace;
  128. int tickXLocation;
  129. seriesSpace = xAxisWidth / graphSeries->GetCount();
  130. tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
  131. pDC->MoveTo(tickXLocation,yApexPoint - 60);
  132. pDC->LineTo(tickXLocation,yApexPoint + 60);
  133. //draw tick label
  134. CString tickLabel;
  135. tickLabel = tmpSeries->GetLabel();
  136. if(!xAxisAlign)  //horizontal
  137. pDC->TextOut(tickXLocation - ((tickLabel.GetLength() / 2) * (xTickFontSize * 10)), yApexPoint - 160, tickLabel);
  138. else
  139. {
  140. CFont sideFont2;
  141. sideFont2.CreateFont(xTickFontSize * 20, 0, ((360 - xAxisAlign) * 10), 0, 700, FALSE, FALSE, 0,
  142. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  143. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  144. pOldFont = (CFont*) pDC->SelectObject(&sideFont2);
  145. pDC->GetTextMetrics(&tm);
  146. charWidth = tm.tmAveCharWidth;
  147. if(xAxisAlign < 180)
  148. pDC->TextOut(tickXLocation - (xTickFontSize * 10), yApexPoint - (xTickFontSize * 10) - (xAxisLabelLength * charWidth), tickLabel);
  149. else
  150. pDC->TextOut(tickXLocation + (xTickFontSize * 10), yApexPoint - 160, tickLabel);
  151. }
  152. p_rightXTick = tickXLocation;
  153. pDC->SelectObject(pOldFont);
  154. }
  155. }
  156. else
  157. {
  158. //scatter graphs will use the same tick marking on both axis lines
  159. int seriesSpace;
  160. seriesSpace = (xAxisWidth - 200) / numTicks;
  161. for(int x = 1; x <= numTicks; x++)  
  162. {
  163. int tickXLocation;
  164. tickXLocation = xApexPoint + (x * seriesSpace);
  165. //draw tick mark
  166. pDC->MoveTo(tickXLocation, yApexPoint - 60);
  167. pDC->LineTo(tickXLocation, yApexPoint + 60);
  168. //draw tick label
  169. CString tickLabel;
  170. tickLabel.Format("%d", x * tickSpace);
  171. CFont xFont;
  172. xFont.CreateFont(xTickFontSize * 20, 0, 0, 0, 700, FALSE, FALSE, 0,
  173. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  174. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  175. pOldFont = (CFont*) pDC->SelectObject(&xFont);
  176. pDC->GetTextMetrics(&tm);
  177. charWidth = tm.tmAveCharWidth;
  178. pDC->TextOut(tickXLocation - (tickLabel.GetLength() * charWidth / 2), yApexPoint - 160, tickLabel);
  179. p_rightXTick = tickXLocation;
  180. pDC->SelectObject(pOldFont);
  181. }
  182. }
  183. }
  184. else
  185. {
  186. //reverse above stuff and treat as horizontal graph
  187. pDC->TextOut(pGraphL + 10, pGraphT - (maxHeight / 2) - ((axisXLabel.GetLength() / 2) * charHeight), axisXLabel);
  188. pDC->SelectObject(&axisFont);
  189. pDC->GetTextMetrics(&tm);
  190. charWidth = tm.tmAveCharWidth;
  191. int labelHeight = tm.tmHeight + 50;
  192. if(axisYLabel.GetLength() == 0)
  193. labelHeight = 0;
  194. pDC->TextOut(xApexPoint + (xAxisWidth / 2) - ((axisYLabel.GetLength() / 2) * charWidth), pGraphB + 50 + labelHeight, axisYLabel);
  195. pDC->SelectObject(pOldFont);
  196. //to allow scalability (height may be less than tickRange)
  197. double tickScale;
  198. tickScale = 0.00;
  199. //draw y axis ticks
  200. if(graphType != SCATTER_GRAPH)
  201. {
  202. tickScale = (yAxisHeight - 100) / seriesSize;
  203. POSITION pos;
  204. pos = graphSeries->GetHeadPosition();
  205. CGraphSeries* tmpSeries;
  206. for(int y = 1; y <= graphSeries->GetCount(); y++)  
  207. {
  208. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  209. int seriesSpace;
  210. int tickYLocation;
  211. seriesSpace = (yAxisHeight - 50) / graphSeries->GetCount();
  212. tickYLocation = yApexPoint + ((y * seriesSpace) - (seriesSpace / 2));
  213. //draw tick mark
  214. pDC->MoveTo(xApexPoint - 60, tickYLocation);
  215. pDC->LineTo(xApexPoint + 60, tickYLocation);
  216. //draw tick label
  217. CString tickLabel;
  218. tickLabel = tmpSeries->GetLabel();
  219. CFont sideFont2;
  220. sideFont2.CreateFont(yTickFontSize * 20, 0, 0, 0, 700, FALSE, FALSE, 0,
  221. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  222. DEFAULT_QUALITY, FIXED_PITCH | FF_ROMAN,"Arial");
  223. pOldFont = (CFont*) pDC->SelectObject(&sideFont2);
  224. pDC->GetTextMetrics(&tm);
  225. pDC->TextOut(xApexPoint - (tickLabel.GetLength() * (yTickFontSize * 10)) - 200, tickYLocation + 120, tickLabel);
  226. p_topYTick = tickYLocation;
  227. pDC->SelectObject(pOldFont);
  228. }
  229. }
  230. else
  231. {
  232. //scatter graphs will use the same tick marking on both axis lines
  233. for(int y = 1; y <= numTicks; y++)  
  234. {
  235. tickScale = (yAxisHeight - 100) / numTicks;
  236. int tickYLocation;
  237. tickYLocation = yApexPoint + (int)(y * tickScale);
  238. //draw tick mark
  239. pDC->MoveTo(xApexPoint - 60, tickYLocation);
  240. pDC->LineTo(xApexPoint + 60, tickYLocation);
  241. //draw tick label
  242. CString tickLabel;
  243. tickLabel.Format("%d", y * tickSpace);
  244. CFont yFont;
  245. yFont.CreateFont(yTickFontSize * 20, 0, 0, 0, 700, FALSE, FALSE, 0,
  246. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  247. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  248. pOldFont = (CFont*) pDC->SelectObject(&yFont);
  249. pDC->TextOut(xApexPoint - (tickLabel.GetLength() * (yTickFontSize * 10)) - 200, tickYLocation + 120, tickLabel);
  250. p_topYTick = tickYLocation;
  251. pDC->SelectObject(pOldFont);
  252. }
  253. }
  254. //draw X axis tick marks
  255. tickScale = (xAxisWidth - 200) / numTicks;
  256. for(int x = 1; x <= numTicks; x++)
  257. {
  258. int tickXLocation;
  259. tickXLocation = xApexPoint + (int)(x * tickScale);
  260. pDC->MoveTo(tickXLocation,yApexPoint - 60);
  261. pDC->LineTo(tickXLocation,yApexPoint + 60);
  262. if(graphHasGridLines)
  263. {
  264. //draw grid lines
  265. COLORREF gridLineColor;
  266. gridLineColor = DARK_GREY;
  267. CBrush gridBrush (gridLineColor);
  268. CBrush* pOldBrush;
  269. pOldBrush = pDC->SelectObject(&gridBrush);
  270. pDC->MoveTo(tickXLocation, yApexPoint);
  271. pDC->LineTo(tickXLocation, yApexPoint + yAxisHeight);
  272. pDC->SelectObject(pOldBrush);
  273. }
  274. //draw tick label
  275. CString tickLabel;
  276. tickLabel.Format("%d", x * tickSpace);
  277. if(!xAxisAlign)  //horizontal
  278. {
  279. CFont xFont;
  280. xFont.CreateFont(xTickFontSize * 20, 0, 0, 0, 700, FALSE, FALSE, 0,
  281. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  282. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  283. pOldFont = (CFont*) pDC->SelectObject(&xFont);
  284. charWidth = tm.tmAveCharWidth;
  285. pDC->TextOut(tickXLocation - ((tickLabel.GetLength() * charWidth) / 2), yApexPoint - 160, tickLabel);
  286. pDC->SelectObject(pOldFont);
  287. }
  288. else
  289. {
  290. CFont sideFont2;
  291. sideFont2.CreateFont(xTickFontSize * 20, 0, (xAxisAlign * 10), 0, 700, FALSE, FALSE, 0,
  292. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  293. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  294. pOldFont = (CFont*) pDC->SelectObject(&sideFont2);
  295. pDC->GetTextMetrics(&tm);
  296. charWidth = tm.tmAveCharWidth;
  297. if(xAxisAlign < 180)
  298. pDC->TextOut(tickXLocation - (xTickFontSize * 10), yApexPoint - (xTickFontSize * 10) - (xAxisLabelLength * charWidth), tickLabel);
  299. else
  300. pDC->TextOut(tickXLocation + (xTickFontSize * 10), yApexPoint - 160, tickLabel);
  301. pDC->SelectObject(pOldFont);
  302. }
  303. p_rightXTick = tickXLocation;
  304. }
  305. }
  306. break;
  307. case BAR_GRAPH_3D :
  308. case LINE_GRAPH_3D :
  309. case STACKED_BAR_GRAPH_3D :
  310. if(graphAlignment)
  311. depth = (int)(yAxisHeight * .05);
  312. else
  313. depth = (int)(xAxisWidth * .05);
  314. xApexPoint += depth;
  315. yApexPoint += depth;
  316. xAxisWidth -= depth;
  317. yAxisHeight -= depth;
  318. //draw y axis
  319. pDC->MoveTo(xApexPoint, yApexPoint);  
  320. pDC->LineTo(xApexPoint, yApexPoint + yAxisHeight);
  321. //draw x axis
  322. pDC->MoveTo(xApexPoint, yApexPoint);  
  323. pDC->LineTo(xApexPoint + xAxisWidth, yApexPoint);
  324. //adjust graph settings for 3D look
  325. yApexPoint -= depth;
  326. xApexPoint -= depth;
  327. //foreground axis
  328. pDC->MoveTo(xApexPoint, yApexPoint - (int)(depth * .5));  
  329. pDC->LineTo(xApexPoint, yApexPoint + yAxisHeight);
  330. pDC->MoveTo(xApexPoint - (int)(depth * .5), yApexPoint);  
  331. pDC->LineTo(xApexPoint + xAxisWidth, yApexPoint);
  332. //connecting line at apex
  333. pDC->MoveTo(xApexPoint, yApexPoint);  
  334. pDC->LineTo(xApexPoint + depth, yApexPoint + depth);
  335. //connecting line at height
  336. pDC->MoveTo(xApexPoint, yApexPoint + yAxisHeight);  
  337. pDC->LineTo(xApexPoint + depth, yApexPoint + yAxisHeight + depth);
  338. //connecting line at width
  339. pDC->MoveTo(xApexPoint + xAxisWidth, yApexPoint);  
  340. pDC->LineTo(xApexPoint + xAxisWidth + depth, yApexPoint + depth);
  341. //top and right border lines
  342. pDC->MoveTo(xApexPoint + depth, yApexPoint + yAxisHeight + depth);
  343. pDC->LineTo(xApexPoint + xAxisWidth + depth, yApexPoint + yAxisHeight + depth);
  344. pDC->LineTo(xApexPoint + xAxisWidth + depth, yApexPoint + depth);
  345. //Tick marks ... and labels too
  346. //draw labels
  347. tFontSize = 16;
  348. if(maxWidth > maxHeight)
  349. {
  350. while((axisYLabel.GetLength() * (tFontSize / 2)) > maxHeight)
  351. {
  352. tFontSize -= 2;
  353. }
  354. }
  355. else
  356. {
  357. while((axisXLabel.GetLength() * (tFontSize / 2)) > maxWidth)
  358. {
  359. tFontSize -= 2;
  360. }
  361. }
  362. axisFont.CreateFont(tFontSize * 20, 0, 0, 0, 700, FALSE, FALSE, 0,
  363. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  364. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  365. sideFont.CreateFont(tFontSize * 20, 0, 2700, 0, 700, FALSE, FALSE, 0,
  366. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  367. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  368. pOldFont = (CFont*) pDC->SelectObject(&sideFont);
  369. pDC->GetTextMetrics(&tm);
  370. charWidth = tm.tmAveCharWidth;
  371. charHeight = tm.tmHeight;
  372. if(graphAlignment)
  373. {
  374. pDC->TextOut(pGraphL + 10, pGraphT - (maxHeight / 2) - ((axisYLabel.GetLength() * charWidth) / 2), axisYLabel);
  375. pDC->SelectObject(&axisFont);
  376. pDC->GetTextMetrics(&tm);
  377. charWidth = tm.tmAveCharWidth;
  378. pDC->TextOut(xApexPoint + (xAxisWidth / 2) - ((axisXLabel.GetLength() / 2) * charWidth), pGraphB + 50 + charHeight, axisXLabel);
  379. pDC->SelectObject(pOldFont);
  380. //to allow scalability (height may be less than tickRange)
  381. tickScale = 0.00;
  382. tickScale = yAxisHeight / numTicks;
  383. //draw y axis ticks
  384. for(int y = 1; y <= numTicks; y++)  
  385. {
  386. tickYLocation = yApexPoint + (int)(y * tickScale);
  387. //draw tick mark
  388. pDC->MoveTo(xApexPoint - (int)(depth * .5), tickYLocation);
  389. pDC->LineTo(xApexPoint, tickYLocation);
  390. COLORREF gridLineColor;
  391. CPen* pOldPen;
  392. if(graphHasGridLines)
  393. {
  394. //draw grid lines
  395. gridLineColor = DARK_GREY;
  396. CPen gridPen (PS_SOLID, 1, gridLineColor);
  397. pOldPen = pDC->SelectObject(&gridPen);
  398. pDC->MoveTo(xApexPoint, tickYLocation);
  399. pDC->LineTo(xApexPoint + depth, tickYLocation + depth);
  400. pDC->LineTo(xApexPoint + xAxisWidth + depth, tickYLocation + depth);
  401. pDC->SelectObject(pOldPen);
  402. }
  403. //draw tick label
  404. CString tickLabel;
  405. tickLabel.Format("%d", y * tickSpace);
  406. CFont yFont;
  407. yFont.CreateFont(yTickFontSize * 20, 0, 0, 0, 700, FALSE, FALSE, 0,
  408. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  409. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  410. pOldFont = (CFont*) pDC->SelectObject(&yFont);
  411. pDC->TextOut(xApexPoint - 200 - (tickLabel.GetLength() * ((yTickFontSize / 2) * 20)), tickYLocation + 120, tickLabel);
  412. topYTick = tickYLocation;
  413. pDC->SelectObject(pOldFont);
  414. //draw 1/2 tick line (grey)
  415. int midTickYLocation;
  416. midTickYLocation = yApexPoint + (int)(y * tickScale * .5) + (int)((y - 1) * tickScale * .5);
  417. //draw tick mark
  418. pDC->MoveTo(xApexPoint - (int)(depth * .5), midTickYLocation);
  419. pDC->LineTo(xApexPoint, midTickYLocation);
  420. if(graphHasGridLines)
  421. {
  422. //draw grid lines
  423. gridLineColor = LIGHT_GREY;
  424. CPen midGridPen (PS_SOLID, 1, gridLineColor);
  425. pOldPen = pDC->SelectObject(&midGridPen);
  426. pDC->MoveTo(xApexPoint, midTickYLocation);
  427. pDC->LineTo(xApexPoint + depth, midTickYLocation + depth);
  428. pDC->LineTo(xApexPoint + xAxisWidth + depth, midTickYLocation + depth);
  429. pDC->SelectObject(pOldPen);
  430. }
  431. }
  432. //draw X axis tick marks
  433. POSITION pos;
  434. pos = graphSeries->GetHeadPosition();
  435. CGraphSeries* tmpSeries;
  436. for(int x = 1; x <= graphSeries->GetCount(); x++)
  437. {
  438. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  439. seriesSpace = xAxisWidth / graphSeries->GetCount();
  440. tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
  441. //unlike normal series, we put ticks here
  442. //on the outsides of the series
  443. pDC->MoveTo(xApexPoint + (x * seriesSpace),yApexPoint - (int)(depth * .5));
  444. pDC->LineTo(xApexPoint + (x * seriesSpace),yApexPoint);
  445. pDC->LineTo(xApexPoint + (x * seriesSpace) + depth,yApexPoint + depth);
  446. //draw tick label
  447. CString tickLabel;
  448. tickLabel = tmpSeries->GetLabel();
  449. if(!xAxisAlign)  //horizontal
  450. pDC->TextOut(tickXLocation - ((tickLabel.GetLength() / 2) * (xTickFontSize * 10)), yApexPoint - 160, tickLabel);
  451. else
  452. {
  453. CFont sideFont2;
  454. sideFont2.CreateFont(xTickFontSize * 20, 0, (xAxisAlign * 10), 0, 700, FALSE, FALSE, 0,
  455. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  456. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  457. pOldFont = (CFont*) pDC->SelectObject(&sideFont2);
  458. pDC->GetTextMetrics(&tm);
  459. charWidth = tm.tmAveCharWidth;
  460. if(xAxisAlign < 180)
  461. pDC->TextOut(tickXLocation - (xTickFontSize * 10), yApexPoint - (xTickFontSize * 10) - (xAxisLabelLength * charWidth), tickLabel);
  462. else
  463. pDC->TextOut(tickXLocation + (xTickFontSize * 10), yApexPoint - 160, tickLabel);
  464. pDC->SelectObject(pOldFont);
  465. }
  466. p_rightXTick = tickXLocation;
  467. }
  468. }
  469. else
  470. {
  471. //reverse above stuff and treat as horizontal graph
  472. pDC->TextOut(pGraphL + 10, pGraphT - (maxHeight / 2) - ((axisXLabel.GetLength() / 2) * charHeight), axisXLabel);
  473. pDC->SelectObject(&axisFont);
  474. pDC->GetTextMetrics(&tm);
  475. charWidth = tm.tmAveCharWidth;
  476. int labelHeight;
  477. labelHeight = tm.tmHeight + 50;
  478. if(axisYLabel.GetLength() == 0)
  479. labelHeight = 0;
  480. pDC->TextOut(xApexPoint + (xAxisWidth / 2) - ((axisXLabel.GetLength() / 2) * charWidth), pGraphB + 50 + labelHeight, axisYLabel);
  481. pDC->SelectObject(pOldFont);
  482. //to allow scalability (height may be less than tickRange)
  483. tickScale = 0.00;
  484. //draw y axis ticks
  485. tickScale = (yAxisHeight - 100) / seriesSize;
  486. POSITION pos;
  487. pos = graphSeries->GetHeadPosition();
  488. CGraphSeries* tmpSeries;
  489. for(int y = 1; y <= graphSeries->GetCount(); y++)  
  490. {
  491. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  492. seriesSpace = (yAxisHeight - 50) / graphSeries->GetCount();
  493. tickYLocation = yApexPoint + (y * seriesSpace);
  494. //draw tick mark
  495. //unlike normal series, we put ticks here on the 
  496. //outside of the series
  497. pDC->MoveTo(xApexPoint - (int)(depth * .5), tickYLocation);
  498. pDC->LineTo(xApexPoint, tickYLocation);
  499. //draw tick label
  500. CString tickLabel;
  501. tickLabel = tmpSeries->GetLabel();
  502. CFont yFont;
  503. yFont.CreateFont(yTickFontSize * 20, 0, 0, 0, 700, FALSE, FALSE, 0,
  504. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  505. DEFAULT_QUALITY, FIXED_PITCH | FF_ROMAN,"Arial");
  506. pOldFont = (CFont*) pDC->SelectObject(&yFont);
  507. pDC->GetTextMetrics(&tm);
  508. pDC->TextOut(xApexPoint - (tickLabel.GetLength() * (yTickFontSize * 10)), tickYLocation + 120, tickLabel);
  509. p_topYTick = tickYLocation;
  510. pDC->SelectObject(pOldFont);
  511. }
  512. //draw X axis tick marks
  513. tickScale = (xAxisWidth - 200) / numTicks;
  514. for(int x = 1; x <= numTicks; x++)
  515. {
  516. tickXLocation = xApexPoint + (int)(x * tickScale);
  517. pDC->MoveTo(tickXLocation,yApexPoint - (int)(depth * .25));
  518. pDC->LineTo(tickXLocation,yApexPoint);
  519. COLORREF gridLineColor;
  520. CPen* pOldPen;
  521. if(graphHasGridLines)
  522. {
  523. //draw grid lines
  524. gridLineColor = DARK_GREY;
  525. CPen gridPen (PS_SOLID, 1, gridLineColor);
  526. pOldPen = pDC->SelectObject(&gridPen);
  527. pDC->MoveTo(tickXLocation, yApexPoint);
  528. pDC->LineTo(tickXLocation + depth, yApexPoint + depth);
  529. pDC->LineTo(tickXLocation + depth, yApexPoint + yAxisHeight + depth);
  530. pDC->SelectObject(pOldPen);
  531. }
  532. //draw tick label
  533. CString tickLabel;
  534. tickLabel.Format("%d", x * tickSpace);
  535. if(!xAxisAlign)  //horizontal
  536. {
  537. CFont xFont;
  538. xFont.CreateFont(xTickFontSize * 20, 0, 0, 0, 700, FALSE, FALSE, 0,
  539. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  540. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  541. pOldFont = (CFont*) pDC->SelectObject(&xFont);
  542. charWidth = tm.tmAveCharWidth;
  543. pDC->TextOut(tickXLocation - ((tickLabel.GetLength() * charWidth) / 2), yApexPoint - 160, tickLabel);
  544. pDC->SelectObject(pOldFont);
  545. }
  546. else
  547. {
  548. CFont sideFont2;
  549. sideFont2.CreateFont(xTickFontSize * 20, 0, (xAxisAlign * 10), 0, 700, FALSE, FALSE, 0,
  550. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  551. DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,"Arial");
  552. pOldFont = (CFont*) pDC->SelectObject(&sideFont2);
  553. pDC->GetTextMetrics(&tm);
  554. charWidth = tm.tmAveCharWidth;
  555. if(xAxisAlign < 180)
  556. pDC->TextOut(tickXLocation - (xTickFontSize * 10), yApexPoint - (xTickFontSize * 10) - (xAxisLabelLength * charWidth), tickLabel);
  557. else
  558. pDC->TextOut(tickXLocation + (xTickFontSize * 10), yApexPoint - 160, tickLabel);
  559. pDC->SelectObject(pOldFont);
  560. }
  561. p_rightXTick = tickXLocation;
  562. //draw 1/2 tick line (grey)
  563. int midTickXLocation;
  564. midTickXLocation = xApexPoint + (int)(x * tickScale * .5) + (int)((x - 1) * tickScale * .5);
  565. //draw tick mark
  566. pDC->MoveTo(midTickXLocation,yApexPoint - (int)(depth * .25));
  567. pDC->LineTo(midTickXLocation,yApexPoint);
  568. if(graphHasGridLines)
  569. {
  570. //draw grid lines
  571. gridLineColor = LIGHT_GREY;
  572. CPen midGridPen (PS_SOLID, 1, gridLineColor);
  573. pDC->SelectObject(&midGridPen);
  574. pDC->MoveTo(midTickXLocation, yApexPoint);
  575. pDC->LineTo(midTickXLocation + depth, yApexPoint + depth);
  576. pDC->LineTo(midTickXLocation + depth, yApexPoint + yAxisHeight + depth);
  577. pDC->SelectObject(pOldPen);
  578. }
  579. }
  580. }
  581. break;
  582. }
  583. }
  584. void CGraph::PrintSeries(CDC *pDC)
  585. {
  586. switch(graphType)
  587. {
  588. case BAR_GRAPH :
  589.  PrintBarSeries(pDC);
  590.  break;
  591. case LINE_GRAPH :
  592.  PrintLineSeries(pDC);
  593.  break;
  594. case PIE_GRAPH :
  595.  PrintPieSeries(pDC);
  596.  break;
  597. case SCATTER_GRAPH :
  598.  PrintScatterSeries(pDC);
  599.  break;
  600. case BOX_WHISKER_GRAPH :
  601.  PrintBoxWhiskerSeries(pDC);
  602.  break;
  603. case STACKED_BAR_GRAPH :
  604.  PrintStackedBarSeries(pDC);
  605.  break;
  606. case XY_LINE_GRAPH :
  607.  PrintXYLineSeries(pDC);
  608.  break;
  609. // case RADAR_GRAPH :
  610. //  PrintRadarSeries(pDC);
  611. //  break;
  612. case BAR_GRAPH_3D :
  613.  Print3DBarSeries(pDC);
  614.  break;
  615. case LINE_GRAPH_3D :
  616.  Print3DLineSeries(pDC);
  617.  break;
  618. case STACKED_BAR_GRAPH_3D :
  619.  Print3DStackedBarSeries(pDC);
  620.  break;
  621. case PIE_GRAPH_3D :
  622.  Print3DPieSeries(pDC);
  623.  break;
  624. default :
  625.  AfxMessageBox("No graph type to print");
  626.  break;
  627. }
  628. }
  629. void CGraph::SetMargins(int top, int bottom, int left, int right, int graphTop)
  630. {
  631. //page margins for portrait or landscape distinction
  632. topMargin = top;
  633. bottomMargin = bottom;
  634. leftMargin = left;
  635. rightMargin = right;
  636. //set up rectangle area for showing the graph
  637. pGraphL = leftMargin;
  638. pGraphT = graphTop;
  639. pGraphB = pGraphT - 5760/*7200*/;
  640. pGraphR = rightMargin;
  641. if(pGraphB < bottomMargin)
  642. pGraphB = bottomMargin; 
  643. }
  644. void CGraph::SetGridLines(BOOL hasGridLines)
  645. {
  646. graphHasGridLines = hasGridLines;
  647. }
  648. void CGraph::SetGraphAlignment(int alignment)
  649. {
  650. graphAlignment = alignment;
  651. //because of how it ends up looking, I'm forcing 3D line graphs
  652. //to always display as if in vertical mode graph
  653. if(graphType == LINE_GRAPH_3D)
  654. graphAlignment = VERTICAL_ALIGN;  
  655. }
  656. void CGraph::SetTickLimits(int minTickValue, int maxTickValue, int tickStep)
  657. {
  658. maxTick = maxTickValue;
  659. minTick = minTickValue;
  660. tickSpace = tickStep;
  661. numTicks = (maxTick - minTick) / tickStep;
  662. if((numTicks * tickStep) < (maxTick - minTick))
  663. numTicks++;
  664. }
  665. void CGraph::DrawBarSeries(CDC* pDC)
  666. {
  667. int barWidth;
  668. int dataPlotSize;   //used to plot rects of data
  669. int barL, barT, barR, barB;
  670. int tickXLocation, tickYLocation;
  671. int seriesSpace;
  672. int barHeight;
  673. POSITION pos;
  674. CGraphSeries* tmpSeries;
  675. int x, y, s;
  676. if(graphAlignment)
  677. {
  678. //determine width of barchart data blocks
  679. seriesSpace = xAxisWidth / graphSeries->GetCount();
  680. barWidth = (int)((seriesSpace * .6) / seriesSize);
  681. dataPlotSize = seriesSize * barWidth;
  682. pos = graphSeries->GetHeadPosition();
  683. switch(graphQuadType)
  684. {
  685. case 1 :
  686. for(x = 1; x <= graphSeries->GetCount(); x++)
  687. {
  688. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  689. tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
  690. for(s = 0; s < seriesSize; s++)
  691. {
  692. if(tmpSeries->GetData(s) > -1)
  693. {
  694. double dataScale = 0.00;
  695. dataScale = ((yAxisHeight - 10) * 1.00) / (maxTick - minTick);
  696. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  697. if(((tmpSeries->GetData(s) - minTick) > 0) && (barHeight < 1))
  698. barHeight = (int)dataScale;
  699. barL = tickXLocation - (dataPlotSize / 2) + (s * barWidth);
  700. if(barHeight > yAxisHeight)
  701. barT = yApexPoint - yAxisHeight;
  702. else
  703. barT = yApexPoint - barHeight;
  704. barR = barL + barWidth;
  705. barB = yApexPoint;
  706. COLORREF barColor;
  707. barColor = GetColor(s);
  708. CBrush brush (barColor);
  709. CBrush* pOldBrush;
  710. pOldBrush = pDC->SelectObject(&brush);
  711. pDC->Rectangle(barL, barT, barR, barB);
  712. pDC->SelectObject(pOldBrush);
  713. }
  714. }
  715. }
  716. break;
  717. case 2 :
  718. for(x = 1; x <= graphSeries->GetCount() / 2; x++)
  719. {
  720. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  721. tickXLocation = xApexPoint - (xAxisWidth / 2) + ((x * seriesSpace) - (seriesSpace / 2));
  722. for(s = 0; s < seriesSize; s++)
  723. {
  724. double dataScale = 0.00;
  725. dataScale = ((yAxisHeight - 10) * 1.00) / (maxTick - minTick);
  726. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  727. if(barHeight < 1)
  728. barHeight = (int)dataScale;
  729. barL = tickXLocation - (dataPlotSize / 2) + (s * barWidth);
  730. if(barHeight > (yAxisHeight / 2))
  731. barT = yApexPoint - (yAxisHeight / 2);
  732. else
  733. barT = yApexPoint - barHeight;
  734. barR = barL + barWidth;
  735. barB = yApexPoint;
  736. COLORREF barColor;
  737. barColor = GetColor(s);
  738. CBrush brush (barColor);
  739. CBrush* pOldBrush;
  740. pOldBrush = pDC->SelectObject(&brush);
  741. pDC->Rectangle(barL, barT, barR, barB);
  742. pDC->SelectObject(pOldBrush);
  743. }
  744. }
  745. //draw at the 0 location
  746. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  747. tickXLocation = xApexPoint;
  748. for(s = 0; s < seriesSize; s++)
  749. {
  750. double dataScale = 0.00;
  751. dataScale = ((yAxisHeight - 10) * 1.00) / (maxTick - minTick);
  752. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  753. if(((tmpSeries->GetData(s) - minTick) > 0) && (barHeight < 1))
  754. barHeight = (int)dataScale;
  755. barL = tickXLocation - (dataPlotSize / 2) + (s * barWidth);
  756. if(barHeight > yAxisHeight)
  757. barT = yApexPoint - yAxisHeight;
  758. else
  759. barT = yApexPoint - barHeight;
  760. barR = barL + barWidth;
  761. barB = yApexPoint;
  762. COLORREF barColor;
  763. barColor = GetColor(s);
  764. CBrush brush (barColor);
  765. CBrush* pOldBrush;
  766. pOldBrush = pDC->SelectObject(&brush);
  767. pDC->Rectangle(barL, barT, barR, barB);
  768. pDC->SelectObject(pOldBrush);
  769. }
  770. x++;
  771. for(; x <= graphSeries->GetCount(); x++)
  772. {
  773. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  774. tickXLocation = xApexPoint - (xAxisWidth / 2) + ((x * seriesSpace) - (seriesSpace / 2));
  775. for(s = 0; s < seriesSize; s++)
  776. {
  777. double dataScale = 0.00;
  778. dataScale = ((yAxisHeight - 10) * 1.00) / (maxTick - minTick);
  779. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  780. if(((tmpSeries->GetData(s) - minTick) > 0) && (barHeight < 1))
  781. barHeight = (int)dataScale;
  782. barL = tickXLocation - (dataPlotSize / 2) + (s * barWidth);
  783. if(barHeight > (yAxisHeight / 2))
  784. barT = yApexPoint - (yAxisHeight / 2);
  785. else
  786. barT = yApexPoint - barHeight;
  787. barR = barL + barWidth;
  788. barB = yApexPoint;
  789. COLORREF barColor;
  790. barColor = GetColor(s);
  791. CBrush brush (barColor);
  792. CBrush* pOldBrush;
  793. pOldBrush = pDC->SelectObject(&brush);
  794. pDC->Rectangle(barL, barT, barR, barB);
  795. pDC->SelectObject(pOldBrush);
  796. }
  797. }
  798. break;
  799. case 3 :
  800. for(x = 1; x <= graphSeries->GetCount(); x++)
  801. {
  802. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  803. tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
  804. for(s = 0; s < seriesSize; s++)
  805. {
  806. double dataScale = 0.00;
  807. dataScale = ((yAxisHeight - 10) * 1.00) / (maxTick - minTick);
  808. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  809. barL = tickXLocation - (dataPlotSize / 2) + (s * barWidth);
  810. if(barHeight < 0)
  811. {
  812. if((0 - barHeight) > (yAxisHeight / 2))
  813. barT = yApexPoint - (yAxisHeight / 2);
  814. else
  815. barT = yApexPoint - barHeight;
  816. }
  817. else
  818. {
  819. if(barHeight > (yAxisHeight / 2))
  820. barT = yApexPoint - (yAxisHeight / 2);
  821. else
  822. barT = yApexPoint - barHeight;
  823. }
  824. barR = barL + barWidth;
  825. barB = yApexPoint;
  826. COLORREF barColor;
  827. barColor = GetColor(s);
  828. CBrush brush (barColor);
  829. CBrush* pOldBrush;
  830. pOldBrush = pDC->SelectObject(&brush);
  831. pDC->Rectangle(barL, barT, barR, barB);
  832. pDC->SelectObject(pOldBrush);
  833. }
  834. }
  835. break;
  836. case 4 :
  837. for(x = 1; x <= graphSeries->GetCount() / 2; x++)
  838. {
  839. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  840. tickXLocation = xApexPoint - (xAxisWidth / 2) + ((x * seriesSpace) - (seriesSpace / 2));
  841. for(s = 0; s < seriesSize; s++)
  842. {
  843. double dataScale = 0.00;
  844. dataScale = ((yAxisHeight - 10) * 1.00) / (maxTick - minTick);
  845. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  846. barL = tickXLocation - (dataPlotSize / 2) + (s * barWidth);
  847. if(barHeight < 0)
  848. {
  849. if((0 - barHeight) > (yAxisHeight / 2))
  850. barT = yApexPoint - (yAxisHeight / 2);
  851. else
  852. barT = yApexPoint - barHeight;
  853. }
  854. else
  855. {
  856. if(barHeight > (yAxisHeight / 2))
  857. barT = yApexPoint - (yAxisHeight / 2);
  858. else
  859. barT = yApexPoint - barHeight;
  860. }
  861. barR = barL + barWidth;
  862. barB = yApexPoint;
  863. COLORREF barColor;
  864. barColor = GetColor(s);
  865. CBrush brush (barColor);
  866. CBrush* pOldBrush;
  867. pOldBrush = pDC->SelectObject(&brush);
  868. pDC->Rectangle(barL, barT, barR, barB);
  869. pDC->SelectObject(pOldBrush);
  870. }
  871. }
  872. //draw at the 0 location
  873. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  874. tickXLocation = xApexPoint;
  875. for(s = 0; s < seriesSize; s++)
  876. {
  877. double dataScale = 0.00;
  878. dataScale = ((yAxisHeight - 10) * 1.00) / (maxTick - minTick);
  879. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  880. if(((tmpSeries->GetData(s) - minTick) > 0) && (barHeight < 1))
  881. barHeight = (int)dataScale;
  882. barL = tickXLocation - (dataPlotSize / 2) + (s * barWidth);
  883. if(barHeight < 0)
  884. {
  885. if((0 - barHeight) > (yAxisHeight / 2))
  886. barT = yApexPoint - (yAxisHeight / 2);
  887. else
  888. barT = yApexPoint - barHeight;
  889. }
  890. else
  891. {
  892. if(barHeight > (yAxisHeight / 2))
  893. barT = yApexPoint - (yAxisHeight / 2);
  894. else
  895. barT = yApexPoint - barHeight;
  896. }
  897. barR = barL + barWidth;
  898. barB = yApexPoint;
  899. COLORREF barColor;
  900. barColor = GetColor(s);
  901. CBrush brush (barColor);
  902. CBrush* pOldBrush;
  903. pOldBrush = pDC->SelectObject(&brush);
  904. pDC->Rectangle(barL, barT, barR, barB);
  905. pDC->SelectObject(pOldBrush);
  906. }
  907. x++;
  908. for(; x <= graphSeries->GetCount(); x++)
  909. {
  910. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  911. tickXLocation = xApexPoint - (xAxisWidth / 2) + ((x * seriesSpace) - (seriesSpace / 2));
  912. for(s = 0; s < seriesSize; s++)
  913. {
  914. double dataScale = 0.00;
  915. dataScale = ((yAxisHeight - 10) * 1.00) / (maxTick - minTick);
  916. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  917. if(((tmpSeries->GetData(s) - minTick) > 0) && (barHeight < 1))
  918. barHeight = (int)dataScale;
  919. barL = tickXLocation - (dataPlotSize / 2) + (s * barWidth);
  920. if(barHeight < 0)
  921. {
  922. if((0 - barHeight) > (yAxisHeight / 2))
  923. barT = yApexPoint - (yAxisHeight / 2);
  924. else
  925. barT = yApexPoint - barHeight;
  926. }
  927. else
  928. {
  929. if(barHeight > (yAxisHeight / 2))
  930. barT = yApexPoint - (yAxisHeight / 2);
  931. else
  932. barT = yApexPoint - barHeight;
  933. }
  934. barR = barL + barWidth;
  935. barB = yApexPoint;
  936. COLORREF barColor;
  937. barColor = GetColor(s);
  938. CBrush brush (barColor);
  939. CBrush* pOldBrush;
  940. pOldBrush = pDC->SelectObject(&brush);
  941. pDC->Rectangle(barL, barT, barR, barB);
  942. pDC->SelectObject(pOldBrush);
  943. }
  944. }
  945. break;
  946. }
  947. }
  948. else
  949. {
  950. //determine width of barchart data blocks
  951. seriesSpace = yAxisHeight / graphSeries->GetCount();
  952. barHeight = (int)((seriesSpace * .6) / seriesSize);
  953. dataPlotSize = seriesSize * barHeight;
  954. pos = graphSeries->GetHeadPosition();
  955. switch(graphQuadType)
  956. {
  957. case 1 :
  958. for(y = 1; y <= graphSeries->GetCount(); y++)
  959. {
  960. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  961. tickYLocation = yApexPoint - ((y * seriesSpace) - (seriesSpace / 2));
  962. for(s = 0; s < seriesSize; s++)
  963. {
  964. double dataScale = 0.00;
  965. dataScale = ((xAxisWidth - 10) * 1.00) / (maxTick - minTick);
  966. barWidth = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  967. if(((tmpSeries->GetData(s) - minTick) > 0) && (barWidth < 1))
  968. barWidth = (int)dataScale;
  969. barL = xApexPoint;
  970. barT = tickYLocation - (dataPlotSize / 2) + (s * barHeight);
  971. barB = barT + barHeight;
  972. if(barWidth > xAxisWidth)
  973. barR = xApexPoint + xAxisWidth;
  974. else
  975. barR = xApexPoint + barWidth;
  976. COLORREF barColor;
  977. barColor = GetColor(s);
  978. CBrush brush (barColor);
  979. CBrush* pOldBrush;
  980. pOldBrush = pDC->SelectObject(&brush);
  981. pDC->Rectangle(barL, barT, barR, barB);
  982. pDC->SelectObject(pOldBrush);
  983. }
  984. }
  985. break;
  986. case 2 :
  987. for(y = 1; y <= graphSeries->GetCount(); y++)
  988. {
  989. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  990. tickYLocation = yApexPoint - ((y * seriesSpace) - (seriesSpace / 2));
  991. for(s = 0; s < seriesSize; s++)
  992. {
  993. double dataScale = 0.00;
  994. dataScale = ((xAxisWidth - 10) * 1.00) / (maxTick - minTick);
  995. barWidth = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  996. if(((tmpSeries->GetData(s) - minTick) > 0) && (barWidth < 1))
  997. barWidth = (int)dataScale;
  998. barL = xApexPoint;
  999. barT = tickYLocation - (dataPlotSize / 2) + (s * barHeight);
  1000. barB = barT + barHeight;
  1001. if(barWidth < 0)
  1002. {
  1003. if((0 - barWidth) > (xAxisWidth / 2))
  1004. barR = xApexPoint + (xAxisWidth / 2);
  1005. else
  1006. barR = xApexPoint + barWidth;
  1007. }
  1008. else
  1009. {
  1010. if(barWidth > (xAxisWidth / 2))
  1011. barR = xApexPoint + (xAxisWidth / 2);
  1012. else
  1013. barR = xApexPoint + barWidth;
  1014. }
  1015. COLORREF barColor;
  1016. barColor = GetColor(s);
  1017. CBrush brush (barColor);
  1018. CBrush* pOldBrush;
  1019. pOldBrush = pDC->SelectObject(&brush);
  1020. pDC->Rectangle(barL, barT, barR, barB);
  1021. pDC->SelectObject(pOldBrush);
  1022. }
  1023. }
  1024. break;
  1025. case 3 :
  1026. for(y = 1; y <= graphSeries->GetCount(); y++)
  1027. {
  1028. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  1029. tickYLocation = yApexPoint - (yAxisHeight / 2) + ((y * seriesSpace) - (seriesSpace / 2));
  1030. for(s = 0; s < seriesSize; s++)
  1031. {
  1032. double dataScale = 0.00;
  1033. dataScale = ((xAxisWidth - 10) * 1.00) / (maxTick - minTick);
  1034. barWidth = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  1035. if(((tmpSeries->GetData(s) - minTick) > 0) && (barWidth < 1))
  1036. barWidth = (int)dataScale;
  1037. barL = xApexPoint;
  1038. barT = tickYLocation - (dataPlotSize / 2) + (s * barHeight);
  1039. barB = barT + barHeight;
  1040. if(barWidth > xAxisWidth)
  1041. barR = xApexPoint + xAxisWidth;
  1042. else
  1043. barR = xApexPoint + barWidth;
  1044. COLORREF barColor;
  1045. barColor = GetColor(s);
  1046. CBrush brush (barColor);
  1047. CBrush* pOldBrush;
  1048. pOldBrush = pDC->SelectObject(&brush);
  1049. pDC->Rectangle(barL, barT, barR, barB);
  1050. pDC->SelectObject(pOldBrush);
  1051. }
  1052. }
  1053. break;
  1054. case 4 :
  1055. for(y = 1; y <= graphSeries->GetCount() / 2; y++)
  1056. {
  1057. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  1058. tickYLocation = yApexPoint - (yAxisHeight / 2) + ((y * seriesSpace) - (seriesSpace / 2));
  1059. for(s = 0; s < seriesSize; s++)
  1060. {
  1061. double dataScale = 0.00;
  1062. dataScale = ((xAxisWidth - 10) * 1.00) / (maxTick - minTick);
  1063. barWidth = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  1064. if(((tmpSeries->GetData(s) - minTick) > 0) && (barWidth < 1))
  1065. barWidth = (int)dataScale;
  1066. barL = xApexPoint;
  1067. barT = tickYLocation - (dataPlotSize / 2) + (s * barHeight);
  1068. barB = barT + barHeight;
  1069. if(barWidth < 0)
  1070. {
  1071. if((0 - barWidth) > (xAxisWidth / 2))
  1072. barR = xApexPoint + (xAxisWidth / 2);
  1073. else
  1074. barR = xApexPoint + barWidth;
  1075. }
  1076. else
  1077. {
  1078. if(barWidth > (xAxisWidth / 2))
  1079. barR = xApexPoint + (xAxisWidth / 2);
  1080. else
  1081. barR = xApexPoint + barWidth;
  1082. }
  1083. COLORREF barColor;
  1084. barColor = GetColor(s);
  1085. CBrush brush (barColor);
  1086. CBrush* pOldBrush;
  1087. pOldBrush = pDC->SelectObject(&brush);
  1088. pDC->Rectangle(barL, barT, barR, barB);
  1089. pDC->SelectObject(pOldBrush);
  1090. }
  1091. }
  1092. //draw the 0 location
  1093. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  1094. tickYLocation = yApexPoint;
  1095. for(s = 0; s < seriesSize; s++)
  1096. {
  1097. double dataScale = 0.00;
  1098. dataScale = ((xAxisWidth - 10) * 1.00) / (maxTick - minTick);
  1099. barWidth = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  1100. if(((tmpSeries->GetData(s) - minTick) > 0) && (barWidth < 1))
  1101. barWidth = (int)dataScale;
  1102. barL = xApexPoint;
  1103. barT = tickYLocation - (dataPlotSize / 2) + (s * barHeight);
  1104. barB = barT + barHeight;
  1105. if(barWidth < 0)
  1106. {
  1107. if((0 - barWidth) > (xAxisWidth / 2))
  1108. barR = xApexPoint + (xAxisWidth / 2);
  1109. else
  1110. barR = xApexPoint + barWidth;
  1111. }
  1112. else
  1113. {
  1114. if(barWidth > (xAxisWidth / 2))
  1115. barR = xApexPoint + (xAxisWidth / 2);
  1116. else
  1117. barR = xApexPoint + barWidth;
  1118. }
  1119. COLORREF barColor;
  1120. barColor = GetColor(s);
  1121. CBrush brush (barColor);
  1122. CBrush* pOldBrush;
  1123. pOldBrush = pDC->SelectObject(&brush);
  1124. pDC->Rectangle(barL, barT, barR, barB);
  1125. pDC->SelectObject(pOldBrush);
  1126. }
  1127. y++;
  1128. for(; y <= graphSeries->GetCount(); y++)
  1129. {
  1130. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  1131. tickYLocation = yApexPoint - (yAxisHeight / 2) + ((y * seriesSpace) - (seriesSpace / 2));
  1132. for(s = 0; s < seriesSize; s++)
  1133. {
  1134. double dataScale = 0.00;
  1135. dataScale = ((xAxisWidth - 10) * 1.00) / (maxTick - minTick);
  1136. barWidth = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  1137. if(((tmpSeries->GetData(s) - minTick) > 0) && (barWidth < 1))
  1138. barWidth = (int)dataScale;
  1139. barL = xApexPoint;
  1140. barT = tickYLocation - (dataPlotSize / 2) + (s * barHeight);
  1141. barB = barT + barHeight;
  1142. if(barWidth < 0)
  1143. {
  1144. if((0 - barWidth) > (xAxisWidth / 2))
  1145. barR = xApexPoint + (xAxisWidth / 2);
  1146. else
  1147. barR = xApexPoint + barWidth;
  1148. }
  1149. else
  1150. {
  1151. if(barWidth > (xAxisWidth / 2))
  1152. barR = xApexPoint + (xAxisWidth / 2);
  1153. else
  1154. barR = xApexPoint + barWidth;
  1155. }
  1156. COLORREF barColor;
  1157. barColor = GetColor(s);
  1158. CBrush brush (barColor);
  1159. CBrush* pOldBrush;
  1160. pOldBrush = pDC->SelectObject(&brush);
  1161. pDC->Rectangle(barL, barT, barR, barB);
  1162. pDC->SelectObject(pOldBrush);
  1163. }
  1164. }
  1165. break;
  1166. }
  1167. }
  1168. }
  1169. void CGraph::DrawLineSeries(CDC* pDC)
  1170. {
  1171. int barWidth;
  1172. int dataPlotSize;   //used to plot rects of data
  1173. int tickXLocation, tickYLocation;
  1174. int seriesSpace;
  1175. int barHeight;
  1176. POSITION pos;
  1177. CGraphSeries* tmpSeries;
  1178. int lastXLoc, lastYLoc;
  1179. if(graphAlignment)
  1180. {
  1181. for(int s = 0; s < seriesSize; s++)
  1182. {
  1183. //determine width of barchart data blocks
  1184. seriesSpace = xAxisWidth / graphSeries->GetCount();
  1185. barWidth = (int)((seriesSpace * .6) / seriesSize);
  1186. dataPlotSize = seriesSize * barWidth;
  1187. pos = graphSeries->GetHeadPosition();
  1188. for(int x = 1; x <= graphSeries->GetCount(); x++)
  1189. {
  1190. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  1191. if(tmpSeries->GetData(s) > -1)
  1192. {
  1193. tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
  1194. barHeight = 0;
  1195. double dataScale = 0.00;
  1196. dataScale = ((yAxisHeight - 10) * 1.00) / (maxTick - minTick);
  1197. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  1198. if(((tmpSeries->GetData(s) - minTick) > 0) && (barHeight < 1))
  1199. barHeight = (int)dataScale;
  1200. if(barHeight > yApexPoint)
  1201. barHeight = (int)((maxTick - minTick) * dataScale) + 5;
  1202. int yDataLocation = yApexPoint - barHeight;
  1203. //now have x and y location of center of ellipse
  1204. COLORREF barColor;
  1205. barColor = GetColor(s);
  1206. CBrush brush (barColor);
  1207. CBrush* pOldBrush;
  1208. pOldBrush = pDC->SelectObject(&brush);
  1209. //draw line back to last data member
  1210. if(x > 1)
  1211. {
  1212. CPen* pOldPen;
  1213. CPen linePen (PS_SOLID, 1, barColor);
  1214. pOldPen = pDC->SelectObject(&linePen);
  1215. pDC->MoveTo(lastXLoc + 2, lastYLoc - 1);
  1216. pDC->LineTo(tickXLocation - 3, yDataLocation - 1);
  1217. pDC->SelectObject(pOldPen);
  1218. }
  1219. //now draw ellipse...
  1220. pDC->Ellipse(tickXLocation - 3, yDataLocation - 3,
  1221. tickXLocation + 3, yDataLocation + 3);
  1222. lastXLoc = tickXLocation;
  1223. lastYLoc = yDataLocation;
  1224. pDC->SelectObject(pOldBrush);
  1225. }
  1226. }
  1227. }
  1228. }
  1229. else
  1230. {
  1231. for(int s = 0; s < seriesSize; s++)
  1232. {
  1233. //determine width of barchart data blocks
  1234. seriesSpace = yAxisHeight / graphSeries->GetCount();
  1235. barHeight = (int)((seriesSpace * .6) / seriesSize);
  1236. dataPlotSize = seriesSize * barHeight;
  1237. pos = graphSeries->GetHeadPosition();
  1238. for(int x = 1; x <= graphSeries->GetCount(); x++)
  1239. {
  1240. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  1241. if(tmpSeries->GetData(s) > -1)
  1242. {
  1243. tickYLocation = yApexPoint - ((x * seriesSpace) - (seriesSpace / 2));
  1244. barWidth = 0;
  1245. double dataScale = 0.00;
  1246. if((maxTick - minTick) != xAxisWidth)
  1247. dataScale = (xAxisWidth * 1.00) / ((maxTick - minTick) * 1.00);
  1248. else dataScale = 1;
  1249. barWidth = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  1250. if(((tmpSeries->GetData(s) - minTick) > 0) && (barWidth < 1))
  1251. barWidth = (int)dataScale;
  1252. int xDataLocation = xApexPoint + barWidth;
  1253. //now have x and y location of center of ellipse
  1254. COLORREF barColor;
  1255. barColor = GetColor(s);
  1256. CBrush brush (barColor);
  1257. CBrush* pOldBrush;
  1258. pOldBrush = pDC->SelectObject(&brush);
  1259. //draw line back to last data member
  1260. if(x > 1)
  1261. {
  1262. CPen* pOldPen;
  1263. CPen linePen (PS_SOLID, 1, barColor);
  1264. pOldPen = pDC->SelectObject(&linePen);
  1265. pDC->MoveTo(lastXLoc + 2, lastYLoc - 1);
  1266. pDC->LineTo(xDataLocation - 3, tickYLocation - 1);
  1267. pDC->SelectObject(pOldPen);
  1268. }
  1269. //now draw ellipse...
  1270. pDC->Ellipse(xDataLocation - 3, tickYLocation - 3,
  1271. xDataLocation + 3, tickYLocation + 3);
  1272. lastYLoc = tickYLocation;
  1273. lastXLoc = xDataLocation;
  1274. pDC->SelectObject(pOldBrush);
  1275. }
  1276. }
  1277. }
  1278. }
  1279. }
  1280. void CGraph::DrawPieSeries(CDC* pDC)
  1281. {
  1282. double dataSum = 0.00;  //for storing cumulative sum
  1283. double labelData = 0.00;
  1284. int lastXLocation, lastYLocation;
  1285. int newXLocation, newYLocation;
  1286. int labelXLocation, labelYLocation;
  1287. double percent = 0.00;
  1288. double labelPercent = 0.00;
  1289. int degrees;
  1290. int labelDegrees;
  1291. double totalSum = 0.00;
  1292. int deltaXY;
  1293. int labelDeltaXY;
  1294. int radius;
  1295. POSITION pos;
  1296. CGraphSeries* tmpSeries;
  1297. int seriesSpace;
  1298. int labelLineXStart, labelLineYStart;
  1299. int labelLineXEnd, labelLineYEnd;
  1300. int maxLabelWidth;
  1301. int maxLabelHeight;
  1302. TEXTMETRIC tm;
  1303. lastXLocation = 0;
  1304. lastYLocation = 0;
  1305. pDC->GetTextMetrics(&tm);
  1306. maxLabelWidth = tm.tmMaxCharWidth + 10;
  1307. maxLabelHeight = tm.tmHeight + 6;
  1308. //pie labels will be stored in a list and drawn after entire pie
  1309. //is completed.
  1310. CObList *pieLabels;
  1311. CGraphPieLabel *pieLabel;
  1312. //determine width of pie display area
  1313. if(xAxisWidth > yAxisHeight)
  1314. seriesSpace = yAxisHeight / graphSeries->GetCount();
  1315. else
  1316. seriesSpace = xAxisWidth / graphSeries->GetCount();
  1317. seriesSpace -= (3 * maxLabelWidth);  //allows text like 25%  (3 chars)
  1318. //to plot a pie plus labels inside of series space, use the following :
  1319. //(3 * radius) + (2 * label width) = series space 
  1320. //so, 3*radius = series space - (2 * label width)
  1321. // 1 radius = (series space - (2 * label width)) / 3
  1322. radius = seriesSpace / 3;  //pie needs 2 radius, + 1 extra for line to labels = 3 for my divisor
  1323. int centerYPie = (yAxisHeight + 60) / 2;
  1324. pos = graphSeries->GetHeadPosition();
  1325. for(int x = 1; x <= graphSeries->GetCount(); x++)
  1326. {
  1327. pieLabels = new CObList();
  1328. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  1329. totalSum = 0;
  1330. for(int s = 0; s < seriesSize; s++)
  1331. totalSum += tmpSeries->GetData(s);
  1332. int pieLeft, pieRight;
  1333. if(graphSeries->GetCount() == 1)
  1334. {
  1335. pieLeft = xApexPoint + (xAxisWidth / 2) - radius;
  1336. }
  1337. else
  1338. {
  1339. pieLeft = xApexPoint + 15 + ((x * 2 - 1) * ((xAxisWidth / graphSeries->GetCount()) / 2)) - radius;
  1340. }
  1341. pieRight = pieLeft + (2 * radius);
  1342. CRect pieRect (pieLeft, 
  1343. centerYPie - radius,
  1344. pieRight, 
  1345. centerYPie + radius);
  1346. int centerXPie = pieLeft + radius;
  1347. //plot series label
  1348. pDC->TextOut(centerXPie - ((tmpSeries->GetLabel().GetLength() * 8) / 2),
  1349. centerYPie + (int)(radius * 1.5) + maxLabelHeight + 15, tmpSeries->GetLabel());
  1350. lastXLocation = pieLeft;
  1351. lastYLocation = centerYPie;
  1352. dataSum = 0;
  1353. for(s = 0; s < seriesSize; s++)
  1354. {
  1355. if(tmpSeries->GetData(s) > 0)
  1356. {
  1357. int seriesDataValue;
  1358. seriesDataValue = tmpSeries->GetData(s);
  1359. labelData = seriesDataValue / 2;
  1360. dataSum += seriesDataValue;
  1361. percent = (dataSum / totalSum) * 100;
  1362. labelPercent = ((dataSum - labelData) / totalSum) * 100;
  1363. degrees = (int)((360 * percent) / 100);
  1364. labelDegrees = (int)((360 * labelPercent) / 100);
  1365. deltaXY = (degrees * radius) / 90;
  1366. labelDeltaXY = (labelDegrees * radius) / 90;
  1367. //deltaXY is change from start point of pie 0
  1368. //this value is total change.  so if radius is 300
  1369. //and degrees is 270, delta is 300.  The change 
  1370. //would move both x and y 300 pixels.  For x, 100
  1371. //to right is center, another 100 to right edge,
  1372. //100 back to center.  For y, 100 to bottom, 100
  1373. //back to center, 100 to top. thus gives 270 degree
  1374. //rotation.
  1375. //determine destination quadrant...
  1376. //and set newXLocation and newYLocation values...
  1377. //degress / 90 will never exceed 4.
  1378. //this can tell us the quadrant of destination
  1379. int quadrant = degrees / 90;  //truncates decimal
  1380. int labelQuadrant = labelDegrees / 90;
  1381. switch(quadrant)
  1382. {
  1383. //in the computations below, the remarked line is
  1384. //the original computation.  The line above it, for
  1385. //actual use, is the simplified line, and gives the
  1386. //exact same result
  1387. case 0 : newXLocation = pieLeft + deltaXY;
  1388.  newYLocation = centerYPie + deltaXY;
  1389.  break;
  1390. case 1 : newXLocation = pieLeft + deltaXY;
  1391.  newYLocation = centerYPie + (2 * radius) - deltaXY;
  1392.  break;
  1393. case 2 : newXLocation = pieLeft + (4 * radius) - deltaXY;
  1394.  newYLocation = centerYPie + (2 * radius) - deltaXY;
  1395.  break;
  1396. case 3 : newXLocation = pieLeft + (4 * radius) - deltaXY;
  1397.  newYLocation = centerYPie - (4 * radius) + deltaXY;
  1398.  break;
  1399. case 4 : newXLocation = pieLeft;
  1400.  newYLocation = centerYPie - 1;
  1401.  break;
  1402. }
  1403. switch(labelQuadrant)
  1404. {
  1405. //after getting X & Y location for label, we take
  1406. //1/2 the delta between x y locations and center pie
  1407. case 0 : labelXLocation = pieLeft + labelDeltaXY;
  1408.  labelYLocation = centerYPie + labelDeltaXY;
  1409.  labelLineXStart = labelXLocation + ((centerXPie - labelXLocation) / 2);
  1410.  labelLineYStart = labelYLocation - ((labelYLocation - centerYPie) / 2);
  1411.  labelLineXEnd = labelXLocation - (radius / 2);
  1412.  labelLineYEnd = labelYLocation + (radius / 2);
  1413.  break;
  1414. case 1 : labelXLocation = pieLeft + labelDeltaXY;
  1415.  labelYLocation = centerYPie + (2 * radius) - labelDeltaXY;
  1416.  labelLineXStart = labelXLocation - ((labelXLocation - centerXPie) / 2);
  1417.  labelLineYStart = labelYLocation - ((labelYLocation - centerYPie) / 2);
  1418.  labelLineXEnd = labelXLocation + (radius / 2);
  1419.  labelLineYEnd = labelYLocation + (radius / 2);
  1420.  break;
  1421. case 2 : labelXLocation = pieLeft + (4 * radius) - labelDeltaXY;
  1422.  labelYLocation = centerYPie + (2 * radius) - labelDeltaXY;
  1423.  labelLineXStart = labelXLocation - ((labelXLocation - centerXPie) / 2);
  1424.  labelLineYStart = labelYLocation + ((centerYPie - labelYLocation) / 2);
  1425.  labelLineXEnd = labelXLocation + (radius / 2);
  1426.  labelLineYEnd = labelYLocation - (radius / 2);
  1427.  break;
  1428. case 3 : labelXLocation = pieLeft + (4 * radius) - labelDeltaXY;
  1429.  labelYLocation = centerYPie - (4 * radius) + labelDeltaXY;
  1430.  labelLineXStart = labelXLocation + ((centerXPie - labelXLocation) / 2);
  1431.  labelLineYStart = labelYLocation + ((centerYPie - labelYLocation) / 2);
  1432.  labelLineXEnd = labelXLocation - (radius / 2);
  1433.  labelLineYEnd = labelYLocation - (radius / 2);
  1434.  break;
  1435. //there should never be a half point ending on 4, so leave it out
  1436. }
  1437. pieLabel = new CGraphPieLabel();
  1438. pieLabel->lineXStart = labelLineXStart;
  1439. pieLabel->lineYStart = labelLineYStart;
  1440. pieLabel->lineXEnd = labelLineXEnd;
  1441. pieLabel->lineYEnd = labelLineYEnd;
  1442. switch(labelQuadrant)
  1443. {
  1444. case 0 : //label to left of line
  1445.  pieLabel->topLeftX = labelLineXEnd - maxLabelWidth;
  1446.  pieLabel->topLeftY = labelLineYEnd;
  1447.  break;
  1448. case 1 : //label to right of line
  1449.  pieLabel->topLeftX = labelLineXEnd + 5;
  1450.  pieLabel->topLeftY = labelLineYEnd;
  1451.  break;
  1452. case 2 : //label to right of line
  1453.  pieLabel->topLeftX = labelLineXEnd + 5;
  1454.  pieLabel->topLeftY = labelLineYEnd - maxLabelHeight;
  1455.  break;
  1456. case 3 : //label to left of line
  1457.  pieLabel->topLeftX = labelLineXEnd - maxLabelWidth;
  1458.  pieLabel->topLeftY = labelLineYEnd - maxLabelHeight;
  1459.  break;
  1460. }
  1461. pieLabel->labelQuadrant = labelQuadrant;
  1462. int roundPercent;
  1463. roundPercent = (int)((seriesDataValue * 100) / totalSum);
  1464. pieLabel->pieLabel.Format("%d%%", roundPercent);
  1465. pieLabels->AddTail(pieLabel);
  1466. if(s == 0)
  1467. lastYLocation -= 1;
  1468. CPoint p1 (lastXLocation, lastYLocation);
  1469. CPoint p2 (newXLocation, newYLocation);
  1470. COLORREF barColor;
  1471. barColor = GetColor(s);
  1472. CBrush brush (barColor);
  1473. CBrush* pOldBrush;
  1474. CPen piePen(PS_SOLID, 1, barColor);
  1475. CPen* pOldPen;
  1476. pOldBrush = pDC->SelectObject(&brush);
  1477. pOldPen = pDC->SelectObject(&piePen);
  1478. pDC->Pie(pieRect, p1, p2); 
  1479. pDC->SelectObject(pOldBrush);
  1480. pDC->SelectObject(pOldPen);
  1481. lastXLocation = newXLocation;
  1482. lastYLocation = newYLocation;
  1483. }
  1484. }
  1485. //draw lines and labels for pies slices
  1486. POSITION labelPos;
  1487. CBrush lineBrush (BLACK);
  1488. CBrush* pOldBrush;
  1489. pOldBrush = pDC->SelectObject(&lineBrush);
  1490. POSITION mainLinePos, checkLinePos;
  1491. mainLinePos = pieLabels->GetHeadPosition();
  1492. int numLinesDrawn = 0;
  1493. CGraphPieLabel* currentLabel;
  1494. CGraphPieLabel* tmpLabel;
  1495. while(mainLinePos != NULL)
  1496. {
  1497. currentLabel = (CGraphPieLabel*)pieLabels->GetNext(mainLinePos);
  1498. int r = 0;
  1499. checkLinePos = pieLabels->GetHeadPosition();
  1500. while(r < numLinesDrawn)
  1501. {
  1502. //check if any overlap in label areas
  1503. tmpLabel = (CGraphPieLabel*)pieLabels->GetAt(checkLinePos);
  1504. if((currentLabel->topLeftX > tmpLabel->topLeftX) &&
  1505. (currentLabel->topLeftX < (tmpLabel->topLeftX + maxLabelWidth)) &&
  1506. (currentLabel->topLeftY > tmpLabel->topLeftY) &&
  1507. (currentLabel->topLeftY < (tmpLabel->topLeftY + maxLabelHeight)))
  1508. {
  1509. //OVERLAP !!!
  1510. //move current label top left position up or down
  1511. //depending on its quadrant
  1512. if(currentLabel->labelQuadrant < 2)
  1513. {
  1514. //move label down to tmplabel topleft + height
  1515. currentLabel->topLeftY = tmpLabel->topLeftY + maxLabelHeight;
  1516. currentLabel->lineYEnd = tmpLabel->lineYEnd + maxLabelHeight;
  1517. }
  1518. else
  1519. {
  1520. //move label up to tmpLabel topleft - height
  1521. currentLabel->topLeftY = tmpLabel->topLeftY - maxLabelHeight;
  1522. currentLabel->lineYEnd = tmpLabel->lineYEnd - maxLabelHeight;
  1523. }
  1524. //reset r value to 0 so it starts over, just in
  1525. //case we moved the label and it overlaps another
  1526. r = 0;
  1527. checkLinePos = pieLabels->GetHeadPosition();
  1528. }
  1529. else
  1530. {
  1531. r++;
  1532. pieLabels->GetNext(checkLinePos);
  1533. }
  1534. }
  1535. //draw the line and label
  1536. pDC->MoveTo(currentLabel->lineXStart, currentLabel->lineYStart);
  1537. pDC->LineTo(currentLabel->lineXEnd, currentLabel->lineYEnd);
  1538. //write the label
  1539. pDC->TextOut(currentLabel->topLeftX, currentLabel->topLeftY,
  1540. currentLabel->pieLabel);
  1541. numLinesDrawn++;
  1542. }
  1543. pDC->SelectObject(pOldBrush);
  1544. //now done, remove everything inside the label list
  1545. labelPos = pieLabels->GetHeadPosition();
  1546. while(labelPos != NULL)
  1547. {
  1548. pieLabel = (CGraphPieLabel*)pieLabels->GetNext(labelPos);
  1549. delete pieLabel;
  1550. }
  1551. delete pieLabels;
  1552. }
  1553. }
  1554. void CGraph::DrawScatterSeries(CDC* pDC)
  1555. {
  1556. //rightXTick and topYTick contain the outer bounds of the axis ticks.
  1557. //So, if maxTick is 100 on both axis lines, then 100, 100 would be top
  1558. //right.  We will use the bounds to see spacing from apex points and then
  1559. //scale so any point can be plotted inside
  1560. double yAxisScale, xAxisScale;
  1561. int tickXLocation, tickYLocation;
  1562. //multiply each value by 1.00 to force result into a double value, and therefore
  1563. //make it more accurate in it's plot location.
  1564. switch(graphQuadType)
  1565. {
  1566. case 1 :
  1567. yAxisScale = ((yApexPoint - topYTick) / (maxTick * 1.00));
  1568. xAxisScale = ((rightXTick - xApexPoint) / (maxTick * 1.00));
  1569. break;
  1570. case 2 :
  1571. yAxisScale = ((yApexPoint - topYTick) / (maxTick * 1.00));
  1572. xAxisScale = ((rightXTick - xApexPoint) / (maxTick * 1.00));
  1573. break;
  1574. case 3 :
  1575. yAxisScale = ((topYTick - yApexPoint) / (maxTick * 1.00));
  1576. xAxisScale = ((rightXTick - xApexPoint) / (maxTick * 1.00));
  1577. break;
  1578. case 4 :
  1579. yAxisScale = ((topYTick - yApexPoint) / (maxTick * 1.00));
  1580. xAxisScale = ((rightXTick - xApexPoint) / (maxTick * 1.00));
  1581. break;
  1582. }
  1583. //points will now plot as ((value * scale) + apex point)
  1584. COLORREF barColor;
  1585. barColor = BLACK;
  1586. CBrush brush (barColor);
  1587. CBrush* pOldBrush;
  1588. pOldBrush = pDC->SelectObject(&brush);
  1589. POSITION pos;
  1590. CGraphSeries* tmpSeries;
  1591. for(pos = graphSeries->GetHeadPosition(); pos != NULL; graphSeries->GetNext(pos))
  1592. {
  1593. tmpSeries = (CGraphSeries*)graphSeries->GetAt(pos);
  1594. //multiply each value by 1.00 to force result into a double value, and therefore
  1595. //make it more accurate in it's plot location.
  1596. tickXLocation = (int)((tmpSeries->GetXDataValue() * 1.00) * xAxisScale) + xApexPoint;
  1597. tickYLocation = yApexPoint - (int)((tmpSeries->GetYDataValue() * 1.00) * yAxisScale);
  1598. //draw ellipse...
  1599. pDC->Ellipse(tickXLocation - 3, tickYLocation - 3,
  1600. tickXLocation + 3, tickYLocation + 3);
  1601. }
  1602. pDC->SelectObject(pOldBrush);
  1603. }
  1604. void CGraph::DrawBoxWhiskerSeries(CDC* pDC)
  1605. {
  1606. int upperQuartile;
  1607. int lowerQuartile;
  1608. int median;
  1609. int highValue;
  1610. int lowValue;
  1611. COLORREF barColor;
  1612. barColor = BLACK;
  1613. CBrush brush (barColor);
  1614. CBrush* pOldBrush;
  1615. pOldBrush = pDC->SelectObject(&brush);
  1616. int barWidth;
  1617. int barL, barT, barR, barB;
  1618. int tickXLocation, tickYLocation;
  1619. int seriesSpace;
  1620. int barHeight;
  1621. POSITION pos;
  1622. CGraphSeries* tmpSeries;
  1623. pos = graphSeries->GetHeadPosition();
  1624. CUIntArray dataArray;
  1625. CUIntArray sortedArray;
  1626. for(int x = 1; x <= graphSeries->GetCount(); x++)
  1627. {
  1628. dataArray.RemoveAll();
  1629. sortedArray.RemoveAll();
  1630. CObList *sortedData;
  1631. sortedData = new CObList();
  1632. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  1633. seriesSize = tmpSeries->GetDataCount();
  1634. int dataValue;
  1635. for(int s = 0; s < seriesSize; s++)
  1636. {
  1637. dataValue = 0;
  1638. if(tmpSeries->GetData(s) > -1)
  1639. dataValue = tmpSeries->GetData(s);
  1640. dataArray.Add(dataValue);
  1641. }
  1642. //sort the array
  1643. dataValue = dataArray.GetAt(0);
  1644. sortedArray.Add(dataValue);
  1645. for(int d = 1; d < dataArray.GetSize(); d++)
  1646. {
  1647. dataValue = dataArray.GetAt(d);
  1648. BOOL placed = FALSE;
  1649. for(int s = 0; s < sortedArray.GetSize(); s++)
  1650. {
  1651. int tmpI = sortedArray.GetAt(s);
  1652. if(dataValue <= tmpI)
  1653. {
  1654. sortedArray.InsertAt(s, dataValue);
  1655. placed = TRUE;
  1656. break;
  1657. }
  1658. }
  1659. if(!placed) //add at end
  1660. sortedArray.Add(dataValue);
  1661. }
  1662. //sortedArray now contains the sorted list of all data in this
  1663. //series.  From here, we derive the other box-whisker data
  1664. int medialElement;
  1665. div_t div_result;
  1666. div_result = div(sortedArray.GetSize(), 2);
  1667. if(div_result.rem == 0) //even number of elements
  1668. {
  1669. //size is not 0 base, so below, I subtract 1 to 0 base it.
  1670. medialElement = (sortedArray.GetSize() / 2) - 1;
  1671. median = sortedArray.GetAt(medialElement) + 
  1672. ((sortedArray.GetAt(medialElement + 1) - 
  1673. sortedArray.GetAt(medialElement)) / 2);
  1674. highValue = sortedArray.GetAt(sortedArray.GetSize() - 1);
  1675. lowValue = sortedArray.GetAt(0);
  1676. div_t div2Result;
  1677. div2Result = div(medialElement + 1, 2);
  1678. if(div2Result.rem == 0) //even again
  1679. {
  1680. upperQuartile = sortedArray.GetAt(medialElement + 1 + (medialElement / 2)) +
  1681. (sortedArray.GetAt(medialElement + (medialElement / 2) + 2) -
  1682. sortedArray.GetAt(medialElement + (medialElement / 2))) / 2;
  1683. lowerQuartile = sortedArray.GetAt(medialElement / 2) +
  1684. ((sortedArray.GetAt((medialElement / 2) + 1) -
  1685. sortedArray.GetAt(medialElement / 2)) / 2);
  1686. }
  1687. else //odd
  1688. {
  1689. upperQuartile = sortedArray.GetAt(medialElement + 1 + (medialElement / 2));
  1690. lowerQuartile = sortedArray.GetAt(medialElement / 2);
  1691. }
  1692. }
  1693. else //odd number of elements
  1694. {
  1695. //size is not 0 base, so below, I subtract 1 to 0 base it.
  1696. medialElement = sortedArray.GetSize() / 2;
  1697. median = sortedArray.GetAt(medialElement);
  1698. highValue = sortedArray.GetAt(sortedArray.GetSize() - 1);
  1699. lowValue = sortedArray.GetAt(0);
  1700. div_t div2Result;
  1701. div2Result = div(medialElement, 2);
  1702. if(div2Result.rem == 0) //even 
  1703. {
  1704. upperQuartile = sortedArray.GetAt(medialElement + (medialElement / 2)) +
  1705. (sortedArray.GetAt(medialElement + (medialElement / 2) + 1) -
  1706. sortedArray.GetAt(medialElement + (medialElement / 2))) / 2;
  1707. lowerQuartile = sortedArray.GetAt((medialElement - 1) / 2) +
  1708. ((sortedArray.GetAt((medialElement + 1) / 2) -
  1709. sortedArray.GetAt((medialElement - 1) / 2)) / 2);
  1710. }
  1711. else //odd
  1712. {
  1713. upperQuartile = sortedArray.GetAt(medialElement + 1 + (medialElement / 2));
  1714. lowerQuartile = sortedArray.GetAt(medialElement / 2);
  1715. }
  1716. }
  1717. //data has been computed for median, high, low, and interquartile range
  1718. //now we can draw the series
  1719. if(graphAlignment)
  1720. {
  1721. seriesSpace = xAxisWidth / graphSeries->GetCount();
  1722. barWidth = (int)(seriesSpace * .8);
  1723. double tickScale = 0.00;
  1724. tickScale = (yAxisHeight - 10) / numTicks;
  1725. tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
  1726. barL = tickXLocation - (barWidth / 2);
  1727. barR = barL + barWidth;
  1728. double dataScale = 0.00;
  1729. dataScale = ((yAxisHeight - 10) * 1.00) / (maxTick - minTick);
  1730. //top cross bar (max value)
  1731. barHeight = (int)((highValue * 1.00) * tickScale);
  1732. barT = yApexPoint - barHeight;
  1733. barB = barT + 3;
  1734. pDC->Rectangle(barL, barT, barR, barB);
  1735. //bottom cross bar (min value)
  1736. barHeight = (int)((lowValue * 1.00) * tickScale);
  1737. barT = yApexPoint - barHeight;
  1738. barB = barT - 3;
  1739. pDC->Rectangle(barL, barT, barR, barB);
  1740. //vertical line (whisker)
  1741. barHeight = (int)((highValue * 1.00) * tickScale);
  1742. barT = yApexPoint - barHeight;
  1743. //barB = ?; //this will be left over from bottom cross bar
  1744. pDC->Rectangle(tickXLocation - 2, barT, tickXLocation + 2, barB);
  1745. //box (interquartile range, from upper quartile to lower quartile)
  1746. barHeight = (int)(upperQuartile * tickScale);
  1747. barT = yApexPoint - barHeight;
  1748. barHeight = (int)(lowerQuartile * tickScale);
  1749. barB = yApexPoint - barHeight;
  1750. pDC->Rectangle(barL, barT, barR, barB);
  1751. //draw median line (in RED)
  1752. CPen* pOldPen;
  1753. CPen linePen (PS_SOLID, 1, RED);
  1754. pOldPen = pDC->SelectObject(&linePen);
  1755. barHeight = (int)((median * 1.00) * tickScale);
  1756. pDC->MoveTo(barL, yApexPoint - barHeight);
  1757. pDC->LineTo(barR, yApexPoint - barHeight);
  1758. pDC->SelectObject(pOldPen);
  1759. }
  1760. else
  1761. {
  1762. seriesSpace = yAxisHeight / graphSeries->GetCount();
  1763. barHeight = (int)(seriesSpace * .8);
  1764. double tickScale = 0.00;
  1765. tickScale = (xAxisWidth - 10) / numTicks;
  1766. tickYLocation = yApexPoint - ((x * seriesSpace) - (seriesSpace / 2));
  1767. barT = tickYLocation - (barHeight / 2);
  1768. barB = barT + barHeight;
  1769. double dataScale = 0.00;
  1770. dataScale = ((xAxisWidth - 10) * 1.00) / (maxTick - minTick);
  1771. //top cross bar (max value)
  1772. barWidth = (int)((highValue * 1.00) * tickScale);
  1773. barR = xApexPoint + barWidth;
  1774. barL = barR - 3;
  1775. pDC->Rectangle(barL, barT, barR, barB);
  1776. //bottom cross bar (min value)
  1777. barWidth = (int)((lowValue * 1.00) * tickScale);
  1778. barR = xApexPoint + barWidth;
  1779. barL = barR + 3;
  1780. pDC->Rectangle(barL, barT, barR, barB);
  1781. //vertical line (whisker)
  1782. barWidth = (int)((highValue * 1.00) * tickScale);
  1783. barR = xApexPoint + barWidth;
  1784. pDC->Rectangle(barL, tickYLocation - 2, barR, tickYLocation + 2);
  1785. //box (interquartile range, from upper quartile to lower quartile)
  1786. barWidth = (int)(upperQuartile * tickScale);
  1787. barL = xApexPoint + barWidth;
  1788. barWidth = (int)(lowerQuartile * tickScale);
  1789. barR = xApexPoint + barWidth;
  1790. pDC->Rectangle(barL, barT, barR, barB);
  1791. //draw median line (in RED)
  1792. CPen* pOldPen;
  1793. CPen linePen (PS_SOLID, 1, RED);
  1794. pOldPen = pDC->SelectObject(&linePen);
  1795. barWidth = (int)((median * 1.00) * tickScale);
  1796. pDC->MoveTo(xApexPoint + barWidth, barT);
  1797. pDC->LineTo(xApexPoint + barWidth, barB);
  1798. pDC->SelectObject(pOldPen);
  1799. }
  1800. }
  1801. pDC->SelectObject(pOldBrush);
  1802. }
  1803. void CGraph::DrawStackedBarSeries(CDC* pDC)
  1804. {
  1805. int barWidth;
  1806. int barL, barT, barR, barB;
  1807. int tickXLocation, tickYLocation;
  1808. int seriesSpace;
  1809. int barHeight;
  1810. POSITION pos;
  1811. CGraphSeries* tmpSeries;
  1812. if(graphAlignment)
  1813. {
  1814. //determine width of barchart data blocks
  1815. seriesSpace = xAxisWidth / graphSeries->GetCount();
  1816. barWidth = (int)(seriesSpace * .6);
  1817. pos = graphSeries->GetHeadPosition();
  1818. double dataScale = 0.00;
  1819. dataScale = ((yAxisHeight - 10) * 1.00) / (maxTick - minTick);
  1820. for(int x = 1; x <= graphSeries->GetCount(); x++)
  1821. {
  1822. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  1823. tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
  1824. barT = yApexPoint; //this is a running total;
  1825. //it starts at yApexPoint so barB can
  1826. //start there, then moves up by barHeight
  1827. for(int s = 0; s < seriesSize; s++)
  1828. {
  1829. if(tmpSeries->GetData(s) > -1)
  1830. {
  1831. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  1832. if(((tmpSeries->GetData(s) - minTick) > 0) && (barHeight < 1))
  1833. barHeight = (int)dataScale;
  1834. barB = barT;
  1835. barL = tickXLocation - (barWidth / 2);
  1836. if(barHeight > yAxisHeight)
  1837. barT = barB - yAxisHeight;
  1838. else
  1839. barT = barB - barHeight;
  1840. barR = barL + barWidth;
  1841. COLORREF barColor;
  1842. barColor = GetColor(s);
  1843. CBrush brush (barColor);
  1844. CBrush* pOldBrush;
  1845. pOldBrush = pDC->SelectObject(&brush);
  1846. pDC->Rectangle(barL, barT, barR, barB);
  1847. pDC->SelectObject(pOldBrush);
  1848. }
  1849. }
  1850. }
  1851. }
  1852. else
  1853. {
  1854. //determine width of barchart data blocks
  1855. seriesSpace = yAxisHeight / graphSeries->GetCount();
  1856. barHeight = (int)(seriesSpace * .6);
  1857. pos = graphSeries->GetHeadPosition();
  1858. double dataScale = 0.00;
  1859. dataScale = ((xAxisWidth - 10) * 1.00) / (maxTick - minTick);
  1860. for(int y = 1; y <= graphSeries->GetCount(); y++)
  1861. {
  1862. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  1863. tickYLocation = yApexPoint - ((y * seriesSpace) - (seriesSpace / 2));
  1864. barR = xApexPoint; //this is a running total;
  1865. //it starts at xApexPoint so barL can
  1866. //start there, then moves right by barWidth
  1867. for(int s = 0; s < seriesSize; s++)
  1868. {
  1869. if(tmpSeries->GetData(s) > -1)
  1870. {
  1871. barWidth = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  1872. if(((tmpSeries->GetData(s) - minTick) > 0) && (barWidth < 1))
  1873. barWidth = (int)dataScale;
  1874. barL = barR;
  1875. barT = tickYLocation - (barHeight / 2);
  1876. barB = barT + barHeight;
  1877. if(barWidth > xAxisWidth)
  1878. barR = barL + xAxisWidth;
  1879. else
  1880. barR = barL + barWidth;
  1881. COLORREF barColor;
  1882. barColor = GetColor(s);
  1883. CBrush brush (barColor);
  1884. CBrush* pOldBrush;
  1885. pOldBrush = pDC->SelectObject(&brush);
  1886. pDC->Rectangle(barL, barT, barR, barB);
  1887. pDC->SelectObject(pOldBrush);
  1888. }
  1889. }
  1890. }
  1891. }
  1892. }
  1893. void CGraph::DrawXYLineSeries(CDC* pDC)
  1894. {
  1895. //XY Line graph is same as Line graph, but has no circles at endpoints
  1896. int barWidth;
  1897. int dataPlotSize;   //used to plot rects of data
  1898. int tickXLocation, tickYLocation;
  1899. int seriesSpace;
  1900. int barHeight;
  1901. POSITION pos;
  1902. CGraphSeries* tmpSeries;
  1903. int lastXLoc, lastYLoc;
  1904. if(graphAlignment)
  1905. {
  1906. for(int s = 0; s < seriesSize; s++)
  1907. {
  1908. //determine width of barchart data blocks
  1909. seriesSpace = xAxisWidth / graphSeries->GetCount();
  1910. barWidth = (int)((seriesSpace * .6) / seriesSize);
  1911. dataPlotSize = seriesSize * barWidth;
  1912. pos = graphSeries->GetHeadPosition();
  1913. for(int x = 1; x <= graphSeries->GetCount(); x++)
  1914. {
  1915. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  1916. if(tmpSeries->GetData(s) > -1)
  1917. {
  1918. tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
  1919. barHeight = 0;
  1920. double dataScale = 0.00;
  1921. if((maxTick - minTick) != yAxisHeight)
  1922. dataScale = (yAxisHeight * 1.00) / ((maxTick - minTick) * 1.00);
  1923. else dataScale = 1;
  1924. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  1925. if(((tmpSeries->GetData(s) - minTick) > 0) && (barHeight < 1))
  1926. barHeight = (int)dataScale;
  1927. if(barHeight > yApexPoint)
  1928. barHeight = (int)((maxTick - minTick) * dataScale) + 5;
  1929. int yDataLocation = yApexPoint - barHeight;
  1930. //now have x and y location of center of ellipse
  1931. COLORREF barColor;
  1932. barColor = GetColor(s);
  1933. //draw line back to last data member
  1934. if(x > 1)
  1935. {
  1936. CPen* pOldPen;
  1937. CPen linePen (PS_SOLID, 2, barColor);
  1938. pOldPen = pDC->SelectObject(&linePen);
  1939. pDC->MoveTo(lastXLoc, lastYLoc);
  1940. pDC->LineTo(tickXLocation, yDataLocation);
  1941. pDC->SelectObject(pOldPen);
  1942. }
  1943. lastXLoc = tickXLocation;
  1944. lastYLoc = yDataLocation;
  1945. }
  1946. }
  1947. }
  1948. }
  1949. else
  1950. {
  1951. for(int s = 0; s < seriesSize; s++)
  1952. {
  1953. //determine width of barchart data blocks
  1954. seriesSpace = yAxisHeight / graphSeries->GetCount();
  1955. barHeight = (int)((seriesSpace * .6) / seriesSize);
  1956. dataPlotSize = seriesSize * barHeight;
  1957. pos = graphSeries->GetHeadPosition();
  1958. for(int x = 1; x <= graphSeries->GetCount(); x++)
  1959. {
  1960. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  1961. if(tmpSeries->GetData(s) > -1)
  1962. {
  1963. tickYLocation = yApexPoint - ((x * seriesSpace) - (seriesSpace / 2));
  1964. barWidth = 0;
  1965. double dataScale = 0.00;
  1966. if((maxTick - minTick) != xAxisWidth)
  1967. dataScale = (xAxisWidth * 1.00) / ((maxTick - minTick) * 1.00);
  1968. else dataScale = 1;
  1969. barWidth = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  1970. if(((tmpSeries->GetData(s) - minTick) > 0) && (barWidth < 1))
  1971. barWidth = (int)dataScale;
  1972. int xDataLocation = xApexPoint + barWidth;
  1973. //now have x and y location of center of ellipse
  1974. COLORREF barColor;
  1975. barColor = GetColor(s);
  1976. //draw line back to last data member
  1977. if(x > 1)
  1978. {
  1979. CPen* pOldPen;
  1980. CPen linePen (PS_SOLID, 2, barColor);
  1981. pOldPen = pDC->SelectObject(&linePen);
  1982. pDC->MoveTo(lastXLoc, lastYLoc);
  1983. pDC->LineTo(xDataLocation, tickYLocation);
  1984. pDC->SelectObject(pOldPen);
  1985. }
  1986. lastYLoc = tickYLocation;
  1987. lastXLoc = xDataLocation;
  1988. }
  1989. }
  1990. }
  1991. }
  1992. }
  1993. //I may implement radar graphs in the future, after I really determine
  1994. //what the purpose is and what the dynamics of it involves
  1995. //void CGraph::DrawRadarSeries(CDC* pDC)
  1996. //{
  1997. //}
  1998. void CGraph::Draw3DBarSeries(CDC* pDC)
  1999. {
  2000. int barWidth;
  2001. int dataPlotSize;   //used to plot rects of data
  2002. int barL, barT, barR, barB;
  2003. int tickXLocation, tickYLocation;
  2004. int seriesSpace;
  2005. int barHeight;
  2006. POSITION pos;
  2007. CGraphSeries* tmpSeries;
  2008. int blue;
  2009. int red;
  2010. int green;
  2011. if(graphAlignment)
  2012. {
  2013. //determine width of barchart data blocks
  2014. seriesSpace = xAxisWidth  / graphSeries->GetCount();
  2015. barWidth = (int)((seriesSpace * .8) / seriesSize);
  2016. dataPlotSize = seriesSize * barWidth;
  2017. pos = graphSeries->GetHeadPosition();
  2018. for(int x = 1; x <= graphSeries->GetCount(); x++)
  2019. {
  2020. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  2021. tickXLocation = xApexPoint + ((x * seriesSpace) - (seriesSpace / 2));
  2022. for(int s = 0; s < seriesSize; s++)
  2023. {
  2024. if(tmpSeries->GetData(s) > -1)
  2025. {
  2026. double dataScale = 0.00;
  2027. dataScale = (yAxisHeight * 1.00) / (maxTick - minTick);
  2028. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  2029. if(((tmpSeries->GetData(s) - minTick) > 0) && (barHeight < 1))
  2030. barHeight = (int)dataScale;
  2031. barL = tickXLocation - (dataPlotSize / 2) + (s * barWidth);
  2032. if(barHeight > yAxisHeight)
  2033. barT = yApexPoint - yAxisHeight;
  2034. else
  2035. barT = yApexPoint - barHeight;
  2036. barR = barL + barWidth;
  2037. barB = yApexPoint;
  2038. COLORREF barColor;
  2039. barColor = GetColor(s);
  2040. CBrush brush (barColor);
  2041. CPen rectPen (PS_SOLID, 1, barColor);
  2042. CPen* pOldPen;
  2043. pOldPen = pDC->SelectObject(&rectPen);
  2044. CBrush* pOldBrush;
  2045. pOldBrush = pDC->SelectObject(&brush);
  2046. pDC->Rectangle(barL, barT, barR, barB);
  2047. //now, we do the side
  2048. //side is darker than front, so subtract
  2049. //from color to make closer to black
  2050. red = GetRValue(barColor);
  2051. green = GetGValue(barColor);
  2052. blue = GetBValue(barColor);
  2053. int sideRed = red - 35;
  2054. int sideGreen = green - 35;
  2055. int sideBlue = blue - 35;
  2056. if(sideRed < 0) sideRed = 0;
  2057. if(sideGreen < 0) sideGreen = 0;
  2058. if(sideBlue < 0) sideBlue = 0;
  2059. COLORREF sideColor;
  2060. sideColor = RGB(sideRed, sideGreen, sideBlue);
  2061. CBrush sideBrush (sideColor);
  2062. CPen sidePen (PS_SOLID, 1, sideColor);
  2063. pDC->SelectObject(&sideBrush);
  2064. pDC->SelectObject(&sidePen);
  2065. CPoint sidePolyArray[4];
  2066. CPoint sp1(barR, barT);
  2067. CPoint sp2(barR, barB);
  2068. CPoint sp3(barR + depth, barB - depth);
  2069. CPoint sp4(barR + depth, barT - depth);
  2070. sidePolyArray[0] = sp1;
  2071. sidePolyArray[1] = sp2;
  2072. sidePolyArray[2] = sp3;
  2073. sidePolyArray[3] = sp4;
  2074. pDC->Polygon(sidePolyArray, 4);
  2075. //finally, the top
  2076. int topRed = red + 35;
  2077. int topGreen = green + 35;
  2078. int topBlue = blue + 35;
  2079. if(topRed > 255) topRed = 255;
  2080. if(topGreen > 255) topGreen = 255;
  2081. if(topBlue > 255) topBlue = 255;
  2082. COLORREF topColor;
  2083. topColor = RGB(topRed, topGreen, topBlue);
  2084. CBrush topBrush (topColor);
  2085. CPen topPen (PS_SOLID, 1, topColor);
  2086. pDC->SelectObject(&topBrush);
  2087. pDC->SelectObject(&topPen);
  2088. CPoint topPolyArray[4];
  2089. CPoint tp1(barL, barT);
  2090. CPoint tp2(barR, barT);
  2091. CPoint tp3(barR + depth, barT - depth);
  2092. CPoint tp4(barL + depth, barT - depth);
  2093. topPolyArray[0] = tp1;
  2094. topPolyArray[1] = tp2;
  2095. topPolyArray[2] = tp3;
  2096. topPolyArray[3] = tp4;
  2097. pDC->Polygon(topPolyArray, 4);
  2098. pDC->SelectObject(pOldBrush);
  2099. pDC->SelectObject(pOldPen);
  2100. }
  2101. }
  2102. }
  2103. }
  2104. else
  2105. {
  2106. //determine width of barchart data blocks
  2107. seriesSpace = yAxisHeight / graphSeries->GetCount();
  2108. barHeight = (int)((seriesSpace * .8) / seriesSize);
  2109. dataPlotSize = seriesSize * barHeight;
  2110. pos = graphSeries->GetHeadPosition();
  2111. for(int y = 1; y <= graphSeries->GetCount(); y++)
  2112. {
  2113. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  2114. tickYLocation = yApexPoint - ((y * seriesSpace) - (seriesSpace / 2));
  2115. for(int s = 0; s < seriesSize; s++)
  2116. {
  2117. if(tmpSeries->GetData(s) > -1)
  2118. {
  2119. double dataScale = 0.00;
  2120. dataScale = ((xAxisWidth - 10) * 1.00) / (maxTick - minTick);
  2121. barWidth = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  2122. if(((tmpSeries->GetData(s) - minTick) > 0) && (barWidth < 1))
  2123. barWidth = (int)dataScale;
  2124. barL = xApexPoint;
  2125. barB = tickYLocation + (dataPlotSize / 2) - (s * barHeight);
  2126. barT = barB - barHeight;
  2127. if(barWidth > xAxisWidth)
  2128. barR = xApexPoint + xAxisWidth;
  2129. else
  2130. barR = xApexPoint + barWidth;
  2131. COLORREF barColor;
  2132. barColor = GetColor(s);
  2133. CBrush brush (barColor);
  2134. CBrush* pOldBrush;
  2135. pOldBrush = pDC->SelectObject(&brush);
  2136. CPen rectPen (PS_SOLID, 1, barColor);
  2137. CPen* pOldPen;
  2138. pOldPen = pDC->SelectObject(&rectPen);
  2139. pDC->Rectangle(barL, barT, barR, barB);
  2140. //now, we do the side
  2141. //side is darker than front, so subtract
  2142. //from color to make closer to black
  2143. red = GetRValue(barColor);
  2144. green = GetGValue(barColor);
  2145. blue = GetBValue(barColor);
  2146. int sideRed = red - 35;
  2147. int sideGreen = green - 35;
  2148. int sideBlue = blue - 35;
  2149. if(sideRed < 0) sideRed = 0;
  2150. if(sideGreen < 0) sideGreen = 0;
  2151. if(sideBlue < 0) sideBlue = 0;
  2152. COLORREF sideColor;
  2153. sideColor = RGB(sideRed, sideGreen, sideBlue);
  2154. CBrush sideBrush (sideColor);
  2155. CPen sidePen (PS_SOLID, 1, sideColor);
  2156. pDC->SelectObject(&sideBrush);
  2157. pDC->SelectObject(&sidePen);
  2158. CPoint sidePolyArray[4];
  2159. CPoint sp1(barL, barT);
  2160. CPoint sp2(barR, barT);
  2161. CPoint sp3(barR + depth, barT - depth);
  2162. CPoint sp4(barL + depth, barT - depth);
  2163. sidePolyArray[0] = sp1;
  2164. sidePolyArray[1] = sp2;
  2165. sidePolyArray[2] = sp3;
  2166. sidePolyArray[3] = sp4;
  2167. pDC->Polygon(sidePolyArray, 4);
  2168. //finally, the top
  2169. int topRed = red + 35;
  2170. int topGreen = green + 35;
  2171. int topBlue = blue + 35;
  2172. if(topRed > 255) topRed = 255;
  2173. if(topGreen > 255) topGreen = 255;
  2174. if(topBlue > 255) topBlue = 255;
  2175. COLORREF topColor;
  2176. topColor = RGB(topRed, topGreen, topBlue);
  2177. CBrush topBrush (topColor);
  2178. CPen topPen (PS_SOLID, 1, topColor);
  2179. pDC->SelectObject(&topBrush);
  2180. pDC->SelectObject(&topPen);
  2181. CPoint topPolyArray[4];
  2182. CPoint tp1(barR, barT);
  2183. CPoint tp2(barR, barB);
  2184. CPoint tp3(barR + depth, barB - depth);
  2185. CPoint tp4(barR + depth, barT - depth);
  2186. topPolyArray[0] = tp1;
  2187. topPolyArray[1] = tp2;
  2188. topPolyArray[2] = tp3;
  2189. topPolyArray[3] = tp4;
  2190. pDC->Polygon(topPolyArray, 4);
  2191. pDC->SelectObject(pOldBrush);
  2192. pDC->SelectObject(pOldPen);
  2193. }
  2194. }
  2195. }
  2196. }
  2197. }
  2198. void CGraph::Draw3DLineSeries(CDC* pDC)
  2199. {
  2200. int barHeight;
  2201. POSITION pos;
  2202. CGraphSeries* tmpSeries;
  2203. int blue;
  2204. int red;
  2205. int green;
  2206. CBrush* pOldBrush;
  2207. CPen* pOldPen;
  2208. int deltaX, deltaY;
  2209. double yAxisScale, xAxisScale;
  2210. int tickXLocation;
  2211. //multiply each value by 1.00 to force result into a double value, and therefore
  2212. //make it more accurate in it's plot location.
  2213. switch(graphQuadType)
  2214. {
  2215. case 1 :
  2216. yAxisScale = ((yApexPoint - topYTick) / (maxTick * 1.00));
  2217. xAxisScale = ((rightXTick - xApexPoint) / (maxTick * 1.00));
  2218. break;
  2219. case 2 :
  2220. yAxisScale = ((yApexPoint - topYTick) / (maxTick * 1.00));
  2221. xAxisScale = ((rightXTick - xApexPoint) / (maxTick * 1.00));
  2222. break;
  2223. case 3 :
  2224. yAxisScale = ((topYTick - yApexPoint) / (maxTick * 1.00));
  2225. xAxisScale = ((rightXTick - xApexPoint) / (maxTick * 1.00));
  2226. break;
  2227. case 4 :
  2228. yAxisScale = ((topYTick - yApexPoint) / (maxTick * 1.00));
  2229. xAxisScale = ((rightXTick - xApexPoint) / (maxTick * 1.00));
  2230. break;
  2231. }
  2232. int lastXLoc, lastYLoc;
  2233. //because of how it ends up looking, I'm forcing 3D line graphs
  2234. //to always display as if in vertical mode graph
  2235. // if(graphAlignment)
  2236. // {
  2237. for(int s = 0; s < seriesSize; s++)
  2238. {
  2239. lastXLoc = xApexPoint + line3DXBase;
  2240. lastYLoc = yApexPoint - line3DYBase;
  2241. //determine width of barchart data blocks
  2242. pos = graphSeries->GetHeadPosition();
  2243. int yDataLocation;
  2244. for(int x = 1; x <= graphSeries->GetCount(); x++)
  2245. {
  2246. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  2247. if(tmpSeries->GetData(s) > -1)
  2248. {
  2249. tickXLocation = xApexPoint + (int)(x * (xAxisWidth / graphSeries->GetCount() + 1));
  2250. barHeight = 0;
  2251. double dataScale = 0.00;
  2252. if((maxTick - minTick) != yAxisHeight)
  2253. dataScale = (yAxisHeight * 1.00) / ((maxTick - minTick) * 1.00);
  2254. else dataScale = 1;
  2255. barHeight = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  2256. if(((tmpSeries->GetData(s) - minTick) > 0) && (barHeight < 1))
  2257. barHeight = (int)dataScale;
  2258. if(barHeight > yApexPoint)
  2259. barHeight = (int)((maxTick - minTick) * dataScale) + 5;
  2260. yDataLocation = yApexPoint - barHeight;
  2261. //now have x and y location of center of ellipse
  2262. COLORREF barColor;
  2263. barColor = GetColor(s);
  2264. red = GetRValue(barColor);
  2265. green = GetGValue(barColor);
  2266. blue = GetBValue(barColor);
  2267. CBrush brush (barColor);
  2268. pOldBrush = pDC->SelectObject(&brush);
  2269. //draw line back to last data member
  2270. CPen linePen (PS_SOLID, 2, BLACK);
  2271. pOldPen = pDC->SelectObject(&linePen);
  2272. //front side of line
  2273. pDC->MoveTo(lastXLoc + ((seriesSize - s) * (depth / seriesSize)), lastYLoc - ((seriesSize - s) * (depth / seriesSize)));
  2274. pDC->LineTo(tickXLocation + ((seriesSize - s) * (depth / seriesSize)), yDataLocation - ((seriesSize - s) * (depth / seriesSize)));
  2275. pDC->MoveTo(lastXLoc + ((seriesSize - s) * (depth / seriesSize)) - (depth / seriesSize), lastYLoc - ((seriesSize - s) * (depth / seriesSize)) + (depth / seriesSize));
  2276. pDC->LineTo(tickXLocation + ((seriesSize - s) * (depth / seriesSize)) - (depth / seriesSize), yDataLocation - ((seriesSize - s) * (depth / seriesSize)) + (depth / seriesSize));
  2277. pDC->MoveTo(lastXLoc + ((seriesSize - s) * (depth / seriesSize)) - (depth / seriesSize), lastYLoc - ((seriesSize - s) * (depth / seriesSize)) + (depth / seriesSize));
  2278. pDC->LineTo(lastXLoc + ((seriesSize - s) * (depth / seriesSize)), lastYLoc - ((seriesSize - s) * (depth / seriesSize)));
  2279. pDC->MoveTo(tickXLocation + ((seriesSize - s) * (depth / seriesSize)) - (depth / seriesSize), yDataLocation - ((seriesSize - s) * (depth / seriesSize)) + (depth / seriesSize));
  2280. pDC->LineTo(tickXLocation + ((seriesSize - s) * (depth / seriesSize)), yDataLocation - ((seriesSize - s) * (depth / seriesSize)));
  2281. //top part of line, lighter than front
  2282. int topRed = red + 35;
  2283. int topGreen = green + 35;
  2284. int topBlue = blue + 35;
  2285. if(topRed > 255) topRed = 255;
  2286. if(topGreen > 255) topGreen = 255;
  2287. if(topBlue > 255) topBlue = 255;
  2288. COLORREF topColor;
  2289. topColor = RGB(topRed, topGreen, topBlue);
  2290. int bottomRed = red - 55;
  2291. int bottomGreen = green - 55;
  2292. int bottomBlue = blue - 55;
  2293. if(bottomRed < 0) bottomRed = 0;
  2294. if(bottomGreen < 0) bottomGreen = 0;
  2295. if(bottomBlue < 0) bottomBlue = 0;
  2296. COLORREF bottomColor;
  2297. bottomColor = RGB(bottomRed, bottomGreen, bottomBlue);
  2298. deltaX = tickXLocation - lastXLoc;
  2299. deltaY = lastYLoc - yDataLocation;
  2300. if(deltaX == deltaY)
  2301. {
  2302. pDC->MoveTo(tickXLocation + ((seriesSize - s) * (depth / seriesSize)), yDataLocation - ((seriesSize - s) * (depth / seriesSize)));
  2303. pDC->LineTo(tickXLocation + ((seriesSize - s) * (depth / seriesSize)) - (depth / seriesSize), yDataLocation - ((seriesSize - s) * (depth / seriesSize)) + (depth / seriesSize));
  2304. }
  2305. else
  2306. {
  2307. CPoint d3linePolyArray[4];
  2308. if(  
  2309. ((deltaX > deltaY) && (deltaX < 0)) ||
  2310. ((deltaX < deltaY) && (deltaX > 0))
  2311.   )
  2312. {
  2313. CPen bottomPen(PS_SOLID, 1, BLACK);
  2314. CBrush bottomBrush(bottomColor);
  2315. pDC->SelectObject(&bottomPen);
  2316. pDC->SelectObject(&bottomBrush);
  2317. CPoint bp1(lastXLoc + ((seriesSize - s) * (depth / seriesSize)), lastYLoc - ((seriesSize - s) * (depth / seriesSize)));
  2318. CPoint bp2(lastXLoc + ((seriesSize - s) * (depth / seriesSize)) - (depth / seriesSize), lastYLoc - ((seriesSize - s) * (depth / seriesSize)) + (depth / seriesSize));
  2319. CPoint bp3(tickXLocation + ((seriesSize - s) * (depth / seriesSize)) - (depth / seriesSize), yDataLocation - ((seriesSize - s) * (depth / seriesSize)) + (depth / seriesSize));
  2320. CPoint bp4(tickXLocation + ((seriesSize - s) * (depth / seriesSize)), yDataLocation - ((seriesSize - s) * (depth / seriesSize)));
  2321. d3linePolyArray[0] = bp1;
  2322. d3linePolyArray[1] = bp2;
  2323. d3linePolyArray[2] = bp3;
  2324. d3linePolyArray[3] = bp4;
  2325. pDC->Polygon(d3linePolyArray, 4);
  2326. }
  2327. else
  2328. {
  2329. CPen topPen(PS_SOLID, 1, BLACK);
  2330. CBrush topBrush(topColor);
  2331. pDC->SelectObject(&topPen);
  2332. pDC->SelectObject(&topBrush);
  2333. CPoint tp1(lastXLoc + ((seriesSize - s) * (depth / seriesSize)), lastYLoc - ((seriesSize - s) * (depth / seriesSize)));
  2334. CPoint tp2(lastXLoc + ((seriesSize - s) * (depth / seriesSize)) - (depth / seriesSize), lastYLoc - ((seriesSize - s) * (depth / seriesSize)) + (depth / seriesSize));
  2335. CPoint tp3(tickXLocation + ((seriesSize - s) * (depth / seriesSize)) - (depth / seriesSize), yDataLocation - ((seriesSize - s) * (depth / seriesSize)) + (depth / seriesSize));
  2336. CPoint tp4(tickXLocation + ((seriesSize - s) * (depth / seriesSize)), yDataLocation - ((seriesSize - s) * (depth / seriesSize)));
  2337. d3linePolyArray[0] = tp1;
  2338. d3linePolyArray[1] = tp2;
  2339. d3linePolyArray[2] = tp3;
  2340. d3linePolyArray[3] = tp4;
  2341. pDC->Polygon(d3linePolyArray, 4);
  2342. }
  2343. }
  2344. pDC->SelectObject(pOldBrush);
  2345. pDC->SelectObject(pOldPen);
  2346. lastXLoc = tickXLocation;
  2347. lastYLoc = yDataLocation;
  2348. }
  2349. }
  2350. }
  2351. /* }
  2352. else
  2353. {
  2354. for(int s = 0; s < seriesSize; s++)
  2355. {
  2356. //determine width of barchart data blocks
  2357. seriesSpace = yAxisHeight / graphSeries->GetCount();
  2358. pos = graphSeries->GetHeadPosition();
  2359. int xDataLocation;
  2360. for(int x = 1; x <= graphSeries->GetCount(); x++)
  2361. {
  2362. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  2363. if(tmpSeries->GetData(s) > -1)
  2364. {
  2365. tickYLocation = yApexPoint - ((x * seriesSpace) - (seriesSpace / 2));
  2366. int barWidth;
  2367. double dataScale = 0.00;
  2368. if((maxTick - minTick) != xAxisWidth)
  2369. dataScale = (xAxisWidth * 1.00) / ((maxTick - minTick) * 1.00);
  2370. else dataScale = 1;
  2371. barWidth = (int)(((tmpSeries->GetData(s) - minTick) * 1.00) * dataScale);
  2372. if(((tmpSeries->GetData(s) - minTick) > 0) && (barWidth < 1))
  2373. barWidth = (int)dataScale;
  2374. xDataLocation = xApexPoint + barWidth;
  2375. //now have x and y location of center of ellipse
  2376. COLORREF barColor;
  2377. barColor = GetColor(s);
  2378. red = GetRValue(barColor);
  2379. green = GetGValue(barColor);
  2380. blue = GetBValue(barColor);
  2381. CBrush brush (barColor);
  2382. pOldBrush = pDC->SelectObject(&brush);
  2383. //draw line back to last data member
  2384. if(x > 1)
  2385. {
  2386. CPen linePen (PS_SOLID, 1, barColor);
  2387. pOldPen = pDC->SelectObject(&linePen);
  2388. //front side of line
  2389. pDC->MoveTo(lastXLoc, lastYLoc);
  2390. pDC->LineTo(xDataLocation, tickYLocation);
  2391. //top part of line, lighter than front
  2392. int topRed = red + 35;
  2393. int topGreen = green + 35;
  2394. int topBlue = blue + 35;
  2395. if(topRed > 255) topRed = 255;
  2396. if(topGreen > 255) topGreen = 255;
  2397. if(topBlue > 255) topBlue = 255;
  2398. COLORREF topColor;
  2399. topColor = RGB(topRed, topGreen, topBlue);
  2400. int bottomRed = red - 55;
  2401. int bottomGreen = green - 55;
  2402. int bottomBlue = blue - 55;
  2403. if(bottomRed < 0) bottomRed = 0;
  2404. if(bottomGreen < 0) bottomGreen = 0;
  2405. if(bottomBlue < 0) bottomBlue = 0;
  2406. COLORREF bottomColor;
  2407. bottomColor = RGB(bottomRed, bottomGreen, bottomBlue);
  2408. deltaX = xDataLocation - lastXLoc;
  2409. deltaY = lastYLoc - tickYLocation;
  2410. if(deltaX == deltaY)
  2411. {
  2412. pDC->MoveTo(xDataLocation, tickYLocation);
  2413. pDC->LineTo(xDataLocation + depth, tickYLocation - depth);
  2414. }
  2415. else
  2416. {
  2417. CPoint d3linePolyArray[4];
  2418. if(  
  2419. ((deltaY > deltaX) && (deltaY < 0)) ||
  2420. ((deltaY < deltaX) && (deltaY > 0))
  2421.   )
  2422. {
  2423. CPen bottomPen(PS_SOLID, 1, BLACK);
  2424. CBrush bottomBrush(bottomColor);
  2425. pDC->SelectObject(&bottomPen);
  2426. pDC->SelectObject(&bottomBrush);
  2427. CPoint bp1(lastXLoc, lastYLoc);
  2428. CPoint bp2(lastXLoc + depth, lastYLoc - depth);
  2429. CPoint bp3(xDataLocation + depth, tickYLocation - depth);
  2430. CPoint bp4(xDataLocation, tickYLocation);
  2431. d3linePolyArray[0] = bp1;
  2432. d3linePolyArray[1] = bp2;
  2433. d3linePolyArray[2] = bp3;
  2434. d3linePolyArray[3] = bp4;
  2435. pDC->Polygon(d3linePolyArray, 4);
  2436. }
  2437. else
  2438. {
  2439. CPen topPen(PS_SOLID, 1, BLACK);
  2440. CBrush topBrush(topColor);
  2441. pDC->SelectObject(&topPen);
  2442. pDC->SelectObject(&topBrush);
  2443. CPoint tp1(lastXLoc, lastYLoc);
  2444. CPoint tp2(lastXLoc + depth, lastYLoc - depth);
  2445. CPoint tp3(xDataLocation + depth, tickYLocation - depth);
  2446. CPoint tp4(xDataLocation, tickYLocation);
  2447. d3linePolyArray[0] = tp1;
  2448. d3linePolyArray[1] = tp2;
  2449. d3linePolyArray[2] = tp3;
  2450. d3linePolyArray[3] = tp4;
  2451. pDC->Polygon(d3linePolyArray, 4);
  2452. }
  2453. }
  2454. pDC->SelectObject(pOldBrush);
  2455. pDC->SelectObject(pOldPen);
  2456. }
  2457. lastXLoc = xDataLocation;
  2458. lastYLoc = tickYLocation;
  2459. }
  2460. }
  2461. }
  2462. }*/
  2463. }
  2464. void CGraph::Draw3DPieSeries(CDC* pDC)
  2465. {
  2466. double dataSum = 0.00;  //for storing cumulative sum
  2467. double labelData = 0.00;
  2468. int lastXLocation, lastYLocation;
  2469. int newXLocation, newYLocation;
  2470. int labelXLocation, labelYLocation;
  2471. double percent = 0.00;
  2472. double labelPercent = 0.00;
  2473. int degrees;
  2474. int labelDegrees;
  2475. double totalSum = 0.00;
  2476. int radius;
  2477. POSITION pos;
  2478. CGraphSeries* tmpSeries;
  2479. int seriesSpace;
  2480. int labelLineXStart, labelLineYStart;
  2481. int labelLineXEnd, labelLineYEnd;
  2482. int maxLabelWidth;
  2483. int maxLabelHeight;
  2484. TEXTMETRIC tm;
  2485. CPen* pOldPen;
  2486. CBrush* pOldBrush;
  2487. CPen tmpPen(PS_SOLID, 1, BLACK);
  2488. CBrush tmpBrush(WHITE);
  2489. pOldPen = pDC->SelectObject(&tmpPen);
  2490. pOldBrush = pDC->SelectObject(&tmpBrush);
  2491. //deltaX and deltaY will be based on distance from x and y
  2492. //axis for the new endpoint of the pie.  These values can 
  2493. //then be used to find the true distance between starting 
  2494. //line and ending line of pie boundary.
  2495. double deltaX, deltaY;
  2496. double degreeRadians, degreeRadians2;
  2497. double labelDeltaX, labelDeltaY;
  2498. double labelDegreeRadians, labelDegreeRadians2;
  2499. lastXLocation = 0;
  2500. lastYLocation = 0;
  2501. pDC->GetTextMetrics(&tm);
  2502. maxLabelWidth = tm.tmMaxCharWidth + 10;
  2503. maxLabelHeight = tm.tmHeight + 6;
  2504. //pie labels will be stored in a list and drawn after entire pie
  2505. //is completed.
  2506. CObList *pieLabels;
  2507. CGraphPieLabel *pieLabel;
  2508. //determine width of pie display area
  2509. if(xAxisWidth > yAxisHeight)
  2510. seriesSpace = yAxisHeight / graphSeries->GetCount();
  2511. else
  2512. seriesSpace = xAxisWidth / graphSeries->GetCount();
  2513. seriesSpace -= (3 * maxLabelWidth);  //allows text like 25%  (3 chars)
  2514. //to plot a pie plus labels inside of series space, use the following :
  2515. //(3 * radius) + (2 * label width) = series space 
  2516. //so, 3*radius = series space - (2 * label width)
  2517. // 1 radius = (series space - (2 * label width)) / 3
  2518. radius = seriesSpace / 3;  //pie needs 2 radius, + 1 extra for line to labels = 3 for my divisor
  2519. int depth = (int)(radius * depthRatio); //for shadow pie
  2520. int centerYPie = (yAxisHeight + 60) / 2;
  2521. pos = graphSeries->GetHeadPosition();
  2522. for(int x = 1; x <= graphSeries->GetCount(); x++)
  2523. {
  2524. pDC->SelectObject(pOldBrush);
  2525. pDC->SelectObject(pOldPen);
  2526. pieLabels = new CObList();
  2527. tmpSeries = (CGraphSeries*)graphSeries->GetNext(pos);
  2528. totalSum = 0;
  2529. for(int s = 0; s < seriesSize; s++)
  2530. totalSum += tmpSeries->GetData(s);
  2531. int pieLeft, pieRight;
  2532. if(graphSeries->GetCount() == 1)
  2533. {
  2534. pieLeft = xApexPoint + (xAxisWidth / 2) - radius;
  2535. }
  2536. else
  2537. {
  2538. pieLeft = xApexPoint + 15 + ((x * 2 - 1) * ((xAxisWidth / graphSeries->GetCount()) / 2)) - radius;
  2539. }
  2540. pieRight = pieLeft + (2 * radius);
  2541. CRect pieRect (pieLeft, 
  2542. centerYPie - radius,
  2543. pieRight, 
  2544. centerYPie + radius);
  2545. CRect shadowRect (pieLeft + depth,
  2546. centerYPie - radius + depth,
  2547. pieRight + depth,
  2548. centerYPie + radius + depth);
  2549. int centerXPie = pieLeft + radius;
  2550. //plot series label
  2551. pDC->TextOut(centerXPie - ((tmpSeries->GetLabel().GetLength() * 8) / 2),
  2552. centerYPie + (int)(radius * 1.5) + maxLabelHeight + 15, tmpSeries->GetLabel());
  2553. int centerShadowXPie;
  2554. int centerShadowYPie;
  2555. //draw shadow pie first
  2556. centerShadowYPie = centerYPie + depth;
  2557. centerShadowXPie = centerXPie + depth;
  2558. lastXLocation = centerShadowXPie - radius;
  2559. lastYLocation = centerShadowYPie;
  2560. int lastTopX = centerXPie - radius;
  2561. int lastTopY = centerYPie;
  2562. int newTopX, newTopY;
  2563. dataSum = 0;
  2564. int lastQuad = 0;
  2565. CPoint lastSidePolyArray[4];
  2566. COLORREF lastColor;
  2567. CPoint spa1;
  2568. CPoint spa2;
  2569. CPoint spa3;
  2570. CPoint spa4;
  2571. for(s = 0; s < seriesSize; s++)
  2572. {
  2573. if(tmpSeries->GetData(s) > 0)
  2574. {
  2575. int seriesDataValue;
  2576. seriesDataValue = tmpSeries->GetData(s);
  2577. dataSum += seriesDataValue;
  2578. percent = (dataSum / totalSum) * 100;
  2579. degrees = (int)((360 * percent) / 100);
  2580. //determine destination quadrant...
  2581. //and set newXLocation and newYLocation values...
  2582. //degrees / 90 will never exceed 4.
  2583. //this can tell us the quadrant of destination
  2584. int quadrant = degrees / 90;  //truncates decimal
  2585. //using the law of sines to determine the deltas :
  2586. //deltaX = radius * sin(90 - degrees)
  2587. //deltaY = radius * sin(degrees)
  2588. //we convert degrees into radians so sin() function works right
  2589. //note :  in quad 1 and 3, we reverse the angle used to compute
  2590. // the deltas, since the triangle plots reversed.
  2591. switch(quadrant)
  2592. {
  2593. case 0 : //this is the base quadrant, so no manipulation needed
  2594.  degreeRadians = degrees * (3.14159 / 180);
  2595.  degreeRadians2 = (90 - degrees) * (3.14159 / 180);
  2596.  deltaX = radius * sin(degreeRadians2);
  2597.  deltaY = radius * sin(degreeRadians);
  2598.  newXLocation = (int)(centerShadowXPie - deltaX);
  2599.  newYLocation = (int)(centerShadowYPie + deltaY);
  2600.  newTopX = (int)(centerXPie - deltaX);
  2601.  newTopY = (int)(centerYPie + deltaY);
  2602.  break;
  2603. case 1 : //bottom right quadrant, subtract 90 from angle
  2604.  degreeRadians = (degrees - 90) * (3.14159 / 180);
  2605.  degreeRadians2 = (90 - (degrees - 90)) * (3.14159 / 180);
  2606.  deltaX = radius * sin(degreeRadians);
  2607.  deltaY = radius * sin(degreeRadians2);
  2608.  newXLocation = (int)(centerShadowXPie + deltaX);
  2609.  newYLocation = (int)(centerShadowYPie + deltaY);
  2610.  newTopX = (int)(centerXPie + deltaX);
  2611.  newTopY = (int)(centerYPie + deltaY);
  2612.  break;
  2613. case 2 : //top right quadrant, subtract 180 from angle
  2614.  degreeRadians = (degrees - 180) * (3.14159 / 180);
  2615.  degreeRadians2 = (90 - (degrees - 180)) * (3.14159 / 180);
  2616.  deltaX = radius * sin(degreeRadians2);
  2617.  deltaY = radius * sin(degreeRadians);
  2618.  newXLocation = (int)(centerShadowXPie + deltaX);
  2619.  newYLocation = (int)(centerShadowYPie - deltaY);
  2620.  newTopX = (int)(centerXPie + deltaX);
  2621.  newTopY = (int)(centerYPie - deltaY);
  2622.  break;
  2623. case 3 : //upper left quadrant, subtract 270 from angle
  2624.  degreeRadians = (degrees - 270) * (3.14159 / 180);
  2625.  degreeRadians2 = (90 - (degrees - 270)) * (3.14159 / 180);
  2626.  deltaX = radius * sin(degreeRadians);