Advertisement
digemall

MSChart Polar chart with selection

Sep 21st, 2012
1,160
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 15.24 KB | None | 0 0
  1. // This code shows how to implement mouse-drag selection of points in a Polar chart using mschart.
  2. //
  3. // Features:
  4. //  - points inside the selection are highlighted
  5. //  - after the selection, the points coordinates are shown in a textbox
  6. //
  7. // To test it follow these steps:
  8. //  - open VS and create a new Windows Forms Application project called "PolarChartSelectionTest"
  9. //  - remove the automatically generated Form1.cs class
  10. //  - then add a new class called Form1 (yes, the same name of the just-deleted class)
  11. //  - open Form1.cs and replace the code with the following
  12. //  - add a reference to the assembly System.Windows.Forms.DataVisualization.dll
  13. //
  14. //
  15. // Requirements:
  16. //  - .net framework 4 (or .net framework 3.5 with mschart.exe installed)
  17.  
  18.  
  19. using System;
  20. using System.Drawing;
  21. using System.Windows.Forms;
  22. using System.Windows.Forms.DataVisualization.Charting;
  23.  
  24. namespace PolarChartSelectionTest
  25. {
  26.     public partial class Form1: Form
  27.     {
  28.         #region Nested Classes
  29.  
  30.         internal class PolarPoint
  31.         {
  32.             public double Angle { get; private set; }
  33.             public double Y { get; private set; }
  34.             public PolarPoint(double angle, double y)
  35.             {
  36.                 this.Angle = angle;
  37.                 this.Y = y;
  38.             }
  39.         }
  40.  
  41.         internal class RectangleInPolarPoints
  42.         {
  43.             public PolarPoint TopLeft { get; private set; }
  44.             public PolarPoint TopRight { get; private set; }
  45.             public PolarPoint BottomLeft { get; private set; }
  46.             public PolarPoint BottonRight { get; private set; }
  47.             public RectangleInPolarPoints(PolarPoint topLeft, PolarPoint bottomLeft, PolarPoint topRight, PolarPoint bottomRight)
  48.             {
  49.                 this.TopLeft = topLeft;
  50.                 this.TopRight = topRight;
  51.                 this.BottomLeft = bottomLeft;
  52.                 this.BottonRight = bottomRight;
  53.             }
  54.         }
  55.  
  56.         internal struct PointD
  57.         {
  58.             public double X { get; private set; }
  59.             public double Y { get; private set; }
  60.             public PointD(double x, double y)
  61.                 : this()
  62.             {
  63.                 this.X = x;
  64.                 this.Y = y;
  65.             }
  66.         }
  67.  
  68.         #endregion
  69.  
  70.         #region Designer code
  71.  
  72.         private System.Windows.Forms.DataVisualization.Charting.Chart chart1;
  73.         private System.Windows.Forms.TextBox textBox1;
  74.         private System.Windows.Forms.SplitContainer splitContainer1;
  75.  
  76.         private void InitializeComponent()
  77.         {
  78.             System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
  79.             System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
  80.             System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
  81.             this.chart1 = new System.Windows.Forms.DataVisualization.Charting.Chart();
  82.             this.textBox1 = new System.Windows.Forms.TextBox();
  83.             this.splitContainer1 = new System.Windows.Forms.SplitContainer();
  84.             ((System.ComponentModel.ISupportInitialize)(this.chart1)).BeginInit();
  85.             this.splitContainer1.Panel1.SuspendLayout();
  86.             this.splitContainer1.Panel2.SuspendLayout();
  87.             this.splitContainer1.SuspendLayout();
  88.             this.SuspendLayout();
  89.             //
  90.             // chart1
  91.             //
  92.             chartArea1.Name = "ChartArea1";
  93.             this.chart1.ChartAreas.Add(chartArea1);
  94.             this.chart1.Dock = System.Windows.Forms.DockStyle.Fill;
  95.             legend1.Name = "Legend1";
  96.             this.chart1.Legends.Add(legend1);
  97.             this.chart1.Location = new System.Drawing.Point(0, 0);
  98.             this.chart1.Name = "chart1";
  99.             series1.ChartArea = "ChartArea1";
  100.             series1.Legend = "Legend1";
  101.             series1.Name = "Series1";
  102.             this.chart1.Series.Add(series1);
  103.             this.chart1.Size = new System.Drawing.Size(644, 339);
  104.             this.chart1.TabIndex = 0;
  105.             this.chart1.Text = "chart1";
  106.             //
  107.             // textBox1
  108.             //
  109.             this.textBox1.Dock = System.Windows.Forms.DockStyle.Fill;
  110.             this.textBox1.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
  111.             this.textBox1.Location = new System.Drawing.Point(0, 0);
  112.             this.textBox1.Multiline = true;
  113.             this.textBox1.Name = "textBox1";
  114.             this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
  115.             this.textBox1.Size = new System.Drawing.Size(644, 79);
  116.             this.textBox1.TabIndex = 1;
  117.             //
  118.             // splitContainer1
  119.             //
  120.             this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
  121.             this.splitContainer1.Location = new System.Drawing.Point(0, 0);
  122.             this.splitContainer1.Name = "splitContainer1";
  123.             this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
  124.             //
  125.             // splitContainer1.Panel1
  126.             //
  127.             this.splitContainer1.Panel1.Controls.Add(this.chart1);
  128.             //
  129.             // splitContainer1.Panel2
  130.             //
  131.             this.splitContainer1.Panel2.Controls.Add(this.textBox1);
  132.             this.splitContainer1.Size = new System.Drawing.Size(644, 422);
  133.             this.splitContainer1.SplitterDistance = 339;
  134.             this.splitContainer1.TabIndex = 2;
  135.             //
  136.             // Form1
  137.             //
  138.             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
  139.             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
  140.             this.ClientSize = new System.Drawing.Size(644, 422);
  141.             this.Controls.Add(this.splitContainer1);
  142.             this.Name = "MyForm";
  143.             this.Text = "Polar chart with selection";
  144.             ((System.ComponentModel.ISupportInitialize)(this.chart1)).EndInit();
  145.             this.splitContainer1.Panel1.ResumeLayout(false);
  146.             this.splitContainer1.Panel2.ResumeLayout(false);
  147.             this.splitContainer1.Panel2.PerformLayout();
  148.             this.splitContainer1.ResumeLayout(false);
  149.             this.ResumeLayout(false);
  150.  
  151.         }
  152.         #endregion
  153.  
  154.         #region Constructor
  155.  
  156.         public Form1()
  157.         {
  158.             InitializeComponent();
  159.  
  160.             this.chart1.MouseDown += new MouseEventHandler(chart1_MouseDown);
  161.             this.chart1.MouseMove += new MouseEventHandler(chart1_MouseMove);
  162.             this.chart1.MouseUp += new MouseEventHandler(chart1_MouseUp);
  163.             this.chart1.PostPaint += new EventHandler<ChartPaintEventArgs>(chart1_PostPaint);
  164.         }
  165.         #endregion
  166.  
  167.         #region Chart Data Initialization
  168.  
  169.         protected override void OnLoad(EventArgs e)
  170.         {
  171.             this.FillChart();
  172.         }
  173.  
  174.         private void FillChart()
  175.         {
  176.             var items = new[] { new PolarPoint(0, 10), new PolarPoint(30, 4), new PolarPoint(120, 2), new PolarPoint(185, 9), new PolarPoint(240, 7) };
  177.  
  178.             this.chart1.Series.Clear();
  179.             var seriesLines = this.chart1.Series.Add("Values");
  180.             seriesLines.XValueMember = "Angle";
  181.             seriesLines.YValueMembers = "Y";
  182.             seriesLines.ChartType = SeriesChartType.Polar;
  183.  
  184.             this.chart1.DataSource = items;
  185.         }
  186.         #endregion
  187.  
  188.         #region Selection Management
  189.  
  190.         Point? clickPoint;
  191.         RectangleF? highlightRectAbs;
  192.         RectangleInPolarPoints highlightRect;
  193.  
  194.         void chart1_MouseDown(object sender, MouseEventArgs e)
  195.         {
  196.             this.highlightRectAbs = null;
  197.             this.highlightRect = null;
  198.  
  199.             // deselect all points
  200.             var s = this.chart1.Series[0];
  201.             for (int i = 0; i < s.Points.Count; i++)
  202.                 s.Points[i].Tag = false;
  203.  
  204.             this.clickPoint = e.Location;
  205.         }
  206.  
  207.         void chart1_MouseMove(object sender, MouseEventArgs e)
  208.         {
  209.             if (this.clickPoint.HasValue && this.clickPoint != e.Location)
  210.             {
  211.                 int width = Math.Abs(e.X - this.clickPoint.Value.X);
  212.                 int height = Math.Abs(e.Y - this.clickPoint.Value.Y);
  213.                 int x = Math.Min(e.X, this.clickPoint.Value.X);
  214.                 int y = Math.Min(e.Y, this.clickPoint.Value.Y);
  215.  
  216.                 this.highlightRectAbs = new RectangleF(x, y, width, height);
  217.                 this.highlightRect = null;
  218.                 if (this.highlightRectAbs.Value.Width != 0 && this.highlightRectAbs.Value.Height != 0)
  219.                 {
  220.                     this.chart1.Invalidate();
  221.                 }
  222.             }
  223.         }
  224.  
  225.         void chart1_MouseUp(object sender, MouseEventArgs e)
  226.         {
  227.             this.clickPoint = null;
  228.             this.chart1.Invalidate();
  229.  
  230.             // here we have finished our selection
  231.             this.SelectionFinished();
  232.         }
  233.  
  234.         void chart1_PostPaint(object sender, ChartPaintEventArgs e)
  235.         {
  236.             var area = e.ChartElement as ChartArea;
  237.             if (area == null)
  238.                 return;
  239.  
  240.             if (!this.highlightRectAbs.HasValue)
  241.                 return;
  242.  
  243.             // get center and radius
  244.             var minY = area.AxisY.ValueToPixelPosition(area.AxisY.Minimum);
  245.             var maxX = area.AxisX.ValueToPixelPosition(area.AxisX.Maximum);
  246.             var maxY = area.AxisY.ValueToPixelPosition(area.AxisY.Maximum);
  247.             var radius = Math.Abs(maxY - minY);
  248.             var centerX = maxX;
  249.             var centerY = minY;
  250.  
  251.             if (this.highlightRect == null)
  252.                 this.highlightRect = GetRectangleInPolarPoints(this.highlightRectAbs.Value, area, centerX, centerY, radius);
  253.             this.highlightRectAbs = GetRectangleF(this.highlightRect, area, centerX, centerY, radius);
  254.  
  255.             using (var brush = new SolidBrush(Color.FromArgb(15, Color.Black)))
  256.             {
  257.                 var cg = e.ChartGraphics;
  258.                 cg.Graphics.FillRectangle(brush, this.highlightRectAbs.Value);
  259.                 cg.Graphics.DrawRectangle(Pens.Red, this.highlightRectAbs.Value.X, this.highlightRectAbs.Value.Y,
  260.                                           this.highlightRectAbs.Value.Width, this.highlightRectAbs.Value.Height);
  261.  
  262.                 var s = e.Chart.Series[0];
  263.                 for (int i = 0; i < s.Points.Count; i++)
  264.                 {
  265.                     var point = s.Points[i];
  266.  
  267.                     var pt = GetCoordsOfPoint(point.XValue, point.YValues[0], area, centerX, centerY, radius);
  268.  
  269.                     // highlights the points if they're into the selection
  270.                     if (this.highlightRectAbs.Value.Contains(pt))
  271.                     {
  272.                         cg.Graphics.FillEllipse(Brushes.GreenYellow, pt.X - 5, pt.Y - 5, 10, 10);
  273.                         point.Tag = true;
  274.                     }
  275.                     else
  276.                     {
  277.                         point.Tag = false;
  278.                     }
  279.                 }
  280.             }
  281.  
  282.         }
  283.  
  284.         private void SelectionFinished()
  285.         {
  286.             this.textBox1.Text = "Selection:" + Environment.NewLine;
  287.             var s = this.chart1.Series[0];
  288.             for (int i = 0; i < s.Points.Count; i++)
  289.             {
  290.                 var point = s.Points[i];
  291.                 if (point.Tag is bool && (bool)point.Tag == true)
  292.                     this.textBox1.AppendText(string.Format("Angle = {0,6:N2}, Y = {1,6:N2}\r\n", point.XValue, point.YValues[0]));
  293.             }
  294.         }
  295.  
  296.         #endregion
  297.  
  298.         #region Helper Methods
  299.  
  300.         static PointF GetCoordsOfPoint(PolarPoint polPt, ChartArea area, double centerX, double centerY, double radius)
  301.         {
  302.             return GetCoordsOfPoint(polPt.Angle, polPt.Y, area, centerX, centerY, radius);
  303.         }
  304.  
  305.         static PointF GetCoordsOfPoint(double angle, double yVal, ChartArea area, double centerX, double centerY, double radius)
  306.         {
  307.             double xRatio = 360.0 / Math.Abs(area.AxisX.Maximum - area.AxisX.Minimum);
  308.             double radAngle = (-(angle * xRatio + area.AxisX.Crossing) - 270) * Math.PI / 180;
  309.             double yRadius = Scale(yVal, area.AxisY.Minimum, area.AxisY.Maximum, 0, radius);
  310.  
  311.             double h = Math.Sin(radAngle);
  312.             double w = Math.Cos(radAngle);
  313.  
  314.             return new PointF((float)(centerX + w * yRadius), (float)(centerY - h * yRadius));
  315.         }
  316.  
  317.         static PolarPoint GetPolarPointFromCoords(double x, double y, ChartArea area, double centerX, double centerY, double radius)
  318.         {
  319.             double xRatio = 360.0 / Math.Abs(area.AxisX.Maximum - area.AxisX.Minimum);
  320.  
  321.             var xComp = x - centerX;
  322.             var yComp = centerY - y;
  323.  
  324.             var hypotenuseLength = Math.Sqrt(xComp * xComp + yComp * yComp);
  325.             var angle = GetZero360Angle(-(Math.Atan2(yComp, xComp) * 180 / Math.PI) - 270);
  326.  
  327.             //angle = Scale(angle, 0, 360, area.AxisX.Minimum, area.AxisX.Maximum);
  328.             angle = (angle - area.AxisX.Crossing) / xRatio;
  329.  
  330.             return new PolarPoint(angle , Scale(hypotenuseLength, 0, radius, area.AxisY.Minimum, area.AxisY.Maximum));
  331.         }
  332.  
  333.         static RectangleInPolarPoints GetRectangleInPolarPoints(RectangleF rect, ChartArea area, double centerX, double centerY, double radius)
  334.         {
  335.             var topLeft = GetPolarPointFromCoords(rect.Left, rect.Top, area, centerX, centerY, radius);
  336.             var bottomLeft = GetPolarPointFromCoords(rect.Left, rect.Bottom, area, centerX, centerY, radius);
  337.             var topRight = GetPolarPointFromCoords(rect.Right, rect.Top, area, centerX, centerY, radius);
  338.             var bottomRight = GetPolarPointFromCoords(rect.Right, rect.Bottom, area, centerX, centerY, radius);
  339.             return new RectangleInPolarPoints(topLeft, bottomLeft, topRight, bottomRight);
  340.         }
  341.  
  342.         static RectangleF GetRectangleF(RectangleInPolarPoints recPolar, ChartArea area, double centerX, double centerY, double radius)
  343.         {
  344.             var topLeftPt = GetCoordsOfPoint(recPolar.TopLeft, area, centerX, centerY, radius);
  345.             var bottomLeftPt = GetCoordsOfPoint(recPolar.BottomLeft, area, centerX, centerY, radius);
  346.             var topRightPt = GetCoordsOfPoint(recPolar.TopRight, area, centerX, centerY, radius);
  347.  
  348.             var width = (float)(topRightPt.X - topLeftPt.X);
  349.             var height = (float)(bottomLeftPt.Y - topLeftPt.Y);
  350.  
  351.             return new RectangleF(topLeftPt, new SizeF(width, height));
  352.         }
  353.  
  354.         static double GetZero360Angle(double angle)
  355.         {
  356.             while (angle < 0)
  357.                 angle += 360;
  358.             while (angle > 360)
  359.                 angle -= 360;
  360.             return angle;
  361.         }
  362.  
  363.  
  364.         static double Scale(double oldScaleVal, double oldScaleMin, double oldScaleMax, double newScaleMin, double newScaleMax)
  365.         {
  366.             return newScaleMin + (oldScaleVal - oldScaleMin) / (oldScaleMax - oldScaleMin) * (newScaleMax - newScaleMin);
  367.         }
  368.  
  369.         #endregion
  370.     }
  371. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement