Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

With ZoomMode=X, chart pans on click without dragging #1513

Open
planetarian opened this issue May 16, 2024 · 1 comment
Open

With ZoomMode=X, chart pans on click without dragging #1513

planetarian opened this issue May 16, 2024 · 1 comment

Comments

@planetarian
Copy link

planetarian commented May 16, 2024

Describe the bug
Charts pan undesireably when clicked for the first time, and ZoomMode and ChartPointPointerDown behaviors fire simultaneously even when the mouse was not dragged.

To Reproduce
Steps to reproduce the behavior:

  1. Create a CartesianChart similar to the following, and populate it with a ColumnSeries:
<wpf:CartesianChart
    Series="{Binding Series}"
    XAxes="{Binding XAxes}"
    YAxes="{Binding YAxes}"
    Height="250"
    LegendPosition="Hidden"
    ZoomMode="X"
    ChartPointPointerDown="CartesianChart_ChartPointPointerDown"
    />
  1. The X axis is set up as follows:
private static Axis GetLabelXAxis<TObj>(IEnumerable<TObj> items, Func<TObj, string> keySelector, string? name = null)
    => new Axis()
    {
        Labels = items.Select(keySelector).ToArray(),
        Name = name,
        Padding = new Padding(0, 0, 3, 0),
        LabelsRotation = 90,
        TextSize = 12
    }
  1. The series is set up as follows:
private static ColumnSeries<TObj> GetColumnSeries<TObj>(IEnumerable<TObj> items, Func<TObj, double> valueSelector)
    => new ColumnSeries<TObj>()
    {
        Values = items,
        Mapping = (item, index) => new(index, valueSelector(item))
    };
  1. Click on one of the columns, without dragging the mouse.

Expected behavior
The ChartPointPointerDown event fires, and the chart pan position / zoom level do not change (as the mouse was not moved).

Actual behavior
The ChartPointPointerDown event fires, and at the same time, the chart pans slightly to the right.

Screenshots
Initial state:
image

After clicking the bar on the far right (without moving the mouse -- no pan operation should have been performed):
image

The entire X axis shifts to the right, even though the mouse wasn't moved.

Desktop (please complete the following information):

  • OS: Windows 11 23H2 22631.3593
  • Platform: .NET 7.0 / WPF
  • LiveCharts2: v2.0.0-rc2
  • CommunityToolkit.Mvvm: 8.0.0

Additional context
Standard behavior in controls that support both click events and pan/zoom events is to not allow them to interfere with one another by default. Click events should not fire if the mouse was dragged between mousedown and mouseup events. Conversely, zoom/pan events should not fire if the mouse was single-clicked without dragging.

I understand that the "click" event in this case is a "pointerdown" event, rather than a "click/tap" event. This likely somewhat complicates matters, as pointerdown is more broad and independent of click, as I understand it. Still, currently I am struggling to determine how to ensure both behaviors don't interfere with each other, without completely reinventing the wheel on the entire pan/zoom system by removing ZoomMode and using MouseUp/MouseDown to drive the whole thing myself.

@planetarian planetarian changed the title Zoom interferes with Click With ZoomMode=X, chart pans on click without dragging May 16, 2024
@planetarian
Copy link
Author

planetarian commented May 16, 2024

Currently I am partially working around this by setting MinLimit = -(items.Count()/16.0), MaxLimit = items.Count() on the X Axis. This doesn't actually fix anything, but it at least sets the limits to be roughly similar to the post-pan limits by default, so that the movement on click isn't as jarring.

The secondary issue is that ChartPointPointerDown executes before it can even be determined whether the user is dragging or clicking, and there is no ChartPointPressed or ChartPointPointerUp or ChartPointClicked.
For that, I'm making use of everything I have at my disposal: ChartPointPointerDown to get the ChartPoint, and MouseDown and MouseUp to determine whether we're clicking or dragging.

        object? mouseDownObject;
        Point? mouseDownPos;
        ChartPoint? chartPoint;

        private void CartesianChart_MouseDown(object sender, MouseButtonEventArgs e)
        {
            // Store the clicked object and mouse position for comparison on MouseUp
            mouseDownObject = sender;
            mouseDownPos = e.GetPosition(this);
        }

        private void CartesianChart_ChartPointPointerDown(IChartView chart, ChartPoint point)
        {
            // Store the clicked point for use on MouseUp
            chartPoint = point;
        }

        private void CartesianChart_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (DataContext is not MyViewModel vm)
                return;

            // Ensure we're still acting on the same object
            if (sender != mouseDownObject)
            {
                mouseDownObject = null;
                return;
            }

            // If the new position isn't the same as the old one, we're dragging, not clicking
            Point pos = e.GetPosition(this);
            if (pos != mouseDownPos)
                return;
            
            // Get the series and point model and execute the appropriate point activation function for that series
            var series = (ColumnSeries<(string Key, double Value)>)((CartesianChart)sender).Series.First();
            var pointModel = ((string Key, double Value))chartPoint.Context.DataSource;
            vm.ActivatePoint(series, pointModel);
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant