Original is not easy, I hope you can pay attention to us, and then easily point a praise ~~

This article was first published in the front end team blog: pure JS zoom in and zoom out drag pit trip

preface

Recently, the team needs to make an intelligent customer service suspension window function, which needs to support dragging, zooming in and out and other functions. Because this is a global plug-in, all native JS is used for compatibility, without reference to any third-party libraries or plug-ins. Some problems encountered in the development process and solutions, here to share and exchange with you.

Note: The following “treasure” is the product name of this function.

Look at the effect

Given this effect, most developers will find it relatively easy to implement. In the actual development, the author summarizes three main pit points and their solutions.

Three pit

  • Drag and drop will cause the harvest to zoom in and out
  • Treasure collection display is blocked when the screen boundary is not fully displayed
  • When the treasure is zoomed in and out, its position changes

(I) Dragging will lead to zoom in and out of treasure collection

When we operate treasure collection, whether we drag the mouse or click to zoom in and out, our events need to be bound to the icon of treasure collection head, so we need to bind click and drag events on the icon at the same time. But when we add the Click and MouseDown events directly, we find that the Click event is also triggered when the MouseDown event is triggered. This will appear when you drag the treasure, the treasure will zoom in and out.

We don’t want to see this effect, so we need to distinguish between the Click and mousedown events on the mine and find a way to make sure that the two events don’t affect each other.

So we bind both mousedown and Click events to the same DIV, and then print each event through the console to see the order in which each event is fired during the process.

const moveBox = document.querySelector('.move');
moveBox.onmousedown = function (evt) {
	console.log('Trigger mouse press')

  moveBox.onmousemove = function (evt) {
    console.log('Trigger mouse drag')}}function moveBoxClick(e) {
	console.log('trigger click')
}

moveBox.onmouseup = function () {
	console.log('Trigger mouse lift')}Copy the code

Then we get this:

From the output of the console, we can see the various events triggered after the mouse click: first the Mousedown event is executed, then the Mousemove event, then the Mouseup event, and finally the Click event.

Knowing the triggering order of events, we can distinguish the drag events from the click events by setting a variable isMove. Each time the mouse is pressed, we will restore isMove, and the state of isMove will change when the mouse moves.

Since the mousedown event is also triggered every time the click event is triggered, we add a judgment to the click event that the click event is not triggered when the mouse moves. In this way, you can separate click events from mouseDown events and achieve a separation between MouseDown and Click events.

The Click event adds judgment

function moveBoxClick(e) {
  // Click On it
  const target = document.querySelector(".move");
  const smallImg = document.querySelector(".small-img");
  const magnifyImg = document.querySelector(".magnify-img");
  // Click move box
  if(! isMove) {if (isBig) {
      smallImg.style.display = "block";
      magnifyImg.style.display = "none";
      target.style.width = "32px";
    } else {
      smallImg.style.display = "none";
      magnifyImg.style.display = "block";
      target.style.width = "130px";
    }
    isBig = !isBig;
  }
}
Copy the code

The mouseDown event resets isMove and mousemove changes isMove

let isMove = false; // Whether to drag
let isBig = false; // Is it a bigger box
let isMove = false; // Determine whether to move to collect treasure
smallImg.onmousedown = magnifyImg.onmousedown = function(evt) {
  isMove = false; // Reset isMove each time the mouse is pressed
  document.onmousemove = function(e) {
    isMove = true; // Change isMove every time the mouse moves
  };
};
Copy the code

Using isMove state, we can distinguish mousemove events from click events, so that we can drag the treasure without triggering the zoom in and out.

(2) The treasure collection display is blocked at the screen boundary and the display is not complete

When we drag to collect treasure, we judge whether the current positioning coordinate of the drag exceeds the height and width of the current display screen. We need to limit the maximum distance of the drag to collect treasure. When the small treasure collection is clicked to enlarge, it also needs to be processed to display all the treasure collection.

When the drag

const moveBox = document.querySelector(".move");
const smallImg = document.querySelector(".move .small-img");
const magnifyImg = document.querySelector(".move .magnify-img");
let isMove = false; // Whether to drag
let isBig = false; // Is it a bigger box

