当前位置: 首页 > news >正文

以鼠标位置为中心进行滚动缩放

需求:在图片上进行手动标注,当目标较小时需要放大后再进行框选标注。默认状态下,图片是以左上角为中心进行缩放的,如果对图片设置了居中则是以中点为中心进行缩放的。现在我们需要实现以目标(即鼠标位置)为中心进行滚动缩放。

1.原理

以鼠标位置为中心进行缩放其实就是先进行缩放然后再进行平移操作,将缩放完成的图形平移到鼠标位置,使得缩放前后鼠标指向的图形位置不变。

那么我们最重要的就是计算出偏移量,具体怎么算不再赘述,详情点击偏移量计算原理

2.套公式

首先我们需要先确定我们的图形是以什么位置进行缩放,这点很重要,因为不同的缩放位置进行平移的时候算法不同

  • 以图片左上角缩放
deltaX -= (1 - n) * (width / 2 - e.clientX + x1)
deltaY -= (1 - n) * (height / 2 - e.clientY + y1)
  • 以图片中点缩放
deltaX -= (e.clientX - x1) * (n - 1)
deltaY -= (e.clientY - y1) * (n - 1)

以上两种方式只有 deltaX 和 deltaY的计算有区别,其他逻辑是一样的,即缩放再平移

3.绑定缩放事件

以下为以图片左上角缩放的例子

<template><div class="img-wrap" @mousewheel.prevent="rollImg($event)"><img class="imgDiv" ref="imgDiv" :src="imgSrc" alt="" /><div>
</template><script>
const imgDiv = ref(null)
const deltaX = ref(0) // 需要平移的x轴距离
const deltaY = ref(0) // 需要平移的y轴距离
const preScale = ref(1) // 记录图片缩放前的比例
// 图片参数
const params = ref({zoomVal: 1, // 缩放比例deg: 0,offsetLeft: 0,offsetTop: 0,
})// 以鼠标位置为中心进行缩放
function rollImg(e) {params.value.zoomVal += e.wheelDelta / 1200const n = params.value.zoomVal / preScale.valueconst { x: x1, y: y1, width, height } = imgDiv.value.getBoundingClientRect()deltaX.value -= (1 - n) * (width / 2 - e.clientX + x1)deltaY.value -= (1 - n) * (height / 2 - e.clientY + y1)if (params.value.zoomVal >= 0.2) {img.style.transform = `translate(${deltaX.value}px, ${deltaY.value}px) scale(${params.value.zoomVal})`} else {params.value.zoomVal = 0.2img.style.transform = `translate(${deltaX.value}px, ${deltaY.value}px) scale(${params.value.zoomVal})`return false}preScale.value = params.value.zoomVal
}
</script>

以图片中点缩放只需要替换deltaX 和 deltaY的计算即可,但是中点缩放有一个坑,下面详细说明

4.以图片中点缩放的坑

如果

.img-wrap {position: relative;.imgDiv {position: absolute;left: 50%;transform: translateX(-50%);}
}
  • 初始状态下图片使用 left: 50% + transform: translate(-50%, 0) 实现水平居中

  • 缩放计算时使用 deltaX/deltaY 的绝对像素位移transform: `translate(${deltaX.value}px, ${deltaY.value}px)`

  • 根本原因在于初始状态下的居中定位方式与缩放时的位移计算逻辑存在冲突,首次缩放时这个偏移量未被纳入 deltaX/deltaY 计算

解决方法:

不再使用CSS的百分比和translate来实现居中,而是用`deltaX`和`deltaY`来模拟居中。这样,在缩放时,位移计算就可以正确叠加

function resetParams(){const imgWrapWidth = imgWrap.value.clientWidthconst imgDivWidth = imgDiv.value.offsetWidthdeltaX.value = (imgWrapWidth - imgDivWidth ) / 2deltaY.value = 0preScale.value = 1imgDiv.value.style.left = 0imgDiv.value.style.top = 0imgDiv.value.style.transform = `translate(${deltaX.value}px, ${deltaY.value}}px)`
}

http://www.lryc.cn/news/620227.html

相关文章:

  • 力扣top100(day02-03)--链表03
  • 修复运动模糊的视频用什么软件?快速解决方案分享
  • ECCV-2018《Variational Wasserstein Clustering》
  • AI工程化闭环法(AIEC – AI Engineering Cycle) 适合TRAE CURSOR CLAUDE等工具
  • Transformer 之自注意力机制(一)
  • TF-IDF------词向量转化:从“文字”到“向量”
  • 可视化调试LangChain SQLChatMessageHistory:SQLite数据库查看全攻略
  • Java多线程进阶-从乐观锁到读写锁
  • 西门子TIA-SCL转STL指令项目案例及技巧
  • 【Python】Python 函数基本介绍(详细版)​
  • ARM 实操 流水灯 按键控制 day53
  • ACL 可以限制哪些流量?入方向和出方向怎么判断?
  • vue路由_router
  • rk3588 ubuntu20.04安装包经常出现的问题总结(chatgpt回复)
  • C++ 优选算法 力扣 209.长度最小的子数组 滑动窗口 (同向双指针)优化 每日一题 详细题解
  • VUE基础笔记
  • 计算机网络---IPv6
  • 向长波红外成像图注入非均匀噪声
  • ROS2实用工具
  • 小电视视频内容获取GUI工具
  • Ansible 实操笔记:Playbook 与变量管理
  • 传输层协议 TCP(1)
  • C语言队列的实现
  • 浪浪山小妖怪电影
  • HarmonyOS 开发实战:搞定应用名字与图标更换,全流程可运行示例
  • 《卷积神经网络(CNN):解锁视觉与多模态任务的深度学习核心》
  • 从 VLA 到 VLM:低延迟RTSP|RTMP视频链路在多模态AI中的核心角色与工程实现
  • AI驱动的前端革命:10项颠覆性技术如何在LibreChat中融为一体
  • Java19 Integer 位操作精解:compress与expand《Hacker‘s Delight》(第二版,7.4节)
  • Docker部署RAGFlow:开启Kibana查询ES数据指南