Moving stuff around.
This commit is contained in:
parent
7f4c8fe591
commit
dfc4531bfa
|
@ -1,3 +1,9 @@
|
||||||
.map {
|
.map {
|
||||||
overflow: hidden;
|
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 react, { useState } from 'react';
|
||||||
|
|
||||||
import './Map.css';
|
import './Map.css';
|
||||||
|
@ -13,13 +13,35 @@ interface MapProperties {
|
||||||
const Map: react.FC<MapProperties> = (props: MapProperties) => {
|
const Map: react.FC<MapProperties> = (props: MapProperties) => {
|
||||||
const boardSize = Math.max(props.width, props.height) * 2;
|
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 (
|
return (
|
||||||
<IonContent fullscreen={true}>
|
<IonContent fullscreen={true}>
|
||||||
<div
|
<div
|
||||||
className='map'
|
className='map'
|
||||||
style={{ width: props.width + 'px', height: props.height + 'px' }}
|
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>
|
</div>
|
||||||
</IonContent>
|
</IonContent>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
import react, { useState } from 'react';
|
import react, { useState } from 'react';
|
||||||
import Viewport from './Viewport';
|
import './Map.css';
|
||||||
|
|
||||||
|
interface Point {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
interface MouseHandlerProperties {
|
interface MouseHandlerProperties {
|
||||||
boardSize: number;
|
boardSize: number;
|
||||||
shift: { x: number; y: number };
|
shift: Point;
|
||||||
|
addShift: (shift: Point) => void;
|
||||||
zoom: number;
|
zoom: number;
|
||||||
|
addZoom: (zoomFactor: number, center: Point) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MouseHandler: react.FC<MouseHandlerProperties> = (
|
const MouseHandler: react.FC<MouseHandlerProperties> = (
|
||||||
|
@ -18,12 +25,12 @@ const MouseHandler: react.FC<MouseHandlerProperties> = (
|
||||||
|
|
||||||
const [mouseState, setMouseState] = useState(initialMouseState);
|
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, mouseState: ' + JSON.stringify(mouseState));
|
||||||
console.log(
|
console.log(
|
||||||
'MouseHandler, shift: ' + JSON.stringify(shift) + ', zoom:' + zoom
|
'MouseHandler, shift: ' +
|
||||||
|
JSON.stringify(props.shift) +
|
||||||
|
', zoom:' +
|
||||||
|
props.zoom
|
||||||
);
|
);
|
||||||
|
|
||||||
const genericHandler = (event: any) => {
|
const genericHandler = (event: any) => {
|
||||||
|
@ -69,9 +76,9 @@ const MouseHandler: react.FC<MouseHandlerProperties> = (
|
||||||
y: event.pageY - mouseState.starting.y,
|
y: event.pageY - mouseState.starting.y,
|
||||||
})}`
|
})}`
|
||||||
);
|
);
|
||||||
setShift({
|
props.addShift({
|
||||||
x: shift.x + (event.pageX - mouseState.starting.x),
|
x: event.pageX - mouseState.starting.x,
|
||||||
y: shift.y + (event.pageY - mouseState.starting.y),
|
y: event.pageY - mouseState.starting.y,
|
||||||
});
|
});
|
||||||
setMouseState({
|
setMouseState({
|
||||||
down: true,
|
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) => {
|
const doubleClickHandler = (event: any) => {
|
||||||
genericHandler(event);
|
genericHandler(event);
|
||||||
doScale(event.pageX, event.pageY, Math.SQRT2);
|
props.addZoom(Math.SQRT2, { x: event.pageX, y: event.pageY });
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialWheelState = {
|
const initialWheelState = {
|
||||||
|
@ -109,11 +108,10 @@ const MouseHandler: react.FC<MouseHandlerProperties> = (
|
||||||
event.deltaMode === WheelEvent.DOM_DELTA_PIXEL &&
|
event.deltaMode === WheelEvent.DOM_DELTA_PIXEL &&
|
||||||
Date.now() - wheelState.timestamp > 100
|
Date.now() - wheelState.timestamp > 100
|
||||||
) {
|
) {
|
||||||
doScale(
|
props.addZoom(event.deltaY < 0 ? Math.SQRT2 : Math.SQRT1_2, {
|
||||||
event.pageX,
|
x: event.pageX,
|
||||||
event.pageY,
|
y: event.pageY,
|
||||||
event.deltaY < 0 ? Math.SQRT2 : Math.SQRT1_2
|
});
|
||||||
);
|
|
||||||
|
|
||||||
setWheelState({
|
setWheelState({
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
|
@ -122,16 +120,14 @@ const MouseHandler: react.FC<MouseHandlerProperties> = (
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className='handler'
|
||||||
onMouseDown={mouseDownHandler}
|
onMouseDown={mouseDownHandler}
|
||||||
onMouseMove={mouseMoveHandler}
|
onMouseMove={mouseMoveHandler}
|
||||||
onMouseUp={mouseUpHandler}
|
onMouseUp={mouseUpHandler}
|
||||||
onMouseLeave={mouseLeaveHandler}
|
onMouseLeave={mouseLeaveHandler}
|
||||||
onDoubleClick={doubleClickHandler}
|
onDoubleClick={doubleClickHandler}
|
||||||
onWheel={wheelEventHandler}
|
onWheel={wheelEventHandler}
|
||||||
>
|
></div>
|
||||||
<Viewport boardSize={props.boardSize} shift={shift} zoom={zoom} />
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import react from 'react';
|
import react from 'react';
|
||||||
|
import TiledLayer from './TiledLayer';
|
||||||
|
|
||||||
interface ViewportProperties {
|
interface ViewportProperties {
|
||||||
boardSize: number;
|
boardSize: number;
|
||||||
|
@ -6,55 +7,17 @@ interface ViewportProperties {
|
||||||
zoom: number;
|
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) => {
|
const Viewport: react.FC<ViewportProperties> = (props: ViewportProperties) => {
|
||||||
return (
|
return (
|
||||||
<svg height={props.boardSize} width={props.boardSize}>
|
<svg height={props.boardSize} width={props.boardSize}>
|
||||||
|
<defs>
|
||||||
|
<TiledLayer id='tl16' zoomLevel={16} />
|
||||||
|
</defs>
|
||||||
<g
|
<g
|
||||||
transform={`translate(${props.shift.x}, ${props.shift.y}) scale(${props.zoom})`}
|
transform={`translate(${props.shift.x}, ${props.shift.y}) scale(${props.zoom})`}
|
||||||
>
|
>
|
||||||
<circle cx='50' cy='50' r='50' />
|
<circle cx='50' cy='50' r='50' />
|
||||||
|
<use x={0} y={0} href='#tl16' />
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue