drag and drop, растяжение элемента по ширине
Я делаю такое: https://codepen.io/mihinov/pen/yLegxYv
Там используется localeStorage, такое не пропускает stackoverflow.
Когда я тяну с левого края вправо, у меня блок становится шириной в 0, и я начинаю как бы увеличивать ширину вправо.
Не понимаю как прописать нужное условие.
this.node - это DOM элемент, с которым происходит событие
const leftEdge = this.node.getBoundingClientRect().left; // левый край блока
const rightEdge = this.node.getBoundingClientRect().right; // правый край блока
const x = e.clientX; // позиция мышки по X
let width;
if (x > leftEdge) {
width = x - leftEdge;
} else {
this.node.style.left = x + 'px';
width = rightEdge - x;
}
this.node.style.width = width + 'px';
Ответы (1 шт):
Автор решения: Михаил Камахин
→ Ссылка
Надо было опираться на середину элемента, а не на его края:
const leftEdge = this.node.getBoundingClientRect().left; // левый край блока
const rightEdge = this.node.getBoundingClientRect().right; // правый край блока
const centerX = leftEdge + this.node.clientWidth / 2;
const x = e.clientX; // позиция мышки по X
let width;
if (x > centerX) {
width = x - leftEdge;
} else {
width = rightEdge - x;
this.node.style.left = x + 'px';
}
this.node.style.width = width + 'px';
class BlockInGame {
constructor(src = 'move__block', styles) {
this.global();
this.src = src;
this.styles = styles;
this.node = document.createElement('div');
this.node.classList.add(src);
this.addInBody();
this.listeners();
if (!this.constructor.block_counter) {
this.constructor.block_counter = 1
} else {
this.constructor.block_counter++;
}
this.node.id = 'move__block-' + this.constructor.block_counter;
this.addStyles(styles);
setTimeout(() => {
this.nodeElemsThisClass = [...this.global.body.querySelectorAll('.' + this.src)];
}, 50);
}
listeners() {
this.node.ondragstart = () => (false);
const border_definition = (x_OR_y, width_0R_height, borderWidth) => {
return (x_OR_y > width_0R_height - borderWidth || x_OR_y < borderWidth);
}
let clickOnTheBorder = false;
const beforeClicking = (e) => {
const width = this.node.offsetWidth;
const height = this.node.offsetHeight;
const borderWidth = 5;
const x = e.offsetX;
const y = e.offsetY;
if (border_definition(x, width, borderWidth)) {
this.node.style.cursor = 'ew-resize';
clickOnTheBorder = {
axis: 'x'
};
return;
} else {
clickOnTheBorder = true;
this.node.style.cursor = 'pointer';
}
if (border_definition(y, height, borderWidth)) {
this.node.style.cursor = 'ns-resize';
clickOnTheBorder = {
axis: 'y'
};
return;
} else {
clickOnTheBorder = true;
this.node.style.cursor = 'pointer';
}
};
const stretching = () => {
const mouseMoveStretching = (e) => {
if (clickOnTheBorder != false) {
if (clickOnTheBorder.axis === 'x') {
const leftEdge = this.node.getBoundingClientRect().left; // левый край блока
const rightEdge = this.node.getBoundingClientRect().right; // правый край блока
const centerX = leftEdge + this.node.clientWidth / 2;
const x = e.clientX; // позиция мышки по X
let width;
if (x > centerX) {
width = x - leftEdge;
} else {
width = rightEdge - x;
this.node.style.left = x + 'px';
}
this.node.style.width = width + 'px';
return;
} else if (clickOnTheBorder.axis === 'y') {
const topEdge = this.node.getBoundingClientRect().top;
const bottomEdge = this.node.getBoundingClientRect().bottom;
const centerY = topEdge + this.node.clientHeight / 2;
const y = e.clientY;
let height;
if (y > centerY) {
height = y - topEdge;
} else {
height = bottomEdge - y;
this.node.style.top = y + 'px';
}
this.node.style.height = height + 'px';
return;
}
}
};
this.global.game.addEventListener('mousemove', mouseMoveStretching);
this.global.game.addEventListener('mouseup', () => {
this.global.game.removeEventListener('mousemove', mouseMoveStretching);
this.node.addEventListener('mousemove', beforeClicking);
});
};
this.node.addEventListener('mousemove', beforeClicking);
this.node.addEventListener('mousedown', () => {
this.node.removeEventListener('mousemove', beforeClicking);
this.nodeElemsThisClass.forEach((item) => {
item.style.zIndex = '10';
});
this.node.style.zIndex = '20';
if (clickOnTheBorder !== true) {
return stretching();
}
this.node.style.cursor = 'move';
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);
this.node.style.cursor = 'pointer';
this.node.addEventListener('mousemove', beforeClicking);
}
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];
}
this.node.style.position = 'absolute';
this.node.style.cursor = 'pointer';
this.node.style.zIndex = '10';
}
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);
}
}
addBlocks();
function addBlocks() {
const width = '100px';
const height = '100px';
const block1 = new BlockInGame(undefined, {
backgroundColor: 'red',
width: width,
height: height,
left: '50px',
top: '50px'
});
const block2 = new BlockInGame(undefined, {
backgroundColor: 'yellow',
width: width,
height: height,
left: '250px',
top: '50px'
});
const block3 = new BlockInGame(undefined, {
backgroundColor: 'black',
width: width,
height: height,
left: '450px',
top: '50px'
});
}
@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);
}
<section class="game">
</section>