How to compose RX.Net Observables for mouse dragging interaction?

211 Views Asked by At

I want to use RX to enable mouse dragging behaviour to select areas in a plot. (Oxyplot) It should be possible to select multiple areas in a plot and their should be a live update of the select area.

So far i have set up three observables from events:

var mouseDownObservable = Observable.FromEventPattern<OxyMouseDownEventArgs>(tmp, nameof(tmp.MouseDown))
            .Where(e => e.EventArgs.ChangedButton == OxyMouseButton.Left)
            .Where(e => e.EventArgs.IsControlDown == true);
var mouseMoveObservable = Observable.FromEventPattern<OxyMouseEventArgs>(tmp, nameof(tmp.MouseMove));
var mouseUpObservable = Observable.FromEventPattern<OxyMouseEventArgs>(tmp, nameof(tmp.MouseUp));

Iam new to RX, so my first attempt was:

var result = mouseDownObservable
                .Select(m => m.EventArgs.Position)
                .Merge(mouseMoveObservable
                .SkipUntil(mouseDownObservable.Select(e => e.EventArgs.Position).Do(e1 =>
                {
                    // .. create annotation in plot
                }))
                .TakeUntil(mouseUpObservable)
                .Select(m => m.EventArgs.Position)
                .Repeat());
                .CombineLatest(mouseDownObservable.Select(e => e.EventArgs.Position),
                        (endPoint, startPoint) => new List<ScreenPoint>() { endPoint, startPoint })
                .Do(e =>
                {
                    // .. update actual annotation to current endPoint
                })
                .Subscribe();

I didnt know how to preserve the state (startPoint of mouseDown) so i choose to use CombineLatest.

The first i select an area it works quite well. If i want to select another area i get the correct startPoint (d1) but the endpoint is still the last element of (r). Marble Diagram

  1. What is a good approach to preserve the information of the starting point? I feel a bit clumsy about that.
  2. How can i group the result, so that there will be exactly one mouseDragObservable per combined mouse drag interaction?
1

There are 1 best solutions below

1
On BEST ANSWER

I think you're overthinking things a bit.

Here's the query you need:

var deltas =
    from down in mouseDownObservable
    from move in mouseMoveObservable.TakeUntil(mouseUpObservable)
    select new
    {
        X = move.EventArgs.Position.X - down.EventArgs.Position.X,
        Y = move.EventArgs.Position.Y - down.EventArgs.Position.Y
    };

So this is simply waiting for a mouse down and then recording all moves that happen after that until there's a mouse up. So, basically a drag operation.

Because the first part is from down in mouseDownObservable you have a record of the X/Y coordinates at the time of the mouse down. It's very easy to then produce a series of coordinate deltas based on the position during each move.