DK2/public/assets/scripts/WindowManager.js

177 lines
4.5 KiB
JavaScript
Raw Normal View History

2024-11-07 11:19:33 -06:00
/*
The WindowManager is responsible for creation, destruction, modification and tracking of game UI windows.
*/
class WindowManager
{
constructor(container)
{
this.windows = {}
this.container = container
}
updateWindow(id, content, title = '')
{
if (id in this.windows) {
let w = this.windows[id]
w.querySelector('header .title').innerHTML = title
w.querySelector('.body').innerHTML = content
return
}
this.createWindow(id, content, title)
}
createWindow(id, content, title = '')
{
// create window
let w = document.createElement('div')
w.id = `window-${id}`
w.classList.add('window')
// create header
let h = document.createElement('header')
w.appendChild(h)
// create header title
let ht = document.createElement('span')
ht.classList.add('title')
ht.innerHTML = title
h.appendChild(ht)
// create close button
ht.insertAdjacentHTML('afterend', `
<svg class="close" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"/>
</svg>
`)
h.querySelector('svg').addEventListener('click', () => {
this.windows[id].remove()
delete this.windows[id]
})
// create body
let b = document.createElement('div')
b.classList.add('body')
b.innerHTML = content
w.appendChild(b)
// track window and add it to the container
this.makeWindowDraggable(w, this.container)
this.windows[id] = w
this.container.appendChild(w)
}
makeWindowDraggable(w, c)
{
const header = w.querySelector('header');
if (!header) return;
let isDragging = false;
let currentX;
let currentY;
let initialX;
let initialY;
header.addEventListener('mousedown', startDragging);
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stopDragging);
w.addEventListener('mousedown', () => this.bringToFront(w));
function startDragging(e)
{
isDragging = true;
initialX = e.clientX - w.offsetLeft;
initialY = e.clientY - w.offsetTop;
}
function drag(e)
{
if (!isDragging) return;
e.preventDefault();
// Calculate new position
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;
// Get viewport dimensions
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
// Get window dimensions
const windowRect = w.getBoundingClientRect();
// Constrain to viewport bounds
// Left edge
currentX = Math.max(0, currentX);
// Right edge
currentX = Math.min(viewportWidth - windowRect.width, currentX);
// Top edge
currentY = Math.max(0, currentY);
// Bottom edge
currentY = Math.min(viewportHeight - windowRect.height, currentY);
// Apply the constrained position
w.style.left = currentX + 'px';
w.style.top = currentY + 'px';
}
function stopDragging()
{
isDragging = false;
}
// Handle window resize
window.addEventListener('resize', () => {
// Get current position and dimensions
const rect = w.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
// Adjust position if window is outside viewport after resize
let newX = parseInt(w.style.left);
let newY = parseInt(w.style.top);
// Constrain to new viewport bounds
newX = Math.min(Math.max(0, newX), viewportWidth - rect.width);
newY = Math.min(Math.max(0, newY), viewportHeight - rect.height);
w.style.left = newX + 'px';
w.style.top = newY + 'px';
});
}
normalizeZIndices()
{
const array = Array.from(this.windows);
array.sort((a, b) => (parseInt(a.style.zIndex) || 0) - (parseInt(b.style.zIndex) || 0));
// Reassign z-indices starting from 1
array.forEach((win, index) => {
win.style.zIndex = index + 1;
});
return array.length + 1; // Return next available z-index
}
bringToFront(windowElement)
{
const currentMax = Math.max(...Object.values(this.windows)
.map(w => parseInt(w.style.zIndex) || 0));
if (parseInt(windowElement.style.zIndex) >= currentMax) {
return
}
// If z-index is getting too high, normalize all z-indices
if (currentMax > 10000) {
const newZ = this.normalizeZIndices();
windowElement.style.zIndex = newZ;
} else {
windowElement.style.zIndex = currentMax + 1;
}
}
}