|
|
@@ -0,0 +1,186 @@
|
|
|
+import React, { useMemo, useState, useRef, useCallback } from 'react'
|
|
|
+import styles from './index.module.scss'
|
|
|
+import { Button } from 'antd'
|
|
|
+import { baseURL } from '@/utils/http'
|
|
|
+
|
|
|
+const pageObj: any = {
|
|
|
+ 户外裸眼3D短屏侧: [2240, 1920, 900],
|
|
|
+ 户外裸眼3D长屏侧: [12800, 1920, 1900],
|
|
|
+ 文物互动墙: [19440, 3840, 1900],
|
|
|
+ 数字艺术触摸屏: [3840, 2160, 1200],
|
|
|
+ AI数字人: [3840, 2160, 1200]
|
|
|
+}
|
|
|
+
|
|
|
+const btnArr = ['短屏侧', '长屏侧']
|
|
|
+
|
|
|
+type Props = {
|
|
|
+ html: string
|
|
|
+ closeFu: () => void
|
|
|
+ name: string
|
|
|
+ url: string
|
|
|
+ txtMoveTemp: any
|
|
|
+ setTxtMove: any
|
|
|
+}
|
|
|
+
|
|
|
+function A4look({ html, closeFu, name, url, txtMoveTemp, setTxtMove }: Props) {
|
|
|
+ const [cut, setCut] = useState('短屏侧')
|
|
|
+
|
|
|
+ const txtMove = useMemo(() => {
|
|
|
+ let obj = txtMoveTemp['1']
|
|
|
+ if (name === '户外裸眼3D') obj = txtMoveTemp[cut === '短屏侧' ? '1' : '']
|
|
|
+ return obj
|
|
|
+ }, [cut, name, txtMoveTemp])
|
|
|
+
|
|
|
+ const page = useMemo(() => {
|
|
|
+ let txt = name
|
|
|
+ if (name === '户外裸眼3D') txt += cut
|
|
|
+ return pageObj[txt]
|
|
|
+ }, [cut, name])
|
|
|
+
|
|
|
+ // 根据真实宽高设置元素宽高
|
|
|
+ const domSize = useMemo(() => {
|
|
|
+ let size = 1
|
|
|
+ if (page && page[0]) {
|
|
|
+ size = page[2] / page[0]
|
|
|
+ }
|
|
|
+ return size
|
|
|
+ }, [page])
|
|
|
+
|
|
|
+ // 文字拖动相关
|
|
|
+ const txtDragRef = useRef({
|
|
|
+ isDragging: false,
|
|
|
+ startX: 0,
|
|
|
+ startY: 0,
|
|
|
+ startLeft: 0,
|
|
|
+ startTop: 0
|
|
|
+ })
|
|
|
+
|
|
|
+ const handleTxtMouseDown = useCallback(
|
|
|
+ (e: React.MouseEvent) => {
|
|
|
+ e.preventDefault()
|
|
|
+ txtDragRef.current = {
|
|
|
+ isDragging: true,
|
|
|
+ startX: e.clientX,
|
|
|
+ startY: e.clientY,
|
|
|
+ startLeft: txtMove.left,
|
|
|
+ startTop: txtMove.top
|
|
|
+ }
|
|
|
+ },
|
|
|
+ [txtMove.left, txtMove.top]
|
|
|
+ )
|
|
|
+
|
|
|
+ // 滑块拖动相关
|
|
|
+ const scaleDragRef = useRef({
|
|
|
+ isDragging: false,
|
|
|
+ startX: 0,
|
|
|
+ startScale: 0
|
|
|
+ })
|
|
|
+ const scaleBarRef = useRef<HTMLDivElement>(null)
|
|
|
+
|
|
|
+ const handleScaleMouseDown = useCallback(
|
|
|
+ (e: React.MouseEvent) => {
|
|
|
+ e.preventDefault()
|
|
|
+ scaleDragRef.current = {
|
|
|
+ isDragging: true,
|
|
|
+ startX: e.clientX,
|
|
|
+ startScale: txtMove.scale
|
|
|
+ }
|
|
|
+ },
|
|
|
+ [txtMove.scale]
|
|
|
+ )
|
|
|
+
|
|
|
+ // 全局鼠标移动和抬起事件
|
|
|
+ React.useEffect(() => {
|
|
|
+ const handleMouseMove = (e: MouseEvent) => {
|
|
|
+ // 文字拖动
|
|
|
+ if (txtDragRef.current.isDragging) {
|
|
|
+ const deltaX = e.clientX - txtDragRef.current.startX
|
|
|
+ const deltaY = e.clientY - txtDragRef.current.startY
|
|
|
+ // 将像素转换为百分比 (假设父容器宽高为参考)
|
|
|
+ const percentX = (deltaX / page[0]) * 100 * (1 / domSize)
|
|
|
+ const percentY = (deltaY / page[1]) * 100 * (1 / domSize)
|
|
|
+ const newLeft = Math.max(0, Math.min(100, txtDragRef.current.startLeft + percentX))
|
|
|
+ const newTop = Math.max(0, Math.min(100, txtDragRef.current.startTop + percentY))
|
|
|
+ setTxtMove((prev: any) => ({ ...prev, left: newLeft, top: newTop }))
|
|
|
+ }
|
|
|
+ // 滑块拖动
|
|
|
+ if (scaleDragRef.current.isDragging && scaleBarRef.current) {
|
|
|
+ const barRect = scaleBarRef.current.getBoundingClientRect()
|
|
|
+ const deltaX = e.clientX - scaleDragRef.current.startX
|
|
|
+ const percentPerPixel = 99 / barRect.width // scale范围1~100,滑块移动范围对应99
|
|
|
+ const newScale = Math.max(
|
|
|
+ 1,
|
|
|
+ Math.min(100, scaleDragRef.current.startScale + deltaX * percentPerPixel)
|
|
|
+ )
|
|
|
+ setTxtMove((prev: any) => ({ ...prev, scale: newScale }))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const handleMouseUp = () => {
|
|
|
+ txtDragRef.current.isDragging = false
|
|
|
+ scaleDragRef.current.isDragging = false
|
|
|
+ }
|
|
|
+
|
|
|
+ document.addEventListener('mousemove', handleMouseMove)
|
|
|
+ document.addEventListener('mouseup', handleMouseUp)
|
|
|
+
|
|
|
+ return () => {
|
|
|
+ document.removeEventListener('mousemove', handleMouseMove)
|
|
|
+ document.removeEventListener('mouseup', handleMouseUp)
|
|
|
+ }
|
|
|
+ }, [page, domSize, setTxtMove])
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className={styles.A4look}>
|
|
|
+ <div
|
|
|
+ className='A4Lmain'
|
|
|
+ style={{
|
|
|
+ width: page[0] + 'px',
|
|
|
+ height: page[1] + 'px',
|
|
|
+ backgroundImage: `url(${baseURL + url})`,
|
|
|
+ transform: `translate(-50%,-50%) scale(${domSize})`
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ className='A4Lmove'
|
|
|
+ dangerouslySetInnerHTML={{ __html: html }}
|
|
|
+ style={{
|
|
|
+ left: txtMove.left + '%',
|
|
|
+ top: txtMove.top + '%',
|
|
|
+ transform: `scale(${txtMove.scale})`
|
|
|
+ }}
|
|
|
+ onMouseDown={handleTxtMouseDown}
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 顶部放大进度条 */}
|
|
|
+ <div className='A4Lscale'>
|
|
|
+ <h3>鼠标移入文字,按住可拖动文字移动</h3>
|
|
|
+ <div className='A4Lscale2' ref={scaleBarRef}>
|
|
|
+ <div
|
|
|
+ style={{ left: ((txtMove.scale - 1) / 99) * 100 + '%' }}
|
|
|
+ onMouseDown={handleScaleMouseDown}
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {name === '户外裸眼3D' ? (
|
|
|
+ <div className='A4Lbtn'>
|
|
|
+ {btnArr.map(v => (
|
|
|
+ <Button onClick={() => setCut(v)} key={v} type={v === cut ? 'primary' : 'default'}>
|
|
|
+ {v}
|
|
|
+ </Button>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ ) : null}
|
|
|
+
|
|
|
+ <Button className='A4Lx' onClick={closeFu}>
|
|
|
+ 关闭
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+const MemoA4look = React.memo(A4look)
|
|
|
+
|
|
|
+export default MemoA4look
|