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 (
-
-
-
-
+
+
+
+
+
+
+
+
+
+
);
};