Handling window resize (and rotate).

This commit is contained in:
Eric van der Vlist 2022-11-02 15:14:34 +01:00
parent 7811f00779
commit 61fc42b251
6 changed files with 63 additions and 59 deletions

View File

@ -26,6 +26,7 @@
"jotai": "^1.8.6", "jotai": "^1.8.6",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"react": "^18.2.0", "react": "^18.2.0",
"react-cool-dimensions": "^2.0.7",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router": "^5.2.0", "react-router": "^5.2.0",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",

View File

@ -1,15 +1,12 @@
import { Redirect, Route } from 'react-router-dom';
import { import {
IonApp, IonApp,
IonButtons, IonButtons,
IonContent, IonContent,
IonFooter, IonFooter,
IonHeader, IonHeader,
IonRouterOutlet,
IonToolbar, IonToolbar,
setupIonicReact, setupIonicReact,
} from '@ionic/react'; } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
/* Core CSS required for Ionic components to work properly */ /* Core CSS required for Ionic components to work properly */
import '@ionic/react/css/core.css'; import '@ionic/react/css/core.css';

View File

@ -79,11 +79,7 @@ export const LayerStack: react.FC<LayerStackProperties> = (
// console.log(`tiledLayers: ${JSON.stringify(tiledLayers)}`); // console.log(`tiledLayers: ${JSON.stringify(tiledLayers)}`);
return ( return (
<svg <svg width='100%' height='100%' data-testid='layer-stack'>
width={window.innerWidth}
height={window.innerHeight}
data-testid='layer-stack'
>
<g <g
transform={`translate(${props.coordinateSystem.shift.x}, ${props.coordinateSystem.shift.y}) scale(${props.coordinateSystem.zoom})`} transform={`translate(${props.coordinateSystem.shift.x}, ${props.coordinateSystem.shift.y}) scale(${props.coordinateSystem.zoom})`}
> >

View File

@ -1,4 +1,6 @@
import react, { useEffect, useState } from 'react'; import react, { useEffect, useState } from 'react';
import useDimensions from 'react-cool-dimensions';
import { MapScope, Point } from './types'; import { MapScope, Point } from './types';
import Map from './Map'; import Map from './Map';
import Handlers from './Handlers'; import Handlers from './Handlers';
@ -58,6 +60,7 @@ export const LiveMap: react.FC<LiveMapProperties> = (
setScope(props.scope); setScope(props.scope);
}, [props.scope]); }, [props.scope]);
console.log(`LiveMap rendering: ${JSON.stringify(scope)}`); console.log(`LiveMap rendering: ${JSON.stringify(scope)}`);
const { observe, width, height } = useDimensions<HTMLDivElement>();
const transform = (t: Transformation) => { const transform = (t: Transformation) => {
const deltaZoom = t.deltaZoom === null ? 1 : t.deltaZoom; const deltaZoom = t.deltaZoom === null ? 1 : t.deltaZoom;
const deltaZoomLevel = Math.log2(deltaZoom); const deltaZoomLevel = Math.log2(deltaZoom);
@ -96,12 +99,12 @@ export const LiveMap: react.FC<LiveMapProperties> = (
x: x:
tilesCenter.x - tilesCenter.x -
actualDeltaShiftTiles.x - actualDeltaShiftTiles.x -
(window.innerWidth / 2 / visibleTileSize - actualZoomCenterTiles.x) * (width / 2 / visibleTileSize - actualZoomCenterTiles.x) *
(deltaZoom - 1), (deltaZoom - 1),
y: y:
tilesCenter.y - tilesCenter.y -
actualDeltaShiftTiles.y - actualDeltaShiftTiles.y -
(window.innerHeight / 2 / visibleTileSize - actualZoomCenterTiles.y) * (height / 2 / visibleTileSize - actualZoomCenterTiles.y) *
(deltaZoom - 1), (deltaZoom - 1),
}; };
@ -127,10 +130,10 @@ export const LiveMap: react.FC<LiveMapProperties> = (
}; };
return ( return (
<> <div style={{ width: '100%', height: '100%' }} ref={observe}>
<Handlers transformMap={transform} /> <Handlers transformMap={transform} />
<Map scope={scope} numberOfTiledLayers={props.numberOfTiledLayers} /> <Map scope={scope} numberOfTiledLayers={props.numberOfTiledLayers} />
</> </div>
); );
}; };

View File

