Drag And Drop как избавиться от дребезжания при заведении за пределы экрана
Я не понимаю как реализовать логику того, чтобы не было дребезжания при заведении за пределы экрана.
onMouseMove срабатывает после того, как на блок кликнули и начали перетаскивать
onMouseMove(event) {
this.doNotGoBeyond();
if (this.limitBool) {
event.preventDefault();
return false;
}
const page = {
x: event.pageX,
y: event.pageY
};
this.move(page);
}
doNotGoBeyond - проверяет, достиг ли перетаскиваемый элемент границ игрового поля, т.е. если какие-то координаты стали больше, чем нужно, то перенести блок к краю экрана. Тут проблема в том, что когда я задаю координаты равные краю экрана, то при перетаскивании 0 не меньше 0 и блок можно перетащить и происходит дребезжание
doNotGoBeyond() {
this.limitBool = false;
const bottom = this.heightGame - this.node.offsetTop - this.node.offsetHeight;
const right = this.widthGame - this.node.offsetLeft - this.node.offsetWidth;
if (this.node.offsetLeft < 0 || this.node.offsetTop < 0 || right < 0 || bottom < 0) {
this.limitBool = true;
if (this.node.offsetLeft < 0) {
this.node.style.left = '0px';
} else if (this.node.offsetTop < 0) {
this.node.style.top = '0px';
} else if (right < 0) {
this.node.style.left = this.widthGame - this.node.offsetWidth + 'px';
} else if (bottom < 0) {
this.node.style.top = this.heightGame - this.node.offsetHeight + 'px';
}
}
}
class BlockInGame {
constructor(src = 'move__block', styles) {
this.global();
this.node = document.createElement('div');
this.node.classList.add(src);
this.addStyles(styles);
this.addInBody();
this.listeners();
}
listeners() {
this.node.ondragstart = () => {
return false;
}
this.node.addEventListener('mousedown', () => {
this.shift = {
x: event.clientX - this.node.getBoundingClientRect().left,
y: event.clientY - this.node.getBoundingClientRect().top
};
const localMouseupFunc = () => {
this.global.game.removeEventListener('mousemove', onMouseMoveBind);
this.global.game.removeEventListener('mouseup', localMouseupFunc);
}
const onMouseMoveBind = this.onMouseMove.bind(this);
this.global.game.addEventListener('mousemove', onMouseMoveBind);
this.global.game.addEventListener('mouseup', localMouseupFunc);
});
const heightAndWidthGame = this.heightAndWidthGame.bind(this);
heightAndWidthGame();
window.addEventListener('resize', heightAndWidthGame);
}
global() {
if (!this.global.body) {
this.global.body = document.querySelector('body');
}
if (!this.global.game) {
this.global.game = this.global.body.querySelector('.game');
}
}
heightAndWidthGame() {
this.widthGame = this.global.game.offsetWidth;
this.heightGame = this.global.game.offsetHeight;
}
addStyles(styles) {
for (let key in styles) {
this.node.style[key] = styles[key];
}
}
addInBody() {
this.global.game.append(this.node);
}
move(page) {
this.node.style.left = page.x - this.shift.x + 'px';
this.node.style.top = page.y - this.shift.y + 'px';
}
doNotGoBeyond() {
this.limitBool = false;
const bottom = this.heightGame - this.node.offsetTop - this.node.offsetHeight;
const right = this.widthGame - this.node.offsetLeft - this.node.offsetWidth;
if (this.node.offsetLeft < 0 || this.node.offsetTop < 0 || right < 0 || bottom < 0) {
this.limitBool = true;
if (this.node.offsetLeft < 0) {
this.node.style.left = '0px';
} else if (this.node.offsetTop < 0) {
this.node.style.top = '0px';
} else if (right < 0) {
this.node.style.left = this.widthGame - this.node.offsetWidth + 'px';
} else if (bottom < 0) {
this.node.style.top = this.heightGame - this.node.offsetHeight + 'px';
}
}
}
onMouseMove(event) {
this.doNotGoBeyond();
if (this.limitBool) {
event.preventDefault();
return false;
}
const page = {
x: event.pageX,
y: event.pageY
};
this.move(page);
}
}
const block = new BlockInGame(undefined, {
backgroundColor: 'red',
width: '80px',
height: '80px'
});
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800&display=swap');
*,
*::before,
*::after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Poppins', sans-serif;
}
section {
background-color: #00cbff;
min-height: 100vh;
}
.game {
position: relative;
overflow: hidden;
}
.move__block {
-webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.75);
-moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.75);
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.75);
cursor: pointer;
position: absolute;
left: 30px;
top: 30px;
}
<section class="game">
</section>
Ответы (1 шт):
Чуть изменил Ваш код чтобы не переписывать много отвечая конкретно на вопрос, как избавиться от дребезжания. поправил метод move и doNotGoBeyond. дребезжание из-за того что Вы проверяете только значения меньше 0 а не равное ему. Такой эффект можете использовать не при движении, а при отпускании
class BlockInGame {
constructor(src = 'move__block', styles) {
this.global();
this.node = document.createElement('div');
this.node.classList.add(src);
this.addStyles(styles);
this.addInBody();
this.listeners();
}
listeners() {
this.node.ondragstart = () => {
return false;
}
this.node.addEventListener('mousedown', () => {
this.shift = {
x: event.clientX - this.node.getBoundingClientRect().left,
y: event.clientY - this.node.getBoundingClientRect().top
};
const localMouseupFunc = () => {
this.global.game.removeEventListener('mousemove', onMouseMoveBind);
this.global.game.removeEventListener('mouseup', localMouseupFunc);
}
const onMouseMoveBind = this.onMouseMove.bind(this);
this.global.game.addEventListener('mousemove', onMouseMoveBind);
this.global.game.addEventListener('mouseup', localMouseupFunc);
});
const heightAndWidthGame = this.heightAndWidthGame.bind(this);
heightAndWidthGame();
window.addEventListener('resize', heightAndWidthGame);
}
global() {
if (!this.global.body) {
this.global.body = document.querySelector('body');
}
if (!this.global.game) {
this.global.game = this.global.body.querySelector('.game');
}
}
heightAndWidthGame() {
this.widthGame = this.global.game.offsetWidth;
this.heightGame = this.global.game.offsetHeight;
}
addStyles(styles) {
for (let key in styles) {
this.node.style[key] = styles[key];
}
}
addInBody() {
this.global.game.append(this.node);
}
move(page) {
const pageX = page.x - this.shift.x; // Позиция мышки по X
const pageY = page.y - this.shift.y; // Позиция мышки по Y
if ((!this.limitBoolRight || (this.node.offsetLeft > pageX)) && pageX > 0) {
// Если (не заходили справа за пределы ИЛИ позиция блока слева больше позиция мышки по X) И позиция мышки по X больше 0
this.node.style.left = pageX + 'px';
}
if ((!this.limitBoolBottom || (this.node.offsetTop > pageY)) && pageY > 0) {
// Если (не заходили снизу за пределы ИЛИ позиция блока сверху больше позиция мышки по Y) И позиция мышки по Y больше 0
this.node.style.top = pageY + 'px';
}
}
doNotGoBeyond() {
this.limitBoolRight = false;
this.limitBoolBottom = false;
const bottom = this.heightGame - this.node.offsetTop - this.node.offsetHeight;
const right = this.widthGame - this.node.offsetLeft - this.node.offsetWidth;
if (right <= 0) { // Если зашли справа за пределы
this.limitBoolRight = true;
this.node.style.left = this.widthGame - this.node.offsetWidth + 'px';
}
if (bottom <= 0) { // Если зашли снизу за пределы
this.limitBoolBottom = true;
this.node.style.top = this.heightGame - this.node.offsetHeight + 'px';
}
}
onMouseMove(event) {
this.doNotGoBeyond();
const page = {
x: event.pageX,
y: event.pageY
};
this.move(page);
}
}
const block = new BlockInGame(undefined, {
backgroundColor: 'red',
width: '80px',
height: '80px'
});
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800&display=swap');
*,
*::before,
*::after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Poppins', sans-serif;
}
section {
background-color: #00cbff;
min-height: 100vh;
}
.game {
position: relative;
overflow: hidden;
}
.move__block {
-webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.75);
-moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.75);
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.75);
cursor: pointer;
position: absolute;
left: 30px;
top: 30px;
}
<section class="game">
</section>