59 lines
1.6 KiB
JavaScript
59 lines
1.6 KiB
JavaScript
export class Viewport {
|
|
constructor() {
|
|
this.panX = 0;
|
|
this.panY = 0;
|
|
this.zoomLevel = 0;
|
|
}
|
|
|
|
get zoom() {
|
|
return Math.pow(2, this.zoomLevel * 0.25);
|
|
}
|
|
|
|
zoomIn(delta) {
|
|
this.zoomLevel += delta;
|
|
this.zoomLevel = Math.max(-16, Math.min(20, this.zoomLevel));
|
|
}
|
|
|
|
// ndcX and ndcY are in -0.5 .. 0.5
|
|
// -0.5 -> (x) left or (y) top
|
|
// 0.5 -> (x) right or (y) bottom
|
|
// (0, 0) is the center of the screen
|
|
zoomIntoPoint(delta, ndcX, ndcY, windowSize) {
|
|
let beforePixelsX = (ndcX * windowSize.width) / this.zoom;
|
|
let beforePixelsY = (ndcY * windowSize.height) / this.zoom;
|
|
|
|
this.zoomIn(delta);
|
|
|
|
let afterPixelsX = (ndcX * windowSize.width) / this.zoom;
|
|
let afterPixelsY = (ndcY * windowSize.height) / this.zoom;
|
|
|
|
this.panX += beforePixelsX - afterPixelsX;
|
|
this.panY += beforePixelsY - afterPixelsY;
|
|
}
|
|
|
|
getVisibleRect(windowSize) {
|
|
let invZoom = 1 / this.zoom;
|
|
let width = windowSize.width * invZoom;
|
|
let height = windowSize.height * invZoom;
|
|
return {
|
|
x: this.panX - width / 2,
|
|
y: this.panY - height / 2,
|
|
width,
|
|
height,
|
|
};
|
|
}
|
|
|
|
toViewportSpace(x, y, windowSize) {
|
|
return [
|
|
(x - windowSize.width / 2) / this.zoom + this.panX,
|
|
(y - windowSize.height / 2) / this.zoom + this.panY,
|
|
];
|
|
}
|
|
|
|
toScreenSpace(x, y, windowSize) {
|
|
return [
|
|
(x - this.panX) * this.zoom + windowSize.width / 2,
|
|
(y - this.panY) * this.zoom + windowSize.height / 2,
|
|
];
|
|
}
|
|
}
|