diff --git a/svgmap/.gitignore b/svgmap/.gitignore index e36333d..3f1167e 100644 --- a/svgmap/.gitignore +++ b/svgmap/.gitignore @@ -10,6 +10,7 @@ # production /build +/android # misc .DS_Store diff --git a/svgmap/package-lock.json b/svgmap/package-lock.json index e91b449..340caf4 100644 --- a/svgmap/package-lock.json +++ b/svgmap/package-lock.json @@ -8,6 +8,7 @@ "name": "empty-ionic-react", "version": "0.0.1", "dependencies": { + "@capacitor/android": "4.1.0", "@capacitor/app": "4.0.1", "@capacitor/core": "4.1.0", "@capacitor/haptics": "4.0.1", @@ -1980,6 +1981,14 @@ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" }, + "node_modules/@capacitor/android": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-4.1.0.tgz", + "integrity": "sha512-aYHvpYVlS6WC+bG9jJfwqgHMxTw3e8f3taNnl/y9qCjglmMmtFcZWFAVLlOleVK4Q7olSirqjx37f0ppvxRTLg==", + "peerDependencies": { + "@capacitor/core": "^4.0.0" + } + }, "node_modules/@capacitor/app": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@capacitor/app/-/app-4.0.1.tgz", @@ -17290,6 +17299,12 @@ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" }, + "@capacitor/android": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-4.1.0.tgz", + "integrity": "sha512-aYHvpYVlS6WC+bG9jJfwqgHMxTw3e8f3taNnl/y9qCjglmMmtFcZWFAVLlOleVK4Q7olSirqjx37f0ppvxRTLg==", + "requires": {} + }, "@capacitor/app": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@capacitor/app/-/app-4.0.1.tgz", diff --git a/svgmap/package.json b/svgmap/package.json index 0e9f937..12e0b0a 100644 --- a/svgmap/package.json +++ b/svgmap/package.json @@ -3,6 +3,7 @@ "version": "0.0.1", "private": true, "dependencies": { + "@capacitor/android": "4.1.0", "@capacitor/app": "4.0.1", "@capacitor/core": "4.1.0", "@capacitor/haptics": "4.0.1", diff --git a/svgmap/src/components/map/DoubleTouchHandler.tsx b/svgmap/src/components/map/DoubleTouchHandler.tsx new file mode 100644 index 0000000..31b077f --- /dev/null +++ b/svgmap/src/components/map/DoubleTouchHandler.tsx @@ -0,0 +1,127 @@ +import react, { useState } from 'react'; + +interface Point { + x: number; + y: number; +} + +interface DoubleTouchHandlerProps { + boardSize: number; + shift: Point; + addShift: (shift: Point) => void; + zoom: number; + addZoom: (zoomFactor: number, center: Point) => void; + children?: any; +} + +const DoubleTouchHandler: react.FC = ( + props: DoubleTouchHandlerProps +) => { + const initialTouchState = { + state: 'up', + touches: [ + { x: -1, y: -1 }, + { x: -1, y: -1 }, + ], + distance: -1, + timestamp: 0, + }; + + const [touchState, setTouchState] = useState(initialTouchState); + + console.log('DoubleTouchHandler, 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); + 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 + ), + timestamp: Date.now(), + }); + } + }; + + const touchEndHandler = (event: any) => { + genericHandler(event); + setTouchState(initialTouchState); + }; + + const touchMoveHandler = (event: any) => { + if ( + touchState.state === 'double' && + Date.now() - touchState.timestamp > 100 + ) { + 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: newDistance, + timestamp: Date.now(), + }); + const previousCenter = { + x: (touchState.touches[0].x + touchState.touches[1].x) / 2, + y: (touchState.touches[0].y + touchState.touches[1].y) / 2, + }; + const currentCenter = { + x: (event.touches[0].pageX + event.touches[1].pageX) / 2, + y: (event.touches[0].pageY + event.touches[1].pageY) / 2, + }; + props.addShift({ + x: currentCenter.x - previousCenter.x, + y: currentCenter.y - previousCenter.y, + }); + props.addZoom(factor, currentCenter); + } + } + }; + + return ( +
+ {props.children === undefined ? <> : props.children} +
+ ); +}; + +export default DoubleTouchHandler; diff --git a/svgmap/src/components/map/Map.tsx b/svgmap/src/components/map/Map.tsx index caef2f2..d1c861c 100644 --- a/svgmap/src/components/map/Map.tsx +++ b/svgmap/src/components/map/Map.tsx @@ -6,6 +6,8 @@ import MouseHandler from './MouseHandler'; import SlippyBoard from './SlippyBoard'; import Tile from './Tile'; import fakeTile from './FakeTile.svg'; +import SingleTouchHandler from './SingleTouchHandler'; +import DoubleTouchHandler from './DoubleTouchHandler'; interface MapProperties { height: number; @@ -112,7 +114,23 @@ const Map: react.FC = (props: MapProperties) => { zoom={zoom} addZoom={addZoom} boardSize={boardSize} - /> + > + + + + void; zoom: number; addZoom: (zoomFactor: number, center: Point) => void; + children?: any; } const MouseHandler: react.FC = ( @@ -128,7 +129,10 @@ const MouseHandler: react.FC = ( onMouseLeave={mouseLeaveHandler} onDoubleClick={doubleClickHandler} onWheel={wheelEventHandler} - > + > + {' '} + {props.children === undefined ? <> : props.children} + ); }; diff --git a/svgmap/src/components/map/SingleTouchHandler.tsx b/svgmap/src/components/map/SingleTouchHandler.tsx new file mode 100644 index 0000000..60359f3 --- /dev/null +++ b/svgmap/src/components/map/SingleTouchHandler.tsx @@ -0,0 +1,103 @@ +import react, { useState } from 'react'; + +interface Point { + x: number; + y: number; +} + +interface SingleTouchHandlerProps { + boardSize: number; + shift: Point; + addShift: (shift: Point) => void; + zoom: number; + addZoom: (zoomFactor: number, center: Point) => void; + children?: any; +} + +const SingleTouchHandler: react.FC = ( + props: SingleTouchHandlerProps +) => { + const initialTouchState = { + state: 'up', + touch: { x: -1, y: -1 }, + timestamp: 0, + }; + + const [touchState, setTouchState] = useState(initialTouchState); + + console.log('SingleTouchHandler, 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); + 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 }, + timestamp: Date.now(), + }); + } + }; + + const touchEndHandler = (event: any) => { + genericHandler(event); + // event.preventDefault(); + setTouchState(initialTouchState); + }; + + const touchMoveHandler = (event: any) => { + // event.preventDefault(); + if ( + touchState.state === 'pointer' && + Date.now() - touchState.timestamp > 50 + ) { + if (event.touches.length === 1) { + genericHandler(event); + props.addShift({ + x: event.touches[0].pageX - touchState.touch.x, + y: event.touches[0].pageY - touchState.touch.y, + }); + setTouchState({ + state: 'pointer', + touch: { + x: event.touches[0].pageX, + y: event.touches[0].pageY, + }, + timestamp: Date.now(), + }); + } + } + }; + + return ( +
+ {props.children === undefined ? <> : props.children} +
+ ); +}; + +export default SingleTouchHandler;