/** * Class for handling zoom operations. */ class ZoomManager { /** * Creates a new instance of the ZoomManager class. * @param {boolean} horizontalZoom - Indicates if horizontal zoom is enabled. * @param {boolean} verticalZoom - Indicates if vertical zoom is enabled. */ constructor(horizontalZoom, verticalZoom) { this.x = 0 // Horizontal position this.y = 0 // Vertical position this.scaleX = 1 // Horizontal scale this.scaleY = 1 // Vertical scale this.horizontalZoom = horizontalZoom // Flag for horizontal zoom this.verticalZoom = verticalZoom // Flag for vertical zoom this.lastPos = { x: 0, y: 0 } } /** * Convert world coordinates to screen coordinates. * * @param {number} worldX - The x-coordinate in world space. * @param {number} worldY - The y-coordinate in world space. * @returns {Array} The screen coordinates [screenX, screenY]. */ worldToScreen(worldX, worldY) { let screenX = (worldX - this.x) * this.scaleX let screenY = (worldY - this.y) * this.scaleY return { x: screenX, y: screenY } } /** * Convert screen coordinates to world coordinates. * * @param {number} screenX - The x-coordinate on the screen. * @param {number} screenY - The y-coordinate on the screen. * @returns {Array} The world coordinates [worldX, worldY]. */ screenToWorld(screenX, screenY) { let worldX = screenX / this.scaleX + this.x let worldY = screenY / this.scaleY + this.y return { x: worldX, y: worldY } } /** * Recalculates zoom based on mouse wheel event or panning. * @param {MouseEvent} event - The mouse wheel event object. * @param {boolean} [panning=false] - Whether panning is enabled. */ recalculate(event, panning = false) { // Get mouse position const pos = { x: event.clientX, y: event.clientY } // Zooming if (event.deltaY) { // Calculate world coordinates before zoom let beforeZoom, afterZoom beforeZoom = this.screenToWorld(pos.x, pos.y) // Adjust zoom scale based on mouse wheel delta if (this.horizontalZoom) this.scaleX -= (10 * this.scaleX) / event.deltaY if (this.verticalZoom) this.scaleY -= (10 * this.scaleY) / event.deltaY // Calculate world coordinates after zoom afterZoom = this.screenToWorld(pos.x, pos.y) // Adjust zoom position to keep zoom centered around mouse position this.x += beforeZoom.x - afterZoom.x this.y += beforeZoom.y - afterZoom.y } // Panning if (panning) { // Only pan if the mouse movement exceeds minimum distance if ((this.lastPos.x - pos.x) ** 2 + (this.lastPos.y - pos.y) ** 2 > 10) { if (this.horizontalZoom) this.x += (this.lastPos.x - pos.x) / this.scaleX if (this.verticalZoom) this.y += (this.lastPos.y - pos.y) / this.scaleY this.lastPos = pos } } // Reset zoom if it goes below 1 if (this.scaleX < 1 || this.scaleY < 1) { this.x = 0 this.y = 0 this.scaleX = 1 this.scaleY = 1 } } }