@@ -0,0 +1,106 @@ | |||
import { useCallback, useEffect, useRef, useState } from 'react'; | |||
import { motion } from 'framer-motion'; | |||
function Ruler(props) { | |||
const ruler = useRef(null); | |||
const [left, setLeft] = useState(props.left || '100px'); | |||
const [dragging, setDragging] = useState(false); | |||
const handleUp = useCallback(() => { | |||
setDragging(false); | |||
}, []); | |||
const handleMove = useCallback( | |||
(e) => { | |||
if (!dragging) return; | |||
const x = e.clientX; | |||
setLeft(x + 'px'); | |||
}, | |||
[dragging], | |||
); | |||
useEffect(() => { | |||
document.addEventListener('mouseup', handleUp); | |||
document.addEventListener('mousemove', handleMove); | |||
return () => { | |||
document.removeEventListener('mouseup', handleUp); | |||
document.removeEventListener('mousemove', handleMove); | |||
}; | |||
}, [dragging]); | |||
function handleMouseDown() { | |||
setDragging(true); | |||
} | |||
return ( | |||
<motion.div | |||
ref={ruler} | |||
className="ruler-line" | |||
style={{ | |||
position: 'relative', | |||
top: 0, | |||
left: left, | |||
overflow: 'visible', | |||
height: '100vh', | |||
width: '1px', | |||
cursor: 'pointer', | |||
userSelect: 'none', | |||
background: props.background || '#ccc', | |||
}} | |||
onMouseDown={handleMouseDown} | |||
> | |||
<div | |||
className="ruler-tooltip" | |||
style={{ | |||
position: 'absolute', | |||
top: '200px', | |||
right: '-132px', | |||
width: '128px', | |||
border: '1px solid #0008', | |||
padding: '0 12px', | |||
background: '#ecc100', | |||
color: '#0008', | |||
}} | |||
> | |||
left: <b>{left}</b> | |||
</div> | |||
</motion.div> | |||
); | |||
} | |||
function RulerContainer(props) { | |||
const [rulers, setRulers] = useState([]); | |||
const rulerCfg = { | |||
width: '2px', | |||
height: '100vh', | |||
background: '#ccc', | |||
}; | |||
// 监听事件 | |||
useEffect(() => { | |||
let fn = (e) => { | |||
if (e.shiftKey && e.key === 'R') { | |||
setRulers((rulers) => [...rulers, rulerCfg]); | |||
} | |||
if (e.shiftKey && e.key === 'Q') { | |||
setRulers((rulers) => []); | |||
} | |||
}; | |||
document.addEventListener('keydown', fn); | |||
}, []); | |||
return ( | |||
<div | |||
id="ruler-container" | |||
style={{ position: 'fixed', top: 0, left: 0, width: 0, height: 0 }} | |||
> | |||
{rulers.map((ruler) => ( | |||
<Ruler key={Math.random()} {...ruler} /> | |||
))} | |||
</div> | |||
); | |||
} | |||
export default RulerContainer; |
@@ -16,15 +16,15 @@ function FloorOneToTwo(props) { | |||
className="video-wrapper" | |||
style={{ | |||
position: 'fixed', | |||
top: 0, | |||
left: 0, | |||
top: '7px', | |||
left: '50px', | |||
width: '100%', | |||
height: '100%', | |||
zIndex: -998, | |||
}} | |||
initial={{ opacity: 0 }} | |||
animate={{ opacity: 1 }} | |||
exit={{ opacity: [1, 1, 0], transition: { duration: 0.5 } }} | |||
exit={{ opacity: 0, transition: { duration: 0, delay: 0.1 } }} | |||
> | |||
<video ref={vd} muted width={'100%'}> | |||
<source src="/video/1to2.webm" type="video/mp4" /> | |||
@@ -16,15 +16,15 @@ function FloorTwoToOne(props) { | |||
className="video-wrapper" | |||
style={{ | |||
position: 'fixed', | |||
top: 0, | |||
left: 0, | |||
top: '7px', | |||
left: '50px', | |||
width: '100%', | |||
height: '100%', | |||
zIndex: -998, | |||
}} | |||
initial={{ opacity: 0 }} | |||
animate={{ opacity: 1 }} | |||
exit={{ opacity: [1, 1, 0], transition: { duration: 0.5 } }} | |||
exit={{ opacity: 0, transition: { duration: 0.2, delay: 0.2 } }} | |||
> | |||
<video ref={vd} muted width={'100%'}> | |||
<source src="/video/2to1.webm" type="video/mp4" /> | |||
@@ -1,14 +1,11 @@ | |||
<head> | |||
<script src="<%= context.publicPath %>./v3d.js"></script> | |||
<script src="<%= context.publicPath %>./font.css"></script> | |||
<!-- <script src="<%= context.publicPath %>./v3d.js"></script> | |||
<script src="<%= context.publicPath %>./font.css"></script> --> | |||
</head> | |||
<body> | |||
<div id="root"> | |||
</div> | |||
<div id="v1" style="color: brown;"> | |||
</div> | |||
</div> | |||
</body> |
@@ -1,7 +1,6 @@ | |||
import './global.less'; | |||
import './index.less'; | |||
import Head from '../components/公共组件/顶部公司名称'; | |||
import { SocketContextProvider } from '../store/socket-data-provider'; | |||
import useSlider, { Slider } from '../hooks/useSlider'; | |||
import NavMenu from '../components/公共组件/导航菜单'; | |||
@@ -9,6 +8,8 @@ import { useState } from 'react'; | |||
// import V3D from './V3D'; | |||
import Home from './总览'; | |||
import EnergyAnalysis from './能耗分析'; | |||
import RulerContainer from '../components/工具组件/Ruler'; | |||
import { createPortal } from 'react-dom'; | |||
export default function index() { | |||
const { styles, value, setValue } = useSlider(75); | |||
@@ -30,6 +31,7 @@ export default function index() { | |||
</SocketContextProvider> | |||
</div> | |||
<Slider value={value} setValue={setValue} /> | |||
{createPortal(<RulerContainer />, document.body)} | |||
</> | |||
); | |||
} |