У меня есть компонент просмотра изображений с контейнером, который можно масштабировать с помощью мыши. Реализовали это и это работает. проблема, с которой я сталкиваюсь, заключается в том, чтобы сделать изображение перетаскиваемым после увеличения. Код работает, когда я получаю некоторые изменения в свойстве 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%;
}