Draggable menu (React)
Меню, созданное React, я отделил от основного меню. Для разнообразия сделал там три кнопки, переключающими отображение разного содержимого в одном окне.
Первое, что мне было интересно сделать это перемещение окна. Для этого я создал div в виде полосы в верхней части окна. При нажатии на неё активируется Drag Mode, при отпускании клавиши мыши над всем окном Matcap режим отключается.
<div className="MatCap" onMouseUp={disableDragMode} style={ {left:newX, top:newY} }> <div className='dragLine' onMouseDown={enableDragMode} > …
Функция enableDragMode переключает state
const [dragModeEnabled, setDragMode ] = useState(false);
и устанавливает точку, в который произошел клик
const [clickPoint, setClickPoint] = useState({x: undefined, y: undefined}); function enableDragMode () { if( event.buttons !== 1 ) return; let blockStyle = getComputedStyle(event.target.parentNode.parentNode) let blockOffset = {x: blockStyle.left.replace('px',''), y: blockStyle.top.replace('px','')}; let point = {x: event.offsetX, y: event.offsetY, blockOffset: blockOffset} setClickPoint( point ); setDragMode(true); event.stopPropagation() event.preventDefault() }
При переключении режима в useEffect добавляется или удаляется listener на событие движения мыши:
useEffect(() => { if( dragModeEnabled ) { document.addEventListener( "mousemove", onMouseMove, false) } return function cleanup() { document.removeEventListener( "mousemove", onMouseMove, false) } }, [dragModeEnabled] );
При перемещении мыши с зажатой левой клавишей происходит изменение координат div.
const [newX, setNewX] = useState('0px'); const [newY, setNewY] = useState('30px');
Так же добавлены проверки, чтобы div не мог двигаться дальше краев окна.
function onMouseMove () { if( event.pageX < 20 || event.pageX > document.documentElement.clientWidth-20 || event.pageY < 20 || event.pageY > document.documentElement.clientHeight-20 ){ return; } if( event.buttons !== 1 ) { setDragMode(false); return; } moveAt(event.pageX, event.pageY); } function moveAt(pageX, pageY) { setNewX( pageX - clickPoint.x - clickPoint.blockOffset.x + 'px'); setNewY( pageY - clickPoint.y - clickPoint.blockOffset.y + 'px'); }
Полный код компонента Matcap.js
import React, { useState, useEffect, useContext } from 'react'; import './Matcap.css'; import { MatcapContext } from '../../../ReactPanel'; let headers = { 'MatCaps': "Select Matcap", 'Textures': "Select Texture", 'Models': "Select Model" } function Matcap( props ) { const [dragModeEnabled, setDragMode ] = useState(false); const [newX, setNewX] = useState('0px'); const [newY, setNewY] = useState('30px'); const [ cardsDiv, setCardsDiv ] = useState(null); const [clickPoint, setClickPoint] = useState({x: undefined, y: undefined}); const selectedCard = useContext( MatcapContext ) useEffect(() => { if( dragModeEnabled ) { document.addEventListener( "mousemove", onMouseMove, false) } return function cleanup() { document.removeEventListener( "mousemove", onMouseMove, false) } }, [dragModeEnabled] ); useEffect( () => { setCardsDiv( props.cardsDiv ); }, [] ) function clickUseButton () { appState.changeAppState( 'matcapChanged', selectedCard.src ); } function changeCheckbox( e ) { console.log('changeCheckbox', e.target.checked ); } function setPanelInvisible() { props.setPanel("") } function enableDragMode () { if( event.buttons !== 1 ) return; let blockStyle = getComputedStyle(event.target.parentNode.parentNode) let blockOffset = {x: blockStyle.left.replace('px',''), y: blockStyle.top.replace('px','')}; let point = {x: event.offsetX, y: event.offsetY, blockOffset: blockOffset} setClickPoint( point ); setDragMode(true); event.stopPropagation() event.preventDefault() } function onMouseMove () { if( event.pageX < 20 || event.pageX > document.documentElement.clientWidth-20 || event.pageY < 20 || event.pageY > document.documentElement.clientHeight-20 ){ return; } if( event.buttons !== 1 ) { setDragMode(false); return; } moveAt(event.pageX, event.pageY); } function moveAt(pageX, pageY) { setNewX( pageX - clickPoint.x - clickPoint.blockOffset.x + 'px'); setNewY( pageY - clickPoint.y - clickPoint.blockOffset.y + 'px'); } function disableDragMode() { setDragMode(false); } return ( <div className="MatCap" onMouseUp={disableDragMode} style={ {left:newX, top:newY} }> <div className='dragLine' onMouseDown={enableDragMode} > {headers[props.panel]} <button className="addPanel_CloseButton" onClick={ setPanelInvisible }> X </button> </div> <div className="HeadMatCab"> <div className="matCapPreview"> {props.panel === "MatCaps" && selectedCard.img ? <img className="cardImgSelected" src = {selectedCard.img}></img> : "" } </div> <div className="HeadMatCabButtons"> <label>Preview <input type='checkbox' name="checkbox" onChange={ changeCheckbox } /> </label> <button className='addPanel_Buttons' onClick={ clickUseButton }> Use </button> </div> </div> { props.panel === "MatCaps" && cardsDiv } </div> ); } export default Matcap;
Are you building a Trello clone with draggable cards or a table with draggable rows and columns or you are building some other cool application where you allow the user to drag and drop objects? Do, you use react? Well, you don’t really need to implement everything from scratch then. There are packages like react-dnd and react-beautiful-dnd which can help you. While react-dnd is more powerful, react-beautiful-dnd is simple and easy to use.
I’m creating 3d editor. This is mostly educational project, that’s why many things I try to make by myself, I just want to understand how it works. But if this app will be cool, I will be glad ☺️
I think that is among the so much significant information for me. Heidie Emilio Pederson
Article writing is also a excitement, if you be acquainted with afterward you can write otherwise it is complex to write. Brita Pierson Zak
Somebody essentially assist to make seriously posts I would state. Gale Darin Hyde
I think this is among the most vital info for me. And i am glad reading your article. Letitia Leeland Tager
Some truly prime content on this internet site , saved to bookmarks . Kassia Antonino Godding
I was studying some of your articles on this website and I conceive this site is real instructive! Continue putting up. Geneva Poul Celestyn
Thanks a lot for the blog article. Really looking forward to read more. Really Cool. Shay Bern Bunting
You have remarked very interesting details! ps nice web site. Caralie Bertrando Volnay
Say, you got a nice blog article. Really looking forward to read more. Lenette Gonzales Hans
This is a to a great extent signal post. Thanks instead of posting this. Dareen Carr Quiteria
Really appreciate you sharing this article post. Thanks Again. Awesome. Lura Bendick Ferdy
I simply wanted to jot down a brief comment to thank you for the amazing information you are showing on this website. My rather long internet investigation has now been honored with high-quality insight to exchange with my family and friends. I would express that most of us readers actually are unquestionably endowed to live in a decent place with very many outstanding people with insightful advice. I feel very much fortunate to have encountered your entire webpage and look forward to so many more entertaining times reading here. Thanks once again for everything. Cornelle Tedd Durkin