diff --git a/background-move/src/components/layer.tsx b/background-move/src/components/layer.tsx index 3febe17..e555b12 100644 --- a/background-move/src/components/layer.tsx +++ b/background-move/src/components/layer.tsx @@ -12,7 +12,7 @@ const Layer: react.FC<{ children?: JSX.Element; }) => { const {children: children, ...argProps} = props; - console.log(`--- Rendering background, props: ${JSON.stringify(argProps)} ---`); + console.log(`--- Rendering layer, props: ${JSON.stringify(argProps)} ---`); return (
void; + children: any; +} + +const MouseShiftHandler: react.FC = ( + props: MouseShiftHandlerProps +) => { + + const initialMouseState = { + down: false, + starting: { x: -1, y: -1 }, + }; + + const [mouseState, setMouseState] = useState(initialMouseState); + + console.log('MouseShiftHandler, mouseState: ' + JSON.stringify(mouseState)); + + const genericHandler = (event: any) => { + console.log('Log - Event: ' + event.type); + if (event.type.startsWith('mouse')) { + console.log(`Mouse : ${event.pageX}, ${event.pageY}`); + console.log('mouseState: ' + JSON.stringify(mouseState)); + return; + } + }; + + const mouseLeaveHandler = (event: any) => { + genericHandler(event); + throtteledMouseMoveHandler.cancel(); + setMouseState(initialMouseState); + }; + + const mouseDownHandler = (event: any) => { + genericHandler(event); + event.preventDefault(); + setMouseState({ + down: true, + starting: { x: event.pageX, y: event.pageY }, + }); + }; + + const mouseUpHandler = (event: any) => { + genericHandler(event); + event.preventDefault(); + setMouseState(initialMouseState); + }; + + const mouseMoveHandler = (event: any) => { + event.preventDefault(); + if (mouseState.down) { + genericHandler(event); + props.updateShift({ + x: mouseState.starting.x - event.pageX, + y: mouseState.starting.y - event.pageY, + }); + setMouseState({ + down: true, + starting: { + x: event.pageX, + y: event.pageY, + }, + }); + } + }; + + const throtteledMouseMoveHandler = useCallback( + _.throttle(mouseMoveHandler, 50), + [mouseState.down] + ); + + return ( +
+ {props.children} +
+ ); +}; + +export default MouseShiftHandler; diff --git a/background-move/src/components/touch-shift-handler.tsx b/background-move/src/components/touch-shift-handler.tsx new file mode 100644 index 0000000..300b6ae --- /dev/null +++ b/background-move/src/components/touch-shift-handler.tsx @@ -0,0 +1,99 @@ +import react, { useCallback, useState } from 'react'; + +import _ from 'lodash'; + +import { Point } from './viewport'; + +interface TouchShiftHandlerProps { + updateShift: (shiftDelta: Point) => void; + children: any; +} + +const TouchShiftHandler: react.FC = ( + props: TouchShiftHandlerProps +) => { + const initialTouchState = { + state: 'up', + touch: { x: -1, y: -1 }, + }; + + const [touchState, setTouchState] = useState(initialTouchState); + + console.log('TouchShiftHandler, touchState: ' + JSON.stringify(touchState)); + + const genericHandler = (event: any) => { + console.log('Log - Event: ' + event.type); + if (event.type.startsWith('touch')) { + if (event.touches.length > 0) { + console.log( + `Touch1 : (${event.touches[0].pageX}, ${event.touches[0].pageY})` + ); + } + console.log('touchState: ' + JSON.stringify(touchState)); + return; + } + }; + + const touchCancelHandler = (event: any) => { + genericHandler(event); + throtteledTouchMoveHandler.cancel(); + setTouchState(initialTouchState); + }; + + const touchStartHandler = (event: any) => { + genericHandler(event); + // event.preventDefault(); + if (event.touches.length === 1) { + setTouchState({ + state: 'pointer', + touch: { x: event.touches[0].pageX, y: event.touches[0].pageY }, + }); + } + }; + + const touchEndHandler = (event: any) => { + genericHandler(event); + // event.preventDefault(); + setTouchState(initialTouchState); + throtteledTouchMoveHandler.cancel(); + }; + + const touchMoveHandler = (event: any) => { + // event.preventDefault(); + if (touchState.state === 'pointer') { + if (event.touches.length === 1) { + genericHandler(event); + props.updateShift({ + x: touchState.touch.x - event.touches[0].pageX, + y: touchState.touch.y - event.touches[0].pageY, + }); + setTouchState({ + state: 'pointer', + touch: { + x: event.touches[0].pageX, + y: event.touches[0].pageY, + }, + }); + } + } + }; + + const throtteledTouchMoveHandler = useCallback( + _.throttle(touchMoveHandler, 100), + [touchState.state] + ); + + return ( +
+ {props.children} +
+ ); +}; + +export default TouchShiftHandler; diff --git a/background-move/src/components/touch-zoom-handler.tsx b/background-move/src/components/touch-zoom-handler.tsx new file mode 100644 index 0000000..490ad08 --- /dev/null +++ b/background-move/src/components/touch-zoom-handler.tsx @@ -0,0 +1,114 @@ +import react, { useCallback, useState } from 'react'; + +import _ from 'lodash'; + +import { Point } from './viewport'; + +interface TouchZoomHandlerProps { + updateZoom: (zoomFactor: number) => void; + children: any; +} + +const TouchZoomHandler: react.FC = ( + props: TouchZoomHandlerProps +) => { + const initialTouchState = { + state: 'up', + touches: [ + { x: -1, y: -1 }, + { x: -1, y: -1 }, + ], + distance: -1, + initialZoom: 1, + }; + + const [touchState, setTouchState] = useState(initialTouchState); + + console.log('TouchZoomHandler, touchState: ' + JSON.stringify(touchState)); + + const genericHandler = (event: any) => { + console.log('Log - Event: ' + event.type); + if (event.type.startsWith('touch')) { + if (event.touches.length > 1) { + console.log( + `${event.touches.length} touches, (${event.touches[0].pageX}, ${event.touches[0].pageY}), (${event.touches[1].pageX}, ${event.touches[1].pageY})` + ); + } + + console.log('touchState: ' + JSON.stringify(touchState)); + return; + } + }; + const touchCancelHandler = (event: any) => { + genericHandler(event); + throtteledTouchMoveHandler.cancel(); + setTouchState(initialTouchState); + }; + + const touchStartHandler = (event: any) => { + genericHandler(event); + if (event.touches.length === 2) { + setTouchState({ + state: 'double', + touches: [ + { x: event.touches[0].pageX, y: event.touches[0].pageY }, + { x: event.touches[1].pageX, y: event.touches[1].pageY }, + ], + distance: Math.sqrt( + (event.touches[0].pageX - event.touches[1].pageX) ** 2 + + (event.touches[0].pageY - event.touches[1].pageY) ** 2 + ), + initialZoom: 1, + }); + } + }; + + const touchEndHandler = (event: any) => { + genericHandler(event); + setTouchState(initialTouchState); + throtteledTouchMoveHandler.cancel(); + }; + + const touchMoveHandler = (event: any) => { + if (touchState.state === 'double') { + if (event.touches.length === 2) { + genericHandler(event); + const newDistance = Math.sqrt( + (event.touches[0].pageX - event.touches[1].pageX) ** 2 + + (event.touches[0].pageY - event.touches[1].pageY) ** 2 + ); + const factor = newDistance / touchState.distance; + console.log(`+++++++++ ZOOM Factor is ${factor} ++++++++++`); + setTouchState({ + state: 'double', + touches: [ + { x: event.touches[0].pageX, y: event.touches[0].pageY }, + { x: event.touches[1].pageX, y: event.touches[1].pageY }, + ], + distance: touchState.distance, + initialZoom: 1, + }); + props.updateZoom(factor); + } + } + }; + + const throtteledTouchMoveHandler = useCallback( + _.throttle(touchMoveHandler, 100), + [touchState.state] + ); + + return ( +
+ {props.children} +
+ ); +}; + +export default TouchZoomHandler; diff --git a/background-move/src/components/viewport.tsx b/background-move/src/components/viewport.tsx index 59aebc5..cefe4d0 100644 --- a/background-move/src/components/viewport.tsx +++ b/background-move/src/components/viewport.tsx @@ -2,228 +2,54 @@ import react, { useCallback, useState } from 'react'; import _ from 'lodash'; +import MouseShiftHandler from './mouse-shift-handler'; import Layer from './layer'; import '../theme/viewport.css'; +import TouchShiftHandler from './touch-shift-handler'; +import TouchZoomHandler from './touch-zoom-handler'; + +export interface Point { + x: number; + y: number; +} const Viewport: react.FC<{}> = (props: {}) => { console.log(`--- Rendering viewport, props: ${JSON.stringify(props)} ---`); - const [shift, setShift] = useState({ x: 1000, y: 1000 }); + const initialShitf: Point = { x: 1000, y: 1000 }; + + const [shift, setShift] = useState(initialShitf); const [zoom, setZoom] = useState(1); - const initialMouseState = { - down: false, - starting: { x: -1, y: -1 }, - }; - - const initialTouchState = { - state: 'up', - touches: [ - { x: -1, y: -1 }, - { x: -1, y: -1 }, - ], - distance: -1, - initialZoom: 1, - }; - - const [mouseState, setMouseState] = useState(initialMouseState); - const [touchState, setTouchState] = useState(initialTouchState); - - console.log('viewport, mouseState: ' + JSON.stringify(mouseState)); - console.log('viewport, touchState: ' + JSON.stringify(touchState)); - const genericHandler = (event: any) => { console.log('Log - Event: ' + event.type); - if (event.type.startsWith('mouse')) { - console.log(`Mouse : ${event.pageX}, ${event.pageY}`); - console.log('mouseState: ' + JSON.stringify(mouseState)); - return; - } - if (event.type.startsWith('touch')) { - if (event.touches.length > 0) { - console.log( - `Touch : ${event.touches.length} touches, ${ - event.touches[0].pageX - }, ${event.touches[0].pageY}, ${ - event.touches.length > 1 ? event.touches[1].pageX : '-' - }, ${event.touches.length > 1 ? event.touches[1].pageY : '-'}` - ); - } - - console.log('touchState: ' + JSON.stringify(touchState)); - return; - } + return; }; // TODO: implement resize event // TODO: check boundaries - const mouseLeaveHandler = (event: any) => { - genericHandler(event); - event.preventDefault(); - throtteledMouseMoveHandler.cancel(); - throtteledTouchMoveHandler.cancel(); - setMouseState(initialMouseState); - setTouchState(initialTouchState); + const updateShift = (shiftDelta: Point) => { + setShift({ x: shift.x + shiftDelta.x, y: shift.y + shiftDelta.y }); }; - const mouseDownHandler = (event: any) => { - genericHandler(event); - event.preventDefault(); - setMouseState({ - down: true, - starting: { x: event.pageX, y: event.pageY }, - }); + const updateZoom = (zoomFactor: number) => { + setZoom(zoom * zoomFactor); }; - const mouseUpHandler = (event: any) => { - genericHandler(event); - event.preventDefault(); - setMouseState(initialMouseState); - }; - - const mouseMoveHandler = (event: any) => { - event.preventDefault(); - if (mouseState.down) { - genericHandler(event); - // setShift((shift) => ({ - // x: shift.x + (mouseState.starting.x - event.pageX), - // y: shift.y + (mouseState.starting.y - event.pageY), - // })); - // setMouseState((mouseState) => ({ - // down: true, - // starting: { - // x: event.pageX, - // y: event.pageY, - // }, - // })); - setShift({ - x: shift.x + (mouseState.starting.x - event.pageX), - y: shift.y + (mouseState.starting.y - event.pageY), - }); - setMouseState({ - down: true, - starting: { - x: event.pageX, - y: event.pageY, - }, - }); - } - }; - - const throtteledMouseMoveHandler = useCallback( - _.throttle(mouseMoveHandler, 50), - [mouseState.down] - ); - - // Touch - - const touchStartHandler = (event: any) => { - genericHandler(event); - // event.preventDefault(); - if (event.touches.length === 1) { - setTouchState({ - state: 'pointer', - touches: [{ x: event.touches[0].pageX, y: event.touches[0].pageY }], - distance: -1, - initialZoom: -1, - }); - return; - } - - if (event.touches.length === 2) { - setTouchState({ - state: 'double', - touches: [ - { x: event.touches[0].pageX, y: event.touches[0].pageY }, - { x: event.touches[1].pageX, y: event.touches[1].pageY }, - ], - distance: Math.sqrt( - (event.touches[0].pageX - event.touches[1].pageX) ** 2 + - (event.touches[0].pageY - event.touches[1].pageY) ** 2 - ), - initialZoom: zoom, - }); - } - }; - - const touchEndHandler = (event: any) => { - genericHandler(event); - // event.preventDefault(); - setTouchState(initialTouchState); - throtteledTouchMoveHandler.cancel(); - }; - - const touchMoveHandler = (event: any) => { - // event.preventDefault(); - if (touchState.state === 'pointer') { - if (event.touches.length === 1) { - genericHandler(event); - setShift({ - x: shift.x + (touchState.touches[0].x - event.touches[0].pageX), - y: shift.y + (touchState.touches[0].y - event.touches[0].pageY), - }); - setTouchState({ - state: 'pointer', - touches: [ - { - x: event.touches[0].pageX, - y: event.touches[0].pageY, - }, - ], - distance: 0, - initialZoom: -1, - }); - } - return; - } - - if (touchState.state === 'double') { - if (event.touches.length === 2) { - genericHandler(event); - const newDistance = Math.sqrt( - (event.touches[0].pageX - event.touches[1].pageX) ** 2 + - (event.touches[0].pageY - event.touches[1].pageY) ** 2 - ); - const factor = newDistance / touchState.distance; - console.log(`+++++++++ ZOOM Factor is ${factor} ++++++++++`); - setTouchState({ - state: 'double', - touches: [ - { x: event.touches[0].pageX, y: event.touches[0].pageY }, - { x: event.touches[1].pageX, y: event.touches[1].pageY }, - ], - distance: touchState.distance, - initialZoom: zoom, - }); - setZoom(zoom * factor); - } - return; - } - }; - - const throtteledTouchMoveHandler = useCallback( - _.throttle(touchMoveHandler, 100), - [touchState.state] - ); - return ( -
- - - +
+ + + + + + + + +
); };