You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
3.5 KiB
109 lines
3.5 KiB
/**
|
|
* 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
|
|
}
|
|
}
|
|
}
|