519 lines
10 KiB
JavaScript
519 lines
10 KiB
JavaScript
|
||
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";
|
||
|
||
}
|
||
|
||
}
|