smallImg.onmousedown = magnifyImg.onmousedown = function(evt) {
  // Drag the div box
  const clientX = evt.clientX;
  const clientY = evt.clientY;
  const pageX = moveBox.offsetLeft;
  const pageY = moveBox.offsetTop;
  const x = clientX - pageX;
  const y = clientY - pageY;

  document.onmousemove = function(e) {
    // Drag to select the coordinates
    let _x = e.clientX - x;
    let _y = e.clientY - y;
    const boxWidth = moveBox.offsetWidth;
    const boxHeight = moveBox.offsetHeight;
    if (_x < 0) {
      _x = 0;
    }
    // The maximum value of X coordinates
    if (_x > window.screen.width - boxWidth) {
      _x = window.screen.width - boxWidth;
    }
    if (_y < 0) {
      _y = 0;
    }
    // The maximum value of the Y coordinate
    if (_y > document.documentElement.clientHeight - boxHeight) {
      _y = document.documentElement.clientHeight - boxHeight; }}; };Copy the code

Small treasure in the boundary magnification

// When you click, check whether the collection exceeds the display screen
function autoPotion () {
  let x = moveBox.offsetLeft;
  let y = moveBox.offsetTop;

  if (x < 0) {
  	x = 0;
  } else if (x > document.documentElement.clientWidth - moveBox.offsetWidth) {
  	x = document.documentElement.clientWidth - moveBox.offsetWidth;
  }

  if (y < 0) {
  	y = 0;
  } else if (y > document.documentElement.clientHeight - moveBox.offsetHeight) {
  	y = document.documentElement.clientHeight - moveBox.offsetHeight;
  }

  moveBox.style.left = x + "px";
  moveBox.style.top = y + "px";
}
Copy the code

Results the following

(3) The position of the treasure will change after it is zoomed in and out

From the figure above, we can see that when the small collection is at the edge of the display screen, click to enlarge and then click to zoom out, and we find that the position of the collection has changed. This is because collecting treasure is positioned according to the coordinates of the upper left corner. When the small collecting treasure moves to the lower right corner, click to enlarge, the coordinates of the upper left corner of collecting treasure change, so that the position of collecting treasure changes when zooming in and out. Therefore, we need to record the coordinates of the upper left corner of treasure collection when the movement of treasure collection is completed. When clicking, we need to re-assign the coordinates of the last movement of treasure collection to treasure collection, so that the position of treasure collection will not change when it is zooming in and out.

In this way, we recorded the location of the treasure collection during each mouseup event, which solved the problem that the position of the treasure collection changed when the treasure was zooming in and out.

Complete code

HTML:

<div class="box">
  <div class="move">
    <img
      onclick="moveBoxClick()"
      class="small-img"
      draggable="false"
      src="https://zcy-cdn.oss-cn-shanghai.aliyuncs.com/f2e-assets/103bbf76-6248-421c-a3d6-28a525c459db.png"
      alt=""
    />
    <img
      onclick="moveBoxClick()"
      class="magnify-img"
      draggable="false"
      src="https://zcy-cdn.oss-cn-shanghai.aliyuncs.com/f2e-assets/90e26f49-9824-4443-b4aa-8aa64a3c8690.png"
      alt=""
    />
    <div class="content"></div>
  </div>
</div>
Copy the code

JavaScript

const moveBox = document.querySelector(".move");
const smallImg = document.querySelector(".move .small-img");
const magnifyImg = document.querySelector(".move .magnify-img");
var initX = 0; // Record the x coordinates of the small treasure
var initY = 0; // Record the y coordinates of the small treasure
let isMove = false; // Whether to drag
let isBig = false; // Is it a bigger box
    
