171 lines
5.1 KiB
JavaScript
171 lines
5.1 KiB
JavaScript
import { app } from "../../scripts/app.js";
|
|
|
|
class Visualizer {
|
|
constructor(node, container, visualSrc) {
|
|
this.node = node;
|
|
this.iframe = document.createElement('iframe');
|
|
Object.assign(this.iframe, {
|
|
scrolling: "no",
|
|
style: {
|
|
overflow: "hidden",
|
|
border: "none",
|
|
width: "100%",
|
|
height: "100%",
|
|
display: 'none' // 默认隐藏
|
|
},
|
|
src: `/extensions/ComfyUI-PanoCard/html/${visualSrc}.html`
|
|
});
|
|
container.appendChild(this.iframe);
|
|
}
|
|
|
|
updateVisual(params) {
|
|
const iframeDocument = this.iframe.contentWindow.document;
|
|
const previewScript = iframeDocument.getElementById('visualizer');
|
|
previewScript.setAttribute("pano_image", JSON.stringify(params.pano_image));
|
|
}
|
|
|
|
remove() {
|
|
this.iframe.remove();
|
|
}
|
|
|
|
show() {
|
|
this.iframe.style.display = 'block';
|
|
}
|
|
|
|
hide() {
|
|
this.iframe.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
function createVisualizer(node, inputName, typeName, app) {
|
|
node.name = inputName;
|
|
|
|
const widget = {
|
|
type: typeName,
|
|
name: "preview3d",
|
|
callback: () => {},
|
|
draw(ctx, node, widgetWidth, widgetY, widgetHeight) {
|
|
const margin = 10;
|
|
const topOffset = 35;
|
|
const leftOffset = 40;
|
|
const visible = app.canvas.ds.scale > 0.5 && this.type === typeName;
|
|
const width = widgetWidth - margin * 4;
|
|
const rect = ctx.canvas.getBoundingClientRect();
|
|
|
|
const transform = new DOMMatrix()
|
|
.scale(rect.width / ctx.canvas.width, rect.height / ctx.canvas.height)
|
|
.multiply(ctx.getTransform())
|
|
.translate(margin, margin + widgetY);
|
|
|
|
Object.assign(this.visualizer.style, {
|
|
left: `${transform.a * margin + transform.e + leftOffset}px`,
|
|
top: `${transform.d + transform.f + topOffset}px`,
|
|
width: `${width * transform.a}px`,
|
|
height: `${width * transform.d - widgetHeight - (8 * margin) * transform.d}px`,
|
|
position: "absolute",
|
|
overflow: "hidden",
|
|
zIndex: app.graph._nodes.indexOf(node),
|
|
display: visible ? 'block' : 'none'
|
|
});
|
|
|
|
Object.assign(this.visualizer.firstChild.style, {
|
|
transformOrigin: "50% 50%",
|
|
width: '100%',
|
|
height: '100%',
|
|
border: 'none'
|
|
});
|
|
}
|
|
};
|
|
|
|
const container = document.createElement('div');
|
|
container.id = `Comfy3D_${inputName}`;
|
|
container.style.display = 'none'; // 初始状态为隐藏
|
|
|
|
node.visualizer = new Visualizer(node, container, typeName);
|
|
widget.visualizer = container;
|
|
widget.parent = node;
|
|
|
|
document.body.appendChild(container);
|
|
|
|
node.addCustomWidget(widget);
|
|
|
|
node.updateParameters = (params) => {
|
|
node.visualizer.updateVisual(params);
|
|
};
|
|
|
|
node.onDrawBackground = function (ctx) {
|
|
this.visualizer.iframe.hidden = this.flags.collapsed;
|
|
};
|
|
|
|
node.onResize = function () {
|
|
let [w, h] = this.size;
|
|
w = Math.max(w, 600);
|
|
h = Math.max(h, 500);
|
|
|
|
if (w > 600) {
|
|
h = w - 100;
|
|
}
|
|
|
|
this.size = [w, h];
|
|
};
|
|
|
|
node.onRemoved = () => {
|
|
Object.values(node.widgets).forEach(widget => {
|
|
if (widget.visualizer) {
|
|
widget.visualizer.remove();
|
|
}
|
|
});
|
|
};
|
|
|
|
return { widget };
|
|
}
|
|
|
|
function registerVisualizer(nodeType, nodeData, nodeClassName, typeName) {
|
|
if (nodeData.name === nodeClassName) {
|
|
console.log(`[3D Visualizer] Registering node: ${nodeData.name}`);
|
|
|
|
const originalOnNodeCreated = nodeType.prototype.onNodeCreated;
|
|
|
|
nodeType.prototype.onNodeCreated = async function () {
|
|
const result = originalOnNodeCreated
|
|
? await originalOnNodeCreated.apply(this, arguments)
|
|
: undefined;
|
|
|
|
const existingNodes = app.graph._nodes.filter(node => node.type === nodeClassName);
|
|
const nodeName = `Preview3DNode_${existingNodes.length}`;
|
|
|
|
console.log(`[Comfy3D] Create: ${nodeName}`);
|
|
|
|
await createVisualizer(this, nodeName, typeName, app);
|
|
|
|
this.setSize([600, 500]);
|
|
|
|
return result;
|
|
};
|
|
|
|
nodeType.prototype.onExecuted = function (message) {
|
|
console.log(message);
|
|
if (message.pano_image) {
|
|
const params = { pano_image: message.pano_image[0] };
|
|
this.updateParameters(params);
|
|
this.visualizer.show();
|
|
} else {
|
|
if (this.visualizer.parentNode) {
|
|
this.visualizer.hide();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: "Gue.PanoCard.Viewer",
|
|
|
|
async init(app) {
|
|
// 初始化逻辑(如果需要)
|
|
},
|
|
|
|
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
registerVisualizer(nodeType, nodeData, "PanoCardViewer", "threeVisualizer");
|
|
}
|
|
}); |