import { app } from '../../../../scripts/app.js' import { $el } from "../../../../scripts/ui.js"; let origProps = {}; export async function fetchJson(fileAddress) { try { const response = await fetch(fileAddress); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.error(fileAddress + 'JSON 파일을 불러오는 중 오류 발생:', error); return null; } } export function findWidgetByName(node, widgetName) { return node.widgets.find(widget => widget.name === widgetName); } const doesInputWithNameExist = (node, name) => { //return node.inputs ? node.inputs.some((input) => input.name === name) : false; return false; }; export function updateNodeHeight(node) { node.setSize([node.size[0], node.computeSize()[1]]); } export function toggleWidget(node, widget, show = false, suffix = "") { if (!widget || doesInputWithNameExist(node, widget.name)) return; // Store the original properties of the widget if not already stored if (!origProps[widget.name]) { origProps[widget.name] = { origType: widget.type, origComputeSize: widget.computeSize }; } const origSize = node.size; // Set the widget type and computeSize based on the show flag widget.type = show ? origProps[widget.name].origType : "tschide" + suffix; widget.computeSize = show ? origProps[widget.name].origComputeSize : () => [0, -4]; // Recursively handle linked widgets if they exist widget.linkedWidgets?.forEach(w => toggleWidget(node, w, ":" + widget.name, show)); // Calculate the new height for the node based on its computeSize method const height = show ? Math.max(node.computeSize()[1], origSize[1]) : node.size[1]; node.setSize([node.size[0], height]); } export function showMessage(short_msg, detail_msg) { try { app.extensionManager.toast.add({ severity: short_msg.toLowerCase(), summary: short_msg, detail: detail_msg, life: 3500 }); } catch { // do nothing } } export function addStylesheet(url) { if (url.endsWith(".js")) { url = url.substr(0, url.length - 2) + "css"; } $el("link", { parent: document.head, rel: "stylesheet", type: "text/css", href: url.startsWith("http") ? url : getUrl(url), }); } export function getUrl(path, baseUrl) { if (baseUrl) { return new URL(path, baseUrl).toString(); } else { return new URL("../" + path, import.meta.url).toString(); } } export async function loadImage(url) { return new Promise((res, rej) => { const img = new Image(); img.onload = res; img.onerror = rej; img.src = url; }); } export function addMenuHandler(nodeType, cb) { const getOpts = nodeType.prototype.getExtraMenuOptions; nodeType.prototype.getExtraMenuOptions = function () { const r = getOpts.apply(this, arguments); cb.apply(this, arguments); return r; }; } // Utility functions export function addNode(name, nextTo, options) { options = { select: true, shiftX: 0, shiftY: 0, before: false, ...(options || {}) }; const node = LiteGraph.createNode(name); app.graph.add(node); node.pos = [ nextTo.pos[0] + options.shiftX, nextTo.pos[1] + options.shiftY, ]; if (options.select) { app.canvas.selectNode(node, false); } return node; } ////////////////////////////////////////////////////////////////////////// COLOR//////////////////////////////////////////////////////////////////////////// export const hexToRGB = hex => { // #RGB → #RRGGBB 확장 if (hex.length === 4) { hex = "#" + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3]; } const r = parseInt(hex.slice(1, 3), 16); const g = parseInt(hex.slice(3, 5), 16); const b = parseInt(hex.slice(5, 7), 16); return { r, g, b }; }; export const rgbToHex = ({ r, g, b }, shorten = true) => { const hex = "#" + r.toString(16).padStart(2, "0") + g.toString(16).padStart(2, "0") + b.toString(16).padStart(2, "0"); if (shorten) { if (hex[1] === hex[2] && hex[3] === hex[4] && hex[5] === hex[6]) { return "#" + hex[1] + hex[3] + hex[5]; } } return hex; }; export function darkenHex(hex, amount = 6) { const { r, g, b } = hexToRGB(hex); const newR = Math.max(0, r - amount); const newG = Math.max(0, g - amount); const newB = Math.max(0, b - amount); return rgbToHex({ r: newR, g: newG, b: newB }); } // HEX → HSL 객체 const hexToHSL = h => { h = h.replace(/^#/, ''); h = h.length < 6 ? [...h].map(c => c + c).join`` : h; let r = parseInt(h.slice(0, 2), 16) / 255, g = parseInt(h.slice(2, 4), 16) / 255, b = parseInt(h.slice(4, 6), 16) / 255, m = Math.max(r, g, b), n = Math.min(r, g, b), l = (m + n) / 2, s = 0, H = 0; if (m !== n) { let d = m - n; s = l > 0.5 ? d / (2 - m - n) : d / (m + n); H = m === r ? (g - b) / d + (g < b ? 6 : 0) : m === g ? (b - r) / d + 2 : (r - g) / d + 4; H *= 60; } return { h: H, s: s * 100, l: l * 100 }; } // HSL 객체 → HEX const hslToHex = ({ h, s, l }) => { s /= 100; l /= 100; const k = n => (n + h / 30) % 12, a = s * Math.min(l, 1 - l), f = n => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1))), toH = x => x.toString(16).padStart(2, '0'); return `#${toH(Math.round(f(0) * 255))}${toH(Math.round(f(8) * 255))}${toH(Math.round(f(4) * 255))}`; } function overrideBackground_color(widget) { // 이미 오버라이드 되어 있는지 확인 const desc = Object.getOwnPropertyDescriptor(widget, "background_color"); if (desc && (desc.get || desc.set)) { return; // 이미 오버라이드 된 경우 } widget._background_color = widget.background_color; Object.defineProperty(widget, "background_color", { get() { return this._background_color; }, set(value) { this._background_color = value; }, configurable: true, }); } export function flashWidget(node, widgets, maxL = 50, duration = 2000, delay = 300) { if (!Array.isArray(widgets) || widgets.length === 0) return; const orig_bg_list = []; const minHSLList = []; widgets.forEach((widget) => { overrideBackground_color(widget); orig_bg_list.push(widget.background_color); minHSLList.push(hexToHSL(widget.background_color)); }); // 각 위젯마다 현재 HSL값 복사 const hslList = minHSLList.map((hsl) => ({ ...hsl })); const start = performance.now(); // easing 함수 function easeInOutExpo(t) { if (t === 0) return 0; if (t === 1) return 1; return t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2; } function step(time) { let allDone = true; widgets.forEach((widget, i) => { const delayTime = i * delay; const elapsed = time - start - delayTime; let t = elapsed / duration; if (t < 0) { allDone = false; // 아직 시작 전 return; } if (t >= 1) { // 원래 색으로 복원 widget.background_color = orig_bg_list[i]; return; } allDone = false; // 아직 애니메이션 진행 중 let eased; if (t <= 0.5) { eased = easeInOutExpo(t * 2); hslList[i].l = minHSLList[i].l + (maxL - minHSLList[i].l) * eased; } else { eased = easeInOutExpo((t - 0.5) * 2); hslList[i].l = maxL - (maxL - minHSLList[i].l) * eased; } widget.background_color = hslToHex(hslList[i]); }); node.setDirtyCanvas(true, true); if (!allDone) { requestAnimationFrame(step); } } requestAnimationFrame(step); } /* function easeInOutQuad(t) { return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; } // easeInOutQuart easing 함수 function easeInOutQuart(t) { return t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2; } // easeInOutExpo easing 함수 function easeInOutExpo(t) { if (t === 0) return 0; if (t === 1) return 1; return t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2; } */