| | |
| | | "@react-three/fiber": "^8.13.0", |
| | | "@react-three/postprocessing": "^2.14.8", |
| | | "@tweenjs/tween.js": "^21.0.0", |
| | | "antd": "^5.16.4", |
| | | "axios": "^1.6.2", |
| | | "maath": "0.10.7", |
| | | "react": "^18.2.0", |
| | | "react-dom": "^18.2.0", |
| | | "react-router-dom": "^6.15.0", |
| | | "react-spring": "^9.7.1", |
| | | "three": "^0.153.0", |
| | | "valtio": "^1.12.1" |
| | | }, |
| | |
| | | "eslint-plugin-react-hooks": "^4.6.0", |
| | | "eslint-plugin-react-refresh": "^0.4.6", |
| | | "postcss": "^8.4.38", |
| | | "sass": "^1.75.0", |
| | | "tailwindcss": "^3.4.3", |
| | | "vite": "^5.2.0" |
| | | } |
| | |
| | | |
| | | const position = new THREE.Vector3(x + width / 2, Y, y + height / 2); |
| | | const size = [width, 1, height]; |
| | | textHeight ||= Y + 50; |
| | | // textHeight ||= Y + 50; |
| | | |
| | | useFrame(() => { |
| | | const box = meshRef.current; |
New file |
| | |
| | | import { useRef, useState } from 'react'; |
| | | import { useSpring, animated } from '@react-spring/web'; |
| | | import styles from '@/styles/panel.module.scss'; |
| | | |
| | | const Panel = (props = { |
| | | panelConfig: {}, |
| | | title: '', |
| | | children: {}, |
| | | scale: 50 |
| | | } |
| | | ) => { |
| | | const cardRef = useRef(null); |
| | | const config = { |
| | | mass: 1, |
| | | tension: 170, |
| | | friction: 26, |
| | | clamp: false, |
| | | precision: 0.01, |
| | | velocity: 0, |
| | | ...props.panelConfig, |
| | | }; |
| | | |
| | | const calc = (x, y, rect) => [ |
| | | -(y - rect.top - rect.height / 2) / (props.scale || 50), |
| | | (x - rect.left - rect.width / 2) / (props.scale || 50), |
| | | 1.01, |
| | | ]; |
| | | |
| | | const trans = (x, y, s) => `perspective(600px) rotateX(${x}deg) rotateY(${y}deg) scale(${s})`; |
| | | |
| | | const [{ xys }, api] = useSpring(() => ({ xys: [0, 0, 1], config }), [config]); |
| | | |
| | | const handleMouseLeave = () => |
| | | api.start({ |
| | | xys: [0, 0, 1], |
| | | }); |
| | | |
| | | const handleMouseMove = (e) => { |
| | | const rect = cardRef.current.getBoundingClientRect(); |
| | | api.start({ |
| | | xys: calc(e.clientX, e.clientY, rect), |
| | | }); |
| | | }; |
| | | |
| | | return ( |
| | | <div className="w-full mt-2" ref={cardRef}> |
| | | {/* <BorderBox8 dur={12}> */} |
| | | <div> |
| | | <animated.div |
| | | className={`border border-solid ${styles['animate-border-glow']} ${styles.card} `} |
| | | style={{ transform: xys.to(trans) }} |
| | | onMouseLeave={handleMouseLeave} |
| | | onMouseMove={handleMouseMove} |
| | | > |
| | | {props.title && ( |
| | | <p className={`${styles.title} text-sm flex justify-between border-solid`}> |
| | | {props.title} {props.right} |
| | | </p> |
| | | )} |
| | | {props.children} |
| | | </animated.div> |
| | | </div> |
| | | {/* </BorderBox8> */} |
| | | </div> |
| | | ); |
| | | } |
| | | |
| | | export default Panel; |
| | |
| | | import TreeGroup from '../components/tree-group' |
| | | import House from '../components/house' |
| | | import Warehouse from '../core/warehouse' |
| | | import Left from './left' |
| | | |
| | | const Base = (props) => { |
| | | return ( |
| | |
| | | <Environment background preset="night" /> |
| | | <Help /> |
| | | </Canvas> |
| | | <Left /> |
| | | </div> |
| | | |
| | | ) |
New file |
| | |
| | | import { LeftOutlined, RightOutlined } from '@ant-design/icons'; |
| | | import { useSpring, animated } from 'react-spring'; |
| | | import { useState } from 'react'; |
| | | import styles from '@/styles/panel.module.scss'; |
| | | |
| | | import Panel from '@/components/panel'; |
| | | |
| | | // import Buffer from './modules/Buffer'; |
| | | // import Task from './modules/Task'; |
| | | // import AgvPanel from './modules/AgvPanel'; |
| | | |
| | | const Left = () => { |
| | | const [isExpanded, setIsExpanded] = useState(true); |
| | | // 定义动画属性 |
| | | const containerAnimation = useSpring({ |
| | | transform: isExpanded ? 'translate(0%)' : 'translateX(-100%)', |
| | | config: { precision: 0.01 }, |
| | | }); |
| | | |
| | | // 切换容器状态 |
| | | const toggleContainer = () => { |
| | | setIsExpanded(!isExpanded); |
| | | }; |
| | | return ( |
| | | <animated.div |
| | | style={{ |
| | | ...containerAnimation, |
| | | }} |
| | | className={`absolute top-2 left-2 bottom-2 w-[280px] ${styles.panel}`} |
| | | > |
| | | <div className="h-full overflow-auto"> |
| | | <Panel title="库房情况"> |
| | | {/* <Buffer /> */} |
| | | </Panel> |
| | | <Panel title="库存类型"> |
| | | {/* <Task /> */} |
| | | </Panel> |
| | | <Panel title="AGV信息"> |
| | | {/* <AgvPanel /> */} |
| | | </Panel> |
| | | </div> |
| | | <div |
| | | className={`${'absolute text-white top-1/2 -translate-y-1/2 right-[-21px] bg-black bg-opacity-20 text-xl font-bold bg'}`} |
| | | > |
| | | {isExpanded ? ( |
| | | <LeftOutlined |
| | | className="hover:scale-110 transition-transform duration-300 " |
| | | onClick={toggleContainer} |
| | | /> |
| | | ) : ( |
| | | <RightOutlined |
| | | className="hover:scale-110 transition-transform duration-300" |
| | | onClick={toggleContainer} |
| | | /> |
| | | )} |
| | | </div> |
| | | </animated.div> |
| | | ); |
| | | }; |
| | | |
| | | export default Left; |
New file |
| | |
| | | .panel { |
| | | background-color: rgba(89, 89, 89, 0.35); |
| | | backdrop-filter: blur(2px); |
| | | -webkit-backdrop-filter: blur(6px); |
| | | border: 1px solid rgba(255, 255, 255, 0.18); |
| | | box-shadow: rgba(142, 142, 142, 0.19) 0px 6px 15px 0px; |
| | | -webkit-box-shadow: rgba(142, 142, 142, 0.19) 0px 6px 15px 0px; |
| | | border-radius: 12px; |
| | | -webkit-border-radius: 12px; |
| | | color: rgba(255, 255, 255, 0.75); |
| | | padding: 0 8px; |
| | | // overflow: hidden; |
| | | } |
| | | |
| | | .card { |
| | | @extend .panel; |
| | | width: 100%; |
| | | background-color: rgba(23, 23, 23, 0.15); |
| | | will-change: transform; |
| | | border-radius: 0; |
| | | border: none; |
| | | } |
| | | |
| | | @keyframes borderColor1 { |
| | | from { |
| | | box-shadow: 0 0 0px rgba(50, 170, 170, 0.4); |
| | | } |
| | | |
| | | to { |
| | | box-shadow: 0 0 0px rgba(50, 170, 170, 0.9); |
| | | } |
| | | } |
| | | |
| | | .title { |
| | | border: none; |
| | | border-bottom: 1px solid rgba(255, 255, 255, 0.7); |
| | | padding: 6px 0; |
| | | font-weight: bold; |
| | | color: white; |
| | | animation: borderColor1 1.5s alternate infinite ease-in-out; |
| | | } |
| | | |
| | | @keyframes borderColor { |
| | | from { |
| | | border-color: rgba(50, 170, 170, 0.3); |
| | | box-shadow: 0 0 0px rgba(50, 170, 170, 0.7); |
| | | } |
| | | |
| | | to { |
| | | border-color: rgba(50, 170, 170, 0.5); |
| | | box-shadow: 0 0 3px rgba(50, 170, 170, 0.9); |
| | | } |
| | | } |
| | | |
| | | .animate-border-glow { |
| | | animation: borderColor 1.5s alternate infinite ease-in-out; |
| | | } |