react如何实现缩放
这篇文章主要讲解了“react如何实现缩放”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“react如何实现缩放”吧!
react实现缩放的方法:1、监听onWheel事件;2、设置事件对象event的属性deltaY,当向上滚动时“deltaY<0”,向下滚动时“deltay>0”;3、修改每次滚动时缩放的比例,同时更改transform样式按比例进行缩放即可。
react图片缩放、平移(position、transform实现)
很多网页都会给文案附上一些图片补充描述,例如在说到地址时,会在旁边附上一张地图,并且在地图上标注该地址。如果附上的图片很小,很难看清楚地址的具体信息,有些产品经理会给图片设计一个可以平移、放大缩小的功能。本文将一一实现上述功能。
废话不多说,先给上效果图:
主要三个功能点:
图片平移
图片缩放
车站标注
图片平移
图片平移可以监听这三个事件实现:onMouseDown、onMouseMove、onMouseUp
。onMouseDown
事件记录每次鼠标按下的坐标位置;onMouseMove
事件计算出每次平移的距离,该距离加上拖动前图片距离父元素的距离就等于拖动后图片相对于父元素的距离;onMouseUp
事件触发时,注销或者不让执行onMouseDown、onMouseMove
事件,防止只要鼠标移入图片就会平移。
这三个事件需要阻止浏览器的默认行为,不然在移动时会自动打开图片。
const WIDTH = 1200;const HEIGHT = 900;const DynamicStyle= () => { const imgRef = React.createRef<HTMLImageElement>(); const [imgStyle, setImgStyle] = useState<React.CSSProperties>({}); const [mouseDowmFlag, setMouseDowmFlag] = useState(false); const [mouseDowmPos, setMouseDowmPos] = useState<{x: number, y: number}>({x: 0, y: 0}) useEffect(() => { document.onmouseover = () => { if (mouseDowmFlag) { setMouseDowmFlag(false); } }; return () => { document.onmouseover = null; }; }, [mouseDowmFlag]) const handleMouseDown = (event: React.MouseEvent<HTMLImageElement>) => { const { clientX, clientY } = event; event.stopPropagation(); event.preventDefault(); // 阻止浏览器默认行为,拖动会打开图片 setMouseDowmFlag(true); // 控制只有在鼠标按下后才会执行mousemove setMouseDowmPos({ x: clientX, y: clientY, }); }; const handleMouseMove = (event: React.MouseEvent<HTMLImageElement>) => { event.stopPropagation(); event.preventDefault(); const { clientX, clientY } = event; const diffX = clientX - mouseDowmPos.x; const diffY = clientY - mouseDowmPos.y; if (!mouseDowmFlag || (diffX === 0 && diffY === 0)) return; const { offsetLeft, offsetTop } = imgRef.current as HTMLImageElement; const offsetX = parseInt(`${diffX + offsetLeft}`, 10); const offsetY = parseInt(`${diffY + offsetTop}`, 10); setMouseDowmPos({ x: clientX, y: clientY, }); setImgStyle({ ...imgStyle, left: offsetX, top: offsetY, }); }; const handleMouseUp = (event: React.MouseEvent<HTMLImageElement>) => { event.stopPropagation(); event.preventDefault(); setMouseDowmFlag(false); }; return ( <div className={styles.imgArea}> <img class="lazy" data-src={mapImg} alt='part' ref={imgRef} height={HEIGHT} style={imgStyle} onMouseDown={handleMouseDown} onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} > </img> </div> )}
图片缩放
图片缩放可以监听onWheel
事件,事件对象event
有一个记录滚轮滚动的属性deltaY
,当向上滚动时deltaY<0
,向下滚动时deltaY>0
。每次滚动修改其缩放的比例,同时更改transform
样式按比例进行缩放。
const WIDTH = 1200;const HEIGHT = 900;const SCALE = 0.2;const DynamicStyle= () => { const imgRef = React.createRef<HTMLImageElement>(); const [rate, setRate] = useState(1); const [imgStyle, setImgStyle] = useState<React.CSSProperties>({}); const [mouseDowmFlag, setMouseDowmFlag] = useState(false); const [mouseDowmPos, setMouseDowmPos] = useState<{x: number, y: number}>({x: 0, y: 0}) const [initial, setInitial] = useState<{width: number, height: number}>({width: WIDTH, height: HEIGHT}); useEffect(() => { const { naturalWidth, naturalHeight, width, height } = imgRef.current as HTMLImageElement; setInitial({ width, height }); // eslint-disable-next-line react-hooks/exhaustive-deps }, []) // console.log(natural, initial) useEffect(() => { document.onmouseover = () => { if (mouseDowmFlag) { setMouseDowmFlag(false); } }; return () => { document.onmouseover = null; }; }, [mouseDowmFlag]) const handleWheelImage = (event: React.WheelEvent<HTMLImageElement>) => { // 向上为负,向下为正 const bigger = event.deltaY > 0 ? -1 : 1; // transform偏移量 const transformX = -initial.width / 2; const transformY = -initial.height / 2; if (bigger > 0 && rate < 2) { const enlargeRate = rate + SCALE; setImgStyle({ ...imgStyle, transform: `matrix(${enlargeRate}, 0, 0, ${enlargeRate}, ${transformX}, ${transformY})`, // 默认以图片中心为原点进行缩放 }); setRate(enlargeRate); } else if (bigger < 0 && rate > 1) { const shrinkRate = rate - SCALE; setImgStyle({ ...imgStyle, transform: `matrix(${shrinkRate}, 0, 0, ${shrinkRate}, ${transformX}, ${transformY})`, }); setRate(shrinkRate); } } const handleMouseDown = (event: React.MouseEvent<HTMLImageElement>) => { const { clientX, clientY } = event; event.stopPropagation(); event.preventDefault(); // 阻止浏览器默认行为,拖动会打开图片 setMouseDowmFlag(true); // 控制只有在鼠标按下后才会执行mousemove setMouseDowmPos({ x: clientX, y: clientY, }); }; const handleMouseMove = (event: React.MouseEvent<HTMLImageElement>) => { event.stopPropagation(); event.preventDefault(); const { clientX, clientY } = event; const diffX = clientX - mouseDowmPos.x; const diffY = clientY - mouseDowmPos.y; if (!mouseDowmFlag || (diffX === 0 && diffY === 0)) return; const { offsetLeft, offsetTop } = imgRef.current as HTMLImageElement; const offsetX = parseInt(`${diffX + offsetLeft}`, 10); const offsetY = parseInt(`${diffY + offsetTop}`, 10); setMouseDowmPos({ x: clientX, y: clientY, }); setImgStyle({ ...imgStyle, left: offsetX, top: offsetY, }); }; const handleMouseUp = (event: React.MouseEvent<HTMLImageElement>) => { event.stopPropagation(); event.preventDefault(); setMouseDowmFlag(false); }; return ( <div className={styles.imgArea}> <img class="lazy" data-src={mapImg} alt='part' height={HEIGHT} style={imgStyle} ref={imgRef} onWheel={handleWheelImage} onMouseDown={handleMouseDown} onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} > </img> </div> )}
.imgArea { position: relative; width: 1200px; height: 900px; margin: auto; border: 1px solid #da2727; overflow: hidden; & > img { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); cursor: move; }}
如果没有设置transformOrigin
,默认是相对于图片中心进行缩放,但是在初始为了让图片在可视区域内水平垂直居中,使用了transform: translate(-50%, -50%);
,因此为了缩放时相对于图片中心点,需要设置matrix
的第5、6个参数矫正transformOrigin
,transform: matrix(${shrinkRate}, 0, 0, ${shrinkRate}, ${transformX}, ${transformY})
车站标注
首先,定义一个常量表示图标的坐标,这个坐标是相对于原始图片左上角的定位。
const imgInfo = { lableLeft: "1900", lableTop: "2000",}
这里,解释一下原始图的概念:
随便在网上查看一个图片元素,比如上面。1200 x 900是页面定的图片大小,但图片还有一个真实大小4535 x 3402。
要计算图标在没有平移缩放时的初始坐标之前,需要算出图片的缩放比例(不是上面的rate
):
const [natural, setNatural] = useState<{width: number, height: number}>({width: 1, height: 1});const [initial, setInitial] = useState<{width: number, height: number}>({width: WIDTH, height: HEIGHT});useEffect(() => { const { naturalWidth, naturalHeight, width, height } = imgRef.current as HTMLImageElement; setNatural({ width: naturalWidth, height: naturalHeight }); setInitial({ width, height }); // eslint-disable-next-line react-hooks/exhaustive-deps}, []) // 初始图片缩放比例(图片有原始的图片大小)const imgScaleRateX = initial.width / natural.width;const imgScaleRateY = initial.height / natural.height;
图标初始的坐标就可以计算出:
const labelLeft = parseInt(`${imgInfo.lableLeft}`, 10) * imgScaleRateX;const labelTop = parseInt(`${imgInfo.lableTop}`, 10) * imgScaleRateY;
当图片平移时,图标也需要跟着平移,这是的坐标计算:
// 图标相对父元素坐标 = 图标位置坐标 + 图片坐标const labelLeft = parseInt(`${imgInfo.lableLeft}`, 10) * imgScaleRateX + Number(imgStyle.left || WIDTH / 2);const labelTop = parseInt(`${imgInfo.lableTop}`, 10) * imgScaleRateY + Number(imgStyle.top || HEIGHT / 2);
当图片缩放时,图标需要随着图片一起缩放。如果没有对图标设置transformOrigin
,默认时相对图标的中心缩放的。为了保证图标随着图片一起缩放,那就必须使得图片和图标的缩放参照原点相同,图标的transformOrigin
应该设置为相对于图片原点的距离。
const labelTransformOrigin = () => { return `${initial.width / 2 - Number(imgInfo.lableLeft) * imgScaleRateX}px ${ initial.height / 2 - Number(imgInfo.lableTop) * imgScaleRateY }px`;}
整体代码示例:
const imgInfo = { lableLeft: "1900", lableTop: "2000",}const WIDTH = 1200;const HEIGHT = 900;const SCALE = 0.2;const DynamicStyle= () => { const imgRef = React.createRef<HTMLImageElement>(); const [rate, setRate] = useState(1); const [imgStyle, setImgStyle] = useState<React.CSSProperties>({}); const [mouseDowmFlag, setMouseDowmFlag] = useState(false); const [mouseDowmPos, setMouseDowmPos] = useState<{x: number, y: number}>({x: 0, y: 0}) const [natural, setNatural] = useState<{width: number, height: number}>({width: 1, height: 1}); const [initial, setInitial] = useState<{width: number, height: number}>({width: WIDTH, height: HEIGHT}); useEffect(() => { const { naturalWidth, naturalHeight, width, height } = imgRef.current as HTMLImageElement; setNatural({ width: naturalWidth, height: naturalHeight }); setInitial({ width, height }); // eslint-disable-next-line react-hooks/exhaustive-deps }, []) useEffect(() => { document.onmouseover = () => { if (mouseDowmFlag) { setMouseDowmFlag(false); } }; return () => { document.onmouseover = null; }; }, [mouseDowmFlag]) const handleWheelImage = (event: React.WheelEvent<HTMLImageElement>) => { // 向上为负,向下为正 const bigger = event.deltaY > 0 ? -1 : 1; // transform偏移量 const transformX = -initial.width / 2; const transformY = -initial.height / 2; if (bigger > 0 && rate < 2) { const enlargeRate = rate + SCALE; setImgStyle({ ...imgStyle, transform: `matrix(${enlargeRate}, 0, 0, ${enlargeRate}, ${transformX}, ${transformY})`, // 默认以图片中心为原点进行缩放 }); setRate(enlargeRate); } else if (bigger < 0 && rate > 1) { const shrinkRate = rate - SCALE; setImgStyle({ ...imgStyle, transform: `matrix(${shrinkRate}, 0, 0, ${shrinkRate}, ${transformX}, ${transformY})`, }); setRate(shrinkRate); } } const handleMouseDown = (event: React.MouseEvent<HTMLImageElement>) => { const { clientX, clientY } = event; event.stopPropagation(); event.preventDefault(); // 阻止浏览器默认行为,拖动会打开图片 setMouseDowmFlag(true); // 控制只有在鼠标按下后才会执行mousemove setMouseDowmPos({ x: clientX, y: clientY, }); }; const handleMouseMove = (event: React.MouseEvent<HTMLImageElement>) => { event.stopPropagation(); event.preventDefault(); const { clientX, clientY } = event; const diffX = clientX - mouseDowmPos.x; const diffY = clientY - mouseDowmPos.y; if (!mouseDowmFlag || (diffX === 0 && diffY === 0)) return; const { offsetLeft, offsetTop } = imgRef.current as HTMLImageElement; const offsetX = parseInt(`${diffX + offsetLeft}`, 10); const offsetY = parseInt(`${diffY + offsetTop}`, 10); setMouseDowmPos({ x: clientX, y: clientY, }); setImgStyle({ ...imgStyle, left: offsetX, top: offsetY, }); }; const handleMouseUp = (event: React.MouseEvent<HTMLImageElement>) => { event.stopPropagation(); event.preventDefault(); setMouseDowmFlag(false); }; // 初始图片缩放比例(图片有原始的图片大小) const imgScaleRateX = initial.width / natural.width; const imgScaleRateY = initial.height / natural.height; const labelTransformOrigin = () => { return `${initial.width / 2 - Number(imgInfo.lableLeft) * imgScaleRateX}px ${ initial.height / 2 - Number(imgInfo.lableTop) * imgScaleRateY }px`; } const labelStyle = (): React.CSSProperties => { const transformX = -initial.width / 2; const transformY = -initial.height / 2; // 图标相对父元素坐标 = 图标初始位置坐标 + 平移量 const labelLeft = parseInt(`${imgInfo.lableLeft}`, 10) * imgScaleRateX + Number(imgStyle.left || WIDTH / 2); const labelTop = parseInt(`${imgInfo.lableTop}`, 10) * imgScaleRateY + Number(imgStyle.top || HEIGHT / 2); return { left: labelLeft, top: labelTop, transformOrigin: labelTransformOrigin(), transform: `matrix(${rate}, 0, 0, ${rate}, ${transformX}, ${transformY})`, } } return ( <div className={styles.imgArea}> <img class="lazy" data-src={mapImg} alt='part' height={HEIGHT} style={imgStyle} ref={imgRef} onWheel={handleWheelImage} onMouseDown={handleMouseDown} onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} > </img> <span className={styles.label} style={labelStyle()}></span> </div> )}
感谢各位的阅读,以上就是“react如何实现缩放”的内容了,经过本文的学习后,相信大家对react如何实现缩放这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341