This commit is contained in:
Ilya Kantor 2017-03-21 14:41:49 +03:00
parent 4ae129054e
commit ab9ab64bd5
476 changed files with 3370 additions and 532 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View file

@ -0,0 +1,51 @@
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:
```css
#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.position.left/top`. They contain field-relative coordinates now.
Here's the picture:
![](move-ball-coords.png)
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:
```js
let left = event.clientX - fieldInnerCoords.left - field.clientLeft;
```
Normally, `ball.style.position.left` means the "left edge of the element" (the ball). So if we assign that `left`, then the ball edge 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:
```js
let left = event.clientX - fieldInnerCoords.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.

View file

@ -0,0 +1,75 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<style>
#field {
width: 200px;
height: 150px;
border: 10px solid black;
background-color: #00FF00;
position: relative;
overflow: hidden;
cursor: pointer;
}
#ball {
position: absolute;
left: 0;
top: 0;
width: 40px;
height: 40px;
transition: all 1s;
}
</style>
</head>
<body style="height:2000px">
Click on a field to move the ball there.
<br>
<div id="field">
<img src="https://en.js.cx/clipart/ball.svg" id="ball"> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
</div>
<script>
field.onclick = function(event) {
// window-relative field coordinates
let fieldCoords = this.getBoundingClientRect();
// the ball has position:absolute, the field: position:relative
// so ball coordinates are relative to the field inner left-upper corner
let ballCoords = {
top: event.clientY - fieldInnerCoords.top - field.clientTop - ball.clientHeight / 2,
left: event.clientX - fieldInnerCoords.left - field.clientLeft - ball.clientWidth / 2
};
// prevent crossing the top field boundary
if (ballCoords.top < 0) ballCoords.top = 0;
// prevent crossing the left field boundary
if (ballCoords.left < 0) ballCoords.left = 0;
// // prevent crossing the right field boundary
if (ballCoords.left + ball.clientWidth > field.clientWidth) {
ballCoords.left = field.clientWidth - ball.clientWidth;
}
// prevent crossing the bottom field boundary
if (ballCoords.top + ball.clientHeight > field.clientHeight) {
ballCoords.top = field.clientHeight - ball.clientHeight;
}
ball.style.left = ballCoords.left + 'px';
ball.style.top = ballCoords.top + 'px';
}
</script>
</body>
</html>

View file

@ -0,0 +1,30 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<style>
#field {
width: 200px;
height: 150px;
border: 10px solid black;
background-color: #00FF00;
overflow: hidden;
}
</style>
</head>
<body style="height:2000px">
Click on a field to move the ball there.
<br> The ball should never leave the field.
<div id="field">
<img src="https://en.js.cx/clipart/ball.svg" id="ball"> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
</div>
</body>
</html>

View file

@ -0,0 +1,21 @@
importance: 5
---
# Move the ball across the field
Move the ball across the field to a click. Like this:
[iframe src="solution" height="260" link]
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.