Check out a free preview of the full Asynchronous Programming in JavaScript (with Rx.js Observables) course:
The "Exercise 33" Lesson is part of the full, Asynchronous Programming in JavaScript (with Rx.js Observables) course featured in this preview video. Here's what you'd learn in this lesson:

Jafar points out the mouse drag code in the previous exercise has a couple issues. The mouse snaps to the upper left corner of the object whenever it is grabbed. Jafar uses the offsetX and offsetY properties to fix this issue.

Get Unlimited Access Now

Transcript from the "Exercise 33" Lesson

[00:00:00]
>> [MUSIC]

[00:00:04]
>> Jafar Husain: Let's move on, but this example is great but anybody think of, I mean usually when you see a mouse drag it, it actually it's kinda got something that's not so great about it. Can anybody tell me what we can improve about this mouse drag?
>> Speaker 2: We will transition like through the glide.

[00:00:18]
>> Jafar Husain: Well, the glide is not that bad but if I click here and then I move, notice what happens? It kinda [SOUND] jumps to the mouse position. What we wanna do with a mouse drag is usually, wherever we click, the click point on that button, we want it to maintain the same offset from the top left of the sprite as we move around.

[00:00:36] So, let's try that. How would I do that? So here, we start off with the exact same program that we started off with before, right?
>> Jafar Husain: But notice that for every mouse down, we get an event object that within it contains the contact point, the offset on the object where we clicked.

[00:00:59] So remember, whenever we convert an event to an observable, every single one of the objects in the stream is actually that event object that you would have gotten on your handler from out of that listener, and so this event object for a mouse down has a lot of information on it.

[00:01:12] It has for example the absolute position pageX pageY. I believe it also has offset x and offset y, right? So this is what an object looks like, at least some of the properties on an event object we get. So offsetX and offsetY describes how far we were from the top left of the sprite when we clicked on it, right?

[00:01:34] Does that make sense? So what we'd like to do is we'd like to turn the objects that come out of the mouseDrag stream, instead of the X being the mouse move position, cuz that's what it currently is, right? Where for every mousedown we're returning all the mousemove event objects until the mouseup.

[00:01:49] What we like is we like to translate that mouse move position so that instead of it being the exact position, we'd like to offset the X and Y positions by the amount of offset that there was when we first clicked it, when we got the mouse down. So for every mouse down, when we remove some of these comments here so we can see all the code on screen.

[00:02:17]
>> Jafar Husain: So for every mousedown, we get the mousedown object which is what we can use to get the contact point, how far we were offset from the object we clicked on by looking at the offsetX and offsetY property. And then what we wanna do is instead of returning mouseups, mousemoves just one of those mouse move objects are, it's almost like we wanna substitute each mouse move object for an object that has the same x and y positions offset by the amount of distance we were when we clicked the original top left position on that button.

[00:02:44] So, what we really wanna use is we wanna use the offsetX and offsetY
>> Jafar Husain: On the contact point.
>> Jafar Husain: And then we want to translate the mousemove objects before we send them back. So we wanna convert all the x and y positions on the mousemove events that we get, before they get returned.

[00:03:15] What operators am I gonna use for this? So I wanna take every mousemove event and I wanna substitute it for some other object that has different properties that are offset by certain amount.
>> Jafar Husain: Anybody know?
>> Speaker 3: No Map is it?
>> Jafar Husain: Yeah, we heard map, right? Just like if I wanna take one two three and map over them and turn them to two three four by adding one to every single one, I can map over all the mousemove event objects and change their x and y positions, right?

[00:03:44] It's the same thing. We're just applying a math operation to each one of those event objects. So, I'm actually not sure am I show answer on this because we faster but,
>> Jafar Husain: So pageX and pageY, are what we read in forEach, when we position things. Cuz we actually position is absolutely in the page.

[00:04:09] So position this drag point absolutely on the page. But, notice we're subtracting the X and Y position of the contact point that we got from the mousedown event. Cuz, we captured the event object we got from the mousedown in the closer scope. So we have access to it and we can use it to offset the pageX and pageY position of the mousedown event that we're returning.

[00:04:35] And so now we should see
>> Jafar Husain: Oops [LAUGH] should see a bug.
>> Speaker 4: Reset?
>> Jafar Husain: Sorry?
>> Speaker 4: Reset?
>> Jafar Husain: Might be.
>> Speaker 4: And then [INAUDIBLE]
>> Jafar Husain: Live coding people.
>> Speaker 5: A lot of public speaking.
>> Jafar Husain: Yeah, a lot of public speaking too.
>> Speaker 4: Keep going, it's the next one.

[00:05:19]
>> Jafar Husain: Next one? Thank you.
>> Jafar Husain: Darn it.
>> Speaker 6: Well, if you refreshed didn't it lose your concatAlls and such?
>> Jafar Husain: Yeah, but those are on the array, so all the methods are already defined on the observable. So I'm not sure what's going on here, but we can probably find out, it's not too much effort.

[00:05:45] I'm gonna remove my map statement which should mean that it works exactly the same way as the last example.
>> Speaker 4: One more down.
>> Jafar Husain: Thank you.
>> Speaker 7: Chatroom saying they had switched to Chrome to get this one to work.
>> Jafar Husain: Okay, this might be a Firefox thing. If so, I apologize.

[00:06:12] This was originally written in Chrome. So there may just be an event, what I expect is different dom implementations may have different properties, so I may have used a proprietary property like offsetX or something like that. So, if so, I apologize.
>> Jafar Husain: It's always good to test on multiple browsers.

[00:06:39]
>> Jafar Husain: Let's checking it out working on Firefox. Or, excuse me, on Chrome.
>> Jafar Husain: There we go. So I'm probably just using a proprietary property like offsetX or pageX on Chrome or it doesn't work the same way in both browsers which I think all of us in here have probably run into at some point.

[00:07:06] But that's effectively all I'm doing. I'm mapping over each one of these mousemove objects and I'm translating the points. So we're just using the same functions we use an array for the same purpose to translate each one of those objects. Okay?