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

操作系统开发

开发平台:

Visual C++

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