我想在网页的图像上标记一个矩形以供选择感兴趣的区域。意思是,给定网页上的图像,我希望能够用鼠标单击拖动,绘制一个矩形并在释放鼠标时返回一组 x、y、w、h。
这怎么办?
谢谢。
这可以通过一些定位技巧来完成。将图像设置在相对定位的div中。然后,您可以在包含图像的 div 内部创建一个绝对定位的 div。这允许您将嵌套的 div 移动到图像的前面。
根据您的更新,我添加了一些 JavaScript 来控制
mousedown
、mousemove
和 mouseup
上的内部 div 的 x、y、w、h
注意:由于此 js 片段使用了 clientX/Y 和 offsetLeft/Top,因此下面的预览可能会因为帖子页面内的溢出容器而运行得有点偏差。我建议在全屏模式下查看“运行代码片段”。
var x,y,oldx,oldy;
var showDrag = false;
document.getElementById("cont").addEventListener("mousedown", function(e) {
oldx = e.clientX; //mousedown x coord
oldy = e.clientY; //mouedown y coord
showDrag = true;
e.preventDefault();
});
document.getElementById("cont").addEventListener("mousemove", function(e) {
if (showDrag == true) {
x = e.clientX; //mouseup x coord
y = e.clientY; //mouseup y coord
var bbox = document.getElementById("bbox");
var contbox = document.getElementById("cont");
//get the width and height of the dragged area
var w = (x > oldx ? x-oldx : oldx-x);
var h = (y > oldy ? y-oldy : oldy-y);
var addx = 0, addy = 0;
//these next two lines judge if the box was dragged backward
//and adds the box's width to the bbox positioning offset
if (x < oldx) { addx = w; }
if (y < oldy) { addy = h; }
bbox.style.left = (oldx-parseInt((contbox.offsetLeft+addx)))+"px";
bbox.style.top = (oldy-parseInt((contbox.offsetTop+addy)))+"px";
bbox.style.width = w+"px";
bbox.style.height = h+"px";
bbox.style.display = "block";
}
e.preventDefault();
});
document.getElementById("cont").addEventListener("mouseup", function(e) {
showDrag = false;
e.preventDefault();
});
div.focus-image {
border:1px solid #dddddd;
display:inline-block;
position:relative;
cursor:pointer;
}
div.focus-image div {
display:none;
border:2px solid red;
position:absolute;
left:90px; /*x*/
top:60px; /*y*/
}
<div id="cont" class="focus-image">
<img src="http://cdn.sstatic.net/Sites/stackoverflow/img/[email protected]?v=73d79a89bded&a" />
<div id="bbox"></div>
</div>
我的 next.js/react + typescript 解决方案(基于 Spencer May 的回答):
"use client";
import Image from "next/image";
import { useState, MouseEvent } from "react";
type BoxState = {
x: number;
y: number;
width: number;
height: number;
controlled: boolean;
visible: boolean;
};
export default function SelectImage() {
const [box, setBox] = useState<BoxState>({
x: 0,
y: 0,
width: 0,
height: 0,
controlled: false,
visible: false,
});
const [start, setStart] = useState({ x: 0, y: 0 });
function handleMouseDown(e: MouseEvent<HTMLDivElement>) {
const rect = e.currentTarget.getBoundingClientRect();
// Offset relative to parent div
const x1 = e.clientX - rect.left;
const y1 = e.clientY - rect.top;
setStart({ x: x1, y: y1 });
setBox((prev) => ({
...prev,
x: x1,
y: y1,
width: 0,
height: 0,
controlled: true,
visible: true,
}));
}
function handleMouseMove(e: MouseEvent<HTMLDivElement>) {
if (box.controlled) {
const rect = e.currentTarget.getBoundingClientRect();
const x2 = e.clientX - rect.left;
const y2 = e.clientY - rect.top;
setBox((prev) => ({
...prev,
// Handle backward drag
x: Math.min(x2, start.x),
y: Math.min(y2, start.y),
width: Math.abs(x2 - start.x),
height: Math.abs(y2 - start.y),
}));
}
}
function handleMouseUp() {
const cancelSize = 20;
const cancelRect = box.width < cancelSize || box.height < cancelSize;
setBox((prev) => ({ ...prev, controlled: false, visible: !cancelRect }));
}
return (
<div className="flex flex-col justify-center items-center bg-white">
<h2>Select image demo</h2>
<div
className="inline-block relative cursor-pointer border border-gray-300 select-none"
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
onMouseLeave={handleMouseUp}
draggable="false"
>
<Image
src="http://cdn.sstatic.net/Sites/stackoverflow/img/[email protected]?v=73d79a89bded&a"
className="pointer-events-none select-none"
alt="demo"
width="400"
height="400"
/>
{box.visible && (
<div
className="absolute border-2 border-red-500 pointer-events-none select-none"
style={{
left: box.x,
top: box.y,
width: box.width,
height: box.height,
display: box.visible ? "block" : "none",
}}
></div>
)}
</div>
</div>
);
}
你有一个图像,并且你希望能够在图像内部绘制一个矩形?
只需在图像内部创建一个带有边框的绝对定位的 div 即可。
向图像添加一个 mousedown 处理程序以获取单击的位置,然后添加一个用于获取光标位置当前位置的处理程序,直到 mouseup。
在光标当前位置的处理程序中 - 设置 div 的尺寸。鼠标松开时,停止调整 div 大小。