import Path from '../../draft/path' import Point from '../../draft/point' import Snippet from '../../draft/snippet' import {PartInner} from '../../draft/part' import {generatePartTransform} from '@freesewing/core/src/part' import { getProps, angle } from '../../draft/utils' import { drag } from 'd3-drag' import { select } from 'd3-selection' import { useRef, useState, useEffect} from 'react' const Buttons = ({ transform, flip, rotate, setRotate, resetPart }) => { const letter = 'F' const style = { style: {fill: 'white', fontSize: 18, fontWeight: 'bold', textAnchor: 'middle'} } return ( {rotate ? : } {letter} flip('y')}> {letter} flip('x')}> {letter} ) } const generateTransform = (x, y, rot, flipX, flipY, part) => { // const center = { // x: part.topLeft.x + (part.bottomRight.x - part.topLeft.x)/2, // y: part.topLeft.y + (part.bottomRight.y - part.topLeft.y)/2, // } // const dx = part.topLeft.x - center.x // const dy = part.topLeft.y - center.y const transforms = [`translate(${x},${y})`] if (flipX) transforms.push( 'scale(-1, 1)', ) if (flipY) transforms.push( 'scale(1, -1)', ) if (rot) transforms.push( `rotate(${rot}, ${center.x}, ${center.y})` ) return transforms.join(' ') } const Part = props => { const { layout, gist, name, part} = props const partLayout = layout.parts[name] // Don't just assume this makes sense if (typeof layout.parts?.[name]?.move?.x === 'undefined') return null // Use a ref for direct DOM manipulation const partRef = useRef(null) const centerRef = useRef(null) // State variable to switch between moving or rotating the part const [rotate, setRotate] = useState(false) // update the layout on mount useEffect(() => { if (partRef.current) updateLayout() }, [partRef]) // Initialize drag handler useEffect(() => { handleDrag(select(partRef.current)) }, [rotate, layout]) // These are kept as vars because re-rendering on drag would kill performance // Managing the difference between re-render and direct DOM updates makes this // whole thing a bit tricky to wrap your head around let translateX = partLayout.move.x let translateY = partLayout.move.y let partRotation = partLayout.rotate || 0; let rotation = partRotation; let flipX = partLayout.flipX ? true : false let flipY = partLayout.flipY ? true : false // let partRect const center = { x: part.topLeft.x + (part.bottomRight.x - part.topLeft.x)/2, y: part.topLeft.y + (part.bottomRight.y - part.topLeft.y)/2, } const getRotation = (event) => angle(center, event.subject) - angle(center, { x:event.x, y: event.y }); const handleDrag = drag() .subject(function(event) { return rotate ? { x: event.x, y: event.y } : {x: translateX, y: translateY} }) .on('start', function(event) { // partRect = partRef.current.getBoundingClientRect() }) .on('drag', function(event) { if (rotate) { let newRotation = getRotation(event); if (flipX) newRotation *= -1 if (flipY) newRotation *= -1 rotation = partRotation + newRotation } else { translateX = event.x translateY = event.y } const transforms = generatePartTransform(translateX, translateY, rotation, flipX, flipY, part); console.log(transforms) const me = select(this); for (var t in transforms) { me.attr(t, transforms[t]) } }) .on('end', function(event) { updateLayout() }) const resetPart = () => { rotation = 0 flipX = 0 flipY = 0 updateLayout() } const toggleDragRotate = () => { updateLayout() setRotate(!rotate) } const updateLayout = () => { const partRect = partRef.current.getBoundingClientRect(); const tl = {x: partRect.left, y: partRect.top}; const br = {x: partRect.right, y: partRect.bottom}; props.updateLayout(name, { move: { x: translateX, y: translateY, }, rotate: rotation, flipX, flipY, tl, br }) } // Method to flip (mirror) the part along the X or Y axis const flip = axis => { if (axis === 'x') flipX = !flipX else flipY = !flipY updateLayout() } return ( {PartInner(props)} {props.name !== 'pages' && <> } ) } export default Part