PieChart.cs

Description du code

PieChart.cs est un fichier du projet BrolDev.
Ce fichier est situé dans /var/www/bin/sniplets/bibliobrol/broldev/src/.

Projet BrolDev : Librairie de composants réutilisables pour les applications BrolDev en CSharp.

Code source ou contenu du fichier

  1. using System;
  2. using System.Collections;
  3. using System.Diagnostics;
  4. using System.Drawing;
  5.  
  6. namespace be.gaudry.model.drawing.chart
  7. {
  8.  
  9. /// <summary>
  10. /// Object representing a pie chart.
  11. /// </summary>
  12. public class PieChart3D : IDisposable {
  13.  
  14. /// <summary>
  15. /// Initializes an empty instance of <c>PieChart3D</c>.
  16. /// </summary>
  17. protected PieChart3D() {
  18. }
  19.  
  20. /// <summary>
  21. /// Initializes an instance of a flat <c>PieChart3D</c> with
  22. /// specified bounds, values to chart and relative thickness.
  23. /// </summary>
  24. /// <param name="xBoundingRect">
  25. /// x-coordinate of the upper-left corner of the rectangle that
  26. /// bounds the chart.
  27. /// </param>
  28. /// <param name="yBoundingRect">
  29. /// y-coordinate of the upper-left corner of the rectangle that
  30. /// bounds the chart.
  31. /// </param>
  32. /// <param name="widthBoundingRect">
  33. /// Width of the rectangle that bounds the chart.
  34. /// </param>
  35. /// <param name="heightBoundingRect">
  36. /// Height of the rectangle that bounds the chart.
  37. /// </param>
  38. /// <param name="values">
  39. /// An array of <c>decimal</c> values to chart.
  40. /// </param>
  41. public PieChart3D(float xBoundingRect, float yBoundingRect, float widthBoundingRect, float heightBoundingRect, double[] values) : this() {
  42. m_xBoundingRect = xBoundingRect;
  43. m_yBoundingRect = yBoundingRect;
  44. m_widthBoundingRect = widthBoundingRect;
  45. m_heightBoundingRect = heightBoundingRect;
  46. Values = values;
  47. }
  48.  
  49. /// <summary>
  50. /// Initializes an instance of <c>PieChart3D</c> with specified
  51. /// bounds, values to chart and relative thickness.
  52. /// </summary>
  53. /// <param name="xBoundingRect">
  54. /// x-coordinate of the upper-left corner of the rectangle bounding
  55. /// the chart.
  56. /// </param>
  57. /// <param name="yBoundingRect">
  58. /// y-coordinate of the upper-left corner of the rectangle bounding
  59. /// the chart.
  60. /// </param>
  61. /// <param name="widthBoundingRect">
  62. /// Width of the rectangle bounding the chart.
  63. /// </param>
  64. /// <param name="heightBoundingRect">
  65. /// Height of the rectangle bounding the chart.
  66. /// </param>
  67. /// <param name="values">
  68. /// An array of <c>decimal</c> values to chart.
  69. /// </param>
  70. /// <param name="sliceRelativeHeight">
  71. /// Thickness of the pie slice to chart relative to the height of the
  72. /// bounding rectangle.
  73. /// </param>
  74. public PieChart3D(float xBoundingRect, float yBoundingRect, float widthBoundingRect, float heightBoundingRect, double[] values, float sliceRelativeHeight)
  75. : this(xBoundingRect, yBoundingRect, widthBoundingRect, heightBoundingRect, values) {
  76. m_sliceRelativeHeight = sliceRelativeHeight;
  77. }
  78.  
  79. /// <summary>
  80. /// Initializes a new instance of <c>PieChart3D</c> with given bounds,
  81. /// array of values and pie slice thickness.
  82. /// </summary>
  83. /// <param name="boundingRectangle">
  84. /// Bounding rectangle.
  85. /// </param>
  86. /// <param name="values">
  87. /// Array of values to initialize with.
  88. /// </param>
  89. /// <param name="sliceRelativeHeight"></param>
  90. public PieChart3D(RectangleF boundingRectangle, double[] values, float sliceRelativeHeight)
  91. : this(boundingRectangle.X, boundingRectangle.Y, boundingRectangle.Width, boundingRectangle.Height, values, sliceRelativeHeight) {
  92. }
  93.  
  94. /// <summary>
  95. /// Initializes a new instance of <c>PieChart3D</c> with given bounds,
  96. /// array of values and relative pie slice height.
  97. /// </summary>
  98. /// <param name="xBoundingRect">
  99. /// x-coordinate of the upper-left corner of the rectangle bounding
  100. /// the chart.
  101. /// </param>
  102. /// <param name="yBoundingRect">
  103. /// y-coordinate of the upper-left corner of the rectangle bounding
  104. /// the chart.
  105. /// </param>
  106. /// <param name="widthBoundingRect">
  107. /// Width of the rectangle bounding the chart.
  108. /// </param>
  109. /// <param name="heightBoundingRect">
  110. /// Height of the rectangle bounding the chart.
  111. /// </param>
  112. /// <param name="values">
  113. /// An array of <c>decimal</c> values to chart.
  114. /// </param>
  115. /// <param name="sliceColors">
  116. /// An array of colors used to render slices.
  117. /// </param>
  118. /// <param name="sliceRelativeHeight">
  119. /// Thickness of the slice to chart relative to the height of the
  120. /// bounding rectangle.
  121. /// </param>
  122. public PieChart3D(float xBoundingRect, float yBoundingRect, float widthBoundingRect, float heightBoundingRect, double[] values, Color[] sliceColors, float sliceRelativeHeight)
  123. : this(xBoundingRect, yBoundingRect, widthBoundingRect, heightBoundingRect, values, sliceRelativeHeight) {
  124. m_sliceColors = sliceColors;
  125. }
  126.  
  127. /// <summary>
  128. /// Initializes a new instance of <c>PieChart3D</c> with given bounds,
  129. /// array of values and corresponding colors.
  130. /// </summary>
  131. /// <param name="boundingRectangle">
  132. /// Bounding rectangle.
  133. /// </param>
  134. /// <param name="values">
  135. /// Array of values to chart.
  136. /// </param>
  137. /// <param name="sliceColors">
  138. /// Colors used for rendering individual slices.
  139. /// </param>
  140. /// <param name="sliceRelativeHeight">
  141. /// Pie slice relative height.
  142. /// </param>
  143. public PieChart3D(RectangleF boundingRectangle, double[] values, Color[] sliceColors, float sliceRelativeHeight)
  144. : this(boundingRectangle, values, sliceRelativeHeight) {
  145. m_sliceColors = sliceColors;
  146. }
  147.  
  148. /// <summary>
  149. /// Initializes a new instance of <c>PieChart3D</c> with given bounds,
  150. /// array of values and relative pie slice height.
  151. /// </summary>
  152. /// <param name="xBoundingRect">
  153. /// x-coordinate of the upper-left corner of the rectangle bounding
  154. /// the chart.
  155. /// </param>
  156. /// <param name="yBoundingRect">
  157. /// y-coordinate of the upper-left corner of the rectangle bounding
  158. /// the chart.
  159. /// </param>
  160. /// <param name="widthBoundingRect">
  161. /// Width of the rectangle bounding the chart.
  162. /// </param>
  163. /// <param name="heightBoundingRect">
  164. /// Height of the rectangle bounding the chart.
  165. /// </param>
  166. /// <param name="values">
  167. /// An array of <c>decimal</c> values to chart.
  168. /// </param>
  169. /// <param name="sliceColors">
  170. /// An array of colors used to render slices.
  171. /// </param>
  172. /// <param name="sliceRelativeHeight">
  173. /// Thickness of the slice to chart relative to the height of the
  174. /// bounding rectangle.
  175. /// </param>
  176. /// <param name="texts">
  177. /// An array of strings that are displayed on corresponding slice.
  178. /// </param>
  179. public PieChart3D(float xBoundingRect, float yBoundingRect, float widthBoundingRect, float heightBoundingRect, double[] values, Color[] sliceColors, float sliceRelativeHeight, string[] texts)
  180. : this(xBoundingRect, yBoundingRect, widthBoundingRect, heightBoundingRect, values, sliceColors, sliceRelativeHeight) {
  181. m_texts = texts;
  182. }
  183.  
  184. /// <summary>
  185. /// Initializes a new instance of <c>PieChart3D</c> with given bounds,
  186. /// array of values and relative pie slice height.
  187. /// </summary>
  188. /// <param name="xBoundingRect">
  189. /// x-coordinate of the upper-left corner of the rectangle bounding
  190. /// the chart.
  191. /// </param>
  192. /// <param name="yBoundingRect">
  193. /// y-coordinate of the upper-left corner of the rectangle bounding
  194. /// the chart.
  195. /// </param>
  196. /// <param name="widthBoundingRect">
  197. /// Width of the rectangle bounding the chart.
  198. /// </param>
  199. /// <param name="heightBoundingRect">
  200. /// Height of the rectangle bounding the chart.
  201. /// </param>
  202. /// <param name="values">
  203. /// An array of <c>decimal</c> values to chart.
  204. /// </param>
  205. /// <param name="sliceRelativeHeight">
  206. /// Thickness of the slice to chart relative to the height of the
  207. /// bounding rectangle.
  208. /// </param>
  209. /// <param name="texts">
  210. /// An array of strings that are displayed on corresponding slice.
  211. /// </param>
  212. public PieChart3D(float xBoundingRect, float yBoundingRect, float widthBoundingRect, float heightBoundingRect, double[] values, float sliceRelativeHeight, string[] texts)
  213. : this(xBoundingRect, yBoundingRect, widthBoundingRect, heightBoundingRect, values, sliceRelativeHeight) {
  214. m_texts = texts;
  215. }
  216.  
  217. /// <summary>
  218. /// <c>Finalize</c> method.
  219. /// </summary>
  220. ~PieChart3D() {
  221. Dispose(false);
  222. }
  223.  
  224. /// <summary>
  225. /// Implementation of <c>IDisposable</c> interface.
  226. /// </summary>
  227. public void Dispose() {
  228. Dispose(true);
  229. GC.SuppressFinalize(this);
  230. }
  231.  
  232. /// <summary>
  233. /// Disposes of all pie slices.
  234. /// </summary>
  235. protected virtual void Dispose(bool disposing) {
  236. if (!m_disposed) {
  237. if (disposing) {
  238. foreach (PieSlice slice in m_pieSlices) {
  239. slice.Dispose();
  240. }
  241. }
  242. m_disposed = true;
  243. }
  244. }
  245.  
  246. /// <summary>
  247. /// Sets values to be displayed on the chart.
  248. /// </summary>
  249. public double[] Values {
  250. set {
  251. Debug.Assert(value != null && value.Length > 0);
  252. m_values = value;
  253. }
  254. }
  255.  
  256. /// <summary>
  257. /// Sets colors used for individual pie slices.
  258. /// </summary>
  259. public Color[] Colors {
  260. set { m_sliceColors = value; }
  261. }
  262.  
  263. /// <summary>
  264. /// Sets text displayed by slices.
  265. /// </summary>
  266. public string[] Texts {
  267. set { m_texts = value; }
  268. }
  269.  
  270. /// <summary>
  271. /// Gets or sets the font of the text displayed by the control.
  272. /// </summary>
  273. public Font Font {
  274. get { return m_font; }
  275. set { m_font = value; }
  276. }
  277.  
  278. /// <summary>
  279. /// Gets or sets the foreground color of the control used to draw text.
  280. /// </summary>
  281. public Color ForeColor {
  282. get { return m_foreColor; }
  283. set { m_foreColor = value; }
  284. }
  285.  
  286. /// <summary>
  287. /// Sets slice edge color mode. If set to <c>PenColor</c> (default),
  288. /// then value set by <c>EdgeColor</c> property is used.
  289. /// </summary>
  290. public EdgeColorType EdgeColorType {
  291. set { m_edgeColorType = value; }
  292. }
  293.  
  294. /// <summary>
  295. /// Sets slice edge line width. If not set, default value is 1.
  296. /// </summary>
  297. public float EdgeLineWidth {
  298. set { m_edgeLineWidth = value; }
  299. }
  300.  
  301. /// <summary>
  302. /// Sets slice height, relative to the top ellipse semi-axis. Must be
  303. /// less than or equal to 0.5.
  304. /// </summary>
  305. public float SliceRelativeHeight {
  306. set {
  307. Debug.Assert(value <= 0.5F);
  308. m_sliceRelativeHeight = value;
  309. }
  310. }
  311.  
  312. /// <summary>
  313. /// Sets the slice displacement relative to the ellipse semi-axis.
  314. /// Must be less than 1.
  315. /// </summary>
  316. public float SliceRelativeDisplacement {
  317. set {
  318. Debug.Assert(IsDisplacementValid(value));
  319. m_sliceRelativeDisplacements = new float[] { value };
  320. }
  321. }
  322.  
  323. /// <summary>
  324. /// Sets the slice displacement relative to the ellipse semi-axis.
  325. /// Must be less than 1.
  326. /// </summary>
  327. public float[] SliceRelativeDisplacements {
  328. set {
  329. m_sliceRelativeDisplacements = value;
  330. Debug.Assert(AreDisplacementsValid(value));
  331. }
  332. }
  333.  
  334. /// <summary>
  335. /// Gets or sets the size of the entire pie chart.
  336. /// </summary>
  337. public SizeF ChartSize {
  338. set {
  339. m_widthBoundingRect = value.Width;
  340. m_heightBoundingRect = value.Height;
  341. }
  342. }
  343.  
  344. /// <summary>
  345. /// Gets or sets the width of the bounding rectangle.
  346. /// </summary>
  347. public float Width {
  348. get { return m_widthBoundingRect; }
  349. set { m_widthBoundingRect = value; }
  350. }
  351.  
  352. /// <summary>
  353. /// Gets or sets the height of the bounding rectangle.
  354. /// </summary>
  355. public float Height {
  356. get { return m_heightBoundingRect; }
  357. set { m_heightBoundingRect = value; }
  358. }
  359.  
  360. /// <summary>
  361. /// Gets the y-coordinate of the bounding rectangle top edge.
  362. /// </summary>
  363. public float Top {
  364. get { return m_yBoundingRect; }
  365. }
  366.  
  367. /// <summary>
  368. /// Gets the y-coordinate of the bounding rectangle bottom edge.
  369. /// </summary>
  370. public float Bottom {
  371. get { return m_yBoundingRect + m_heightBoundingRect; }
  372. }
  373.  
  374. /// <summary>
  375. /// Gets the x-coordinate of the bounding rectangle left edge.
  376. /// </summary>
  377. public float Left {
  378. get { return m_xBoundingRect; }
  379. }
  380.  
  381. /// <summary>
  382. /// Gets the x-coordinate of the bounding rectangle right edge.
  383. /// </summary>
  384. public float Right {
  385. get { return m_xBoundingRect + m_widthBoundingRect; }
  386. }
  387.  
  388. /// <summary>
  389. /// Gets or sets the x-coordinate of the upper-left corner of the
  390. /// bounding rectangle.
  391. /// </summary>
  392. public float X {
  393. get { return m_xBoundingRect; }
  394. set { m_xBoundingRect = value; }
  395. }
  396.  
  397. /// <summary>
  398. /// Gets or sets the y-coordinate of the upper-left corner of the
  399. /// bounding rectangle.
  400. /// </summary>
  401. public float Y {
  402. get { return m_yBoundingRect; }
  403. set { m_yBoundingRect = value; }
  404. }
  405.  
  406. /// <summary>
  407. /// Sets the shadowing style used.
  408. /// </summary>
  409. public ShadowStyle ShadowStyle {
  410. set { m_shadowStyle = value; }
  411. }
  412.  
  413. /// <summary>
  414. /// Sets the flag that stepControls if chart is fit to bounding rectangle
  415. /// exactly.
  416. /// </summary>
  417. public bool FitToBoundingRectangle {
  418. set { m_fitToBoundingRectangle = value; }
  419. }
  420.  
  421. /// <summary>
  422. /// Sets the initial angle from which pies are placed.
  423. /// </summary>
  424. public float InitialAngle {
  425. set {
  426. m_initialAngle = value % 360;
  427. if (m_initialAngle < 0)
  428. m_initialAngle += 360;
  429. }
  430. }
  431.  
  432. /// <summary>
  433. /// Sets the index of the highlighted pie.
  434. /// </summary>
  435. public int HighlightedIndex {
  436. set { m_highlightedIndex = value; }
  437. }
  438.  
  439. /// <summary>
  440. /// Draws the chart.
  441. /// </summary>
  442. /// <param name="graphics">
  443. /// <c>Graphics</c> object used for drawing.
  444. /// </param>
  445. public void Draw(Graphics graphics) {
  446. Debug.Assert(m_values != null && m_values.Length > 0);
  447. InitializePieSlices();
  448. if (m_fitToBoundingRectangle) {
  449. RectangleF newBoundingRectangle = GetFittingRectangle();
  450. ReadjustSlices(newBoundingRectangle);
  451. }
  452. DrawBottoms(graphics);
  453. if (m_sliceRelativeHeight > 0F) {
  454. DrawSliceSides(graphics);
  455. }
  456. DrawTops(graphics);
  457. }
  458.  
  459. /// <summary>
  460. /// Draws strings by individual slices. Position of the text is
  461. /// calculated by overridable <c>GetTextPosition</c> method of the
  462. /// <c>PieSlice</c> type.
  463. /// </summary>
  464. /// <param name="graphics">
  465. /// <c>Graphics</c> object.
  466. /// </param>
  467. public virtual void PlaceTexts(Graphics graphics) {
  468. Debug.Assert(graphics != null);
  469. Debug.Assert(m_font != null);
  470. Debug.Assert(m_foreColor != Color.Empty);
  471. StringFormat drawFormat = new StringFormat();
  472. drawFormat.Alignment = StringAlignment.Center;
  473. drawFormat.LineAlignment = StringAlignment.Center;
  474. using (Brush fontBrush = new SolidBrush(m_foreColor)) {
  475. foreach (PieSlice slice in m_pieSlices) {
  476. if (slice.Text != null && slice.Text.Length > 0) {
  477. PointF point = slice.GetTextPosition();
  478. graphics.DrawString(slice.Text, m_font, fontBrush, point, drawFormat);
  479. }
  480. }
  481. }
  482. }
  483.  
  484. /// <summary>
  485. /// Searches the chart to find the index of the pie slice which
  486. /// contains point given. Search order goes in the direction opposite
  487. /// to drawing order.
  488. /// </summary>
  489. /// <param name="point">
  490. /// <c>PointF</c> point for which pie slice is searched for.
  491. /// </param>
  492. /// <returns>
  493. /// Index of the corresponding pie slice, or -1 if none is found.
  494. /// </returns>
  495. public int FindPieSliceUnderPoint(PointF point) {
  496. // first check tops
  497. for (int i = 0; i < m_pieSlices.Length; ++i) {
  498. PieSlice slice = (PieSlice)m_pieSlices[i];
  499. if (slice.PieSliceContainsPoint(point))
  500. return (int)m_pieSlicesMapping[i];
  501. }
  502. // split the backmost (at 270 degrees) pie slice
  503. ArrayList pieSlicesList = new ArrayList(m_pieSlices);
  504. PieSlice[] splitSlices = m_pieSlices[0].Split(270F);
  505. if (splitSlices.Length > 1) {
  506. pieSlicesList[0] = splitSlices[1];
  507. if (splitSlices[0].SweepAngle > 0F) {
  508. pieSlicesList.Add(splitSlices[0]);
  509. }
  510. }
  511. PieSlice[] pieSlices = (PieSlice[])pieSlicesList.ToArray(typeof(PieSlice));
  512. int indexFound = -1;
  513. // if not found yet, then check for periferies
  514. int incrementIndex = 0;
  515. int decrementIndex = pieSlices.Length - 1;
  516. while (incrementIndex <= decrementIndex) {
  517. PieSlice sliceLeft = pieSlices[decrementIndex];
  518. float angle1 = 270 - sliceLeft.StartAngle;
  519. PieSlice sliceRight = pieSlices[incrementIndex];
  520. float angle2 = (sliceRight.EndAngle + 90) % 360;
  521. Debug.Assert(angle2 >= 0);
  522. if (angle2 < angle1) {
  523. if (sliceRight.PeripheryContainsPoint(point))
  524. indexFound = incrementIndex;
  525. ++incrementIndex;
  526. }
  527. else {
  528. if (sliceLeft.PeripheryContainsPoint(point))
  529. indexFound = decrementIndex;
  530. --decrementIndex;
  531. }
  532. }
  533. // check for start/stop sides, starting from the foremost
  534. if (indexFound < 0) {
  535. int foremostPieIndex = GetForemostPieSlice(pieSlices);
  536. // check for start sides from the foremost slice to the left
  537. // side
  538. int i = foremostPieIndex;
  539. while (i < pieSlices.Length) {
  540. PieSlice sliceLeft = (PieSlice)pieSlices[i];
  541. if (sliceLeft.StartSideContainsPoint(point)) {
  542. indexFound = i;
  543. break;
  544. }
  545. ++i;
  546. }
  547. // if not found yet, check end sides from the foremost to the right
  548. // side
  549. if (indexFound < 0) {
  550. i = foremostPieIndex;
  551. while (i >= 0) {
  552. PieSlice sliceLeft = (PieSlice)pieSlices[i];
  553. if (sliceLeft.EndSideContainsPoint(point)) {
  554. indexFound = i;
  555. break;
  556. }
  557. --i;
  558. }
  559. }
  560. }
  561. // finally search for bottom sides
  562. if (indexFound < 0) {
  563. for (int i = 0; i < m_pieSlices.Length; ++i) {
  564. PieSlice slice = (PieSlice)m_pieSlices[i];
  565. if (slice.BottomSurfaceSectionContainsPoint(point))
  566. return (int)m_pieSlicesMapping[i];
  567. }
  568. }
  569. if (indexFound > -1) {
  570. indexFound %= (m_pieSlicesMapping.Count);
  571. return (int)m_pieSlicesMapping[indexFound];
  572. }
  573. return -1;
  574. }
  575.  
  576. /// <summary>
  577. /// Return the index of the foremost pie slice i.e. the one crossing
  578. /// 90 degrees boundary.
  579. /// </summary>
  580. /// <param name="pieSlices">
  581. /// Array of <c>PieSlice</c> objects to examine.
  582. /// </param>
  583. /// <returns>
  584. /// Index of the foremost pie slice.
  585. /// </returns>
  586. private int GetForemostPieSlice(PieSlice[] pieSlices) {
  587. Debug.Assert(pieSlices != null && pieSlices.Length > 0);
  588. for (int i = 0; i < pieSlices.Length; ++i) {
  589. PieSlice pieSlice = pieSlices[i];
  590. if (((pieSlice.StartAngle <= 90) && ((pieSlice.StartAngle + pieSlice.SweepAngle) >= 90)) ||
  591. ((pieSlice.StartAngle + pieSlice.SweepAngle > 360) && ((pieSlice.StartAngle) <= 450) && (pieSlice.StartAngle + pieSlice.SweepAngle) >= 450)) {
  592. return i;
  593. }
  594. }
  595. Debug.Assert(false, "Foremost pie slice not found");
  596. return -1;
  597. }
  598.  
  599. /// <summary>
  600. /// Finds the smallest rectangle int which chart fits entirely.
  601. /// </summary>
  602. /// <returns>
  603. /// <c>RectangleF</c> into which all member slices fit.
  604. /// </returns>
  605. protected RectangleF GetFittingRectangle() {
  606. RectangleF boundingRectangle = m_pieSlices[0].GetFittingRectangle();
  607. for (int i = 1; i < m_pieSlices.Length; ++i) {
  608. boundingRectangle = RectangleF.Union(boundingRectangle, m_pieSlices[i].GetFittingRectangle());
  609. }
  610. return boundingRectangle;
  611. }
  612.  
  613. /// <summary>
  614. /// Readjusts each slice for new bounding rectangle.
  615. /// </summary>
  616. /// <param name="newBoundingRectangle">
  617. /// <c>RectangleF</c> representing new boundary.
  618. /// </param>
  619. protected void ReadjustSlices(RectangleF newBoundingRectangle) {
  620. float xResizeFactor = m_widthBoundingRect / newBoundingRectangle.Width;
  621. float yResizeFactor = m_heightBoundingRect / newBoundingRectangle.Height;
  622. float xOffset = newBoundingRectangle.X - m_xBoundingRect;
  623. float yOffset = newBoundingRectangle.Y - m_yBoundingRect;
  624. foreach (PieSlice slice in m_pieSlices) {
  625. float x = slice.BoundingRectangle.X - xOffset;
  626. float y = slice.BoundingRectangle.Y - yOffset;
  627. float width = slice.BoundingRectangle.Width * xResizeFactor;
  628. float height = slice.BoundingRectangle.Height * yResizeFactor;
  629. float sliceHeight = slice.SliceHeight * yResizeFactor;
  630. slice.Readjust(x, y, width, height, sliceHeight);
  631. }
  632. }
  633.  
  634. /// <summary>
  635. /// Finds the largest displacement.
  636. /// </summary>
  637. protected float LargestDisplacement {
  638. get {
  639. float value = 0F;
  640. for (int i = 0; i < m_sliceRelativeDisplacements.Length && i < m_values.Length; ++i) {
  641. if (m_sliceRelativeDisplacements[i] > value)
  642. value = m_sliceRelativeDisplacements[i];
  643. }
  644. return value;
  645. }
  646. }
  647.  
  648. /// <summary>
  649. /// Gets the top ellipse size.
  650. /// </summary>
  651. protected SizeF TopEllipseSize {
  652. get {
  653. float factor = 1 + LargestDisplacement;
  654. float widthTopEllipse = m_widthBoundingRect / factor;
  655. float heightTopEllipse = m_heightBoundingRect / factor * (1 - m_sliceRelativeHeight);
  656. return new SizeF(widthTopEllipse, heightTopEllipse);
  657. }
  658. }
  659.  
  660. /// <summary>
  661. /// Gets the ellipse defined by largest displacement.
  662. /// </summary>
  663. protected SizeF LargestDisplacementEllipseSize {
  664. get {
  665. float factor = LargestDisplacement;
  666. float widthDisplacementEllipse = TopEllipseSize.Width * factor;
  667. float heightDisplacementEllipse = TopEllipseSize.Height * factor;
  668. return new SizeF(widthDisplacementEllipse, heightDisplacementEllipse);
  669. }
  670. }
  671.  
  672. /// <summary>
  673. /// Calculates the pie height.
  674. /// </summary>
  675. protected float PieHeight {
  676. get {
  677. return m_heightBoundingRect / (1 + LargestDisplacement) * m_sliceRelativeHeight;
  678. }
  679. }
  680.  
  681. /// <summary>
  682. /// Initializes pies.
  683. /// </summary>
  684. /// Creates a list of pies, starting with the pie that is crossing the
  685. /// 270 degrees boundary, i.e. "backmost" pie that always has to be
  686. /// drawn first to ensure correct surface overlapping.
  687. protected virtual void InitializePieSlices() {
  688. // calculates the sum of values required to evaluate sweep angles
  689. // for individual pies
  690. double sum = 0;
  691. foreach (double itemValue in m_values)
  692. sum += itemValue;
  693. // some values and indices that will be used in the loop
  694. SizeF topEllipeSize = TopEllipseSize;
  695. SizeF largestDisplacementEllipseSize = LargestDisplacementEllipseSize;
  696. int maxDisplacementIndex = m_sliceRelativeDisplacements.Length - 1;
  697. float largestDisplacement = LargestDisplacement;
  698. ArrayList listPieSlices = new ArrayList();
  699. m_pieSlicesMapping.Clear();
  700. int colorIndex = 0;
  701. int backPieIndex = -1;
  702. int displacementIndex = 0;
  703. double startAngle = (double)m_initialAngle;
  704. for (int i = 0; i < m_values.Length; ++i) {
  705. double itemValue = m_values[i];
  706. double sweepAngle = (double)itemValue / sum * 360;
  707. // displacement from the center of the ellipse
  708. float xDisplacement = m_sliceRelativeDisplacements[displacementIndex];
  709. float yDisplacement = m_sliceRelativeDisplacements[displacementIndex];
  710. if (xDisplacement > 0F) {
  711. Debug.Assert(largestDisplacement > 0F);
  712. SizeF pieDisplacement = GetSliceDisplacement((float)(startAngle + sweepAngle / 2), m_sliceRelativeDisplacements[displacementIndex]);
  713. xDisplacement = pieDisplacement.Width;
  714. yDisplacement = pieDisplacement.Height;
  715. }
  716. PieSlice slice = null;
  717. if (i == m_highlightedIndex)
  718. slice = CreatePieSliceHighlighted(m_xBoundingRect + largestDisplacementEllipseSize.Width / 2 + xDisplacement, m_yBoundingRect + largestDisplacementEllipseSize.Height / 2 + yDisplacement, topEllipeSize.Width, topEllipeSize.Height, PieHeight, (float)(startAngle % 360), (float)(sweepAngle), m_sliceColors[colorIndex], m_shadowStyle, m_edgeColorType, m_edgeLineWidth);
  719. else
  720. slice = CreatePieSlice(m_xBoundingRect + largestDisplacementEllipseSize.Width / 2 + xDisplacement, m_yBoundingRect + largestDisplacementEllipseSize.Height / 2 + yDisplacement, topEllipeSize.Width, topEllipeSize.Height, PieHeight, (float)(startAngle % 360), (float)(sweepAngle), m_sliceColors[colorIndex], m_shadowStyle, m_edgeColorType, m_edgeLineWidth);
  721. slice.Text = m_texts[i];
  722. // the backmost pie is inserted to the front of the list for correct drawing
  723. if (backPieIndex > -1 || ((startAngle <= 270) && (startAngle + sweepAngle > 270)) || ((startAngle >= 270) && (startAngle + sweepAngle > 630))) {
  724. ++backPieIndex;
  725. listPieSlices.Insert(backPieIndex, slice);
  726. m_pieSlicesMapping.Insert(backPieIndex, i);
  727. }
  728. else {
  729. listPieSlices.Add(slice);
  730. m_pieSlicesMapping.Add(i);
  731. }
  732. // increment displacementIndex only if there are more displacements available
  733. if (displacementIndex < maxDisplacementIndex)
  734. ++displacementIndex;
  735. ++colorIndex;
  736. // if all colors have been exhausted, reset color index
  737. if (colorIndex >= m_sliceColors.Length)
  738. colorIndex = 0;
  739. // prepare for the next pie slice
  740. startAngle += sweepAngle;
  741. if (startAngle > 360)
  742. startAngle -= 360;
  743. }
  744. m_pieSlices = (PieSlice[])listPieSlices.ToArray(typeof(PieSlice));
  745. }
  746.  
  747. /// <summary>
  748. /// Creates a <c>PieSlice</c> object.
  749. /// </summary>
  750. /// <param name="boundingRectLeft">
  751. /// x-coordinate of the upper-left corner of the rectangle that is
  752. /// used to draw the top surface of the slice.
  753. /// </param>
  754. /// <param name="boundingRectTop">
  755. /// y-coordinate of the upper-left corner of the rectangle that is
  756. /// used to draw the top surface of the slice.
  757. /// </param>
  758. /// <param name="boundingRectWidth">
  759. /// Width of the rectangle that is used to draw the top surface of
  760. /// the slice.
  761. /// </param>
  762. /// <param name="boundingRectHeight">
  763. /// Height of the rectangle that is used to draw the top surface of
  764. /// the slice.
  765. /// </param>
  766. /// <param name="sliceHeight">
  767. /// Slice height.
  768. /// </param>
  769. /// <param name="startAngle">
  770. /// Starting angle.
  771. /// </param>
  772. /// <param name="sweepAngle">
  773. /// Sweep angle.
  774. /// </param>
  775. /// <param name="color">
  776. /// Color used for slice rendering.
  777. /// </param>
  778. /// <param name="shadowStyle">
  779. /// Shadow style used for slice rendering.
  780. /// </param>
  781. /// <param name="edgeColorType">
  782. /// Edge lines color type.
  783. /// </param>
  784. /// <param name="edgeLineWidth">
  785. /// Edge lines width.
  786. /// </param>
  787. /// <returns>
  788. /// <c>PieSlice</c> object with given values.
  789. /// </returns>
  790. protected virtual PieSlice CreatePieSlice(float boundingRectLeft, float boundingRectTop, float boundingRectWidth, float boundingRectHeight, float sliceHeight, float startAngle, float sweepAngle, Color color, ShadowStyle shadowStyle, EdgeColorType edgeColorType, float edgeLineWidth) {
  791. return new PieSlice(boundingRectLeft, boundingRectTop, boundingRectWidth, boundingRectHeight, sliceHeight, (float)(startAngle % 360), sweepAngle, color, shadowStyle, edgeColorType, edgeLineWidth);
  792. }
  793.  
  794. /// <summary>
  795. /// Creates highlighted <c>PieSlice</c> object.
  796. /// </summary>
  797. /// <param name="boundingRectLeft">
  798. /// x-coordinate of the upper-left corner of the rectangle that is
  799. /// used to draw the top surface of the slice.
  800. /// </param>
  801. /// <param name="boundingRectTop">
  802. /// y-coordinate of the upper-left corner of the rectangle that is
  803. /// used to draw the top surface of the slice.
  804. /// </param>
  805. /// <param name="boundingRectWidth">
  806. /// Width of the rectangle that is used to draw the top surface of
  807. /// the slice.
  808. /// </param>
  809. /// <param name="boundingRectHeight">
  810. /// Height of the rectangle that is used to draw the top surface of
  811. /// the slice.
  812. /// </param>
  813. /// <param name="sliceHeight">
  814. /// Slice height.
  815. /// </param>
  816. /// <param name="startAngle">
  817. /// Starting angle.
  818. /// </param>
  819. /// <param name="sweepAngle">
  820. /// Sweep angle.
  821. /// </param>
  822. /// <param name="color">
  823. /// Color used for slice rendering.
  824. /// </param>
  825. /// <param name="shadowStyle">
  826. /// Shadow style used for slice rendering.
  827. /// </param>
  828. /// <param name="edgeColorType">
  829. /// Edge lines color type.
  830. /// </param>
  831. /// <param name="edgeLineWidth">
  832. /// Edge lines width.
  833. /// </param>
  834. /// <returns>
  835. /// <c>PieSlice</c> object with given values.
  836. /// </returns>
  837. protected virtual PieSlice CreatePieSliceHighlighted(float boundingRectLeft, float boundingRectTop, float boundingRectWidth, float boundingRectHeight, float sliceHeight, float startAngle, float sweepAngle, Color color, ShadowStyle shadowStyle, EdgeColorType edgeColorType, float edgeLineWidth) {
  838. Color highLightedColor = ColorUtil.CreateColorWithCorrectedLightness(color, ColorUtil.BrightnessEnhancementFactor1);
  839. return new PieSlice(boundingRectLeft, boundingRectTop, boundingRectWidth, boundingRectHeight, sliceHeight, (float)(startAngle % 360), sweepAngle, highLightedColor, shadowStyle, edgeColorType, edgeLineWidth);
  840. }
  841.  
  842. /// <summary>
  843. /// Calculates the displacement for given angle.
  844. /// </summary>
  845. /// <param name="angle">
  846. /// Angle (in degrees).
  847. /// </param>
  848. /// <param name="displacementFactor">
  849. /// Displacement factor.
  850. /// </param>
  851. /// <returns>
  852. /// <c>SizeF</c> representing displacement.
  853. /// </returns>
  854. protected SizeF GetSliceDisplacement(float angle, float displacementFactor) {
  855. Debug.Assert(displacementFactor > 0F && displacementFactor <= 1F);
  856. if (displacementFactor == 0F)
  857. return SizeF.Empty;
  858. float xDisplacement = (float)(TopEllipseSize.Width * displacementFactor / 2 * Math.Cos(angle * Math.PI / 180));
  859. float yDisplacement = (float)(TopEllipseSize.Height * displacementFactor / 2 * Math.Sin(angle * Math.PI / 180));
  860. return new SizeF(xDisplacement, yDisplacement);
  861. }
  862.  
  863. /// <summary>
  864. /// Draws outer peripheries of all slices.
  865. /// </summary>
  866. /// <param name="graphics">
  867. /// <c>Graphics</c> used for drawing.
  868. /// </param>
  869. protected void DrawSliceSides(Graphics graphics) {
  870. ArrayList pieSlicesList = new ArrayList(m_pieSlices);
  871. PieSlice ps = null;
  872. // if the first pie slice (crossing 270 i.e. back) is crossing 90
  873. // (front) axis too, we have to split it
  874. if ((m_pieSlices[0].StartAngle > 90) && (m_pieSlices[0].StartAngle <= 270) && (m_pieSlices[0].StartAngle + m_pieSlices[0].SweepAngle > 450)) {
  875. ps = (PieSlice)pieSlicesList[0];
  876. // this one is split at 0 deg to avoid line of split to be
  877. // visible on the periphery
  878. PieSlice[] splitSlices = ps.Split(0F);
  879. pieSlicesList[0] = splitSlices[0];
  880. if (splitSlices[1].SweepAngle > 0F) {
  881. pieSlicesList.Insert(1, splitSlices[1]);
  882. }
  883. }
  884. else if (((m_pieSlices[0].StartAngle > 270) && (m_pieSlices[0].StartAngle + m_pieSlices[0].SweepAngle > 450)) || ((m_pieSlices[0].StartAngle < 90) && (m_pieSlices[0].StartAngle + m_pieSlices[0].SweepAngle > 270))) {
  885. ps = (PieSlice)pieSlicesList[0];
  886. // this one is split at 180 deg to avoid line of split to be
  887. // visible on the periphery
  888. PieSlice[] splitSlices = ps.Split(180F);
  889. pieSlicesList[0] = splitSlices[1];
  890. if (splitSlices[1].SweepAngle > 0F) {
  891. pieSlicesList.Add(splitSlices[0]);
  892. }
  893. }
  894. // first draw the backmost pie slice
  895. ps = (PieSlice)pieSlicesList[0];
  896. ps.DrawSides(graphics);
  897. // draw pie slices from the backmost to forward
  898. int incrementIndex = 1;
  899. int decrementIndex = pieSlicesList.Count - 1;
  900. while (incrementIndex < decrementIndex) {
  901. PieSlice sliceLeft = (PieSlice)pieSlicesList[decrementIndex];
  902. float angle1 = sliceLeft.StartAngle - 90;
  903. if (angle1 > 180 || angle1 < 0)
  904. angle1 = 0;
  905. PieSlice sliceRight = (PieSlice)pieSlicesList[incrementIndex];
  906. float angle2 = (450 - sliceRight.EndAngle) % 360;
  907. if (angle2 > 180 || angle2 < 0)
  908. angle2 = 0;
  909. Debug.Assert(angle1 >= 0);
  910. Debug.Assert(angle2 >= 0);
  911. if (angle2 >= angle1) {
  912. sliceRight.DrawSides(graphics);
  913. ++incrementIndex;
  914. }
  915. else if (angle2 < angle1) {
  916. sliceLeft.DrawSides(graphics);
  917. --decrementIndex;
  918. }
  919. }
  920. ps = (PieSlice)pieSlicesList[decrementIndex];
  921. ps.DrawSides(graphics);
  922. }
  923.  
  924. /// <summary>
  925. /// Draws bottom sides of all pie slices.
  926. /// </summary>
  927. /// <param name="graphics">
  928. /// <c>Graphics</c> used for drawing.
  929. /// </param>
  930. protected void DrawBottoms(Graphics graphics) {
  931. foreach (PieSlice slice in m_pieSlices) {
  932. slice.DrawBottom(graphics);
  933. }
  934. }
  935.  
  936. /// <summary>
  937. /// Draws top sides of all pie slices.
  938. /// </summary>
  939. /// <param name="graphics">
  940. /// <c>Graphics</c> used for drawing.
  941. /// </param>
  942. protected void DrawTops(Graphics graphics) {
  943. foreach (PieSlice slice in m_pieSlices) {
  944. slice.DrawTop(graphics);
  945. }
  946. }
  947.  
  948. /// <summary>
  949. /// Helper function used in assertions. Checks the validity of
  950. /// slice displacements.
  951. /// </summary>
  952. /// <param name="displacements">
  953. /// Array of displacements to check.
  954. /// </param>
  955. /// <returns>
  956. /// <c>true</c> if all displacements have a valid value; otherwise
  957. /// <c>false</c>.
  958. /// </returns>
  959. private bool AreDisplacementsValid(float[] displacements) {
  960. foreach (float value in displacements) {
  961. if (!IsDisplacementValid(value))
  962. return false;
  963. }
  964. return true;
  965. }
  966.  
  967. /// <summary>
  968. /// Helper function used in assertions. Checks the validity of
  969. /// a slice displacement.
  970. /// </summary>
  971. /// <param name="value">
  972. /// Displacement value to check.
  973. /// </param>
  974. /// <returns>
  975. /// <c>true</c> if displacement has a valid value; otherwise
  976. /// <c>false</c>.
  977. /// </returns>
  978. private bool IsDisplacementValid(float value) {
  979. return (value >= 0F && value <= 1F);
  980. }
  981.  
  982. /// <summary>
  983. /// x-coordinate of the top left corner of the bounding rectangle.
  984. /// </summary>
  985. protected float m_xBoundingRect;
  986. /// <summary>
  987. /// y-coordinate of the top left corner of the bounding rectangle.
  988. /// </summary>
  989. protected float m_yBoundingRect;
  990. /// <summary>
  991. /// Width of the bounding rectangle.
  992. /// </summary>
  993. protected float m_widthBoundingRect;
  994. /// <summary>
  995. /// Height of the bounding rectangle.
  996. /// </summary>
  997. protected float m_heightBoundingRect;
  998. /// <summary>
  999. /// Slice relative height.
  1000. /// </summary>
  1001. protected float m_sliceRelativeHeight = 0F;
  1002. /// <summary>
  1003. /// Initial angle from which chart is drawn.
  1004. /// </summary>
  1005. protected float m_initialAngle = 0F;
  1006. /// <summary>
  1007. /// Array of ordered pie slices constituting the chart, starting from
  1008. /// 270 degrees axis.
  1009. /// </summary>
  1010. protected PieSlice[] m_pieSlices;
  1011. /// <summary>
  1012. /// Collection of reordered pie slices mapped to original order.
  1013. /// </summary>
  1014. protected ArrayList m_pieSlicesMapping = new ArrayList();
  1015. /// <summary>
  1016. /// Array of values to be presented by the chart.
  1017. /// </summary>
  1018. protected double[] m_values = new double[] {};
  1019. /// <summary>
  1020. /// Array of colors used for rendering.
  1021. /// </summary>
  1022. protected Color[] m_sliceColors = new Color[] {
  1023. Color.Red,
  1024. Color.Green,
  1025. Color.Blue,
  1026. Color.Yellow,
  1027. Color.Purple,
  1028. Color.Olive,
  1029. Color.Navy,
  1030. Color.Aqua,
  1031. Color.Lime,
  1032. Color.Maroon,
  1033. Color.Teal,
  1034. Color.Fuchsia
  1035. };
  1036. /// <summary>
  1037. /// Array of description texts.
  1038. /// </summary>
  1039. protected string[] m_texts;
  1040. /// <summary>
  1041. /// Font used to display texts.
  1042. /// </summary>
  1043. protected Font m_font = System.Windows.Forms.Control.DefaultFont;
  1044. /// <summary>
  1045. /// Fore color used to display texts.
  1046. /// </summary>
  1047. protected Color m_foreColor = SystemColors.WindowText;
  1048. /// <summary>
  1049. /// Array of relative displacements from the common center.
  1050. /// </summary>
  1051. protected float[] m_sliceRelativeDisplacements = new float[] { 0F };
  1052. /// <summary>
  1053. /// Edge color type used for rendering.
  1054. /// </summary>
  1055. protected EdgeColorType m_edgeColorType = EdgeColorType.SystemColor;
  1056. /// <summary>
  1057. /// Edge line width.
  1058. /// </summary>
  1059. protected float m_edgeLineWidth = 1F;
  1060. /// <summary>
  1061. /// Shadow style.
  1062. /// </summary>
  1063. protected ShadowStyle m_shadowStyle = ShadowStyle.NoShadow;
  1064. /// <summary>
  1065. /// Should the chart fit the bounding rectangle exactly.
  1066. /// </summary>
  1067. protected bool m_fitToBoundingRectangle = true;
  1068. /// <summary>
  1069. /// Index of the currently highlighted pie slice.
  1070. /// </summary>
  1071. protected int m_highlightedIndex = -1;
  1072. /// <summary>
  1073. /// Flag indicating if object has been disposed.
  1074. /// </summary>
  1075. private bool m_disposed = false;
  1076. }
  1077. }

