back to the lesson

Move the ball across the field

importance: 5

Move the ball across the field to a click. Like this:

Requirements:

  • The ball center should come exactly under the pointer on click (if possible without crossing the field edge).
  • CSS-animation is welcome.
  • The ball must not cross field boundaries.
  • When the page is scrolled, nothing should break.

Notes:

  • The code should also work with different ball and field sizes, not be bound to any fixed values.
  • Use properties event.clientX/event.clientY for click coordinates.

Open a sandbox for the task.

First we need to choose a method of positioning the ball.

We can’t use position:fixed for it, because scrolling the page would move the ball from the field.

So we should use position:absolute and, to make the positioning really solid, make field itself positioned.

Then the ball will be positioned relatively to the field:

#field {
  width: 200px;
  height: 150px;
  position: relative;
}

#ball {
  position: absolute;
  left: 0; /* relative to the closest positioned ancestor (field) */
  top: 0;
  transition: 1s all; /* CSS animation for left/top makes the ball fly */
}

Next we need to assign the correct ball.style.left/top. They contain field-relative coordinates now.

Here’s the picture:

We have event.clientX/clientY – window-relative coordinates of the click.

To get field-relative left coordinate of the click, we can substract the field left edge and the border width:

let left = event.clientX - fieldCoords.left - field.clientLeft;

Normally, ball.style.left means the “left edge of the element” (the ball). So if we assign that left, then the ball edge, not center, would be under the mouse cursor.

We need to move the ball half-width left and half-height up to make it center.

So the final left would be:

let left = event.clientX - fieldCoords.left - field.clientLeft - ball.offsetWidth/2;

The vertical coordinate is calculated using the same logic.

Please note that the ball width/height must be known at the time we access ball.offsetWidth. Should be specified in HTML or CSS.

Open the solution in a sandbox.