Files
AEmotionStudio-ComfyUI-Shad…/web/gradient_title.js
T

245 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// gradient_title.js - Adds a custom gradient title to ShaderNoiseKSampler node
import { app } from "../../scripts/app.js";
// Cache for rendering optimization
const CACHE = {
titleCanvas: null,
titleCtx: null,
lastWidth: 0,
lastHeight: 0,
lastTime: 0,
frameCount: 0,
frameSkip: 2, // Only update animation every X frames
collapsed: {
canvas: null,
ctx: null,
lastWidth: 0
}
};
// Register a callback to run when ComfyUI is fully loaded
app.registerExtension({
name: "ShaderNoiseKSampler.GradientTitle",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
// Apply to both shader noise ksampler nodes
if (nodeData.name === "ShaderNoiseKSampler" || nodeData.name === "ShaderNoiseKSamplerDirect") {
// Store the original onDrawForeground function if it exists
const origOnDrawForeground = nodeType.prototype.onDrawForeground;
// Add our own onDrawForeground function
nodeType.prototype.onDrawForeground = function(ctx) {
// Call the original onDrawForeground if it exists
if (origOnDrawForeground) {
origOnDrawForeground.apply(this, arguments);
}
// Draw a custom gradient title
drawGradientTitle(this, ctx);
};
// Clean up resources when node is removed
const origOnRemoved = nodeType.prototype.onRemoved;
nodeType.prototype.onRemoved = function() {
if (origOnRemoved) {
origOnRemoved.apply(this, arguments);
}
// Clear cached canvases to prevent memory leaks
CACHE.titleCanvas = null;
CACHE.titleCtx = null;
CACHE.collapsed.canvas = null;
CACHE.collapsed.ctx = null;
};
}
}
});
/**
* Draws a gradient title directly on the canvas
* @param {LGraphNode} node - The node to apply the gradient to
* @param {CanvasRenderingContext2D} ctx - The canvas context
*/
function drawGradientTitle(node, ctx) {
// Get title area dimensions
const titleHeight = node.flags.collapsed ? 20 : 30; // Smaller height when collapsed
const width = node.flags.collapsed ? 190 : node.size[0]; // Smaller width when collapsed
const fullHeight = node.size[1]; // Get actual node height
const equationY = 45; // Y position for the equation, moved lower
// Choose appropriate equation based on node type
let equation, collapsedEquation;
if (node.type === "ShaderNoiseKSamplerDirect") {
equation = "Lt = Sα(N) ∘ Kβ(t) ⟿";
collapsedEquation = "Lt = Sα(N) ∘ Kβ(t) ⟿";
} else {
equation = "Lt = Sα(N) ∘ Kβ(t)";
collapsedEquation = "Lt = Sα(N) ∘ Kβ(t)";
}
// Update animation frame counter (performance optimization)
CACHE.frameCount = (CACHE.frameCount + 1) % (CACHE.frameSkip + 1);
const shouldUpdateAnimation = CACHE.frameCount === 0;
// Save current state
ctx.save();
// Reset shadow properties for gradient drawing
ctx.shadowColor = "transparent";
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
// Create vertical black gradient for entire background that fills node height
const gradient = ctx.createLinearGradient(0, 0, 0, fullHeight);
gradient.addColorStop(0, "#000000"); // Pure black at top
gradient.addColorStop(0.2, "#101010"); // Transition to very dark gray
gradient.addColorStop(1, "#101010"); // Very dark gray at bottom
// Create smooth shimmer effect for mathematical formula - only calculate if animation should update
let shimmerPosition = 0.5; // Default middle position
if (shouldUpdateAnimation) {
const time = Date.now() / 3000; // Faster time factor (changed from 4000)
shimmerPosition = (Math.sin(time) + 1) / 2; // Changed from cos to sin for left-to-right only
// Store for later use if needed
CACHE.lastTime = time;
} else {
// Reuse last calculation for animation frames we're skipping
const time = CACHE.lastTime || Date.now() / 3000;
shimmerPosition = (Math.sin(time) + 1) / 2;
}
// Add collapse button handler
if (node.flags.collapsed) {
// If node is collapsed, adjust the title rendering
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, titleHeight);
// Draw etched shadow for collapsed version
ctx.fillStyle = "rgba(0,0,0,0.3)";
ctx.font = "italic 11px Arial"; // Smaller font for collapsed state
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(collapsedEquation, width / 2 + 1, titleHeight / 2 + 1);
// Create base golden gradient for collapsed version
const baseGradient = ctx.createLinearGradient(0, titleHeight/2 - 5, 0, titleHeight/2 + 5);
baseGradient.addColorStop(0, "#B8860B"); // Darker gold
baseGradient.addColorStop(0.5, "#FFD700"); // Bright gold
baseGradient.addColorStop(1, "#B8860B"); // Darker gold
// Draw base golden text
ctx.fillStyle = baseGradient;
ctx.font = "italic 11px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(collapsedEquation, width / 2, titleHeight / 2);
// Create moving highlight effect for collapsed version
const highlightWidth = width * 0.4; // Width of the highlight
const highlightX = -highlightWidth + (width + highlightWidth) * shimmerPosition; // Adjusted range
const shimmerGradient = ctx.createLinearGradient(
highlightX - highlightWidth/2, 0,
highlightX + highlightWidth/2, 0
);
// Create smooth highlight transition
shimmerGradient.addColorStop(0, "rgba(255, 255, 200, 0)");
shimmerGradient.addColorStop(0.1, "rgba(255, 255, 200, 0)");
shimmerGradient.addColorStop(0.5, "rgba(255, 255, 200, 0.3)");
shimmerGradient.addColorStop(0.9, "rgba(255, 255, 200, 0)");
shimmerGradient.addColorStop(1, "rgba(255, 255, 200, 0)");
// Apply highlight
ctx.fillStyle = shimmerGradient;
ctx.fillText(collapsedEquation, width / 2, titleHeight / 2);
// Add outline glow that follows the highlight
const glowIntensity = Math.max(0, 1 - Math.abs(width/2 - highlightX)/(width/4));
ctx.shadowColor = `rgba(255, 255, 200, ${glowIntensity * 0.3})`;
ctx.shadowBlur = 4; // Less blur for collapsed version
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.fillText(collapsedEquation, width / 2, titleHeight / 2);
// Skip the rest of the rendering when collapsed
ctx.restore();
return;
}
// Draw background that fills the entire node
ctx.fillStyle = gradient;
// Use rounded rectangle for the background with rounded corners at the bottom
if (!node.flags.collapsed) {
const cornerRadius = 8; // Adjust radius as needed
// Create path for rounded rectangle
ctx.beginPath();
ctx.moveTo(0, 0); // Top-left corner (no rounding)
ctx.lineTo(width, 0); // Top-right corner (no rounding)
ctx.lineTo(width, fullHeight - cornerRadius); // Right edge before bottom-right corner
ctx.arcTo(width, fullHeight, width - cornerRadius, fullHeight, cornerRadius); // Bottom-right rounded corner
ctx.lineTo(cornerRadius, fullHeight); // Bottom edge before bottom-left corner
ctx.arcTo(0, fullHeight, 0, fullHeight - cornerRadius, cornerRadius); // Bottom-left rounded corner
ctx.lineTo(0, 0); // Left edge back to top
ctx.closePath();
ctx.fill();
} else {
// Keep regular rectangle for collapsed state
ctx.fillRect(0, 0, width, fullHeight); // No extra padding
}
// Draw etched shadow
ctx.fillStyle = "rgba(0,0,0,0.3)";
ctx.font = "italic 14px Arial"; // Smaller font for equation
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(equation, width / 2 + 2, equationY + 2);
// Create base golden gradient
const baseGradient = ctx.createLinearGradient(0, equationY - 7, 0, equationY + 7);
baseGradient.addColorStop(0, "#B8860B"); // Darker gold
baseGradient.addColorStop(0.5, "#FFD700"); // Bright gold
baseGradient.addColorStop(1, "#B8860B"); // Darker gold
// Draw base golden text
ctx.fillStyle = baseGradient;
ctx.font = "italic 14px Arial"; // Smaller font for equation
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(equation, width / 2, equationY);
// Create moving highlight effect
const highlightWidth = width * 0.4; // Width of the highlight
const highlightX = -highlightWidth + (width + highlightWidth) * shimmerPosition; // Adjusted range
const shimmerGradient = ctx.createLinearGradient(
highlightX - highlightWidth/2, 0,
highlightX + highlightWidth/2, 0
);
// Create smooth highlight transition
shimmerGradient.addColorStop(0, "rgba(255, 255, 200, 0)");
shimmerGradient.addColorStop(0.1, "rgba(255, 255, 200, 0)");
shimmerGradient.addColorStop(0.5, "rgba(255, 255, 200, 0.3)");
shimmerGradient.addColorStop(0.9, "rgba(255, 255, 200, 0)");
shimmerGradient.addColorStop(1, "rgba(255, 255, 200, 0)");
// Apply highlight
ctx.fillStyle = shimmerGradient;
ctx.fillText(equation, width / 2, equationY);
// Add outline glow that follows the highlight
const glowIntensity = Math.max(0, 1 - Math.abs(width/2 - highlightX)/(width/4));
ctx.shadowColor = `rgba(255, 255, 200, ${glowIntensity * 0.3})`;
ctx.shadowBlur = 8;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.fillText(equation, width / 2, equationY);
// Restore context state
ctx.restore();
}