Structure et Fichiers du projet

Afficher/masquer...


Répertoires contenus dans /var/www/bin/sniplets/bibliobrol/broldev/src/model/drawing/chart/ 
IcôneNomTailleModification
Pas de sous-répertoires.
IcôneNomTailleModification
| _ Répertoire parent0 octets1734968978 23/12/2024 16:49:38
Fichiers contenus dans /var/www/bin/sniplets/bibliobrol/broldev/src/model/drawing/chart/ 
IcôneNomTailleModificationAction
IcôneNomTailleModificationAction
Afficher le fichier .cs|.csShadowStyle.cs620 octets31/10/2018 18:33:22-refusé-
Afficher le fichier .cs|.csEdgeColor.cs2.92 Ko31/10/2018 18:33:21-refusé-
Afficher le fichier .cs|.csPieChart.cs44.97 Ko31/10/2018 18:33:22-refusé-
Afficher le fichier .cs|.csColorUtil.cs2.05 Ko31/10/2018 18:33:21-refusé-
Afficher le fichier .resx|.resxPieChartControl.resx1.69 Ko31/10/2018 18:33:22-refusé-
Afficher le fichier .cs|.csPieChartControl.cs14.04 Ko31/10/2018 18:33:22-refusé-
Afficher le fichier .cs|.csPieSlice.cs52.86 Ko31/10/2018 18:33:22-refusé-
Afficher le fichier .cs|.csGraphicsUtil.cs2.33 Ko31/10/2018 18:33:21-refusé-
Afficher le fichier .cs|.csQuadrilateral.cs6.42 Ko31/10/2018 18:33:22-refusé-
Afficher le fichier .cs|.csEdgeColorType.cs1.64 Ko31/10/2018 18:33:21-refusé-