smallImg.onmousedown = magnifyImg.onmousedown = function(evt) {
// Drag the div box
const clientX = evt.clientX;
const clientY = evt.clientY;
const pageX = moveBox.offsetLeft;
const pageY = moveBox.offsetTop;
const x = clientX - pageX;
const y = clientY - pageY;

isMove = false;

document.onmousemove = function(e) {
    const boxWidth = moveBox.offsetWidth;
    const boxHeight = moveBox.offsetHeight;
    let _x = e.clientX - x;
    let _y = e.clientY - y;
    if (_x < 0) {
        _x = 0;
    }
    if (_x > window.screen.width - boxWidth) {
        _x = window.screen.width - boxWidth;
    }
    if (_y < 0) {
         _y = 0;
    }
    if (_y > document.documentElement.clientHeight - boxHeight) {
        _y = document.documentElement.clientHeight - boxHeight;
    }

    if (isBig) {
        initX = _x;
        initY = _y;
    }

    moveBox.style.left = _x + "px";
    moveBox.style.top = _y + "px";

    isMove = true;
    };
};


document.onmouseup = function() {
    if (isMove) {
        initX = moveBox.offsetLeft;
        initY = moveBox.offsetTop;
        }
      document.onmousemove = null;
};

function moveBoxClick(e) {
    const target = document.querySelector(".move");
    const smallImg = document.querySelector(".small-img");
    const magnifyImg = document.querySelector(".magnify-img");
    // Click move box
    if(! isMove) {if (isBig) {
          smallImg.style.display = "block";
          magnifyImg.style.display = "none";
          target.style.width = "32px";
          target.style.left = initX + 'px';
          target.style.top = initY + 'px';
        } else {
          smallImg.style.display = "none";
          magnifyImg.style.display = "block";
          target.style.width = "130px"; } isBig = ! isBig; setTimeout((a)= > {
          autoPotion();
        }, 100)}}// When you click, check whether the collection exceeds the display screen
function autoPotion () {
    let x = moveBox.offsetLeft;
    let y = moveBox.offsetTop;

    if (x < 0) {
        x = 0;
    } else if (x > document.documentElement.clientWidth - moveBox.offsetWidth) {
        x = document.documentElement.clientWidth - moveBox.offsetWidth;
    }

    if (y < 0) {
        y = 0;
    } else if (y > document.documentElement.clientHeight - moveBox.offsetHeight) {
        y = document.documentElement.clientHeight - moveBox.offsetHeight;
    }

    moveBox.style.left = x + "px";
    moveBox.style.top = y + "px";
}
Copy the code

conclusion

By developing a small feature point, a lot of details need to be addressed to improve the user experience. For the solutions to these problems, if you have a better solution, welcome to leave a message to discuss.

, recruiting

ZooTeam, a young passionate and creative front-end team, belongs to the PRODUCT R&D department of ZooTeam, based in picturesque Hangzhou. The team now has more than 50 front-end partners, with an average age of 27, and nearly 30% of them are full-stack engineers, no problem in the youth storm group. The members consist of “old” soldiers from Alibaba and netease, as well as fresh graduates from Zhejiang University, University of Science and Technology of China, Hangzhou Electric And other universities. In addition to daily business docking, the team also carried out technical exploration and practice in material system, engineering platform, building platform, performance experience, cloud application, data analysis and visualization, promoted and implemented a series of internal technical products, and continued to explore the new boundary of front-end technology system.

If you want to change what’s been bothering you, you want to start bothering you. If you want to change, you’ve been told you need more ideas, but you don’t have a solution. If you want change, you have the power to make it happen, but you don’t need it. If you want to change what you want to accomplish, you need a team to support you, but you don’t have the position to lead people. If you want to change the pace, it will be “5 years and 3 years of experience”; If you want to change the original savvy is good, but there is always a layer of fuzzy window… If you believe in the power of believing, believing that ordinary people can achieve extraordinary things, believing that you can meet a better version of yourself. If you want to be a part of the process of growing a front end team with deep business understanding, sound technology systems, technology value creation, and impact spillover as your business takes off, I think we should talk. Any time, waiting for you to write something and send it to [email protected]

Recommended reading

1024 great offering!! A review of the best of the past year

Probably the most complete collection of text overflow truncation ellipsis schemes

Move the universe! React can also “use” computed properties