移动端双指缩放,单指拖动div 您所在的位置:网站首页 ipad双指左右滑动 移动端双指缩放,单指拖动div

移动端双指缩放,单指拖动div

2023-10-13 01:25| 来源: 网络整理| 查看: 265

对于双指缩放,我其实用到了css的transform属性,搭配值matrix(scale(X), skew(X), skew(Y), scale(Y), translate(X), translate(Y)); transform属性它默认是从元素中心点开始向外扩展缩放,且不需要浏览器重绘,由GPU运算渲染,所以我将它的tansform-origin 设置为从左上角开始放大或缩小 transform-origin: 0 0; 缩放比例由双指之间的距离来得出,重要的是要处理:双指落到手机上时中心 如何 位移到 手指拉开或者收缩的两指中心点,这里要注意:div放大缩小 已经改变为 从左上角开始 我定义了 startScale -- 双指开始放到屏幕上div的缩放倍数默认为1 leftNum -- 单次双指离开屏幕后div的左侧偏移量(下次开始操作时左侧偏移量),topNum -- 单次双指离开屏幕后div的上侧偏移量(下次开始操作时上侧偏移量),endScale -- 单次双指离开屏幕后div放大缩小的倍数默认为1(下次开始操作时缩放倍数) 注意:div从始至终在文档上的占位大小并没有变过

微信图片_20211226214732.png

//leftNum 和 topNum是偏移量 我们开始设置它们 都为 0 function getOrigin(e){ if(e.touches.length == 2){ // 双指 const org = { x: (e.touches[0].pageX - 2 * leftNum + e.touches[1].pageX) / 2, y: (e.touches[0].pageY - 2 * topNum + e.touches[1].pageY) / 2, distance: Math.sqrt(Math.pow(e.touches[0].pageX - e.touches[1].pageX, 2) + Math.pow(e.touches[0].pageY - e.touches[1].pageY, 2)) } return org; }else if(e.touches.length == 1){ //单指 return { x: e.touches[0].pageX, y: e.touches[0].pageY } } }

绿点代表开始双指中心点位,我们不做处理的话,它放大后,那个点位会移到蓝色点那儿,黑点是现在我们双指在屏幕上的中心点(位移后), 所以我们要做的就是 让 蓝点跑到黑点那儿,

我们开始获取到绿色点位坐标 (不需要我贴代码吧兄弟们,就是两个手指的pageX加起来除以二,pageY加起来除以二) 然后我们再求出先后的距离(根据直角三角形勾股定理) Math.sqrt(Math.pow(e.touches[0].pageX - e.touches[1].pageX, 2) + Math.pow(e.touches[0].pageY - e.touches[1].pageY, 2)) 然后我们可以得到放大或者缩小的倍数,从而得到蓝点的位置,再通过蓝点的位置减去黑点的位置得到偏移量 //获取双指刚放到屏幕的中心点(绿点) orgData = getOrigin(e); // 获取新的两指中心点(黑点) const nowOrg = getOrigin(e); // 获取放大后的中心点位置(蓝点) const obj = { x: orgData * scale, y: orgData * scale } const scale = nowOrg.distance / orgData.distance; //缩放的倍数 我们现在可以得出偏移量 leftNumfalse = nowOrg.x + leftNum - obj.x; //得出双指离开时需要缩放的倍数 topNumfalse = nowOrg.y + topNum - obj.y; //得出双指离开时需要缩放的倍数 endScale = scale * startScale; //得出双指离开时需要缩放的倍数 -- 当前缩放的倍数 * 开始操作的倍数 //这里注意一下:为什么我要再加上 leftNum 跟 topNum, 因为假如上次我们处理过,那么这两个变量会有值, 并且如果放大的话 div 会向 左上 移动, 仔细想想,我们的目的是让放大后的点位移到缩放后的两指中心点 parentNode.style.transform = `matrix(${scale * startScale}, 0, 0, ${scale * startScale}, ${nowOrg.x + leftNum - obj.x}, ${nowOrg.y + topNum - obj.y})`; 现在操作手指离开屏幕的操作:把变化的内容记录下来 parentNode.addEventListener('touchend', (e) => { parentNode.style.transform = `matrix(${endScale}, 0, 0, ${endScale}, ${leftNumfalse}, ${topNumfalse})`; leftNum = leftNumfalse; //如果放大并溢出屏幕的话 这个值为负值 topNum = topNumfalse; //如果放大并溢出屏幕的话 这个值为负值 startScale = endScale; //这时候我们要把开始倍数 设置为 缩放后的倍数用来下次缩放 }) 现在第一次放大后 我们的布局差不多这样

微信图片_20211226225422.jpg

