jquery 创建一个“套索工具”来选择元素

w8ntj3qf  于 2023-06-22  发布在  jQuery
关注(0)|答案(2)|浏览(112)

我正在尝试在网页上实现这样的功能:
1.通过拖动鼠标选择正方形区域
1.拾取选定区域中的所有元素
1.处理它们
=>所以我基本上想创建一个类似于“photoshop square selection tool”的东西,它可以获取所选区域中的所有HTML元素...这甚至可能以某种方式吗?你们中有谁做过这个或者知道一个js(jQuery)库吗?

smtd7mpg

smtd7mpg1#

使用碰撞选择套索工具

不需要使用jQuery来创建矩形套索工具。
逻辑并不难。

  • 鼠标指针被视为“fixed位置元素”,因此您还需要一个位置固定的样式化套索元素。
  • 启动pointerEvent时,请始终记住启动clientX、clientY的位置
  • 当定位和调整套索元素的大小时,请使用以下简单的数学运算:

x = min(pointerStartX, pointerCurrentX)
w = abs(pointerStartX - pointerCurrentX);并对yh执行等效操作
套索工具示例:

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 */

对于元素的选择-任务非常基本:

  • onMove调用一个checkElementsCollision(x, y, w, h),在这里你基本上可以检查一个元素或一组元素Element.getBoundingClientRect()x,y,widthheight 是否与你的lasso工具传递的x, y, w, h,参数值冲突。
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>

在MDN上阅读更多关于:2D collision detection

uwopmtnx

uwopmtnx2#

好吧,有几种方法可以做到这一点。
事实上,我刚才已落实了这一点。
我使用一个div,id="tool-lasso" style="position: absolute;"在鼠标按下时,我将一个变量mouseMode设置为lasso,并将元素(tool-lasso) css设置为左:

e.pageX; top: e.pageY; width: 0; height: 0;

在鼠标移动时,如果mouseMode == 'lasso',我会更新宽度和高度:

e.pageX - parseInt($('#tool-lasso').css('left')), e.pageY - parseInt($('#tool-lasso').css('top'))

然后在鼠标向上时,将mouseMode设置为normal
对于鼠标移动部分,您可能希望将其设置为function(e) {...},并在鼠标向下和向上事件以及鼠标移动中调用它。

相关问题