current position:Home>How to use js to achieve such a drag and zoom effect

How to use js to achieve such a drag and zoom effect

2022-04-29 20:27:26mayoha

Preface

Writing a simple H5 When the page is , You need to achieve the following drag effect , After looking for a long time, I couldn't find the one that met the requirements , Tearful handwriting
Let's take a look at what kind of

The basic idea

  1. Press the mouse , Record the initial position, width and height of the element
  2. Monitor the movement of the mouse , Constantly change your position according to the movement of the mouse / Wide and high
  3. Whether there are boundary restrictions

Drag implementation

Our common ways to change the position of elements are

  1. location
  2. Use translate Offset

How do we use drag and drop now ?
In terms of function realization , These two methods can well meet our needs
In terms of performance ,translate It's born to make animation effects , therefore translate Performance and fluency are better than positioning .
Start the operation !!

<style> .box{ margin: 50px; width: 500px; height: 300px; border: 1px solid black; position: relative; } .drag{ height: 100px; width: 100px; background-color: #cbd; } </style>

<div class="box">
  <div class="drag"></div>
</div>

<script> let dragEl = document.querySelector(".drag") let container = document.querySelector(".box") let width, height, maxWidth, maxHeight, tx, ty, startX, startY //  initialization  function init() { //  Set the initial offset for the target element , Avoid the problem of being empty when getting the offset for the first time  dragEl.style.transform = "translate(0px,0px)" //  Gets the width and height of the parent element  maxWidth = container.clientWidth maxHeight = container.clientHeight } function getInfo(e) { //  Gets the current width and height of the element  width = dragEl.clientWidth height = dragEl.clientHeight //  Gets the current offset of the element  let translateStr = dragEl.style.transform const reg = /\d+/g let translateArr = translateStr.match(reg) tx = Number(translateArr[0]) ty = Number(translateArr[1]) //  Record the starting position of the mouse  startX = e.clientX startY = e.clientY } function drag() { dragEl.addEventListener("mousedown", (e) => { getInfo(e) document.onmousemove = (e) => { let distanceX = tx + e.clientX - startX let distanceY = ty + e.clientY - startY dragEl.style.transform = `translate(${distanceX}px, ${distanceY}px)` } document.onmouseup = () => { document.onmousemove = null } }) } init() drag() </script>
 Copy code 

By the above code , We have finished dragging the elements , The next thing to consider is , If there are boundary restrictions , How can we achieve
From the example of an appeal , We can observe , The minimum value of element offset is 0, The maximum value is the width and height of the parent element - The width and height of the target element
Therefore, in the case of boundary constraints, the calculation method of offset is

let distanceX = Math.max(0, Math.min(tx + e.clientX - startX, maxWidth - width))
let distanceY = Math.max(0, Math.min(ty + e.clientY - startY, maxHeight - height))
 Copy code 

Zoom to achieve

Here we take zoom left as an example

  1. First, we need to add a border for the target element , Used to zoom
<style> .box{ margin: 50px; width: 500px; height: 300px; border: 1px solid black; position: relative; } .drag{ height: 100px; width: 100px; background-color: #cbd; } .left{ width: 10px; height: calc(100% - 14px); margin: 7px 0px; position: absolute; background-color: #000; cursor: col-resize; top: 0; left: -5px; } </style>
<script> function addLeft() { left = document.createElement("div") left.className = "left" dragEl.append(left) } init() drag() addLeft() </script>
 Copy code 

2. Add zoom function to the left border , Because it's the zoom on the left , So while the width changes , You need to constantly adjust the position of elements , Make it visual

function leftZoom() {
  left.addEventListener("mousedown", (e) => {
    e.stopPropagation()
    getInfo(e)
    document.onmousemove = (e) => {
      //  Notice that this is 
      newWidth = width - (e.clientX - startX)
      let distanceX = tx + (e.clientX - startX)
      dragEl.style.width = `${newWidth}px`
      dragEl.style.transform = `translate(${distanceX}px, ${ty}px)`
    }
    document.onmouseup = () => {
      document.onmousemove = null
    }
  })
}
init()
drag()
addLeft()
leftZoom()
 Copy code 
  1. Limit the minimum value of element scaling
let minWidth = 30
newWidth = Math.max(minWidth, width - (e.clientX - startX))
 Copy code 
  1. Now we have finished scaling , But when the element shrinks to the right to the minimum , The element moves to the right , Obviously, this is illogical , So we need to limit the offset
//  The maximum offset is the offset distance  +  The width of the target element  -  Minimum width 
let distanceX = Math.min(tx + width - minWidth, tx + (e.clientX - startX))
 Copy code 

4. If the scaled size needs to be limited to the parent element , We need to continue to improve the code

//  The maximum width is the current offset of the element  +  Initial width , Minimum width is minWidth
newWidth = Math.min(tx + width, Math.max(minWidth, width - (e.clientX - startX)))
//  The maximum offset is the offset distance  +  The width of the target element  -  Minimum width , The minimum offset is 0
let distanceX = Math.max(0,Math.min(tx + width - minWidth, tx + (e.clientX - startX)))
 Copy code 

The other three sides and four corners are basically implemented in the same way , I won't repeat them here

Last

Although we have completed the drag and zoom of elements , But when we use it , There are still many limitations , such as

  1. The target element cannot be located , If the element is offset using positioning , The restrictions we make will not take effect
  2. Similarly, the target element cannot have margins

Although there are limitations , But we can adjust it according to our actual needs

copyright notice
author[mayoha],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2022/04/202204292027202755.html

Random recommended