好了,我们开始看图说话吧,哈哈哈哈哈 中间中性笔矩形为手机屏幕,左上方虚线矩形为第一次变换后div的样子,现在我们把双指放到屏幕上 中心点为A点, 放大后 两指中心点为B点, 现在有人问C点是什么呀??嗐,又忘了嘛?我们的div是从左上角开始缩放的呀,并且占的位置还是最开始的位置,就是初始位置,上面提到了,所以要让C走到B,思考 c的坐标怎么来,B的坐标又怎么来(这个直接可以取到 通过上面 方法 当然可以直接获取到 这里要注意:B点的坐标包括偏移量从虚线框框到B点的距离 也就是多了leftNum 跟 topNum)c点的坐标可以通过A点的坐标乘以缩放的倍数得到 所以上面的transform偏移量需要再加上leftNum跟topNum 因为C点的坐标是到实线框的距离 因此得到上一步的代码 把上一次缩放的倍数再乘以这次缩放的倍数,大致逻辑就这样,可能我想复杂了 单指拖动的话比较简单,不用处理缩放大小 只关心偏移量就可以,这里我直接监听的pageX跟pageY变化的距离 // 获取单指放到屏幕的位置 SingleFinger = getOrigin(e); // move时新节点 const nowObj = { x: e.touches[0].pageX, y: e.touches[0].pageY } parentNode.style.transform = `matrix(${endScale}, 0, 0, ${endScale}, ${nowObj.x - SingleFinger.x + leftNum}, ${nowObj.y - SingleFinger.y + topNum})`; leftNumfalse = nowObj.x - SingleFinger.x + leftNum; topNumfalse = nowObj.y - SingleFinger.y + topNum; 这里附上我的代码 DOCTYPE html> :root{ --foo: red; --border: 1px solid green; } *{ margin: 0; padding: 0; } body{ box-sizing: border-box; } .parent{ box-sizing: border-box; width: 1000px; height: 500px; border: var(--border); transform-origin: 0 0; position: relative; } .imgStyle{ width: 100%; height: 100%; } /////////////////////////////////////// let orgData = null, nowScale = 1, x, y, twoSig, leftNum = 0, topNum = 0,leftNumfalse, topNumfalse, nowScalefalse; let SingleFinger = null, singLeft, singTop, oneSig; const parentNode = document.querySelector('.parent'); function getOrigin(e){ if(e.touches.length == 2){ // 双指 const org = { x: (e.touches[0].pageX - 2 * leftNum + e.touches[1].pageX) / 2, y: (e.touches[0].pageY - 2 * topNum + e.touches[1].pageY) / 2, distance: Math.sqrt(Math.pow(e.touches[0].pageX - e.touches[1].pageX, 2) + Math.pow(e.touches[0].pageY - e.touches[1].pageY, 2)) } return org; }else if(e.touches.length == 1){ //单指 return { x: e.touches[0].pageX, y: e.touches[0].pageY } } } parentNode.addEventListener('touchstart', (e) => { if(e.touches.length == 2){ let flag = true; for(let i = 0; i < e.touches.length; i++){ if(e.touches[i].target.nodeName != 'IMG'){ flag = false; } } if(flag) { //获取双指刚放到屏幕的中心点 twoSig = true; orgData = getOrigin(e); x = getOrigin(e).x; y = getOrigin(e).y; } }else if(e.touches.length == 1){ oneSig = true; SingleFinger = getOrigin(e); } }) parentNode.addEventListener('touchmove', (e) => { e.preventDefault(); if(e.touches.length == 2){ if(twoSig){ let flag = true; for(let i = 0; i < e.touches.length; i++){ if(e.touches[i].target.nodeName != 'IMG'){ flag = false; } } if(flag) { // 获取新的两指中心点 const nowOrg = getOrigin(e); const scale = nowOrg.distance / orgData.distance; if(scale * nowScale < 1) return false; // 获取放大后的中心点位置1 const obj = { x: orgData.x * scale, y: orgData.y * scale } parentNode.style.transform = `matrix(${scale * nowScale}, 0, 0, ${scale * nowScale}, ${nowOrg.x + leftNum - obj.x}, ${nowOrg.y + topNum - obj.y})`; leftNumfalse = nowOrg.x + leftNum - obj.x; topNumfalse = nowOrg.y + topNum - obj.y; nowScalefalse = scale * nowScale; } } }else if(e.touches.length == 1){ if(oneSig){ const nowObj = { x: e.touches[0].pageX, y: e.touches[0].pageY } parentNode.style.transform = `matrix(${nowScalefalse}, 0, 0, ${nowScalefalse}, ${nowObj.x - SingleFinger.x + leftNum}, ${nowObj.y - SingleFinger.y + topNum})`; leftNumfalse = nowObj.x - SingleFinger.x + leftNum; topNumfalse = nowObj.y - SingleFinger.y + topNum; } } }) parentNode.addEventListener('touchend', (e) => { parentNode.style.transform = `matrix(${nowScalefalse}, 0, 0, ${nowScalefalse}, ${leftNumfalse}, ${topNumfalse})`; leftNum = leftNumfalse; topNum = topNumfalse; nowScale = nowScalefalse; })


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有