Implementing a SVG layout (aka whiteboard).
This commit is contained in:
parent
92700c3964
commit
7808b7db7e
|
@ -7,6 +7,7 @@ import Layer from '../slippy/layer';
|
||||||
import Slippy from '../slippy/slippy';
|
import Slippy from '../slippy/slippy';
|
||||||
import TiledMap from './tiled-map';
|
import TiledMap from './tiled-map';
|
||||||
import GetLocation from './get-location';
|
import GetLocation from './get-location';
|
||||||
|
import Whiteboard from './whiteboard';
|
||||||
|
|
||||||
const Map: react.FC<{}> = (props: {}) => {
|
const Map: react.FC<{}> = (props: {}) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
@ -28,6 +29,7 @@ const Map: react.FC<{}> = (props: {}) => {
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Slippy>
|
<Slippy>
|
||||||
<GetLocation />
|
<GetLocation />
|
||||||
|
<Whiteboard />
|
||||||
</Slippy>
|
</Slippy>
|
||||||
<Layer>
|
<Layer>
|
||||||
<TiledMap />
|
<TiledMap />
|
||||||
|
|
|
@ -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<WhiteboardProps> = (props: WhiteboardProps) => {
|
||||||
|
const whiteBoardState = useSelector(
|
||||||
|
(state: { map: MapState }) => state.map.whiteboard
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg width={window.innerWidth} height={window.innerHeight}>
|
||||||
|
<g
|
||||||
|
transform={`scale(${whiteBoardState.scale}) translate(${whiteBoardState.translation.x},${whiteBoardState.translation.y})`}
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
cx='0.7154276391666667'
|
||||||
|
cy='0.6137091783430285'
|
||||||
|
r={10 / whiteBoardState.scale}
|
||||||
|
fill='green'
|
||||||
|
vector-effect='non-scaling-size'
|
||||||
|
></circle>
|
||||||
|
{props.children}
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Whiteboard;
|
|
@ -4,6 +4,7 @@ import { MapState } from '../../store/map';
|
||||||
|
|
||||||
import '../../theme/layer.css';
|
import '../../theme/layer.css';
|
||||||
|
|
||||||
|
|
||||||
const Layer: react.FC<{
|
const Layer: react.FC<{
|
||||||
children?: JSX.Element;
|
children?: JSX.Element;
|
||||||
}> = (props: { children?: JSX.Element }) => {
|
}> = (props: { children?: JSX.Element }) => {
|
||||||
|
|
|
@ -17,9 +17,9 @@ export interface MapScope {
|
||||||
center: geoPoint;
|
center: geoPoint;
|
||||||
zoom: number;
|
zoom: number;
|
||||||
}
|
}
|
||||||
const initialMapScope: MapScope = {
|
var initialMapScope: MapScope = {
|
||||||
center: { lat: -37.8403508, lon: 77.5539501 },
|
center: { lat: -37.8403508, lon: 77.5539501 },
|
||||||
zoom: 13,
|
zoom: 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Derived properties
|
// Derived properties
|
||||||
|
@ -37,11 +37,18 @@ export interface SlippyState {
|
||||||
translation: Point;
|
translation: Point;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Properties needed to render the SVG whiteboard
|
||||||
|
export interface WhiteboardState {
|
||||||
|
scale: number;
|
||||||
|
translation: Point;
|
||||||
|
}
|
||||||
|
|
||||||
// Global state
|
// Global state
|
||||||
export interface MapState {
|
export interface MapState {
|
||||||
scope: MapScope;
|
scope: MapScope;
|
||||||
tiles: TilesDescription;
|
tiles: TilesDescription;
|
||||||
slippy: SlippyState;
|
slippy: SlippyState;
|
||||||
|
whiteboard: WhiteboardState;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
@ -87,6 +94,30 @@ export var initialMapState: MapState = {
|
||||||
},
|
},
|
||||||
zoom: 0,
|
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) => {
|
export const evaluateStateFromScope = (state: MapState) => {
|
||||||
|
@ -122,6 +153,8 @@ export const evaluateStateFromScope = (state: MapState) => {
|
||||||
tilesCenterTargetLocation.x - tilesCenterActualLocation.x;
|
tilesCenterTargetLocation.x - tilesCenterActualLocation.x;
|
||||||
state.slippy.translation.y =
|
state.slippy.translation.y =
|
||||||
tilesCenterTargetLocation.y - tilesCenterActualLocation.y;
|
tilesCenterTargetLocation.y - tilesCenterActualLocation.y;
|
||||||
|
|
||||||
|
evaluateWhiteboardViewBox(state, visibleTileSize);
|
||||||
};
|
};
|
||||||
|
|
||||||
evaluateStateFromScope(initialMapState);
|
evaluateStateFromScope(initialMapState);
|
||||||
|
@ -146,7 +179,8 @@ export const reevaluateState = (state: MapState) => {
|
||||||
|
|
||||||
state.scope.zoom = state.tiles.zoom + Math.log2(state.slippy.scale);
|
state.scope.zoom = state.tiles.zoom + Math.log2(state.slippy.scale);
|
||||||
|
|
||||||
// TODO: zoom level
|
// Check if the state must be reevaluated
|
||||||
|
|
||||||
if (
|
if (
|
||||||
-state.slippy.translation.x < visibleTileSize ||
|
-state.slippy.translation.x < visibleTileSize ||
|
||||||
-state.slippy.translation.y < visibleTileSize ||
|
-state.slippy.translation.y < visibleTileSize ||
|
||||||
|
@ -158,6 +192,8 @@ export const reevaluateState = (state: MapState) => {
|
||||||
state.slippy.scale < Math.SQRT1_2
|
state.slippy.scale < Math.SQRT1_2
|
||||||
) {
|
) {
|
||||||
evaluateStateFromScope(state);
|
evaluateStateFromScope(state);
|
||||||
|
} else {
|
||||||
|
evaluateWhiteboardViewBox(state, visibleTileSize);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue