سؤال

I'm trying to create new observable based on two others. I have:

var mouseClickObservable = Rx.Observable.fromEvent(this.canvas, "click");
var mouseMoveObservable = Rx.Observable.fromEvent(this.canvas, "mousemove");
function findObject(x, y) {/* logic for finding object under cursor here. */}
var objectUnderCursor = this.mouseMoveObservable.select(function (ev) { 
    return findObject(ev.clientX, clientY);
});

I want to create objectClicked observable, that should produce values when user clicks on an object. I could just call findObject again, like this:

var objectClicked = this.mouseClickObservable.select(function (ev) { 
    return findObject(ev.clientX, clientY);
});

but it's very time-consuming function.

Another way, which I currently use, is to store last hovered object in a variable, but I assume, there should be pure functional way of doing this. I tryed to use Observable.join like this:

var objectClicked = this.objectUnderCursor.join(
    mouseClickObservable,
    function (obj) { return this.objectUnderCursor },
    function (ev) { return  Rx.Observable.empty() },
    function (obj, ev) { return obj })

but it produces multiple values for one click

هل كانت مفيدة؟

المحلول

I don't see any code where you actually subscribe to any of these observables you have defined, so it is hard to provide a good answer. Do you actually need to call findObject on every mouse move? Are you needing to provide some sort of hover effect as the mouse moves? Or do you just need to know the object that was clicked, in which case you only need to call findObject once when clicked?

Assuming you only need to know what object was clicked, you don't even worry about mouse moves and just do something like:

var objectClicked = mouseClickObservable
    .select(function (ev) { return findObject(ev.clientX, ev.clientY); });

objectClicked.subscribe(function(o) { ... });

If you indeed need to know what object the mouse is hovering over, but want to avoid calling your expensive hit test also on a click, then indeed you need to store the intermediate value (which you are needing to store anyway to do your hovering effects). You can use a BehaviorSubject for this purpose:

this.objectUnderCursor = new Rx.BehaviorSubject();
mouseMoveObservable
    .select(function (ev) { return findObject(ev.clientX, ev.clientY); })
    .subscribe(this.objectUnderCursor);


this.objectUnderCursor.subscribe(function (o) { do your hover effects here });
mouseClickObservable
    .selectMany(function () { return this.objectUnderCursor; })
    .subscribe(function (o) { do your click effect });
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top