Question

I'm trying to implement chart zooming using .NET charting by dragging a value on the X Axis to the right and then dropping it to a new location. It kind of working but I have some problems. Here is my code:

public partial class ChartForm : Form
{
    public ChartForm()
    {
        InitializeComponent();
    }

    private Axis AxisX { get; set; }
    private double InitialAxisValue { get; set; }

    protected override void OnLoad(EventArgs e)
    {
        chart1.Series.Add(CreateDataSeries());
        AxisX = chart1.ChartAreas[0].AxisX;
        InitialAxisValue = double.NaN;
        chart1.MouseMove += OnChartMouseMove;
        chart1.MouseDown += OnChartMouseDown;
        chart1.MouseUp += OnChartMouseUp;
    }

    private static Series CreateDataSeries()
    {
        var dataSeries = new Series
                             {
                                 ChartType = SeriesChartType.Line,
                             };

        for (double spotPrice = 1100; spotPrice < 1300; spotPrice++)
        {
            dataSeries.Points.Add(new DataPoint(spotPrice, spotPrice));
        }

        return dataSeries;
    }

    private void OnChartMouseUp(object sender, MouseEventArgs e)
    {
        InitialAxisValue = double.NaN;
    }

    private void OnChartMouseDown(object sender, MouseEventArgs e)
    {
        if (!MouseOnXAxis(e.X, e.Y))
            return;

        double valueX = AxisX.PixelPositionToValue(e.X);
        InitialAxisValue = valueX;
    }

    private void OnChartMouseMove(object sender, MouseEventArgs e)
    {
        try
        {
            Cursor = MouseOnXAxis(e.X, e.Y) ? Cursors.Hand : Cursors.Default;
            HandleZoom(e);
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception);
        }
    }

    private void HandleZoom(MouseEventArgs e)
    {
        if (double.IsNaN(InitialAxisValue))
            return;

        AxisX.Maximum = GetNewAxisMaximumValue(e.X, InitialAxisValue);
    }

    private double GetNewAxisMaximumValue(double currentAxisCoordinate,
                                          double initialAxisZoomPointValue)
    {
        double axisMinimumValue = AxisX.Minimum;
        double axisMaximumValue = AxisX.Maximum;
        double axisMinimumCoordinate = AxisX.ValueToPixelPosition(axisMinimumValue);
        double axisMaximumCoordinate = AxisX.ValueToPixelPosition(axisMaximumValue);
        double relativePos = (currentAxisCoordinate - axisMinimumCoordinate) /
                             (axisMaximumCoordinate - axisMinimumCoordinate);
        double newAxisWidth = ((initialAxisZoomPointValue - axisMinimumValue)/relativePos);
        return axisMinimumValue + newAxisWidth;
    }

    private bool MouseOnXAxis(int xCoor, int yCoor)
    {
        HitTestResult hitTestResult = chart1.HitTest(xCoor, yCoor);
        return hitTestResult.ChartElementType == ChartElementType.AxisLabels &&
               hitTestResult.Axis == AxisX;
    }
}

The actual zooming effect occurs by chaging the maximum value of AxisX in HandleZoom():

AxisX.Maximum = GetNewAxisMaximumValue(e.X, InitialAxisValue);

where 'InitialAxisValue' is the initial dragging value and 'e.X' is the current mouse x axis coordinate.

It works but I have a problem: sometimes the dragging movement is not smooth and sometimes there are back and forth undesired movements / blinks in the chart / grid (you can easily see it by dragging the mouse slowly to the right).

The problem is probably in the implementation of HandleZoom() and GetNewAxisMaximumValue().

Any help would be great.

Thanks

Was it helpful?

Solution

Solved!

My zoom calculation is based on an assumption that the X axis width in pixels is fixed and apparently when the InnerPlotPosition property is set to TRUE, the X Axis width in pixel may change during runtime, for example while zooming.

So the solution is to set the InnerPlotPosition property to FALSE and set the inner plot area manually:

        chart1.ChartAreas[0].InnerPlotPosition.Auto = false;
        chart1.ChartAreas[0].InnerPlotPosition.Height = 80.29209F;
        chart1.ChartAreas[0].InnerPlotPosition.Width = 85F;
        chart1.ChartAreas[0].InnerPlotPosition.X = 15F;
        chart1.ChartAreas[0].InnerPlotPosition.Y = 5.07246F;

OTHER TIPS

I can see you already solved the zooming functionality but why not using the built in .net chart zoom option?

chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;

Does "DoubleBuffer = true" on the graph control help?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top