Files
da2el-ai-D2-nodes-ComfyUI/web/D2_FloatContainer.js
T

170 lines
5.1 KiB
JavaScript

/**
* ボタンを並べた小さいフロートウィンドウのクラス
*/
import { setCookie, getCookie, loadCssFile } from "./utils.js";
class D2_FloatContainer {
static CSS_FILEPATH = "./extensions/D2-nodes-ComfyUI/css/D2_FloatContainer.css";
container = undefined;
buttonContainer = undefined;
cookieNameBase = "";
constructor(cookieNameBase, default_left = 50, default_top = 50) {
this.cookieNameBase = cookieNameBase;
loadCssFile(D2_FloatContainer.CSS_FILEPATH);
this._createContainer();
// 初期位置
const pos = this._getPosition(default_left, default_top);
this.container.style.left = pos[0] + "px";
this.container.style.top = pos[1] + "px";
// ウィンドウリサイズ対策
window.addEventListener("resize", () => {
this.resizeSetting();
});
this.resizeSetting();
}
/**
* ボタン追加
* @param {HTMLElement} button
*/
addButton(button) {
this.buttonContainer.appendChild(button);
}
/**
* ボタン全削除
*/
removeButtons() {
this.buttonContainer.innerHTML = "";
}
/**
* 表示切り替え
*/
changeVisible(bool) {
this.container.style.display = bool ? "block" : "none";
}
///////////////////////////////////////////////
// private method
///////////////////////////////////////////////
/**
* ベース作成
*/
_createContainer() {
this.container = document.createElement("div");
this.container.classList.add("p-panel", "d2-float-container");
document.querySelector("body").appendChild(this.container);
const content = document.createElement("div");
content.classList.add("p-panel-content", "flex", "flex-nowrap", "items-center", "d2-float-container__content");
this.container.appendChild(content);
const dragHandle = document.createElement("span");
dragHandle.classList.add("drag-handle", "cursor-move", "mr-2");
content.appendChild(dragHandle);
this.buttonContainer = document.createElement("div");
this.buttonContainer.classList.add("flex", "flex-nowrap", "items-center", "d2-float-container__button-container");
content.appendChild(this.buttonContainer);
// ドラッグ設定
this._dragSetting(dragHandle, this.container);
}
/**
* 座標をcookieに記録
*/
_savePosition(x, y) {
const cookieName = `${this.cookieNameBase}_pos`;
const cookieValue = [x, y];
setCookie(cookieName, cookieValue);
}
/**
* 座標をcookieから取得
*/
_getPosition(default_left, default_top) {
const cookieName = `${this.cookieNameBase}_pos`;
const cookieValue = getCookie(cookieName);
return cookieValue !== undefined ? cookieValue : [default_left, default_top];
}
/**
* ドラッグ設定
*/
_dragSetting(handle, container) {
let isDragging = false;
let startX, startY, initialLeft, initialTop;
// マウスダウンイベントリスナー
handle.addEventListener("mousedown", (e) => {
isDragging = true;
startX = e.clientX;
startY = e.clientY;
initialLeft = container.offsetLeft;
initialTop = container.offsetTop;
// テキスト選択を防止
e.preventDefault();
});
// マウスムーブイベントリスナー
document.addEventListener("mousemove", (e) => {
if (!isDragging) return;
const x = e.clientX - startX + initialLeft;
const y = e.clientY - startY + initialTop;
container.style.left = `${x}px`;
container.style.top = `${y}px`;
this._savePosition(x, y);
});
// マウスアップイベントリスナー
document.addEventListener("mouseup", () => {
isDragging = false;
});
// マウスリーブイベントリスナー(ブラウザ外にマウスが出た場合)
document.addEventListener("mouseleave", () => {
isDragging = false;
});
}
/**
* ウィンドウリサイズ対策
*/
resizeSetting() {
const container = this.container;
const rect = container.getBoundingClientRect();
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
// 右端の調整
if (rect.right > viewportWidth) {
const newLeft = Math.max(0, viewportWidth - rect.width);
container.style.left = `${newLeft}px`;
} else if (rect.left < 0) {
container.style.left = "0px";
}
// 下端の調整
if (rect.bottom > viewportHeight) {
const newTop = Math.max(0, viewportHeight - rect.height);
container.style.top = `${newTop}px`;
} else if (rect.top < 0) {
container.style.top = "0px";
}
}
}
export { D2_FloatContainer }