Движение элемента по периметру
Как выполнить движение элемента внутри блока по периметру?
var canvas = document.getElementById('perim');
var ctx = canvas.getContext('2d');
var n = 4;
var x = 10;
var y = 10;
function draw(x, y) {
ctx.fillRect(x, y, 20, 20);
}
function move() {
x += n;
if (x > canvas.width || x < 0) {
n = -n
}
}
function game() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
draw(x, y);
move();
requestAnimationFrame(game)
}
game();
canvas {
border: 1px solid black;
}
<canvas id="perim" width="400" height="200"></canvas>
Ответы (3 шт):
Автор решения: Kirill
→ Ссылка
Думаю, не самое изящное решение, но работает.
var canvas = document.getElementById('perim');
var ctx = canvas.getContext('2d');
var n = 5;
var x = 0;
var y = 0;
function draw(x, y) {
ctx.fillRect(x, y, 20, 20);
}
function move() {
if (x < canvas.width - 20 && y == 0) {
x += n;
} else if (x == canvas.width - 20 && y < canvas.height - 20) {
y += n;
} else if (y == canvas.height - 20 && x > 0) {
x -= n;
} else if (x == 0 && y > 0) {
y -= n;
}
}
function game() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
draw(x, y);
move();
requestAnimationFrame(game)
}
game();
canvas {
border: 1px solid black;
}
<canvas id="perim" width="400" height="200"></canvas>
Автор решения: Sevastopol'
→ Ссылка
Первые два варианта не мои, были в заначке, достал. Автора не знаю, но ему спасибо.
Один
var div = document.querySelector('div>div');
(run = () => {
var l = parseFloat(getComputedStyle(div).left),
t = parseFloat(getComputedStyle(div).top);
if (l < 279 && t == 0) div.style.left = l + 1 + 'px';
if (l == 279 && t < 139) div.style.top = t + 1 + 'px';
if (l > 0 && t == 139) div.style.left = l - 1 + 'px';
if (l == 0 && t > 0) div.style.top = t - 1 + 'px';
setTimeout(run, 4);
})();
div {
position: relative;
width: 300px;
height: 160px;
border: 1px solid black;
}
div>div {
display: block;
width: 20px;
height: 20px;
background-color: black;
}
<div>
<div></div>
</div>
Два
var canvas = document.getElementById("perim");
var ctx = canvas.getContext("2d");
var n = 4;
var x = 0;
var y = 0;
function draw(x, y) {
ctx.fillStyle = "black";
ctx.fillRect(x, y, 20, 20)
}
var a = 0;
function move() {
var b = false;
switch (a) {
case 0:
b = x > canvas.width - 24;
break;
case 1:
b = y > canvas.height - 24;
break;
case 2:
b = x < 4;
break;
case 3:
b = y < 4;
break
}
if (b) {
a = ++a % 4;
a % 2 || (n = -n)
}
a % 2 ? y += n : x += n
}
function game() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw(x, y);
move();
requestAnimationFrame(game)
}
game();
canvas {
border: 1px solid black;
}
<canvas id="perim" width="300" height="160"></canvas>
И добавлю свой вариант. Самое простое, что можно сделать для решения этой задачи. Зачем Canvas, если есть CSS.
div {
position: relative;
width: 300px;
height: 160px;
border: 1px solid black;
}
span {
display: block;
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 20px;
background-color: black;
animation: elem 3s linear infinite;
}
@keyframes elem {
0% {
top: 0;
left: 0;
}
34% {
top: 0;
left: 280px;
}
50% {
top: 140px;
left: 280px;
}
84% {
top: 140px;
left: 0;
}
100% {
top: 0;
left: 0;
}
}
<div><span></span></div>
Автор решения: Stranger in the Q
→ Ссылка
Например вот так, поколдовал, чтобы была продолжительность одного цикла задана переменной и постоянная скорость на разных ребрах:
var canvas = document.getElementById('perim');
var ctx = canvas.getContext('2d');
var pad = 2;
var x = 0;
var y = 0;
var s = 20;
var d = 4000;
function clamp(x) {
return Math.max(0, Math.min(x, 1));
}
function draw(x, y) {
ctx.fillRect(x-s/2, y-s/2, s, s);
}
function move(t) {
let ratio = canvas.width/canvas.height
let halfCycle = ratio + 1;
t = t % d / d * 2 * halfCycle;
x = clamp(t/ratio) - clamp((t - halfCycle)/ratio);
y = clamp(t - ratio) - clamp(t - halfCycle - ratio);
x = pad+s/2 + x * (canvas.width - s - pad*2);
y = pad+s/2 + y * (canvas.height - s - pad*2);
}
function game(t) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
move(t);
draw(x, y);
requestAnimationFrame(game);
}
requestAnimationFrame(game);
canvas {
border: 1px solid black;
}
<canvas id="perim" width="400" height="150"></canvas>