Moving stuff around.
This commit is contained in:
parent
7f4c8fe591
commit
dfc4531bfa
|
@ -1,3 +1,9 @@
|
|||
.map {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.handler {
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IonContent, IonApp } from '@ionic/react';
|
||||
import { IonContent } from '@ionic/react';
|
||||
import react, { useState } from 'react';
|
||||
|
||||
import './Map.css';
|
||||
|
@ -13,13 +13,35 @@ interface MapProperties {
|
|||
const Map: react.FC<MapProperties> = (props: MapProperties) => {
|
||||
const boardSize = Math.max(props.width, props.height) * 2;
|
||||
|
||||
const [shift, setShift] = useState({ x: 0, y: 0 });
|
||||
const [zoom, setZoom] = useState(1);
|
||||
|
||||
const addShift = (deltaShift: { x: number; y: number }) => {
|
||||
setShift({ x: shift.x + deltaShift.x, y: shift.y + deltaShift.y });
|
||||
};
|
||||
|
||||
const addZoom = (zoomFactor: number, center: { x: number; y: number }) => {
|
||||
setShift({
|
||||
x: (shift.x - center.x) * (zoomFactor - 1),
|
||||
y: (shift.y - center.y) * (zoomFactor - 1),
|
||||
});
|
||||
setZoom(zoom * zoomFactor);
|
||||
};
|
||||
|
||||
return (
|
||||
<IonContent fullscreen={true}>
|
||||
<div
|
||||
className='map'
|
||||
style={{ width: props.width + 'px', height: props.height + 'px' }}
|
||||
>
|
||||
<MouseHandler shift={{ x: 0, y: 0 }} zoom={1} boardSize={boardSize} />
|
||||
<MouseHandler
|
||||
shift={shift}
|
||||
addShift={addShift}
|
||||
zoom={zoom}
|
||||
addZoom={addZoom}
|
||||
boardSize={boardSize}
|
||||
/>
|
||||
<Viewport boardSize={boardSize} shift={shift} zoom={zoom} />
|
||||
</div>
|
||||
</IonContent>
|
||||
);
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
import react, { useState } from 'react';
|
||||
import Viewport from './Viewport';
|
||||
import './Map.css';
|
||||
|
||||
interface Point {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
interface MouseHandlerProperties {
|
||||
boardSize: number;
|
||||
shift: { x: number; y: number };
|
||||
shift: Point;
|
||||
addShift: (shift: Point) => void;
|
||||
zoom: number;
|
||||
addZoom: (zoomFactor: number, center: Point) => void;
|
||||
}
|
||||
|
||||
const MouseHandler: react.FC<MouseHandlerProperties> = (
|
||||
|
@ -18,12 +25,12 @@ const MouseHandler: react.FC<MouseHandlerProperties> = (
|
|||
|
||||
const [mouseState, setMouseState] = useState(initialMouseState);
|
||||
|
||||
const [shift, setShift] = useState(props.shift);
|
||||
const [zoom, setZoom] = useState(props.zoom);
|
||||
|
||||
console.log('MouseHandler, mouseState: ' + JSON.stringify(mouseState));
|
||||
console.log(
|
||||
'MouseHandler, shift: ' + JSON.stringify(shift) + ', zoom:' + zoom
|
||||
'MouseHandler, shift: ' +
|
||||
JSON.stringify(props.shift) +
|
||||
', zoom:' +
|
||||
props.zoom
|
||||
);
|
||||
|
||||
const genericHandler = (event: any) => {
|
||||
|
@ -69,9 +76,9 @@ const MouseHandler: react.FC<MouseHandlerProperties> = (
|
|||
y: event.pageY - mouseState.starting.y,
|
||||
})}`
|
||||
);
|
||||
setShift({
|
||||
x: shift.x + (event.pageX - mouseState.starting.x),
|
||||
y: shift.y + (event.pageY - mouseState.starting.y),
|
||||
props.addShift({
|
||||
x: event.pageX - mouseState.starting.x,
|
||||
y: event.pageY - mouseState.starting.y,
|
||||
});
|
||||
setMouseState({
|
||||
down: true,
|
||||
|
@ -84,17 +91,9 @@ const MouseHandler: react.FC<MouseHandlerProperties> = (
|
|||
}
|
||||
};
|
||||
|
||||
const doScale = (x: number, y: number, factor: number) => {
|
||||
setShift({
|
||||
x: shift.x + (shift.x - x) * (factor - 1),
|
||||
y: shift.y + (shift.y - y) * (factor - 1),
|
||||
});
|
||||
setZoom(zoom * factor);
|
||||
};
|
||||
|
||||
const doubleClickHandler = (event: any) => {
|
||||
genericHandler(event);
|
||||
doScale(event.pageX, event.pageY, Math.SQRT2);
|
||||
props.addZoom(Math.SQRT2, { x: event.pageX, y: event.pageY });
|
||||
};
|
||||
|
||||
const initialWheelState = {
|
||||
|
@ -109,11 +108,10 @@ const MouseHandler: react.FC<MouseHandlerProperties> = (
|
|||
event.deltaMode === WheelEvent.DOM_DELTA_PIXEL &&
|
||||
Date.now() - wheelState.timestamp > 100
|
||||
) {
|
||||
doScale(
|
||||
event.pageX,
|
||||
event.pageY,
|
||||
event.deltaY < 0 ? Math.SQRT2 : Math.SQRT1_2
|
||||
);
|
||||
props.addZoom(event.deltaY < 0 ? Math.SQRT2 : Math.SQRT1_2, {
|
||||
x: event.pageX,
|
||||
y: event.pageY,
|
||||
});
|
||||
|
||||
setWheelState({
|
||||
timestamp: Date.now(),
|
||||
|
@ -122,16 +120,14 @@ const MouseHandler: react.FC<MouseHandlerProperties> = (
|
|||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
<div className='handler'
|
||||
onMouseDown={mouseDownHandler}
|
||||
onMouseMove={mouseMoveHandler}
|
||||
onMouseUp={mouseUpHandler}
|
||||
onMouseLeave={mouseLeaveHandler}
|
||||
onDoubleClick={doubleClickHandler}
|
||||
onWheel={wheelEventHandler}
|
||||
>
|
||||
<Viewport boardSize={props.boardSize} shift={shift} zoom={zoom} />
|
||||
</div>
|
||||
></div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import react from 'react';
|
||||
import TiledLayer from './TiledLayer';
|
||||
|
||||
interface ViewportProperties {
|
||||
boardSize: number;
|
||||
|
@ -6,55 +7,17 @@ interface ViewportProperties {
|
|||
zoom: number;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Let's call:
|
||||
* - x and y the SVG coordinates
|
||||
* - X and Y the screen coordinates (pixels on screen)
|
||||
*
|
||||
* X0 = (x + shift.x * zoom) * zoom
|
||||
* or
|
||||
* x = X0 * zoom - shift.x
|
||||
* id for Y
|
||||
*
|
||||
* To add a new shift of S screen pixels, we need to apply a zoom of S/zoom
|
||||
*
|
||||
* How can we zoom so that X and x stay constant ?
|
||||
*
|
||||
* Knowing X0, x0, zoom0, zoom1 and shift.x0,
|
||||
*
|
||||
*
|
||||
* X0 = (x0 + shift.x0 *zoom0) * zoom0
|
||||
* X1 = (x1 + shift.x1 *zoom1) * zoom1
|
||||
* X0 = X1 (=X)
|
||||
* x0 = x1 (=x)
|
||||
* =>
|
||||
* (x + shift.x1*zoom1) * zoom1 = (x + shift.x0 * zoom0) * zoom0
|
||||
* =>
|
||||
* (x + shift.x1*zoom1) = (x + shift.x0*zoom0) * zoom0 / zoom1
|
||||
* shift.x1 = ((x + shift.x0) * zoom0 / zoom1 - x) / zoom1
|
||||
*
|
||||
* x = 333
|
||||
* 282 => -25,5
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* viewBox={`${-props.shift.x} ${-props.shift.y} ${
|
||||
props.boardSize / props.zoom
|
||||
} ${props.boardSize / props.zoom}`}
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
const Viewport: react.FC<ViewportProperties> = (props: ViewportProperties) => {
|
||||
return (
|
||||
<svg height={props.boardSize} width={props.boardSize}>
|
||||
<defs>
|
||||
<TiledLayer id='tl16' zoomLevel={16} />
|
||||
</defs>
|
||||
<g
|
||||
transform={`translate(${props.shift.x}, ${props.shift.y}) scale(${props.zoom})`}
|
||||
>
|
||||
<circle cx='50' cy='50' r='50' />
|
||||
<use x={0} y={0} href='#tl16' />
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue