使用HTML写一个悬浮摄像头,可拖拽、放大、缩小
·
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>悬浮摄像头</title>
<style>
body { margin: 0; padding: 0; }
.floating-camera {
position: fixed;
top: 20%;
left: 50%;
transform: translate(-50%, -50%);
width: 320px;
height: 240px;
min-width: 160px;
min-height: 120px;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
z-index: 999999;
background-color: #000;
cursor: move;
user-select: none;
}
video {
width: 100%;
height: 100%;
object-fit: cover;
pointer-events: none;
}
.resize-handle {
position: absolute;
background: rgba(255, 255, 255, 0.3);
pointer-events: auto;
}
.nw { top: 0; left: 0; width: 15px; height: 15px; cursor: nw-resize; }
.ne { top: 0; right: 0; width: 15px; height: 15px; cursor: ne-resize; }
.sw { bottom: 0; left: 0; width: 15px; height: 15px; cursor: sw-resize; }
.se { bottom: 0; right: 0; width: 15px; height: 15px; cursor: se-resize; }
.n { top: 0; left: 15px; right: 15px; height: 5px; cursor: n-resize; }
.s { bottom: 0; left: 15px; right: 15px; height: 5px; cursor: s-resize; }
.w { top: 15px; bottom: 15px; left: 0; width: 5px; cursor: w-resize; }
.e { top: 15px; bottom: 15px; right: 0; width: 5px; cursor: e-resize; }
</style>
</head>
<body>
<!-- 悬浮摄像头容器 -->
<div id="cameraWindow" class="floating-camera">
<video id="cameraVideo" autoplay muted playsinline></video>
<div class="resize-handle nw" data-dir="nw"></div>
<div class="resize-handle ne" data-dir="ne"></div>
<div class="resize-handle sw" data-dir="sw"></div>
<div class="resize-handle se" data-dir="se"></div>
<div class="resize-handle n" data-dir="n"></div>
<div class="resize-handle s" data-dir="s"></div>
<div class="resize-handle w" data-dir="w"></div>
<div class="resize-handle e" data-dir="e"></div>
</div>
<script>
// 1. 初始化摄像头
const video = document.getElementById('cameraVideo');
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ video: true, audio: false })
.then(stream => { video.srcObject = stream; })
.catch(error => {
console.error("无法访问摄像头:", error);
alert("摄像头启动失败,请检查权限或设备连接。");
});
} else {
alert("您的浏览器不支持调用摄像头功能。");
}
// 2. 获取 DOM 元素并初始化居中位置
const cameraWindow = document.getElementById('cameraWindow');
window.addEventListener('load', () => {
const rect = cameraWindow.getBoundingClientRect();
cameraWindow.style.left = rect.left + 'px';
cameraWindow.style.top = rect.top + 'px';
cameraWindow.style.transform = 'none';
});
let isDragging = false;
let dragOffsetX = 0, dragOffsetY = 0;
cameraWindow.addEventListener('mousedown', function(e) {
if (e.target.classList.contains('resize-handle')) return;
isDragging = true;
dragOffsetX = e.clientX - cameraWindow.offsetLeft;
dragOffsetY = e.clientY - cameraWindow.offsetTop;
document.addEventListener('mousemove', onDragMove);
document.addEventListener('mouseup', onDragEnd);
});
function onDragMove(e) {
if (!isDragging) return;
let newX = e.clientX - dragOffsetX;
let newY = e.clientY - dragOffsetY;
const maxX = window.innerWidth - cameraWindow.offsetWidth;
const maxY = window.innerHeight - cameraWindow.offsetHeight;
newX = Math.max(0, Math.min(newX, maxX));
newY = Math.max(0, Math.min(newY, maxY));
cameraWindow.style.left = newX + 'px';
cameraWindow.style.top = newY + 'px';
}
function onDragEnd() {
isDragging = false;
document.removeEventListener('mousemove', onDragMove);
document.removeEventListener('mouseup', onDragEnd);
}
let isResizing = false;
let currentDir = '';
let startWidth = 0, startHeight = 0;
let startX = 0, startY = 0;
let startLeft = 0, startTop = 0;
document.querySelectorAll('.resize-handle').forEach(handle => {
handle.addEventListener('mousedown', function(e) {
isResizing = true;
currentDir = this.dataset.dir;
// 记录初始状态
startWidth = cameraWindow.offsetWidth;
startHeight = cameraWindow.offsetHeight;
startX = e.clientX;
startY = e.clientY;
startLeft = cameraWindow.offsetLeft;
startTop = cameraWindow.offsetTop;
e.stopPropagation();
e.preventDefault();
document.addEventListener('mousemove', onResizeMove);
document.addEventListener('mouseup', onResizeEnd);
});
});
function onResizeMove(e) {
if (!isResizing) return;
let deltaX = e.clientX - startX;
let deltaY = e.clientY - startY;
let newWidth = startWidth;
let newHeight = startHeight;
let newLeft = startLeft;
let newTop = startTop;
// 水平方向处理
if (currentDir.includes('e')) {
newWidth = startWidth + deltaX;
} else if (currentDir.includes('w')) {
newWidth = startWidth - deltaX;
newLeft = startLeft + deltaX;
}
// 垂直方向处理
if (currentDir.includes('s')) {
newHeight = startHeight + deltaY;
} else if (currentDir.includes('n')) {
newHeight = startHeight - deltaY;
newTop = startTop + deltaY;
}
// 应用最小尺寸限制
if (newWidth < 160) {
if (currentDir.includes('w')) newLeft -= (160 - newWidth);
newWidth = 160;
}
if (newHeight < 120) {
if (currentDir.includes('n')) newTop -= (120 - newHeight);
newHeight = 120;
}
// 更新窗口样式
cameraWindow.style.width = newWidth + 'px';
cameraWindow.style.height = newHeight + 'px';
cameraWindow.style.left = newLeft + 'px';
cameraWindow.style.top = newTop + 'px';
}
function onResizeEnd() {
isResizing = false;
document.removeEventListener('mousemove', onResizeMove);
document.removeEventListener('mouseup', onResizeEnd);
}
</script>
</body>
</html>
更多推荐
所有评论(0)