From 7808b7db7ea2e6eb3beb794612d8727e47c30160 Mon Sep 17 00:00:00 2001 From: evlist Date: Wed, 21 Sep 2022 00:23:42 +0200 Subject: [PATCH] Implementing a SVG layout (aka whiteboard). --- src/components/map/map.tsx | 2 ++ src/components/map/whiteboard.tsx | 32 +++++++++++++++++++++++ src/components/slippy/layer.tsx | 1 + src/store/map.ts | 42 ++++++++++++++++++++++++++++--- 4 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 src/components/map/whiteboard.tsx diff --git a/src/components/map/map.tsx b/src/components/map/map.tsx index 675d577..4a1ea0e 100644 --- a/src/components/map/map.tsx +++ b/src/components/map/map.tsx @@ -7,6 +7,7 @@ import Layer from '../slippy/layer'; import Slippy from '../slippy/slippy'; import TiledMap from './tiled-map'; import GetLocation from './get-location'; +import Whiteboard from './whiteboard'; const Map: react.FC<{}> = (props: {}) => { const dispatch = useDispatch(); @@ -28,6 +29,7 @@ const Map: react.FC<{}> = (props: {}) => { + diff --git a/src/components/map/whiteboard.tsx b/src/components/map/whiteboard.tsx new file mode 100644 index 0000000..d364160 --- /dev/null +++ b/src/components/map/whiteboard.tsx @@ -0,0 +1,32 @@ +import React, { Fragment } from 'react'; +import { useSelector } from 'react-redux'; +import { MapState } from '../../store/map'; + +interface WhiteboardProps { + children?: any; +} + +const Whiteboard: React.FC = (props: WhiteboardProps) => { + const whiteBoardState = useSelector( + (state: { map: MapState }) => state.map.whiteboard + ); + + return ( + + + + {props.children} + + + ); +}; + +export default Whiteboard; diff --git a/src/components/slippy/layer.tsx b/src/components/slippy/layer.tsx index fee6385..fcc2547 100644 --- a/src/components/slippy/layer.tsx +++ b/src/components/slippy/layer.tsx @@ -4,6 +4,7 @@ import { MapState } from '../../store/map'; import '../../theme/layer.css'; + const Layer: react.FC<{ children?: JSX.Element; }> = (props: { children?: JSX.Element }) => { diff --git a/src/store/map.ts b/src/store/map.ts index f5b5652..50e6bb7 100644 --- a/src/store/map.ts +++ b/src/store/map.ts @@ -17,9 +17,9 @@ export interface MapScope { center: geoPoint; zoom: number; } -const initialMapScope: MapScope = { +var initialMapScope: MapScope = { center: { lat: -37.8403508, lon: 77.5539501 }, - zoom: 13, + zoom: 4, }; // Derived properties @@ -37,11 +37,18 @@ export interface SlippyState { translation: Point; } +// Properties needed to render the SVG whiteboard +export interface WhiteboardState { + scale: number; + translation: Point; +} + // Global state export interface MapState { scope: MapScope; tiles: TilesDescription; slippy: SlippyState; + whiteboard: WhiteboardState; } /* @@ -87,6 +94,30 @@ export var initialMapState: MapState = { }, zoom: 0, }, + whiteboard: { + scale: 0, + translation: { + x: 0, + y: 0, + }, + }, +}; + +const evaluateWhiteboardViewBox = ( + state: MapState, + visibleTileSize: number +) => { + // Update the whiteboard SVG viewBox + + const scaleFactor = 2 ** state.scope.zoom; + + state.whiteboard.scale = scaleFactor * tileSize; + state.whiteboard.translation.x = + (-state.tiles.first.x * visibleTileSize + state.slippy.translation.x) / + state.whiteboard.scale; + state.whiteboard.translation.y = + (-state.tiles.first.y * visibleTileSize + state.slippy.translation.y) / + state.whiteboard.scale; }; export const evaluateStateFromScope = (state: MapState) => { @@ -122,6 +153,8 @@ export const evaluateStateFromScope = (state: MapState) => { tilesCenterTargetLocation.x - tilesCenterActualLocation.x; state.slippy.translation.y = tilesCenterTargetLocation.y - tilesCenterActualLocation.y; + + evaluateWhiteboardViewBox(state, visibleTileSize); }; evaluateStateFromScope(initialMapState); @@ -146,7 +179,8 @@ export const reevaluateState = (state: MapState) => { state.scope.zoom = state.tiles.zoom + Math.log2(state.slippy.scale); - // TODO: zoom level + // Check if the state must be reevaluated + if ( -state.slippy.translation.x < visibleTileSize || -state.slippy.translation.y < visibleTileSize || @@ -158,6 +192,8 @@ export const reevaluateState = (state: MapState) => { state.slippy.scale < Math.SQRT1_2 ) { evaluateStateFromScope(state); + } else { + evaluateWhiteboardViewBox(state, visibleTileSize); } };