Files
Graph-Explorer-JS/WindowController.js

519 lines
10 KiB
JavaScript
Raw Normal View History

2025-12-25 10:36:24 +01:00
var orderIndex = 1000;
export class WindowController {
win = null;
titlebar = null;
canvas = null;
resizers = null;
btnClose = null;
btnMaximize = null;
isSnapped = false;
isMaximized = false;
isDragging = false;
dragType = null;
currentResizer = null;
savedPosition = null;
savedBeforeMaximize = null;
order = orderIndex++;
startX = 0;
startY = 0;
startLeft = 100;
startTop = 100;
startWidth = 500;
startHeight = 500;
width = this.startWidth;
height = this.startHeight;
constructor() {
}
setElement( element ) {
this.canvas = element;
console.log("set element",element);
}
create( element ) {
var windowFrame = document.createElement( "div" );
windowFrame.id = "win"
windowFrame.style.width = this.startWidth + "px";
windowFrame.style.height = this.startHeight + "px";
windowFrame.style.left = this.startLeft + "px";
windowFrame.style.top = this.startTop + "px";
// Title bar
var titleBar = document.createElement( "div" );
titleBar.className = "titlebar";
titleBar.textContent = "Source Code Graph";
var buttons = document.createElement( "div" );
buttons.className = "buttons";
var btnMaximize = document.createElement( "button" );
btnMaximize.id = "btnMaximize";
btnMaximize.title = "Maximize";
btnMaximize.textContent = "m";
var btnClose = document.createElement( "button" );
btnClose.id = "btnClose";
btnClose.title = "Close";
btnClose.textContent = "×";
buttons.appendChild( btnMaximize );
buttons.appendChild( btnClose );
titleBar.appendChild( buttons );
windowFrame.appendChild( titleBar );
// Content
var content = document.createElement( "div" );
content.className = "content";
console.log(this.canvas);
content.appendChild( this.canvas );
windowFrame.appendChild( content );
// Resizers
var resizerClasses = [
"top-left", "top", "top-right", "right",
"bottom-right", "bottom", "bottom-left", "left"
];
this.resizers = new Array();
for (var i = 0; i < resizerClasses.length; i++) {
var resizer = document.createElement( "div" );
resizer.className = "resizer " + resizerClasses[i];
windowFrame.appendChild( resizer );
this.resizers.push(resizer)
}
this.win = windowFrame;
this.titlebar = titleBar;
this.btnClose = btnClose;
this.btnMaximize = btnMaximize;
this.titlebar.addEventListener("mousedown", this.onTitlebarMouseDown.bind(this));
this.resizers.forEach(this.bindResizer.bind(this));
this.btnClose.addEventListener("click", this.onCloseClick.bind(this));
this.btnMaximize.addEventListener("click", this.onMaximizeClick.bind(this));
document.body.appendChild( windowFrame );
this.win.addEventListener("mousedown", this.reOrder.bind( this ) );
}
setup() {
this.create();
}
setGraphExplorer( graphExplorer ) {
this.graphExplorer = graphExplorer;
}
saveWindowState() {
this.savedPosition = {
left: this.win.offsetLeft,
top: this.win.offsetTop,
width: this.win.offsetWidth,
height: this.win.offsetHeight
};
}
hide() {
this.win.style.display = "none"
}
show() {
this.win.style.display = "flex"
}
restoreWindowState() {
if (!this.savedPosition) return;
this.win.style.left = this.savedPosition.left + "px";
this.win.style.top = this.savedPosition.top + "px";
this.win.style.width = this.savedPosition.width + "px";
this.win.style.height = this.savedPosition.height + "px";
this.savedPosition = null;
this.isSnapped = false;
}
resizeCanvas() {
const style = getComputedStyle(this.win);
const width = parseInt(style.width);
const height = parseInt(style.height);
//this.canvas.width = width;
//this.canvas.height = height;
//this.canvas.style.width = width + "px";
//this.canvas.style.height = height + "px";
//console.log(this.graphExplorer);
if(this.graphExplorer)
this.graphExplorer.onResize( width, height );
//this.draw();
}
snapWindow(mouseX, mouseY) {
if (this.isMaximized) return;
const snapMargin = 30;
const vw = window.innerWidth;
const vh = window.innerHeight;
const nearLeft = mouseX <= snapMargin;
const nearRight = mouseX >= vw - snapMargin;
const nearTop = mouseY <= snapMargin;
const nearBottom = mouseY >= vh - snapMargin;
if (!this.isSnapped && (nearLeft || nearRight || nearTop || nearBottom)) {
this.saveWindowState();
this.isSnapped = true;
} else if (!nearLeft && !nearRight && !nearTop && !nearBottom && this.isSnapped) {
this.restoreWindowState();
return;
}
if (!this.isSnapped) return;
if (nearTop && nearLeft) {
this.setWindowRect(0, 0, vw / 2, vh / 2);
} else if (nearTop && nearRight) {
this.setWindowRect(vw / 2, 0, vw / 2, vh / 2);
} else if (nearBottom && nearLeft) {
this.setWindowRect(0, vh / 2, vw / 2, vh / 2);
} else if (nearBottom && nearRight) {
this.setWindowRect(vw / 2, vh / 2, vw / 2, vh / 2);
} else if (nearTop) {
this.setWindowRect(0, 0, vw, vh / 2);
} else if (nearBottom) {
this.setWindowRect(0, vh / 2, vw, vh / 2);
} else if (nearLeft) {
this.setWindowRect(0, 0, vw / 2, vh);
} else if (nearRight) {
this.setWindowRect(vw / 2, 0, vw / 2, vh);
}
this.resizeCanvas();
}
setWindowRect(left, top, width, height) {
this.win.style.left = Math.floor(left) + "px";
this.win.style.top = Math.floor(top) + "px";
this.win.style.width = Math.floor(width) + "px";
this.win.style.height = Math.floor(height) + "px";
}
onTitlebarMouseDown(event) {
event.preventDefault();
this.dragType = "move";
const offsetX = event.clientX - this.win.offsetLeft;
const offsetY = event.clientY - this.win.offsetTop;
if (this.isSnapped) {
this.restoreWindowState();
this.startX = event.clientX;
this.startY = event.clientY;
this.startLeft = event.clientX - 100;
this.startTop = event.clientY - offsetY;
this.win.style.left = this.startLeft + "px";
this.win.style.top = this.startTop + "px";
} else {
this.startX = event.clientX;
this.startY = event.clientY;
this.startLeft = this.win.offsetLeft;
this.startTop = this.win.offsetTop;
}
this.isDragging = true;
document.addEventListener("mousemove", this.onDragMove);
document.addEventListener("mouseup", this.onDragEnd);
}
onDragMove = (event) => {
event.preventDefault();
if (!this.isDragging) return;
const dx = event.clientX - this.startX;
const dy = event.clientY - this.startY;
if (this.dragType === "move") {
let newLeft = this.startLeft + dx;
let newTop = this.startTop + dy;
newLeft = Math.max(0, Math.min(window.innerWidth - this.win.offsetWidth, newLeft));
newTop = Math.max(0, Math.min(window.innerHeight - this.win.offsetHeight, newTop));
this.win.style.left = newLeft + "px";
this.win.style.top = newTop + "px";
this.snapWindow(event.clientX, event.clientY);
} else if (this.dragType === "resize") {
let newWidth = this.startWidth;
let newHeight = this.startHeight;
let newLeft = this.startLeft;
let newTop = this.startTop;
switch (this.currentResizer) {
case "top":
newHeight = this.startHeight - dy;
newTop = this.startTop + dy;
break;
case "bottom":
newHeight = this.startHeight + dy;
break;
case "left":
newWidth = this.startWidth - dx;
newLeft = this.startLeft + dx;
break;
case "right":
newWidth = this.startWidth + dx;
break;
case "top-left":
newWidth = this.startWidth - dx;
newLeft = this.startLeft + dx;
newHeight = this.startHeight - dy;
newTop = this.startTop + dy;
break;
case "top-right":
newWidth = this.startWidth + dx;
newHeight = this.startHeight - dy;
newTop = this.startTop + dy;
break;
case "bottom-left":
newWidth = this.startWidth - dx;
newLeft = this.startLeft + dx;
newHeight = this.startHeight + dy;
break;
case "bottom-right":
newWidth = this.startWidth + dx;
newHeight = this.startHeight + dy;
break;
}
if (newWidth > 100) {
this.win.style.width = newWidth + "px";
this.win.style.left = newLeft + "px";
}
if (newHeight > 100) {
this.win.style.height = newHeight + "px";
this.win.style.top = newTop + "px";
}
}
this.resizeCanvas();
};
onDragEnd = () => {
this.isDragging = false;
this.dragType = null;
this.currentResizer = null;
document.removeEventListener("mousemove", this.onDragMove);
document.removeEventListener("mouseup", this.onDragEnd);
};
reOrder() {
orderIndex++;
this.win.style['z-index'] = orderIndex;
console.log("this.win.style['z-index']", this.win.style['z-index']);
}
onResizerMouseDown(event) {
event.preventDefault();
this.startX = event.clientX;
this.startY = event.clientY;
this.startLeft = this.win.offsetLeft;
this.startTop = this.win.offsetTop;
this.startWidth = this.win.offsetWidth;
this.startHeight = this.win.offsetHeight;
this.isDragging = true;
this.dragType = "resize";
this.currentResizer = event.target.classList[1];
document.addEventListener("mousemove", this.onDragMove);
document.addEventListener("mouseup", this.onDragEnd);
}
bindResizer(resizerElement) {
resizerElement.addEventListener("mousedown", this.onResizerMouseDown.bind(this));
}
maximizeWindow() {
if (this.isMaximized) return;
this.savedBeforeMaximize = {
left: this.win.offsetLeft,
top: this.win.offsetTop,
width: this.win.offsetWidth,
height: this.win.offsetHeight
};
this.setWindowRect(0, 0, window.innerWidth, window.innerHeight);
this.resizeCanvas();
this.isMaximized = true;
this.isSnapped = false;
this.savedPosition = null;
}
restoreFromMaximize() {
if (!this.isMaximized || !this.savedBeforeMaximize) return;
this.setWindowRect(
this.savedBeforeMaximize.left,
this.savedBeforeMaximize.top,
this.savedBeforeMaximize.width,
this.savedBeforeMaximize.height
);
this.resizeCanvas();
this.isMaximized = false;
this.savedBeforeMaximize = null;
}
onMaximizeClick() {
if (this.isMaximized) {
this.restoreFromMaximize();
} else {
this.maximizeWindow();
}
}
onCloseClick() {
this.win.style.display = "none";
}
}