js实现图片以鼠标为中心滚轮缩放-vue

功能背景

  • 实现以鼠标在图中的位置为中心进行图片的滚轮缩放,现在是无论鼠标位置在哪都以图片中心进行缩放,这不符合预期;

关键点

  • 缩放前鼠标在的位置是 A(clinetX,clientY) 点,缩放后鼠标的位置是 A'(x2,y2)点,为了保持鼠标位置不变,需要将A'平移到A, 就需要计算出disx的距离,即偏移量;
  • 绿色代表:缩小后的图片;
  • 黄色代表:原始图片;
    所以需平移+缩放。

主要步骤:

  1. 监听图片mousewheel事件 计算scale:
  2. 鼠标滚轮事件event.deltaY< 0 ,滚轮向上滚,放大;
  3. 根据当前scale,preScale,clientx ,clienty,计算出偏移量(disx),用上一次的位置 - 计算出新旧之间的相对偏移量 (disx)= 最新的位置(x,y);
  4. 保存新计算得出的位置,以便后续计算;
  5. 根据上式得出新的scale,x,y进行transform;

缩放比例n:

n = w i d t h 1 w i d t h = s c a l e p r e S c a l e n =\frac{width_1}{width}=\frac{scale}{preScale} n=widthwidth1=preScalescale

已知:
w i d t h 1 = n ∗ w i d t h width_1 = n*width width1=n∗width

( x 2 − x ′ ) = ( c l i e n t x − x ) n (x_2 - x') = (clientx-x)n (x2−x′)=(clientx−x)n

由图可知:
d i s x = ( w i d t h − w i d t h 1 ) 2 + ( x 2 − x ′ ) − ( c l i e n t x − x ) disx = \frac{(width-width_1)}{2} + (x_2 - x') - (clientx - x) disx=2(width−width1)+(x2−x′)−(clientx−x)

联立上面两式可得:
d i s x = ( w i d t h − n ∗ w i d t h ) 2 + ( c l i e n t x − x ) n − ( c l i e n t x − x ) disx = \frac{(width-n*width)}{2} +(clientx-x)n - (clientx - x) disx=2(width−n∗width)+(clientx−x)n−(clientx−x)

可简化为:
d i s x = ( 1 − n ) ( w i d t h 2 − c l i e n t x + x ) disx = (1-n)(\frac{width}{2} -clientx+x) disx=(1−n)(2width−clientx+x)

y同理可得

javascript 复制代码
handleMousewheel: debounce(function(event) {
	event.preventDefault();
	let { deltay,clientX,clienty }=event;
	const isZoomout = deltaY<0;//小于0放大
	let scale = this.getNewSacle(this.prescale,isZoomOut);// 计算此次缩放比例
	this.handleZoomImg(this.scale,this.preScale,clientx,clientY);//根据新,旧比例,鼠标位置 进行图片调整
	this.preScale = scale;
}
200)

methods: {
	getNewSacle(preScale,isZoomout){
		if(isZoomout){
			return preScale*1.1;
		} else return preScale /1.1;
	},
	handleZoomImg(scale,preScale,clientX,clienty) {
		let {x: oX, y: oY}=this.lastSite;
		let n =  scale / preScale;
		let img = this.$refs.image; // 图片dom
		let { x:x1,y:y1,width, height }=img.getBoundingclientRect();
		// 带入上面得到的算式, x,y减去偏移量就是新的位置
		oX-= (1-n)*(width/2-clientX + x1);
		oY-= (1-n)*(height/2-clientY + y1);
		this.lastSite={
			x: oX,
			y: oY
		}
		this.updateDom(resScale, oX, oY);
	},
	updateDom(scale,x,y){
		this.$refs.image.style.transform = `matrix(${scale},,θ,${scale},${x}, ${y})`,
	}

注意:updateDom 方法里,如果使用translate和scale要先写translate再scale

相关推荐
lionliu051920 小时前
JavaScript 变量声明最佳实践
前端·javascript·vue.js
计算机毕设VX:Fegn089520 小时前
计算机毕业设计|基于springboot + vue酒店管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
源去_云走20 小时前
自建 Iconfy API 服务:解决国内访问不稳定问题
前端·容器·npm·node.js
AAA阿giao20 小时前
从零开始学 React:用搭积木的方式构建你的第一个网页!
前端·javascript·学习·react.js·前端框架·vite·jsx
遇到困难睡大觉哈哈20 小时前
Harmony OS Web 组件:如何在新窗口中打开网页(实战分享)
前端·华为·harmonyos
你脸上有BUG20 小时前
【工程化】前端打包时间优化
前端
TeleostNaCl20 小时前
Google Chrome 浏览器历史记录的存储位置
前端·chrome·经验分享
大模型教程20 小时前
前端可以转型AI工程师吗?那可太能了...
前端·llm·agent
转转技术团队20 小时前
前端开发应该了解的浏览器背后的黑科技
前端
2503_9284115621 小时前
12.15 element-plus的一些组件(上)
前端·vue.js