1

現在、私のソフトウェアはHitTest()MSCharts のチャート オブジェクトのメソッドを使用していますが、他の要因と組み合わせてチャートのデータ ポイントを増やしていくと、パフォーマンスが大幅に低下する可能性があります。

同じ機能を提供するためにあなたが知っている代替手段があるかどうか疑問に思っていました(カーソル位置のチャートでX座標を取得します)が、ヒットテストは私の答えを得る非常に強引な方法であるように思われるため、パフォーマンスヒットはありません。

私のチャートはクラスから作成されますSystem.Windows.Forms.DataVisualization.Charting.Chart

わかりやすくするために編集します。他の計算に使用するには、チャート上の線の位置を見つける必要があります。

4

1 に答える 1

3

マウスホイール イベントで同じパフォーマンスの問題が発生しました。

これが私の解決策です:

  1. 現在のマウス位置の軸の値を取得するには:

    double posX = Math.Round(currentArea.AxisX.PixelPositionToValue(e.X));
    double posY = Math.Round(currentArea.AxisY.PixelPositionToValue(e.Y));
    

    より正確にするために少し変更を加えたChart Control でのマウス軸座標の表示から取得。

    ただし、マウスがChartAreaにあることを前に確認する必要があります。そうしないと、 Exceptionがスローされます。

  2. マウスがポイントする ChatElement を取得するには:

    // Gets the ChartArea that the mouse points
    private ChartArea mouseinChartArea(Chart source, Point e)
    {
        double relativeX = (double)e.X * 100 / source.Width;
        double relativeY = (double)e.Y * 100 / source.Height;
    
        foreach (ChartArea ca in source.ChartAreas)
        {
            if (relativeX > ca.Position.X && relativeX < ca.Position.Right &&
                relativeY > ca.Position.Y && relativeY < ca.Position.Bottom)
                return ca;
        }
        return null;
    }
    
    // for my purpose, returns an axis. But you can return anything
    private Axis findAxisforZooming(Chart source, Point e)
    {
        ChartArea currentArea = mouseinChartArea(source, new Point(e.X, e.Y)); // Check if inside 
        if (currentArea == null)
            return null;
    
        double axisXfontSize = currentArea.AxisX.LabelAutoFitMinFontSize + ((double)source.Width / SystemInformation.PrimaryMonitorSize.Width)
            * (currentArea.AxisX.LabelAutoFitMaxFontSize - currentArea.AxisX.LabelAutoFitMinFontSize);
        double axisYfontSize = currentArea.AxisY.LabelAutoFitMinFontSize + ((double)source.Height / SystemInformation.PrimaryMonitorSize.Height)
            * (currentArea.AxisY.LabelAutoFitMaxFontSize - currentArea.AxisY.LabelAutoFitMinFontSize);
        double axisYfontHeightSize = (axisYfontSize - currentArea.AxisY.LabelStyle.Font.Size) + currentArea.AxisY.LabelStyle.Font.Height;
    
        Graphics g = this.CreateGraphics();
        if (currentArea.AxisX.LabelStyle.Font.Unit == GraphicsUnit.Point)
            axisXfontSize = axisXfontSize * g.DpiX / 72;
        if (currentArea.AxisY.LabelStyle.Font.Unit == GraphicsUnit.Point)
            axisYfontHeightSize = axisYfontHeightSize * g.DpiX / 72;
        g.Dispose();
    
        // Replacing the SystemInformation.PrimaryMonitorSize with the source.Width / Height will give the accurate TickMarks size.
        // But it doens't count for the gab between the tickMarks and the axis lables (so by replacing, it give a good proximity with the gab)
        int axisYTickMarks = (int)Math.Round(currentArea.AxisY.MajorTickMark.Size / 100 * SystemInformation.PrimaryMonitorSize.Width); // source.Width;
        int axisXTickMarks = (int)Math.Round(currentArea.AxisX.MajorTickMark.Size / 100 * SystemInformation.PrimaryMonitorSize.Height); // source.Height;
    
        int leftInnerPlot = (int)Math.Round(currentArea.Position.X / 100 * source.Width +
            currentArea.InnerPlotPosition.X / 100 * currentArea.Position.Width / 100 * source.Width);
        int rightInnerPlot = (int)Math.Round(currentArea.Position.X / 100 * this.chart1.Width +
            currentArea.InnerPlotPosition.Right / 100 * currentArea.Position.Width / 100 * source.Width);
        int topInnerPlot = (int)Math.Round(currentArea.Position.Y / 100 * this.chart1.Height +
            currentArea.InnerPlotPosition.Y / 100 * currentArea.Position.Height / 100 * source.Height);
        int bottomInnerPlot = (int)Math.Round(currentArea.Position.Y / 100 * source.Height +
            currentArea.InnerPlotPosition.Bottom / 100 * currentArea.Position.Height / 100 * source.Height);
    
        // Now you got the boundaries of every important ChartElement.
        // Only left to check if the mouse is within your desire ChartElement,
        // like the following:    
    
        bottomInnerPlot += axisXTickMarks + (int)Math.Round(axisXfontSize); // Include AxisX
    
        if (e.X > leftInnerPlot && e.X < rightInnerPlot &&
            e.Y > topInnerPlot && e.Y < bottomInnerPlot) // return AxisX if inside the InnerPlot area or on AxisX
            return currentArea.AxisX;
        else if (e.X > (leftInnerPlot - axisYTickMarks - (int)Math.Round(axisYfontHeightSize)) && e.X < rightInnerPlot &&
                 e.Y > topInnerPlot && e.Y < bottomInnerPlot) // return AxisY if on AxisY only
            return currentArea.AxisY;
    
        return null;
    }
    

ご覧のとおり、コードは よりも長くなっていHitTest()ます。しかし、実行時間は短くなります。

于 2014-02-02T13:48:01.223 に答える