前端实现元素的缩放与拖拽

57 阅读1分钟
export default  class ZoomController {
    constructor(wrapper, target, callback) {
      this.scale = 1;
      this.callback = callback;
      this.translateX = 0;
      this.translateY = 0;
      this.isDragging = false;
      this.startX = 0;
      this.startY = 0;
      this.target = target;
      this.wrapper = wrapper;
  
      // 绑定事件上下文
      this.handleWheel = this.handleWheel.bind(this);
      this.handleMouseDown = this.handleMouseDown.bind(this);
      this.handleMouseMove = this.handleMouseMove.bind(this);
      this.handleMouseUp = this.handleMouseUp.bind(this);
  
      this.initEventListeners();
    }
  
    initEventListeners() {
      // 鼠标滚轮事件
      this.wrapper.addEventListener("wheel", this.handleWheel);
      
      // 鼠标事件
      this.wrapper.addEventListener("mousedown", this.handleMouseDown);
      this.wrapper.addEventListener("mousemove", this.handleMouseMove);
      document.body.addEventListener("mouseup", this.handleMouseUp);
    }
  
    removeEventListeners() {
      this.wrapper.removeEventListener("wheel", this.handleWheel);
      this.wrapper.removeEventListener("mousedown", this.handleMouseDown);
      this.wrapper.removeEventListener("mousemove", this.handleMouseMove);
      document.body.removeEventListener("mouseup", this.handleMouseUp);
    }
  
    handleWheel(event) {
      event.preventDefault();
      const rect = this.target.getBoundingClientRect();
      const offsetX = event.clientX - rect.left;
      const offsetY = event.clientY - rect.top;
  
      this.wheelZoom({
        scaleFactor: event.deltaY,
        originX: offsetX / rect.width,
        originY: offsetY / rect.height
      });
    }
  
    handleMouseDown(event) {
      this.isDragging = true;
      this.startX = event.clientX - this.translateX;
      this.startY = event.clientY - this.translateY;
      this.target.style.cursor = "grabbing";
    }
  
    handleMouseMove(event) {
      if (!this.isDragging) return;
      this.translateX = event.clientX - this.startX;
      this.translateY = event.clientY - this.startY;
      this.updateTransform();
    }
  
    handleMouseUp() {
      this.isDragging = false;
      this.target.style.cursor = "grab";
    }
  
    reset() {
      this.scale = 1;
      this.translateX = 0;
      this.translateY = 0;
      this.isDragging = false;
      this.startX = 0;
      this.startY = 0;
      this.target.style.transform = "translate3d(0px, 0px, 0px) scale(1)";
    }
  
    updateTransform() {
      this.target.style.transform = 
        `translate(${this.translateX}px, ${this.translateY}px) scale(${this.scale})`;
    }
  
    wheelZoom({ scaleFactor, originX = 0.5, originY = 0.5 }) {
      let ratio = 1.1;
      if (scaleFactor > 0) ratio = 1 / ratio;
  
      const rect = this.target.getBoundingClientRect();
      const newScale = Math.max(0.5, Math.min(this.scale * ratio, 5));
      
      const deltaScale = newScale / this.scale;
      this.translateX -= (originX - 0.5) * rect.width * (deltaScale - 1);
      this.translateY -= (originY - 0.5) * rect.height * (deltaScale - 1);
      
      this.scale = newScale;
      this.callback?.(+(this.scale * 100).toFixed(0));
      this.updateTransform();
    }
  
    destroy() {
      this.removeEventListeners();
      this.reset();
    }
  }

使用方式

   let wrapper = document.getElementById()
   let content = document.getElementById()
   this.zoomController = new ZoomController(
       wrapper,
       content,
       (percent) => {
            console.log("scale", percent)
       }
   )

参考原文:juejin.cn/post/747094…