unified widget_vector
This commit is contained in:
+46
-1
@@ -2,7 +2,6 @@
|
||||
|
||||
import { api } from "../../../scripts/api.js";
|
||||
import { app } from "../../../scripts/app.js";
|
||||
import { domShowModal } from '../util/util.js'
|
||||
import { apiJovimetrix } from '../util/util_jov.js'
|
||||
import { bubbles } from '../util/util_fun.js'
|
||||
|
||||
@@ -10,6 +9,52 @@ const _id = "DELAY (JOV) ✋🏽"
|
||||
const EVENT_JOVI_DELAY = "jovi-delay-user";
|
||||
const EVENT_JOVI_UPDATE = "jovi-delay-update";
|
||||
|
||||
function domShowModal(innerHTML, eventCallback, timeout=null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const modal = document.createElement("div");
|
||||
modal.className = "modal";
|
||||
modal.innerHTML = innerHTML;
|
||||
document.body.appendChild(modal);
|
||||
|
||||
// center
|
||||
const modalContent = modal.querySelector(".jov-modal-content");
|
||||
modalContent.style.position = "absolute";
|
||||
modalContent.style.left = "50%";
|
||||
modalContent.style.top = "50%";
|
||||
modalContent.style.transform = "translate(-50%, -50%)";
|
||||
|
||||
let timeoutId;
|
||||
|
||||
const handleEvent = (event) => {
|
||||
const targetId = event.target.id;
|
||||
const result = eventCallback(targetId);
|
||||
|
||||
if (result != null) {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = null;
|
||||
}
|
||||
modal.remove();
|
||||
resolve(result);
|
||||
}
|
||||
};
|
||||
modalContent.addEventListener("click", handleEvent);
|
||||
modalContent.addEventListener("dblclick", handleEvent);
|
||||
|
||||
if (timeout) {
|
||||
timeout *= 1000;
|
||||
timeoutId = setTimeout(() => {
|
||||
modal.remove();
|
||||
reject(new Error("TIMEOUT"));
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
//setTimeout(() => {
|
||||
// modal.dispatchEvent(new Event('tick'));
|
||||
//}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: 'jovimetrix.node.' + _id,
|
||||
async beforeRegisterNodeDef(nodeType, nodeData) {
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
/**/
|
||||
|
||||
import { app } from "../../../scripts/app.js"
|
||||
|
||||
function arrayToObject(values, length, parseFn) {
|
||||
const result = {};
|
||||
for (let i = 0; i < length; i++) {
|
||||
result[i] = parseFn(values[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function domRenderTemplate(template, data) {
|
||||
for (const key in data) {
|
||||
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
||||
const regex = new RegExp(`{{\\s*${key}\\s*}}`, 'g')
|
||||
template = template.replace(regex, data[key])
|
||||
}
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
export function domFoldableToggle(elementId, symbolId) {
|
||||
const content = document.getElementById(elementId)
|
||||
const symbol = document.getElementById(symbolId)
|
||||
if (content.style.display == 'none' || content.style.display == '') {
|
||||
content.style.display = 'flex'
|
||||
symbol.innerHTML = '▽' // Down arrow
|
||||
} else {
|
||||
content.style.display = 'none'
|
||||
symbol.innerHTML = '▷' // Right arrow
|
||||
}
|
||||
}
|
||||
|
||||
export function domInnerValueChange(node, pos, widget, value, event=undefined) {
|
||||
const type = widget.type.includes("INT") ? Number : parseFloat
|
||||
widget.value = arrayToObject(value, Object.keys(value).length, type);
|
||||
if (
|
||||
widget.options &&
|
||||
widget.options.property &&
|
||||
node.properties[widget.options.property] !== undefined
|
||||
) {
|
||||
node.setProperty(widget.options.property, widget.value)
|
||||
}
|
||||
if (widget.callback) {
|
||||
|
||||
widget.callback(widget.value, app.canvas, node, pos, event)
|
||||
}
|
||||
}
|
||||
|
||||
export function domWidgetOffset(
|
||||
widget,
|
||||
ctx,
|
||||
node,
|
||||
widgetWidth,
|
||||
widgetY,
|
||||
height
|
||||
) {
|
||||
const margin = 10
|
||||
const elRect = ctx.canvas.getBoundingClientRect()
|
||||
const transform = new DOMMatrix()
|
||||
.scaleSelf(
|
||||
elRect.width / ctx.canvas.width,
|
||||
elRect.height / ctx.canvas.height
|
||||
)
|
||||
.multiplySelf(ctx.getTransform())
|
||||
.translateSelf(0, widgetY + margin)
|
||||
|
||||
const scale = new DOMMatrix().scaleSelf(transform.a, transform.d)
|
||||
Object.assign(widget.inputEl.style, {
|
||||
transformOrigin: '0 0',
|
||||
transform: scale,
|
||||
left: `${transform.e}px`,
|
||||
top: `${transform.d + transform.f}px`,
|
||||
width: `${widgetWidth}px`,
|
||||
height: `${(height || widget.parent?.inputHeight || 32) - margin}px`,
|
||||
position: 'absolute',
|
||||
background: !node.color ? '' : node.color,
|
||||
color: !node.color ? '' : 'white',
|
||||
zIndex: 5, //app.graph._nodes.indexOf(node),
|
||||
})
|
||||
}
|
||||
|
||||
export function domEscapeHtml(unsafe) {
|
||||
return unsafe
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
}
|
||||
|
||||
export function domShowModal(innerHTML, eventCallback, timeout=null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const modal = document.createElement("div");
|
||||
modal.className = "modal";
|
||||
modal.innerHTML = innerHTML;
|
||||
document.body.appendChild(modal);
|
||||
|
||||
// center
|
||||
const modalContent = modal.querySelector(".jov-modal-content");
|
||||
modalContent.style.position = "absolute";
|
||||
modalContent.style.left = "50%";
|
||||
modalContent.style.top = "50%";
|
||||
modalContent.style.transform = "translate(-50%, -50%)";
|
||||
|
||||
let timeoutId;
|
||||
|
||||
const handleEvent = (event) => {
|
||||
const targetId = event.target.id;
|
||||
const result = eventCallback(targetId);
|
||||
|
||||
if (result != null) {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = null;
|
||||
}
|
||||
modal.remove();
|
||||
resolve(result);
|
||||
}
|
||||
};
|
||||
modalContent.addEventListener("click", handleEvent);
|
||||
modalContent.addEventListener("dblclick", handleEvent);
|
||||
|
||||
if (timeout) {
|
||||
timeout *= 1000;
|
||||
timeoutId = setTimeout(() => {
|
||||
modal.remove();
|
||||
reject(new Error("TIMEOUT"));
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
//setTimeout(() => {
|
||||
// modal.dispatchEvent(new Event('tick'));
|
||||
//}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a string "255,255,255,255" or a List[255,255,255,255] into hex
|
||||
*/
|
||||
|
||||
export function colorLerpHex(colorStart, colorEnd, lerp) {
|
||||
// Parse color strings into RGB arrays
|
||||
const startRGB = colorHex2RGB(colorStart);
|
||||
const endRGB = colorHex2RGB(colorEnd);
|
||||
|
||||
// Linearly interpolate each RGB component
|
||||
const lerpedRGB = startRGB.map((component, index) => {
|
||||
return Math.round(component + (endRGB[index] - component) * lerp);
|
||||
});
|
||||
|
||||
// Convert the interpolated RGB values back to a hex color string
|
||||
return colorRGB2Hex(lerpedRGB);
|
||||
}
|
||||
|
||||
|
||||
@@ -125,15 +125,19 @@ export function widgetHookControl(node, control_key, target, matchFloatSize=fals
|
||||
combo.callback = () => {
|
||||
const me = oldCallback?.apply(this, arguments);
|
||||
widgetHide(node, target, "-jov");
|
||||
if (["VEC2", "VEC2INT", "COORD2D", "VEC3", "VEC3INT", "VEC4", "VEC4INT", "BOOLEAN", "INT", "FLOAT"].includes(combo.value)) {
|
||||
//if (["VEC2", "VEC2INT", "COORD2D", "VEC3", "VEC3INT", "VEC4", "VEC4INT", "BOOLEAN", "INT", "FLOAT"].includes(combo.value)) {
|
||||
if (["VEC2", "VEC3", "VEC4", "BOOLEAN", "INT", "FLOAT"].includes(combo.value)) {
|
||||
let type = combo.value;
|
||||
if (matchFloatSize) {
|
||||
type = "FLOAT";
|
||||
if (["VEC2", "VEC2INT", "COORD2D"].includes(combo.value)) {
|
||||
// if (["VEC2", "VEC2INT", "COORD2D"].includes(combo.value)) {
|
||||
if (["VEC2"].includes(combo.value)) {
|
||||
type = "VEC2";
|
||||
} else if (["VEC3", "VEC3INT"].includes(combo.value)) {
|
||||
//} else if (["VEC3", "VEC3INT"].includes(combo.value)) {
|
||||
} else if (["VEC3"].includes(combo.value)) {
|
||||
type = "VEC3";
|
||||
} else if (["VEC4", "VEC4INT"].includes(combo.value)) {
|
||||
//} else if (["VEC4", "VEC4INT"].includes(combo.value)) {
|
||||
} else if (["VEC4"].includes(combo.value)) {
|
||||
type = "VEC4";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,12 @@ const _MAP = {
|
||||
INT: "🔟",
|
||||
FLOAT: "🛟",
|
||||
VEC2: "🇽🇾",
|
||||
COORD2D: "🇽🇾",
|
||||
VEC2INT: "🇽🇾",
|
||||
//COORD2D: "🇽🇾",
|
||||
//VEC2INT: "🇽🇾",
|
||||
VEC3: "🇽🇾\u200c🇿",
|
||||
VEC3INT: "🇽🇾\u200c🇿",
|
||||
//VEC3INT: "🇽🇾\u200c🇿",
|
||||
VEC4: "🇽🇾\u200c🇿\u200c🇼",
|
||||
VEC4INT: "🇽🇾\u200c🇿\u200c🇼",
|
||||
//VEC4INT: "🇽🇾\u200c🇿\u200c🇼",
|
||||
LIST: "🧾",
|
||||
DICT: "📖",
|
||||
IMAGE: "🖼️",
|
||||
|
||||
@@ -1,10 +1,32 @@
|
||||
/**/
|
||||
|
||||
import { app } from "../../../scripts/app.js"
|
||||
import { $el } from "../../../scripts/ui.js"
|
||||
import { domInnerValueChange } from '../util/util.js'
|
||||
import { app } from "../../scripts/app.js"
|
||||
import { $el } from "../../scripts/ui.js"
|
||||
/** @import { IWidget, LGraphCanvas } from '../../types/litegraph/litegraph.d.ts' */
|
||||
|
||||
function arrayToObject(values, length, parseFn) {
|
||||
const result = {};
|
||||
for (let i = 0; i < length; i++) {
|
||||
result[i] = parseFn(values[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function domInnerValueChange(node, pos, widget, value, event=undefined) {
|
||||
//const numtype = widget.type.includes("INT") ? Number : parseFloat
|
||||
widget.value = arrayToObject(value, Object.keys(value).length, widget.convert);
|
||||
if (
|
||||
widget.options &&
|
||||
widget.options.property &&
|
||||
node.properties[widget.options.property] !== undefined
|
||||
) {
|
||||
node.setProperty(widget.options.property, widget.value)
|
||||
}
|
||||
if (widget.callback) {
|
||||
widget.callback(widget.value, app.canvas, node, pos, event)
|
||||
}
|
||||
}
|
||||
|
||||
function colorHex2RGB(hex) {
|
||||
hex = hex.replace(/^#/, '');
|
||||
const bigint = parseInt(hex, 16);
|
||||
@@ -32,13 +54,14 @@ const VectorWidget = (app, inputName, options, initial) => {
|
||||
/** @type {IWidget} */
|
||||
const widget = {
|
||||
name: inputName,
|
||||
type2: options[0],
|
||||
//type2: options[0],
|
||||
type: options[0],
|
||||
y: 0,
|
||||
value: values,
|
||||
options: options[1]
|
||||
}
|
||||
|
||||
widget.convert = parseFloat;
|
||||
widget.options.precision = 3;
|
||||
widget.options.step = 0.01;
|
||||
widget.options.round = 1 / 10 ** widget.options.step;
|
||||
@@ -47,6 +70,7 @@ const VectorWidget = (app, inputName, options, initial) => {
|
||||
widget.options.step = 1;
|
||||
widget.options.round = 1;
|
||||
widget.options.precision = 0;
|
||||
widget.convert = Number;
|
||||
}
|
||||
|
||||
if (widget.options?.rgb || false) {
|
||||
@@ -65,7 +89,8 @@ const VectorWidget = (app, inputName, options, initial) => {
|
||||
let picker;
|
||||
|
||||
widget.draw = function(ctx, node, width, Y, height) {
|
||||
if ((app.canvas.ds.scale < 0.50) || (!this.type2.startsWith("VEC") && this.type2 != "COORD2D")) return;
|
||||
// if ((app.canvas.ds.scale < 0.50) || (!this.type2.startsWith("VEC") && this.type2 != "COORD2D")) return;
|
||||
if ((app.canvas.ds.scale < 0.50) || (!this.type.startsWith("VEC"))) return;
|
||||
ctx.save()
|
||||
ctx.beginPath()
|
||||
ctx.lineWidth = 1
|
||||
@@ -269,15 +294,6 @@ app.registerExtension({
|
||||
}),
|
||||
VEC4: (node, inputName, inputData, app) => ({
|
||||
widget: node.addCustomWidget(VectorWidget(app, inputName, inputData, [0, 0, 0, 0])),
|
||||
}),
|
||||
VEC2INT: (node, inputName, inputData, app) => ({
|
||||
widget: node.addCustomWidget(VectorWidget(app, inputName, inputData, [0, 0])),
|
||||
}),
|
||||
VEC3INT: (node, inputName, inputData, app) => ({
|
||||
widget: node.addCustomWidget(VectorWidget(app, inputName, inputData, [0, 0, 0])),
|
||||
}),
|
||||
VEC4INT: (node, inputName, inputData, app) => ({
|
||||
widget: node.addCustomWidget(VectorWidget(app, inputName, inputData, [0, 0, 0, 0])),
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user