mirror of
https://codeberg.org/demostf/frontend.git
synced 2026-06-03 18:24:12 +02:00
117 lines
No EOL
2.6 KiB
TypeScript
117 lines
No EOL
2.6 KiB
TypeScript
import {CenteredPanZoom} from './CenteredPanZoom';
|
|
import {createSignal, ParentProps} from "solid-js";
|
|
|
|
export interface PannerProps {
|
|
width: number;
|
|
height: number;
|
|
scale: number;
|
|
contentSize: {
|
|
width: number;
|
|
height: number;
|
|
};
|
|
onScale?: (scale: number) => any;
|
|
}
|
|
|
|
export const Panner = (props: ParentProps<PannerProps>) => {
|
|
const panner = new CenteredPanZoom({
|
|
screenHeight: props.height,
|
|
screenWidth: props.width,
|
|
scale: props.scale,
|
|
contentSize: props.contentSize
|
|
});
|
|
|
|
const [scale, setScale] = createSignal(props.scale);
|
|
const [translateX, setTranslateX] = createSignal(Math.floor(panner.viewport.x));
|
|
const [translateY, setTranslateY] = createSignal(Math.floor(panner.viewport.y));
|
|
|
|
let startX = 0;
|
|
let startY = 0;
|
|
|
|
const mouseMove = (event) => {
|
|
const {pageX, pageY} = event;
|
|
panner.panFrom(
|
|
{
|
|
x: startX,
|
|
y: startY
|
|
},
|
|
{
|
|
x: pageX,
|
|
y: pageY
|
|
}
|
|
);
|
|
startX = event.pageX;
|
|
startY = event.pageY;
|
|
|
|
setTranslateX(Math.floor(panner.viewport.x));
|
|
setTranslateY(Math.floor(panner.viewport.y));
|
|
setScale(panner.scale);
|
|
}
|
|
|
|
const mouseDown = (event) => {
|
|
startX = event.pageX;
|
|
startY = event.pageY;
|
|
|
|
const mouseUp = () => {
|
|
document.removeEventListener('mouseup', mouseUp, true);
|
|
document.removeEventListener('mousemove', mouseMove, true);
|
|
};
|
|
document.addEventListener('mouseup', mouseUp, true);
|
|
document.addEventListener('mousemove', mouseMove, true);
|
|
}
|
|
|
|
const applyZoom = (factor: number, center) => {
|
|
panner.zoom(factor, center);
|
|
|
|
setTranslateX(panner.viewport.x);
|
|
setTranslateY(panner.viewport.y);
|
|
setScale(panner.scale);
|
|
|
|
props.onScale(panner.scale);
|
|
}
|
|
|
|
const mouseWheel = (event) => {
|
|
event.preventDefault();
|
|
const center = {x: event.pageX, y: event.pageY};
|
|
let zoomFactor = (event.deltaY < 0) ? 1.05 : 0.95;
|
|
|
|
const factor = scale() * zoomFactor;
|
|
applyZoom(factor, center);
|
|
}
|
|
|
|
const center = () => ({
|
|
x: Math.floor(panner.screen.width / 2),
|
|
y: Math.floor(panner.screen.height / 2)
|
|
});
|
|
|
|
const pannerStyle = () => {
|
|
return {width: `${props.width}px`, height: `${props.height}px`}
|
|
};
|
|
|
|
return (
|
|
<div class="pan-zoom-element"
|
|
style={pannerStyle()}
|
|
onMouseDown={mouseDown}
|
|
onWheel={mouseWheel}>
|
|
<div class="content-container noselect"
|
|
style={{
|
|
transform: `translate(${translateX()}px, ${translateY()}px) scale(${scale()})`,
|
|
"transform-origin": 'top left'
|
|
}}>
|
|
{props.children}
|
|
</div>
|
|
<div class="zoommenu">
|
|
<div class="plus"
|
|
onClick={() => {
|
|
applyZoom(1.10, center())
|
|
}}>+
|
|
</div>
|
|
<div class="minus"
|
|
onClick={() => {
|
|
applyZoom(0.90, center())
|
|
}}>
|
|
-
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |