mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 12:40:46 +00:00
102 lines
3.6 KiB
TypeScript
102 lines
3.6 KiB
TypeScript
import {EventBus} from "../../core/EventBus"
|
|
import {Cell, Game} from "../../core/Game";
|
|
import {ZoomEvent, DragEvent} from "../InputHandler";
|
|
|
|
export class TransformHandler {
|
|
public scale: number = 1.8
|
|
private offsetX: number = -350
|
|
private offsetY: number = -200
|
|
|
|
constructor(private game: Game, private eventBus: EventBus, private canvas: HTMLCanvasElement) {
|
|
this.eventBus.on(ZoomEvent, (e) => this.onZoom(e))
|
|
this.eventBus.on(DragEvent, (e) => this.onMove(e))
|
|
}
|
|
|
|
boundingRect(): DOMRect {
|
|
return this.canvas.getBoundingClientRect()
|
|
}
|
|
|
|
width(): number {
|
|
return this.boundingRect().width
|
|
}
|
|
|
|
handleTransform(context: CanvasRenderingContext2D) {
|
|
// Disable image smoothing for pixelated effect
|
|
if (this.scale > 3) {
|
|
context.imageSmoothingEnabled = false;
|
|
} else {
|
|
context.imageSmoothingEnabled = true;
|
|
}
|
|
|
|
// Apply zoom and pan
|
|
context.setTransform(
|
|
this.scale,
|
|
0,
|
|
0,
|
|
this.scale,
|
|
this.game.width() / 2 - this.offsetX * this.scale,
|
|
this.game.height() / 2 - this.offsetY * this.scale
|
|
);
|
|
}
|
|
|
|
screenToWorldCoordinates(screenX: number, screenY: number): Cell {
|
|
const canvasRect = this.boundingRect();
|
|
const canvasX = screenX - canvasRect.left;
|
|
const canvasY = screenY - canvasRect.top;
|
|
|
|
// Calculate the world point we want to zoom towards
|
|
const centerX = (canvasX - this.game.width() / 2) / this.scale + this.offsetX;
|
|
const centerY = (canvasY - this.game.height() / 2) / this.scale + this.offsetY;
|
|
|
|
const gameX = centerX + this.game.width() / 2
|
|
const gameY = centerY + this.game.height() / 2
|
|
|
|
return new Cell(Math.floor(gameX), Math.floor(gameY));
|
|
}
|
|
|
|
screenBoundingRect(): [Cell, Cell] {
|
|
|
|
// Calculate the world point we want to zoom towards
|
|
const LeftX = (- this.game.width() / 2) / this.scale + this.offsetX;
|
|
const TopY = (- this.game.height() / 2) / this.scale + this.offsetY;
|
|
|
|
const gameLeftX = LeftX + this.game.width() / 2
|
|
const gameTopY = TopY + this.game.height() / 2
|
|
|
|
|
|
// Calculate the world point we want to zoom towards
|
|
const rightX = (screen.width - this.game.width() / 2) / this.scale + this.offsetX;
|
|
const rightY = (screen.height - this.game.height() / 2) / this.scale + this.offsetY;
|
|
|
|
const gameRightX = rightX + this.game.width() / 2
|
|
const gameBottomY = rightY + this.game.height() / 2
|
|
|
|
return [new Cell(Math.floor(gameLeftX), Math.floor(gameTopY)), new Cell(Math.floor(gameRightX), Math.floor(gameBottomY))]
|
|
}
|
|
|
|
onZoom(event: ZoomEvent) {
|
|
const oldScale = this.scale;
|
|
const zoomFactor = 1 + event.delta / 600;
|
|
this.scale /= zoomFactor;
|
|
|
|
// Clamp the scale to prevent extreme zooming
|
|
this.scale = Math.max(0.5, Math.min(20, this.scale));
|
|
|
|
const canvasRect = this.boundingRect()
|
|
const canvasX = event.x - canvasRect.left;
|
|
const canvasY = event.y - canvasRect.top;
|
|
|
|
// Calculate the world point we want to zoom towards
|
|
const zoomPointX = (canvasX - this.game.width() / 2) / oldScale + this.offsetX;
|
|
const zoomPointY = (canvasY - this.game.height() / 2) / oldScale + this.offsetY;
|
|
|
|
// Adjust the offset
|
|
this.offsetX = zoomPointX - (canvasX - this.game.width() / 2) / this.scale;
|
|
this.offsetY = zoomPointY - (canvasY - this.game.height() / 2) / this.scale;
|
|
}
|
|
|
|
onMove(event: DragEvent) {
|
|
this.offsetX -= event.deltaX / this.scale;
|
|
this.offsetY -= event.deltaY / this.scale;
|
|
}
|
|
} |