【问题标题】:Showing Mouse Axis Coordinates on Chart Control在图表控件上显示鼠标轴坐标
【发布时间】:2011-03-24 20:29:31
【问题描述】:

有没有一种简单的方法来检索图表区域中任何点的 X/Y 坐标(当然是相对于该图表轴)?

到目前为止,我只是在鼠标位于系列(而不是外部)上时设法检索坐标

private void chart_GetToolTipText(object sender, ToolTipEventArgs e)
{
    if (e.HitTestResult.Series != null)
    {
        e.Text = e.HitTestResult.Series.Points[e.HitTestResult.PointIndex].YValues[0] + " \n " + DateTime.FromOADate(e.HitTestResult.Series.Points[e.HitTestResult.PointIndex].XValue);
    }
}

【问题讨论】:

    标签: c# .net mschart


    【解决方案1】:

    无论如何,与 MS Chart Controls 一样,没有简单的方法来做事情,
    但是一个时髦的解决方法可以完成事情。可惜我已经习惯了……

    private void chart1_MouseWhatever(object sender, MouseEventArgs e)
    {
        chartArea1.CursorX.SetCursorPixelPosition(new Point(e.X, e.Y), true);
        chartArea1.CursorY.SetCursorPixelPosition(new Point(e.X, e.Y), true);
    
        double pX = chartArea1.CursorX.Position; //X Axis Coordinate of your mouse cursor
        double pY = chartArea1.CursorY.Position; //Y Axis Coordinate of your mouse cursor
    }
    

    【讨论】:

    • 我刚刚尝试过:pX 工作正常,但 pY 保持不变(=1)(而 e.X 和 e.Y 都发生了变化)。它还添加了一个全图十字准线,在某些特定情况下可能不受欢迎。
    【解决方案2】:

    这适用于我的目的,不会影响光标。

    private Tuple<double,double> GetAxisValuesFromMouse(int x, int y)
    {
        var chartArea = _chart.ChartAreas[0];
        var xValue = chartArea.AxisX.PixelPositionToValue(x);
        var yValue = chartArea.AxisY.PixelPositionToValue(y);
        return new Tuple<double, double>(xValue, yValue);
    }
    

    【讨论】:

      【解决方案3】:

      我试过你的答案,但它对我不起作用。它最终将光标放在一个位置并且从不移动。我相信这是因为我在两个轴上都使用十进制/双精度值,并且光标正在四舍五入到最接近的整数。

      经过几次尝试,我找到了一种方法来确定光标在图表中的位置。困难的部分是弄清楚图表元素的所有“位置”实际上都是百分比值(从 0 到 100)。

      根据
      http://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.elementposition.aspx:
      “定义图表元素在相对坐标中的位置,范围从 (0,0) 到 (100,100)。”

      我希望你不介意,我在这里发布这个答案只是为了后代,以防其他人遇到这个问题,而你的方法也不适用于他们。它在任何方面都不漂亮或优雅,但到目前为止它对我有用。

      private struct PointD
      {
        public double X;
        public double Y;
        public PointD(double X, double Y)
        {
          this.X = X;
          this.Y = Y;
        }
      }
      
      private void chart1_MouseMove(object sender, MouseEventArgs e)
      {
        var pos = LocationInChart(e.X, e.Y);
        lblCoords.Text = string.Format("({0}, {1}) ... ({2}, {3})", e.X, e.Y, pos.X, pos.Y);
      }
      
      private PointD LocationInChart(double xMouse, double yMouse)
      {
        var ca = chart1.ChartAreas[0];
      
        //Position inside the control, from 0 to 100
        var relPosInControl = new PointD
        (
          ((double)xMouse / (double)execDetailsChart.Width) * 100,
          ((double)yMouse / (double)execDetailsChart.Height) * 100
        );
      
        //Verify we are inside the Chart Area
        if (relPosInControl.X < ca.Position.X || relPosInControl.X > ca.Position.Right
        || relPosInControl.Y < ca.Position.Y || relPosInControl.Y > ca.Position.Bottom) return new PointD(double.NaN, double.NaN);
      
        //Position inside the Chart Area, from 0 to 100
        var relPosInChartArea = new PointD
        (
          ((relPosInControl.X - ca.Position.X) / ca.Position.Width) * 100,
          ((relPosInControl.Y - ca.Position.Y) / ca.Position.Height) * 100
        );
      
        //Verify we are inside the Plot Area
        if (relPosInChartArea.X < ca.InnerPlotPosition.X || relPosInChartArea.X > ca.InnerPlotPosition.Right
        || relPosInChartArea.Y < ca.InnerPlotPosition.Y || relPosInChartArea.Y > ca.InnerPlotPosition.Bottom) return new PointD(double.NaN, double.NaN);
      
        //Position inside the Plot Area, 0 to 1
        var relPosInPlotArea = new PointD
        (
          ((relPosInChartArea.X - ca.InnerPlotPosition.X) / ca.InnerPlotPosition.Width),
          ((relPosInChartArea.Y - ca.InnerPlotPosition.Y) / ca.InnerPlotPosition.Height)
        );
      
        var X = relPosInPlotArea.X * (ca.AxisX.Maximum - ca.AxisX.Minimum) + ca.AxisX.Minimum;
        var Y = (1 - relPosInPlotArea.Y) * (ca.AxisY.Maximum - ca.AxisY.Minimum) + ca.AxisY.Minimum;
      
        return new PointD(X, Y);
      }
      

      【讨论】:

        【解决方案4】:
        private void OnChartMouseMove(object sender, MouseEventArgs e)
        {
            var sourceChart = sender as Chart;
            HitTestResult result = sourceChart.HitTest(e.X, e.Y);
            ChartArea chartAreas = sourceChart.ChartAreas[0];
        
            if (result.ChartElementType == ChartElementType.DataPoint)  
            {
                chartAreas.CursorX.Position = chartAreas.AxisX.PixelPositionToValue(e.X);
                chartAreas.CursorY.Position = chartAreas.AxisY.PixelPositionToValue(e.Y);
            }
        }
        

        【讨论】:

        • 有效,甚至是axisY!谢谢
        【解决方案5】:

        这行得通

        private void chart1_MouseWhatever(object sender, MouseEventArgs e)
        {   
            Point chartLocationOnForm = chart1.FindForm().PointToClient(chart1.Parent.PointToScreen(chart1.Location));     
        
            double x = chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X - chartLocationOnForm.X);    
            double y = chart1.ChartAreas[0].AxisY.PixelPositionToValue(e.Y - chartLocationOnForm.Y);
        }
        

        这行得通

        private void chart1_MouseWhatever(object sender, MouseEventArgs e)
        { 
            Point chartLocationOnForm = chart1.FindForm().PointToClient(chart1.Parent.PointToScreen(chart1.Location));                
        
            chart1.ChartAreas[0].CursorX.SetCursorPixelPosition(new PointF(e.X - chartLocationOnForm.X, e.Y - chartLocationOnForm.Y), true);
            chart1.ChartAreas[0].CursorY.SetCursorPixelPosition(new PointF(e.X - chartLocationOnForm.X, e.Y - chartLocationOnForm.Y), true);
        
            double x = chart1.ChartAreas[0].CursorX.Position;
            double y = chart1.ChartAreas[0].CursorY.Position;
        }
        

        【讨论】:

        • 多一点解释总是能让你的答案更有价值;)
        • 第一个对我不起作用。 e.X 值为零,chartlocation 为 28,因此当我尝试在那里定位注释时,x 为负数(导致异常)。
        【解决方案6】:

        这就是我得到的,我认为我们中的许多人都在同一条线上,但对您要寻找的东西有不同的解释。

        这将为您提供绘图区域中任何位置的坐标。我发现HitTest 提供了一个简洁明了的解决方案,但是需要进行一些检查,无论光标是在数据点、网格线上还是在绘图区域(似乎按此顺序优先)。我假设您会对坐标感兴趣,无论鼠标在哪个对象上。

        private void chart_GetToolTipText(object sender, ToolTipEventArgs e)
        {
            // If the mouse isn't on the plotting area, a datapoint, or gridline then exit
            HitTestResult htr = chart.HitTest(e.X, e.Y);
            if (htr.ChartElementType != ChartElementType.PlottingArea && htr.ChartElementType != ChartElementType.DataPoint && htr.ChartElementType != ChartElementType.Gridlines)
                return;
        
            ChartArea ca = chart.ChartAreas[0]; // Assuming you only have 1 chart area on the chart
        
            double xCoord = ca.AxisX.PixelPositionToValue(e.X);
            double yCoord = ca.AxisY.PixelPositionToValue(e.Y);
        
            e.Text = "X = " + Math.Round(xCoord, 2).ToString() + "\nY = " + Math.Round(yCoord, 2).ToString();
        }
        

        【讨论】:

          【解决方案7】:

          VB.net 版本,带缩放校正:

          Private Function LocationInChart(xMouse, yMouse) As PointF
              Dim ca = Chart1.ChartAreas(0)
          
              'Position inside the control, from 0 to 100
              Dim relPosInControl = New PointF((xMouse / Chart1.Width) * 100, (yMouse / Chart1.Height) * 100)
          
              'Verify we are inside the Chart Area
              If (relPosInControl.X < ca.Position.X Or relPosInControl.X > ca.Position.Right Or relPosInControl.Y < ca.Position.Y Or relPosInControl.Y > ca.Position.Bottom) Then Return New PointF(Double.NaN, Double.NaN)
          
              'Position inside the Chart Area, from 0 to 100
              Dim relPosInChartArea = New PointF(((relPosInControl.X - ca.Position.X) / ca.Position.Width) * 100, ((relPosInControl.Y - ca.Position.Y) / ca.Position.Height) * 100)
          
              'Verify we are inside the Plot Area
              If (relPosInChartArea.X < ca.InnerPlotPosition.X Or relPosInChartArea.X > ca.InnerPlotPosition.Right Or relPosInChartArea.Y < ca.InnerPlotPosition.Y Or relPosInChartArea.Y > ca.InnerPlotPosition.Bottom) Then Return New PointF(Double.NaN, Double.NaN)
          
              'Position inside the Plot Area, 0 to 1
              Dim relPosInPlotArea = New PointF(((relPosInChartArea.X - ca.InnerPlotPosition.X) / ca.InnerPlotPosition.Width), ((relPosInChartArea.Y - ca.InnerPlotPosition.Y) / ca.InnerPlotPosition.Height))
          
              Dim X = relPosInPlotArea.X * (ca.AxisX.Maximum - ca.AxisX.Minimum) + ca.AxisX.Minimum
              Dim Y = (1 - relPosInPlotArea.Y) * (ca.AxisY.Maximum - ca.AxisY.Minimum) + ca.AxisY.Minimum
          
              ' zoomo korekcija
              Dim zoomx = (ca.AxisX.ScaleView.ViewMaximum - ca.AxisX.ScaleView.ViewMinimum) / (ca.AxisX.Maximum - ca.AxisX.Minimum)
              Dim zoomy = (ca.AxisY.ScaleView.ViewMaximum - ca.AxisY.ScaleView.ViewMinimum) / (ca.AxisY.Maximum - ca.AxisY.Minimum)
              Dim xx = ca.AxisX.ScaleView.ViewMinimum + X * zoomx
              Dim yy = ca.AxisY.ScaleView.ViewMinimum + Y * zoomy
          
              Return New PointF(xx, yy)
          End Function
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-06-18
            • 1970-01-01
            • 1970-01-01
            • 2011-01-05
            • 2014-02-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多