【解决方案】JavaScript实现元素缩放元素、拖拽

实现

实现大概思路是通过transform 的scale属性实现元素缩放,通过translate 设置偏移,transform-origin设置缩放圆点

transform

translate

用translate的主要原因是因为,他的值是相对于父元素的相对位置,方便后面缩放偏移量的计算,而top,left的值是相对于目标元素而言,所以当目标元素的高度或宽度高于容器的高度或宽度时,他的值为负数,不方便计算目标物距离容器左上角的距离,不方便计算偏移量。

scale

scale缩放好处在于不需要考虑被缩放物的内部布局,width、height在缩放div时就不适用了,在缩放图片时没有影响

tranform-origin

在本文中主要作用于元素缩放圆点

计算偏移量公式

如下计算公式,其实就相当于根据鼠标当前位置进行中心缩放
当前鼠标 X 轴的坐标到目标元素左上角的距离 = 相当于X轴的半径
当前鼠标 Y 轴的坐标到目标元素左上角的距离 = 相当于Y轴的半径

translateX-=([缩放后的宽度-缩放前的宽度]*([当前鼠标 X 轴的坐标到目标元素左上角的距离]/缩放前的宽度))
translateY-=([缩放后的高度-缩放前的高度]*([当前鼠标 Y 轴的坐标到目标元素左上角的距离]/缩放前的高度))

实例

<div class="container">
	<div class="draw"></div>
</div>
mouseEvent(target) {
 /**
    * 判断传入参数是否是HTML DOM
    */
   let isElement = (obj) => {
     return typeof HTMLElement === "object"
       ? obj instanceof HTMLElement
       : !!(
           obj &&
           typeof obj === "object" &&
           (obj.nodeType === 1 || obj.nodeType === 9) &&
           typeof obj.nodeName === "string"
         )
   }

   /**
    * 被拖拽物、被缩放元素
    */
   let drawEl =target;
   /**
    * 如果传入参数不是一个HTML DOM,则查找目标元素
    */
   if(!isElement(target)){
     drawEl= document.querySelector(target)
   }
   
   /**
    * 父元素:容器
    */
   const parent = drawEl.parentElement

   /**
    * 获取父元素的大小及其相对于视口的位置。
    */
   const parentRect = parent.getBoundingClientRect()

   /**
    * 鼠标相对于目标物缩放点的距离
    */
   let diffX = 0,
     diffY = 0

   /**
    * 是否正在拖拽
    */
   let isDrawing = false

   /**
    * 鼠标当前相对于父容器的坐标
    */
   let mouseX = 0,
     mouseY = 0

   /**
    * 偏移坐标,缩放比例
    */
   let translateX = 0,
     translateY = 0
   let scale = 1

   /**
    * 一次缩放的比例
    */
   const diff = 0.005

   /**
    * 滚轮滚动方向是否向上
    * 向上,缩小
    * 向下,放大
    */
   let isUpward = false 


   /**
    * 刷新鼠标距离目标元素缩放点的距离
    */
   let refreshMousePositionDiffValue = () => {
     diffX = mouseX - translateX
     diffY = mouseY - translateY
   }

   /**
    * 更新样式
    */
   let refreshTargetStyle = () => {
     drawEl.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scale})`
     parent.style.cursor = isDrawing ? "move" : "default"
   }

   /**
    * 鼠标移动事件
    */
   parent.addEventListener("mousemove", (e) => {
     mouseX = e.x - parentRect.left
     mouseY = e.y - parentRect.top

     if (isDrawing) {
       translateX = mouseX - diffX
       translateY = mouseY - diffY

       refreshTargetStyle()
     }
   })

   /**
    * 鼠标按下事件
    */
   parent.addEventListener("mousedown", () => {
     refreshMousePositionDiffValue()
     isDrawing = true
     refreshTargetStyle()
   })

   /**
    * 鼠标抬起事件
    */
   window.addEventListener("mouseup", () => {
     isDrawing = false
     refreshTargetStyle()
   })

   /**
    * 鼠标滚动事件
    */

   let mouseZoom = (e) => {
     e = e || window.event

     if (e.wheelDelta) {
       isUpward = e.wheelDelta > 0
     } else if (e.detail) {
       isUpward = e.detail < 0
     }

     let oldWidth = scale * drawEl.clientWidth
     let oldHeight = scale * drawEl.clientHeight

     if (isUpward) {
       scale += diff
     } else if (!isUpward && scale > 0.05) {
       scale -= diff
     }

     let newWidth = scale * drawEl.clientWidth
     let newHeight = scale * drawEl.clientHeight

     //刷新鼠标距离目标元素缩放点坐标
     refreshMousePositionDiffValue()

     /**
      * 重新计算缩放偏移量
      */
     translateX -= (newWidth - oldWidth) * (diffX / oldWidth)
     translateY -= (newHeight - oldHeight) * (diffY / oldHeight)

     refreshTargetStyle()
   }

   /**
    * 鼠标滚轮兼容
    */

   /*IE、Opera注册事件*/
   if (document.attachEvent) {
     parent.attachEvent("onmousewheel", mouseZoom)
   }
   //Firefox使用addEventListener添加滚轮事件
   if (document.addEventListener) {
     parent.addEventListener("DOMMouseScroll", mouseZoom, false)
   }
   //Safari与Chrome属于同一类型
   window.onmousewheel = parent.onmousewheel = mouseZoom
   

   /**
    * 页面初始化
    */

   /**
    * 判断缩放元素高度是否高于容器高度
    * 如果大于,则缩放值容器高度
    */
   if (drawEl.clientHeight > parent.clientHeight) {
     scale =
       1 - (drawEl.clientHeight - parent.clientHeight) / drawEl.clientHeight
   }

   /**
    * 让目标元素居中显示
    */
   translateX = (parent.clientWidth - (scale * drawEl.clientWidth)) / 2
   translateY = (parent.clientHeight - (scale * drawEl.clientHeight)) / 2
   
   //设置初始样式
   drawEl.style.transformOrigin = "0 0"

	/**
	* 当目标元素 是img时,需要禁用元素鼠标可拖拽
	* div user-drag 默认是none 可以不设置
	*/
   drawEl.style.userDrag='none'
   drawEl.style.webkitUserDrag='none';

	//禁用选则,防止拖拽时出现先择元素内部元素的情况
   drawEl.style.userSelect='none'

   refreshTargetStyle()
 }

mouseEvent('.draw')
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Space Chars

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值