Сделайте изображение перетаскиваемым внутри контейнера (панорамирование) в ответ. setState вызывает проблемы - PullRequest
1 голос
/ 26 апреля 2020

У меня есть компонент просмотра изображений с контейнером, который можно масштабировать с помощью мыши. Реализовали это и это работает. проблема, с которой я сталкиваюсь, заключается в том, чтобы сделать изображение перетаскиваемым после увеличения. Код работает, когда я получаю некоторые изменения в свойстве translate элемента. При входе в консоль я выяснил, что событие onMouseMove прекращается, как только я обновляю стили, используя состояние. как это работает только на мгновение. Также, так как я новичок, чтобы отреагировать, мне рекомендовали не использовать ссылки. Есть ли лучший подход к этому?

Хорошее объяснение и ссылки очень приветствуются, поскольку я новичок, чтобы реагировать.

import React,{useState,useRef} from 'react';
import './ImageViewer.css'


function ImageViewer(){

    //zoom logic

    const imageViewInitialStyle = {
        transformOrigin: `0px 0px`,
        transform: `translate(0px, 0px) scale(1, 1)`
      }

    const imageViewRef = useRef(null)
    const containerRef = useRef(null)
    const [pos,setPos]=useState({x:0,y:0})
    const [scale,setScale]=useState(1)
    const factor=0.2
    const maxScale= 4
    const [imageViewStyle,setImageViewStyle]=useState(imageViewInitialStyle)

    const updateZoom = (e)=>{

        let myH = imageViewRef.current.clientHeight
        let myW = imageViewRef.current.clientWidth

        let offsetLeft = containerRef.current.offsetLeft
        let offsetTop = containerRef.current.offsetTop

        let zpX= e.pageX - offsetLeft
        let zpY = e.pageY - offsetTop

        let myScale = scale

        e.preventDefault()


        let delta = ((e.deltaY)*(-1));
        if (delta === undefined) {
          //firefox
          delta = e.detail;
        }
        // cap the delta to [-1,1] for cross browser consistency
        delta = Math.max(-1,Math.min(1,delta))

        // determine the point on where the slide is zoomed in
        let ztX = (zpX- pos.x)/myScale
        let ztY= (zpY - pos.y)/myScale


        // apply zoom with a maximum scale barrier
        myScale += delta*factor * myScale
        myScale = Math.max(1,Math.min(maxScale,myScale))

        setScale(myScale)

        // calculate x and y based on zoom
        let posX =  zpX - (ztX * myScale)
        let posY = zpY - (ztY * myScale)

        // Make sure the slide stays in its container area when zooming out
        if(posX>0){
            posX=0
        }
        if(posX+myW*myScale<myW){
            let calcX= -myW*(myScale-1)
            posX=calcX
        }
        if(posY>0){
            posY=0
        }
         if(posY+myH*myScale<myH){
             let calcY= -myH*(myScale-1)
             posY=calcY
        }

        setPos({
            x:posX,
            y:posY
        })

        setImageViewStyle({
            transformOrigin: `0px 0px`,
            transform: `translate(${pos.x}px, ${pos.y}px) scale(${scale}, ${scale})`,
          })


    }

    //Drag Logic

    //Variables and State Variables

    let active = false
    let currentX
    let currentY
    let initialX
    let initialY
    let offsetX
    let offsetY

    const startDrag=(e)=>{

        offsetX = pos.x
        offsetY = pos.y

        if (e.type === "touchstart") {
            initialX = e.touches[0].clientX - offsetX;
            initialY = e.touches[0].clientY - offsetY;
          } else {
            initialX = e.clientX - offsetX;
            initialY = e.clientY - offsetY;
          }


        active = true;
        e.stopPropagation();
        console.log("dragging start")

    }

    const dragging=(e)=>{

        if (active && scale!==1) {

            e.preventDefault();
            e.stopPropagation();


            if (e.type === "touchmove") {
              currentX = e.touches[0].clientX - initialX;
              currentY = e.touches[0].clientY - initialY;
            } else {
              currentX = e.clientX - initialX;
              currentY = e.clientY - initialY;
            }

            offsetX = currentX;
            offsetY = currentY;

            setTranslate(currentX,currentY)
          }

    }

    const stopDrag=(e)=>{

        initialX = currentX;
        initialY = currentY;
        e.stopPropagation();

        active = false;
        console.log("dragging end")
    }


    const setTranslate=(xPos, yPos)=> {
        setImageViewStyle({
            transformOrigin: `0px 0px`,
            transform: `translate(${xPos}px, ${yPos}px) scale(${scale}, ${scale})`,
          })
      }



    return (

        <div id="container-iv" ref={containerRef}>
            <div id="imageViewer" 
            style={imageViewStyle} 
            ref={imageViewRef} 
            onMouseDown={(e)=>{startDrag(e)}}
            onMouseMove={(e)=>{dragging(e)}}
            onMouseUp={(e)=>stopDrag(e)}

            onTouchStart={(e)=>{startDrag(e)}} 
            onTouchMove={(e)=>{dragging(e)}}
            onTouchEnd={(e)=>{stopDrag(e)}} 

            onWheel = {(e) => {updateZoom(e)}}>
                <img draggable="true" src="https://via.placeholder.com/500" alt="placeholder"></img>
            </div>
        </div>
    )

}


export default ImageViewer

Также CSS это:

#container-iv{
    width:500px;
    height:500px;
    overflow:hidden;
    touch-action: none;
  }

  #imageViewer{
    width:100%;
    height:100%;
    touch-action: none;
    user-select: none;
    transition: transform .3s;
  }

  img{
    width:auto;
    height:auto;
    max-width:100%;
  }
...