Utilisation de l'explorateur de code

  • Navigation :
    • Un clic sur une icône de répertoire ouvre ce répertoire pour en afficher les fichiers.
    • Lorsque le répertoire en cours ne contient pas de sous-répertoires il est possible de remonter vers le répertoire parent.
    • La structure de répertoires en treetable (tableau en forme d'arborescence) n'est plus possibledans cette version.
    • Un clic sur une icône de fichier ouvre ce fichier pour en afficher le code avec la coloration syntaxique adaptée en fonction du langage principal utilisé dans le fichier.
  • Affichage :
    • Il est possible de trier les répertoires ou les fichiers selon certains critères (nom, taille, date).
  • Actions :
    • Les actions possible sur les fichiers dépendent de vos droits d'utilisateur sur le site. Veuillez activer le mode utilisateur pour activer les actions.

Nederlandse vertaling

U hebt gevraagd om deze site in het Nederlands te bezoeken. Voor nu wordt alleen de interface vertaald, maar nog niet alle inhoud.

Als je me wilt helpen met vertalingen, is je bijdrage welkom. Het enige dat u hoeft te doen, is u op de site registreren en mij een bericht sturen waarin u wordt gevraagd om u toe te voegen aan de groep vertalers, zodat u de gewenste pagina's kunt vertalen. Een link onderaan elke vertaalde pagina geeft aan dat u de vertaler bent en heeft een link naar uw profiel.

Bij voorbaat dank.

Document heeft de 16/10/2009 gemaakt, de laatste keer de 26/10/2018 gewijzigd
Bron van het afgedrukte document:https://www.gaudry.be/nl/cs-broldev-source-rf-model/drawing/chart/PieChart.cs.html

De infobrol is een persoonlijke site waarvan de inhoud uitsluitend mijn verantwoordelijkheid is. De tekst is beschikbaar onder CreativeCommons-licentie (BY-NC-SA). Meer info op de gebruiksvoorwaarden en de auteur.