绘制拖拽html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>拖拽绘制矩形框 - 可移动可调整大小</title>
<style>body, html {margin: 0; padding: 0; height: 100%;user-select: none;}#container {position: relative;width: 100vw;height: 100vh;background-color: #f0f0f0;border: 1px solid #ccc;overflow: hidden;}.rectangle {position: absolute;border: 2px solid;background-color: rgba(0, 123, 255, 0.2);cursor: move;box-sizing: border-box;}.delete-btn {position: absolute;top: -8px;right: -8px;width: 16px;height: 16px;background: #ff4d4f;color: white;font-weight: bold;font-size: 12px;line-height: 16px;text-align: center;border-radius: 50%;cursor: pointer;user-select: none;z-index: 1000;pointer-events: auto;}.resize-handle {position: absolute;width: 10px;height: 10px;background: white;border: 2px solid #007bff;box-sizing: border-box;z-index: 10;}.resize-handle.nw { top: -6px; left: -6px; cursor: nwse-resize; }.resize-handle.ne { top: -6px; right: -6px; cursor: nesw-resize; }.resize-handle.sw { bottom: -6px; left: -6px; cursor: nesw-resize; }.resize-handle.se { bottom: -6px; right: -6px; cursor: nwse-resize; }#info {position: fixed;bottom: 10px;left: 10px;max-height: 150px;overflow-y: auto;background: rgba(255,255,255,0.9);border: 1px solid #ccc;padding: 8px;font-family: monospace;font-size: 14px;width: 320px;}
</style>
</head>
<body>
<div id="container"></div>
<div id="info"><strong>绘制的矩形框信息:</strong><br/></div>
<script>(function() {const container = document.getElementById('container');const info = document.getElementById('info');let startX = 0;let startY = 0;let currentRect = null;let rectangles = [];let dragData = null; // {rect, startX, startY, origX, origY}let resizeData = null; // {rect, handle, startX, startY, origX, origY, origW, origH}const colors = ['#007bff', '#28a745', '#dc3545', '#ffc107', '#17a2b8','#6f42c1', '#e83e8c', '#fd7e14', '#20c997', '#6610f2'];function getRelativePosition(clientX, clientY) {const rect = container.getBoundingClientRect();return {x: clientX - rect.left,y: clientY - rect.top};}function updateInfoLine(rect) {if (!rect._infoLine) return;const x = parseFloat(rect.style.left);const y = parseFloat(rect.style.top);const w = parseFloat(rect.style.width);const h = parseFloat(rect.style.height);rect._infoLine.textContent = `矩形框 ${rectangles.indexOf(rect) + 1}: x=${Math.round(x)}, y=${Math.round(y)}, 宽=${Math.round(w)}, 高=${Math.round(h)}`;}function createResizeHandle(position) {const handle = document.createElement('div');handle.className = 'resize-handle ' + position;return handle;}container.addEventListener('mousedown', (e) => {if (e.button !== 0) return; // only left mouse buttonconst target = e.target;// 如果点击的是删除按钮if (target.classList.contains('delete-btn')) {return; // 由其自身的监听器处理}// 如果点击的是调整大小的控制点if (target.classList.contains('resize-handle')) {const rect = target.parentElement;const pos = getRelativePosition(e.clientX, e.clientY);resizeData = {rect,handle: target.classList[1], // nw, ne, sw, sestartX: pos.x,startY: pos.y,origX: parseFloat(rect.style.left),origY: parseFloat(rect.style.top),origW: parseFloat(rect.style.width),origH: parseFloat(rect.style.height)};e.preventDefault();return;}// 如果点击的是已有的矩形(非删除或调整大小)if (target.classList.contains('rectangle')) {const rect = target;const pos = getRelativePosition(e.clientX, e.clientY);dragData = {rect,startX: pos.x,startY: pos.y,origX: parseFloat(rect.style.left),origY: parseFloat(rect.style.top)};e.preventDefault();return;}// 否则,开始绘制新的矩形const pos = getRelativePosition(e.clientX, e.clientY);startX = pos.x;startY = pos.y;currentRect = document.createElement('div');currentRect.className = 'rectangle';// 颜色循环分配const color = colors[rectangles.length % colors.length];currentRect.style.borderColor = color;currentRect.style.backgroundColor = color + '33'; // 20% 透明度currentRect.style.left = startX + 'px';currentRect.style.top = startY + 'px';currentRect.style.width = '0px';currentRect.style.height = '0px';container.appendChild(currentRect);rectangles.push(currentRect);// 创建信息行元素const infoLine = document.createElement('div');infoLine.style.display = 'flex';infoLine.style.alignItems = 'center';infoLine.style.marginBottom = '4px';// 创建文本节点,显示矩形信息const infoText = document.createElement('span');infoText.textContent = `矩形框 ${rectangles.length}: x=0, y=0, 宽=0, 高=0`;infoLine.appendChild(infoText);// 创建删除按钮const infoDeleteBtn = document.createElement('button');infoDeleteBtn.textContent = '删除';infoDeleteBtn.style.marginLeft = '10px';infoDeleteBtn.style.cursor = 'pointer';infoDeleteBtn.style.padding = '2px 6px';infoDeleteBtn.style.border = '1px solid #ccc';infoDeleteBtn.style.backgroundColor = '#f8f9fa';infoDeleteBtn.style.borderRadius = '4px';infoDeleteBtn.style.fontSize = '12px';infoDeleteBtn.style.color = '#333';infoDeleteBtn.style.userSelect = 'none';// 删除按钮点击事件,删除对应矩形和信息行(function(rect, line) {infoDeleteBtn.addEventListener('click', function() {// 删除对应矩形元素if (container.contains(rect)) {container.removeChild(rect);}// 删除对应信息行if (info.contains(line)) {info.removeChild(line);}// 从数组中移除对应矩形const index = rectangles.indexOf(rect);if (index > -1) {rectangles.splice(index, 1);}});})(currentRect, infoLine);// 将删除按钮添加到信息行infoLine.appendChild(infoDeleteBtn);// 将信息行添加到info面板info.appendChild(infoLine);// 存储引用以便后续更新和删除currentRect._infoLine = infoText;e.preventDefault();});container.addEventListener('mousemove', (e) => {const pos = getRelativePosition(e.clientX, e.clientY);// 处理调整大小if (resizeData) {const {rect, handle, startX, startY, origX, origY, origW, origH} = resizeData;let newX = origX;let newY = origY;let newW = origW;let newH = origH;const dx = pos.x - startX;const dy = pos.y - startY;switch (handle) {case 'nw':newX = origX + dx;newY = origY + dy;newW = origW - dx;newH = origH - dy;break;case 'ne':newY = origY + dy;newW = origW + dx;newH = origH - dy;break;case 'sw':newX = origX + dx;newW = origW - dx;newH = origH + dy;break;case 'se':newW = origW + dx;newH = origH + dy;break;}// 防止宽高为负if (newW < 10) newW = 10;if (newH < 10) newH = 10;if (newX < 0) newX = 0;if (newY < 0) newY = 0;if (newX + newW > container.clientWidth) newX = container.clientWidth - newW;if (newY + newH > container.clientHeight) newY = container.clientHeight - newH;rect.style.left = newX + 'px';rect.style.top = newY + 'px';rect.style.width = newW + 'px';rect.style.height = newH + 'px';updateInfoLine(rect);e.preventDefault();return;}// 处理拖拽if (dragData) {const {rect, startX, startY, origX, origY} = dragData;let newX = origX + (pos.x - startX);let newY = origY + (pos.y - startY);// 保持在容器内if (newX < 0) newX = 0;if (newY < 0) newY = 0;if (newX + rect.clientWidth > container.clientWidth) newX = container.clientWidth - rect.clientWidth;if (newY + rect.clientHeight > container.clientHeight) newY = container.clientHeight - rect.clientHeight;rect.style.left = newX + 'px';rect.style.top = newY + 'px';updateInfoLine(rect);e.preventDefault();return;}// 处理绘制新矩形if (!currentRect) return;const x = Math.min(pos.x, startX);const y = Math.min(pos.y, startY);const width = Math.abs(pos.x - startX);const height = Math.abs(pos.y - startY);currentRect.style.left = x + 'px';currentRect.style.top = y + 'px';currentRect.style.width = width + 'px';currentRect.style.height = height + 'px';updateInfoLine(currentRect);e.preventDefault();});container.addEventListener('mouseup', (e) => {if (currentRect) {currentRect = null;e.preventDefault();}if (dragData) {dragData = null;e.preventDefault();}if (resizeData) {resizeData = null;e.preventDefault();}});container.addEventListener('mouseleave', (e) => {if (currentRect) {currentRect = null;}if (dragData) {dragData = null;}if (resizeData) {resizeData = null;}});// 监听容器子元素变化,给新矩形添加调整大小控制点const observer = new MutationObserver(mutations => {mutations.forEach(mutation => {mutation.addedNodes.forEach(node => {if (node.classList && node.classList.contains('rectangle')) {['nw', 'ne', 'sw', 'se'].forEach(pos => {const handle = createResizeHandle(pos);node.appendChild(handle);});}});});});observer.observe(container, { childList: true });})();
</script>
</body>
</html>
相关文章:

绘制拖拽html
<!DOCTYPE html> <html lang"zh-CN"> <head> <meta charset"UTF-8" /> <meta name"viewport" content"widthdevice-width, initial-scale1" /> <title>拖拽绘制矩形框 - 可移动可调整大小</ti…...
C++结构体介绍
结构体的定义 在C中,结构体(struct)是一种用户定义的数据类型,允许将不同类型的数据组合在一起。结构体的定义使用struct关键字,后跟结构体名称和一对花括号{},花括号内包含成员变量的声明。 struct Pers…...

ggplot2 | GO barplot with gene list
1. 效果图 2. 代码 数据是GO的输出结果,本文使用的是 metascape 输出的excel挑选的若干行。 # 1. 读取数据 datread.csv("E:\\research\\scPolyA-seq2\\GO-APA-Timepoint\\test.csv", sep"\t") head(dat)# 2. 选择所需要的列 dat.usedat[, c(…...
PostgreSQL 的 pg_advisory_lock 函数
PostgreSQL 的 pg_advisory_lock 函数 pg_advisory_lock 是 PostgreSQL 提供的一种应用级锁机制,它不锁定具体的数据库对象(如表或行),而是通过数字键值来协调应用间的并发控制。 锁的基本概念 PostgreSQL 提供两种咨询锁(advi…...
docker 镜像的导出和导入(导出完整镜像和导出容器快照)
一、导出原始镜像 1. 使用 docker save 导出完整镜像 适用场景:保留镜像的所有层、元数据、标签和历史记录,适合迁移或备份完整镜像环境。 操作命令 docker save -o <导出文件名.tar> <镜像名:标签>示例:docker save -o milvu…...

系统思考:短期困境与长期收益
最近在项目中,一直有学员会提到一个议题,如何平衡当前困境和长期收益? 我的思考是在商业和人生的路上,我们常常听到“鱼和熊掌不可兼得”的说法,似乎短期利益和长期目标注定是对立的。但事实上,鱼与熊掌是…...
4.2【LLaMA-Factory实战】金融财报分析系统:从数据到部署的全流程实践
【LLaMA-Factory实战】金融财报分析系统:从数据到部署的全流程实践 一、引言 在金融领域,财报分析是投资决策的核心环节。传统分析方法面临信息提取效率低、风险识别不全面等挑战。本文基于LLaMA-Factory框架,详细介绍如何构建一个专业的金…...

Cjson格式解析与接入AI大模型
JSON格式的解析与构造 基本概念 JSON是JavaScript Object Notation的简称,中文含义为“JavaScript 对象表示法”,它是一种数据交换的文本格式,而不是一种编程语言。 JSON 是一种轻量级的数据交换格式,采用完全独立于编程语言的…...

基于英特尔 RealSense D455 结构光相机实现裂缝尺寸以及深度测量
目录 一,相机参数规格 二,结合YOLO实例分割实现裂缝尺寸以及深度测量 2.1 应用场景 2.2 实现流程 2.3 效果展示 2.4 精度验证 2.5 实物裂缝尺寸以及深度测量效果展示 一,相机参数规格 英特尔 RealSense D455 是英特尔 RealSense D400 系…...

Nacos源码—7.Nacos升级gRPC分析四
大纲 5.服务变动时如何通知订阅的客户端 6.微服务实例信息如何同步集群节点 6.微服务实例信息如何同步集群节点 (1)服务端处理服务注册时会发布一个ClientChangedEvent事件 (2)ClientChangedEvent事件的处理源码 (3)集群节点处理数据同步请求的源码 (1)服务端处理服务注册…...

TIME - MoE 模型代码 3.2——Time-MoE-main/time_moe/datasets/time_moe_dataset.py
源码:GitHub - Time-MoE/Time-MoE: [ICLR 2025 Spotlight] Official implementation of "Time-MoE: Billion-Scale Time Series Foundation Models with Mixture of Experts" 这段代码定义了一个用于时间序列数据处理的 TimeMoEDataset 类,支…...

【某OTA网站】phantom-token 1004
新版1004 phantom-token 请求头中包含phantom-token 定位到 window.signature 熟悉的vmp 和xhs一样 最新环境检测点 最新检测 canvas 下的 toDataURL方法较严 过程中 会用setAttribute给canvas 设置width height 从而使toDataURL返回不同的值 如果写死toDataURL的返回值…...

OrangePi Zero 3学习笔记(Android篇)2 - 第一个C程序
目录 1. 创建项目文件夹 2. 创建c/cpp文件 3. 创建Android.mk/Android.bp文件 3.1 Android.mk 3.2 Android.bp 4. 编译 5. adb push 6. 打包到image中 在AOSP里面添加一个C或C程序,这个程序在Android中需要通过shell的方式运行。 1. 创建项目文件夹 首先需…...

DeepResearch深度搜索实现方法调研
DeepResearch深度搜索实现方法调研 Deep Research 有三个核心能力 能力一:自主规划解决问题的搜索路径(生成子问题,queries,检索)能力二:在探索路径时动态调整搜索方向(刘亦菲最好的一部电影是…...
使用大语言模型进行机器人规划(Robot planning with LLMs)
李升伟 编译 长期规划在机器人学领域可以从经典控制方法与大型语言模型在现实世界知识能力的结合中获益。 在20世纪80年代,机器人学和人工智能(AI)领域的专家提出了莫雷奇悖论,观察到人类看似简单的涉及移动和感知的任务&#x…...

【论文阅读】基于客户端数据子空间主角度的聚类联邦学习分布相似性高效识别
Efficient distribution similarity identification in clustered federated learning via principal angles between client data subspaces -- 基于客户端数据子空间主角度的聚类联邦学习分布相似性高效识别 论文来源TLDR背景与问题两个子空间之间的主角(Principa…...

Elasticsearch知识汇总之ElasticSearch部署
五 ElasticSearch部署 部署Elasticsearch,可以在任何 Linux、MacOS 或 Windows 机器上运行 Elasticsearch。在Docker 容器 中运行 Elasticsearch 。使用Elastic Cloud on Kubernetes 设置和管理 Elasticsearch、Kibana、Elastic Agent 以及 Kubernetes 上的 Elasti…...

ROBOVERSE:面向可扩展和可泛化机器人学习的统一平台、数据集和基准
25年4月来自UC Berkeley、北大、USC、UMich、UIUC、Stanford、CMU、UCLA 和 北京通用 AI 研究院(BIGAI)的论文“ROBOVERSE: Towards a Unified Platform, Dataset and Benchmark for Scalable and Generalizable Robot Learning”。 数据扩展和标准化评…...
LVGL的核心:lv_timer_handler
文章目录 🧠 一句话总结 LVGL 的运行核心:🔁 1. while(1) 主循环中的 lv_task_handler()⏱️ 2. lv_timer_handler() 定时器调度核心✅ 并发控制✅ 关键行为流程:🌀 任务执行逻辑:🧮 计算下一次…...

(41)VTK C++开发示例 ---qt使用vtk最小示例
文章目录 1. 概述2. CMake链接VTK3. main.cpp文件4. 演示效果 更多精彩内容👉内容导航 👈👉VTK开发 👈 1. 概述 本文演示了在Qt中使用VTK的最小示例程序,使用VTK创建显示一个锥体; 采用Cmake作为构建工具&a…...
⭐️⭐️⭐️【课时1:大模型是什么?】学习总结 ⭐️⭐️⭐️ for《大模型Clouder认证:基于百炼平台构建智能体应用》认证
一、学习目标 概要 通过学习《课时1:大模型是什么?》,全面了解大模型的基础概念、核心特点、发展脉络及阿里云在大模型领域的布局,为后续基于百炼平台构建智能体应用的实践操作打下坚实的理论基础。 具体目标列表 理解人工智能到大模型的演变逻辑,明确大模型在AI发展历…...

OS7.【Linux】基本指令入门(6)
目录 1.zip和unzip 配置指令 使用 两个名词:打包和压缩 打包 压缩 Linux下的操作演示 压缩和解压缩文件 压缩和解压缩目录 -d选项 2.tar Linux下的打包和压缩方案简介 czf选项 xzf选项 -C选项 tzf选项 3.bc 4.uname 不带选项的uname -a选项 -r选项 -v选项…...

国标GB28181视频平台EasyCVR安防系统部署知识:如何解决异地监控集中管理和组网问题
在企业、连锁机构及园区管理等场景中,异地监控集中管控与快速组网需求日益迫切。弱电项目人员和企业管理者亟需整合分散监控资源,实现跨区域统一管理与实时查看。 一、解决方案 案例一:运营商专线方案 利用运营商专线,连接各分…...

O2O上门服务如何颠覆传统足浴行业?真实案例分析
在湖南经营传统足浴店的张总最近遇到了件让他哭笑不得的事。原本他的门店生意还算稳定,虽然这两年行情不好,但靠着老顾客还能勉强维持。可谁想到,一次好心帮忙,竟让他发现了行业的新天地。 几年前,张总的一位做砂石生意…...

金仓数据库永久增量备份技术原理与操作
先用一张图说明一下常见的备份方式 为什么需要永久增量备份 传统的数据库备份方案通常是间隔7天对数据库做一次全量备份(完整备份),每天会基于全量备份做一次增量备份,如此循环,这种备份方案在全备数据量过大场景下…...

19、HashTable(哈希)、位图的实现和布隆过滤器的介绍
一、了解哈希【散列表】 1、哈希的结构 在STL中,HashTable是一个重要的底层数据结构, 无序关联容器包括unordered_set, unordered_map内部都是基于哈希表实现 哈希表又称散列表,一种以「key-value」形式存储数据的数据结构。哈希函数:负责将…...
函数级重构:如何写出高可读性的方法?
1. 引言:为什么方法级别的重构如此重要? 在软件开发中,方法(函数)是程序逻辑的基本单元。一个高质量的方法不仅决定了程序是否能正常运行,更直接影响到: 代码的可读性:能否让其他开发者快速理解可维护性:未来修改是否容易出错可测试性:是否便于编写单元测试协作效率…...

mysql中int(1) 和 int(10) 有什么区别?
困惑 最近遇到个问题,有个表的要加个user_id字段,user_id字段可能很大,于是我提mysql工单alter table xxx ADD user_id int(1)。领导看到我的sql工单,于是说:这int(1)怕是不够用吧,接下来是一通解…...

FreeRTOS如何实现100%的硬实时性?
实时系统在嵌入式应用中至关重要,其核心在于确保任务在指定时间内完成。根据截止时间满足的严格程度,实时系统分为硬实时和软实时。硬实时系统要求任务100%满足截止时间,否则可能导致灾难性后果,例如汽车安全系统或医疗设备。软实…...
深度学习 ----- 数据预处理
常用的高级数据预处理的方法总结 🧠 一、图像数据高级预处理方法汇总表 方法原理常用参数适用场景图像增强(Augmentation)改变图像外观/几何结构,提升泛化能力翻转、旋转、缩放、色调扰动等分类、检测、分割等Mixup / CutMix合成…...