I am trying to achieve this kind of functionality on a web page:
=> So I basically want to create something like "photoshop square selection tool" that would get all the HTML elements that are in the selected area... IS this even possible somehow? Any of you done that or know a js (jQuery) library for that?

No need to use jQuery in order to create a rectangular lasso tool.
The logic is not hard.
fixed position element", therefore you'll also need a styled lasso element that has position fixed.x = min(pointerStartX, pointerCurrentX) andw = abs(pointerStartX - pointerCurrentX); and do the equivalent for y and hLasso tool example:
const el = (sel, par) => (par || document).querySelector(sel);
const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop);
const toolLasso = {
onDown({clientX, clientY}) {
this.startX = clientX;
this.startY = clientY;
this.el = elNew("div", {className: "lasso"});
this.onMove = this.onMove.bind(this);
this.onUp = this.onUp.bind(this);
addEventListener("pointermove", this.onMove);
addEventListener("pointerup", this.onUp);
// Insert into DOM
Object.assign(this.el.style, {
position: `fixed`,
outline: `2px dashed blue`,
zIndex: `99999`,
pointerEvents: `none`,
userSelect: `none`,
});
el("body").append(this.el);
},
onMove({clientX, clientY}) {
this.currX = clientX;
this.currY = clientY;
const x = Math.min(this.startX, this.currX);
const y = Math.min(this.startY, this.currY);
const w = Math.abs(this.startX - this.currX);
const h = Math.abs(this.startY - this.currY);
Object.assign(this.el.style, {
left: `${x}px`,
top: `${y}px`,
width: `${w}px`,
height: `${h}px`,
});
// Check elements selection:
// checkElementsCollision(x, y, w, h);
},
onUp() {
removeEventListener("pointermove", this.onMove);
removeEventListener("pointerup", this.onUp);
this.el.remove();
}
};
addEventListener("pointerdown", (evt) => toolLasso.onDown(evt));
* { margin: 0; box-sizing: border-box; }
body { min-height: 200vh; } /* just to force some demo scrollbars */
For the selecting of elements - the task is pretty basic:
onMove call a checkElementsCollision(x, y, w, h) where you basically check if an element or group of elements Element.getBoundingClientRect() x , y , width and height are colliding with the passed x, y, w, h, arguments values of your lasso tool.const el = (sel, par) => (par || document).querySelector(sel);
const els = (sel, par) => (par || document).querySelectorAll(sel);
const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop);
const collides = (a, b) =>
a.x < b.x + b.width &&
a.x + a.width > b.x &&
a.y < b.y + b.height &&
a.y + a.height > b.y;
const checkElementsCollision = (x, y, width, height) => {
els(".box").forEach(elBox => {
const isColliding = collides({x, y, width, height}, elBox.getBoundingClientRect());
elBox.classList.toggle("is-selected", isColliding);
});
};
const toolLasso = {
onDown({clientX, clientY}) {
this.startX = clientX;
this.startY = clientY;
this.el = elNew("div", {className: "lasso"});
this.onMove = this.onMove.bind(this);
this.onUp = this.onUp.bind(this);
addEventListener("pointermove", this.onMove);
addEventListener("pointerup", this.onUp);
// Insert into DOM
Object.assign(this.el.style, {
position: `fixed`,
outline: `2px dashed blue`,
zIndex: `99999`,
pointerEvents: `none`,
userSelect: `none`,
});
el("body").append(this.el);
},
onMove({clientX, clientY}) {
this.currX = clientX;
this.currY = clientY;
const x = Math.min(this.startX, this.currX);
const y = Math.min(this.startY, this.currY);
const w = Math.abs(this.startX - this.currX);
const h = Math.abs(this.startY - this.currY);
Object.assign(this.el.style, {
left: `${x}px`,
top: `${y}px`,
width: `${w}px`,
height: `${h}px`,
});
// Check elements selection:
checkElementsCollision(x, y, w, h);
},
onUp() {
removeEventListener("pointermove", this.onMove);
removeEventListener("pointerup", this.onUp);
this.el.remove();
}
};
addEventListener("pointerdown", (evt) => toolLasso.onDown(evt));
* { margin: 0; box-sizing: border-box; }
body { min-height: 200vh; } /* just to force some demo scrollbars */
.box {
position: absolute;
background: gray;
width: 40px;
aspect-ratio: 1;
left: calc(var(--x) * 1px );
top: calc(var(--y) * 1px);
}
.box.is-selected {
background: gold;
}
<div class="box" style="--x:100; --y:100;"></div>
<div class="box" style="--x:150; --y:170;"></div>
<div class="box" style="--x:50; --y:200;"></div>
<div class="box" style="--x:180; --y:10;"></div>
Read more on MDN about: 2D collision detection
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With