From a3b2f3feb4585422d7b8db00baeeb7890d28b8f6 Mon Sep 17 00:00:00 2001 From: evlist Date: Sat, 10 Sep 2022 21:41:01 +0200 Subject: [PATCH] Refactoring. --- map/src/components/double-touch-handler.tsx | 24 ++++-- map/src/components/layer.tsx | 17 ++--- map/src/components/mouse-handler.tsx | 26 +++++-- map/src/components/single-touch-handler.tsx | 16 ++-- map/src/components/viewport.tsx | 84 +++++++++++++++------ 5 files changed, 109 insertions(+), 58 deletions(-) diff --git a/map/src/components/double-touch-handler.tsx b/map/src/components/double-touch-handler.tsx index b977b9d..eb3c010 100644 --- a/map/src/components/double-touch-handler.tsx +++ b/map/src/components/double-touch-handler.tsx @@ -2,11 +2,10 @@ import react, { useCallback, useState } from 'react'; import _ from 'lodash'; -import { Point } from './viewport'; +import { Transformation } from './viewport'; interface DoubleTouchHandlerProps { - updateZoom: (zoomFactor: number, center: Point) => void; - updateShift: (shiftDelta: Point) => void; + applyTransformations: (transformations: Transformation[]) => void; children: any; } @@ -97,11 +96,20 @@ const DoubleTouchHandler: react.FC = ( x: (event.touches[0].pageX + event.touches[1].pageX) / 2, y: (event.touches[0].pageY + event.touches[1].pageY) / 2, }; - props.updateZoom(factor, currentCenter); - // props.updateShift({ - // x: currentCenter.x - previousCenter.x, - // y: currentCenter.y - previousCenter.y, - // }); + props.applyTransformations([ + { + scale: { + factor: factor, + center: currentCenter, + }, + }, + { + translate: { + x: currentCenter.x - previousCenter.x, + y: currentCenter.y - previousCenter.y, + }, + }, + ]); } } }; diff --git a/map/src/components/layer.tsx b/map/src/components/layer.tsx index af831dc..37fe355 100644 --- a/map/src/components/layer.tsx +++ b/map/src/components/layer.tsx @@ -1,26 +1,21 @@ import react from 'react'; +import { ViewportState } from './viewport'; + import '../theme/layer.css'; const Layer: react.FC<{ - shift: { x: number; y: number }; - zoom: number; + viewportState: ViewportState; children?: JSX.Element; -}> = (props: { - shift: { x: number; y: number }; - zoom: number; - children?: JSX.Element; -}) => { - const {children: children, ...argProps} = props; +}> = (props: { viewportState: ViewportState; children?: JSX.Element }) => { + const { children: children, ...argProps } = props; console.log(`--- Rendering layer, props: ${JSON.stringify(argProps)} ---`); return (
{props.children} diff --git a/map/src/components/mouse-handler.tsx b/map/src/components/mouse-handler.tsx index ffb8989..b63d2f5 100644 --- a/map/src/components/mouse-handler.tsx +++ b/map/src/components/mouse-handler.tsx @@ -2,11 +2,10 @@ import react, { useCallback, useState } from 'react'; import _ from 'lodash'; -import { Point } from './viewport'; +import { Transformation } from './viewport'; interface MouseHandlerProps { - updateShift: (shiftDelta: Point) => void; - updateZoom: (zoomFactor: number, center: Point) => void; + applyTransformations: (transformations: Transformation[]) => void; children: any; } @@ -56,10 +55,14 @@ const MouseHandler: react.FC = ( event.preventDefault(); if (mouseState.down) { genericHandler(event); - props.updateShift({ - x: event.pageX - mouseState.starting.x, - y: event.pageY - mouseState.starting.y, - }); + props.applyTransformations([ + { + translate: { + x: event.pageX - mouseState.starting.x, + y: event.pageY - mouseState.starting.y, + }, + }, + ]); setMouseState({ down: true, starting: { @@ -77,7 +80,14 @@ const MouseHandler: react.FC = ( const doubleClickHandler = (event: any) => { genericHandler(event); - props.updateZoom(2, { x: event.pageX, y: event.pageY }); + props.applyTransformations([ + { + scale: { + factor: 2, + center: { x: event.pageX, y: event.pageY }, + }, + }, + ]); }; return ( diff --git a/map/src/components/single-touch-handler.tsx b/map/src/components/single-touch-handler.tsx index 663a7a7..f7cc068 100644 --- a/map/src/components/single-touch-handler.tsx +++ b/map/src/components/single-touch-handler.tsx @@ -2,10 +2,10 @@ import react, { useCallback, useState } from 'react'; import _ from 'lodash'; -import { Point } from './viewport'; +import { Transformation } from './viewport'; interface SingleTouchHandlerProps { - updateShift: (shiftDelta: Point) => void; + applyTransformations: (transformations: Transformation[]) => void; children: any; } @@ -63,10 +63,14 @@ const SingleTouchHandler: react.FC = ( if (touchState.state === 'pointer') { if (event.touches.length === 1) { genericHandler(event); - props.updateShift({ - x: event.touches[0].pageX - touchState.touch.x, - y: event.touches[0].pageY - touchState.touch.y, - }); + props.applyTransformations([ + { + translate: { + x: event.touches[0].pageX - touchState.touch.x, + y: event.touches[0].pageY - touchState.touch.y, + }, + }, + ]); setTouchState({ state: 'pointer', touch: { diff --git a/map/src/components/viewport.tsx b/map/src/components/viewport.tsx index add1d23..456db18 100644 --- a/map/src/components/viewport.tsx +++ b/map/src/components/viewport.tsx @@ -1,6 +1,6 @@ import react, { useCallback, useState } from 'react'; -import _ from 'lodash'; +import _, { constant } from 'lodash'; import MouseHandler from './mouse-handler'; import Layer from './layer'; @@ -14,48 +14,82 @@ export interface Point { y: number; } +export interface Translation { + translate: Point; +} + +export interface Scale { + scale: { + center: Point; + factor: number; + }; +} + +export type Transformation = Translation | Scale; + +// const transform1: Transformation = { translate: { x: 0, y: 1 } }; +// const transform2: Transformation = { +// scale: { center: { x: 10, y: 20 }, factor: 2 }, +// }; + interface ViewportProps { children: any; } +export interface ViewportState { + scale: number; + translation: Point; +} + const Viewport: react.FC = (props: ViewportProps) => { //console.log(`--- Rendering viewport, props: ${JSON.stringify(props)} ---`); - const initialShitf: Point = { x: 0, y: 0 }; + const initialState: ViewportState = { scale: 1, translation: { x: 0, y: 0 } }; - const [shift, setShift] = useState(initialShitf); - - const [zoom, setZoom] = useState(1); + const [state, setState] = useState(initialState); const genericHandler = (event: any) => { console.log('Log - Event: ' + event.type); return; }; - // TODO: implement resize event - // TODO: check boundaries - - const updateShift = (shiftDelta: Point) => { - setShift({ x: shift.x + shiftDelta.x, y: shift.y + shiftDelta.y }); - }; - - const updateZoom = (zoomFactor: number, center: Point) => { - const newZoom = zoom * zoomFactor; - updateShift({ - x: (shift.x - center.x) * (zoomFactor - 1), - y: (shift.y - center.y) * (zoomFactor - 1), - }); - setZoom(newZoom); + const applyTransformations = (transformations: Transformation[]) => { + const newState = transformations.reduce( + (previousState: ViewportState, transformation): ViewportState => { + if ('scale' in transformation) { + return { + scale: previousState.scale * transformation.scale.factor, + translation: { + x: + previousState.translation.x + + (previousState.translation.x - transformation.scale.center.x) * + (transformation.scale.factor - 1), + y: + previousState.translation.y + + (previousState.translation.y - transformation.scale.center.y) * + (transformation.scale.factor - 1), + }, + }; + } + return { + scale: previousState.scale, + translation: { + x: previousState.translation.x + transformation.translate.x, + y: previousState.translation.y + transformation.translate.y, + }, + }; + }, + state + ); + setState(newState); }; return (
- - - - - {props.children} - + + + + {props.children}