@ -1,4 +1,5 @@
import react from 'react'; import react from 'react';
import useDimensions from 'react-cool-dimensions';
import { Point, MapScope } from './types'; import { Point, MapScope } from './types';
import LayerStack from './LayerStack'; import LayerStack from './LayerStack';
@ -20,6 +21,8 @@ export interface MapProperties {
* *
*/ */
export const Map: react.FC<MapProperties> = (props: MapProperties) => { export const Map: react.FC<MapProperties> = (props: MapProperties) => {
const { observe, width, height } = useDimensions<HTMLDivElement>();
const tileProvider = tileProviders[props.scope.tileProvider]; const tileProvider = tileProviders[props.scope.tileProvider];
const tilesZoom = Math.min( const tilesZoom = Math.min(
@ -33,13 +36,13 @@ export const Map: react.FC<MapProperties> = (props: MapProperties) => {
const softZoom = props.scope.zoom - tilesZoom; const softZoom = props.scope.zoom - tilesZoom;
const relativeScale = 2 ** softZoom; const relativeScale = 2 ** softZoom;
const visibleTileSize = tileProvider.tileSize * relativeScale; const visibleTileSize = tileProvider.tileSize * relativeScale;
const nbTilesLeft = window.innerWidth / 2 / visibleTileSize; const nbTilesLeft = width / 2 / visibleTileSize;
const nbTilesTop = window.innerHeight / 2 / visibleTileSize; const nbTilesTop = height / 2 / visibleTileSize;
const firstTileLeft = Math.floor(tilesCenter.x - nbTilesLeft); const firstTileLeft = Math.floor(tilesCenter.x - nbTilesLeft);
const firstTileTop = Math.floor(tilesCenter.y - nbTilesTop); const firstTileTop = Math.floor(tilesCenter.y - nbTilesTop);
return ( return (
<> <div style={{ width: '100%', height: '100%' }} ref={observe}>
<LayerStack <LayerStack
numberOfTiledLayers={props.numberOfTiledLayers} numberOfTiledLayers={props.numberOfTiledLayers}
keyObject={{ keyObject={{
@ -56,7 +59,7 @@ export const Map: react.FC<MapProperties> = (props: MapProperties) => {
zoom: relativeScale, zoom: relativeScale,
}} }}
/> />
</> </div>
); );
}; };

View File

@ -1,4 +1,4 @@
import react from 'react'; import react, { useRef } from 'react';
import TileSet from './TileSet'; import TileSet from './TileSet';
import { Point, TileKeyObject } from './types'; import { Point, TileKeyObject } from './types';
import { CoordinateSystem } from './LiveMap'; import { CoordinateSystem } from './LiveMap';
@ -32,48 +32,52 @@ export interface TiledLayerProperties {
export const TiledLayer: react.FC<TiledLayerProperties> = ( export const TiledLayer: react.FC<TiledLayerProperties> = (
props: TiledLayerProperties props: TiledLayerProperties
) => { ) => {
const viewPort = const g = useRef<SVGGElement>(null);
props.zoom === 256 var viewPort: any = undefined;
? { if (
topLeft: { props.zoom === 256 &&
x: g.current !== null &&
props.keyObject.x + g.current.ownerSVGElement !== null &&
Math.floor( g.current.ownerSVGElement.parentElement !== null
-props.coordinateSystem.shift.x / ) {
props.coordinateSystem.zoom / const nearerHTMLParent = g.current.ownerSVGElement.parentElement;
256 viewPort = {
), topLeft: {
y: x:
props.keyObject.y + props.keyObject.x +
Math.floor( Math.floor(
-props.coordinateSystem.shift.y / -props.coordinateSystem.shift.x / props.coordinateSystem.zoom / 256
props.coordinateSystem.zoom / ),
256 y:
), props.keyObject.y +
}, Math.floor(
bottomRight: { -props.coordinateSystem.shift.y / props.coordinateSystem.zoom / 256
x: ),
props.keyObject.x + },
Math.ceil( bottomRight: {
(-props.coordinateSystem.shift.x + window.innerWidth) / x:
props.coordinateSystem.zoom / props.keyObject.x +
256 Math.ceil(
) - (-props.coordinateSystem.shift.x + nearerHTMLParent.offsetWidth) /
1, props.coordinateSystem.zoom /
y: 256
props.keyObject.y + ) -
Math.ceil( 1,
(-props.coordinateSystem.shift.y + window.innerHeight) / y:
props.coordinateSystem.zoom / props.keyObject.y +
256 Math.ceil(
) - (-props.coordinateSystem.shift.y + nearerHTMLParent.offsetHeight) /
1, props.coordinateSystem.zoom /
}, 256
} ) -
: undefined; 1,
},
};
}
return ( return (
<g <g
transform={`scale(${props.zoom}) translate(${props.shift.x}, ${props.shift.y})`} transform={`scale(${props.zoom}) translate(${props.shift.x}, ${props.shift.y})`}
ref={g}
> >
<TileSet <TileSet
keyObject={{ keyObject={{