[feat] fully replicate LiteGraph drawNode color logic in Vue nodes

Now correctly implements all aspects of the LiteGraph drawNode monkey patch:

1. Header colors: Apply opacity + lightness adjustments like LiteGraph
2. Body colors: Apply same adjustments to background as LiteGraph
3. Opacity setting: Support 'Comfy.Node.Opacity' setting from user preferences
4. Light theme: Apply lightness=0.5 to both header and body in light theme

This ensures Vue nodes have pixel-perfect color matching with LiteGraph nodes
across all themes and opacity settings.
This commit is contained in:
bymyself
2025-09-27 10:52:00 -07:00
parent e83ffadeb8
commit 42c130d071
2 changed files with 54 additions and 10 deletions

View File

@@ -35,7 +35,7 @@
{
transform: `translate(${position.x ?? 0}px, ${(position.y ?? 0) - LiteGraph.NODE_TITLE_HEIGHT}px)`,
zIndex: zIndex,
backgroundColor: nodeData.bgcolor || ''
backgroundColor: nodeBodyBackgroundColor
},
dragStyle
]"
@@ -145,6 +145,7 @@ import type { VueNodeData } from '@/composables/graph/useGraphNodeManager'
import { toggleNodeOptions } from '@/composables/graph/useMoreOptionsMenu'
import { useErrorHandling } from '@/composables/useErrorHandling'
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions'
import { TransformStateKey } from '@/renderer/core/layout/injectionKeys'
@@ -157,6 +158,8 @@ import { useNodePreviewState } from '@/renderer/extensions/vueNodes/preview/useN
import { app } from '@/scripts/app'
import { useExecutionStore } from '@/stores/executionStore'
import { useNodeOutputStore } from '@/stores/imagePreviewStore'
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
import { adjustColor } from '@/utils/colorUtil'
import {
getLocatorIdFromNodeData,
getNodeByLocatorId
@@ -227,6 +230,37 @@ const hasAnyError = computed((): boolean => {
const bypassed = computed((): boolean => nodeData.mode === 4)
const muted = computed((): boolean => nodeData.mode === 2) // NEVER mode
// Node body background color that exactly replicates LiteGraph's drawNode logic
const nodeBodyBackgroundColor = computed(() => {
const colorPaletteStore = useColorPaletteStore()
const settingStore = useSettingStore()
// This replicates the drawNode logic for bgColor
let bgColor = nodeData.bgcolor || '' // matches: old_bgcolor || LiteGraph.NODE_DEFAULT_BGCOLOR
if (!bgColor) return '' // No color to adjust
// Apply the exact same adjustments as the drawNode monkey patch
const adjustments: { lightness?: number; opacity?: number } = {}
// 1. Apply opacity setting (same as drawNode)
const opacity = settingStore.get('Comfy.Node.Opacity')
if (opacity) adjustments.opacity = opacity
// 2. Apply light theme background lightening (same as drawNode)
if (colorPaletteStore.completedActivePalette.light_theme) {
// This matches: "if (old_bgcolor) adjustments.lightness = 0.5"
adjustments.lightness = 0.5
}
// Apply all adjustments at once: node.bgcolor = adjustColor(bgColor, adjustments)
if (Object.keys(adjustments).length > 0) {
bgColor = adjustColor(bgColor, adjustments)
}
return bgColor
})
// Use canvas interactions for proper wheel event handling and pointer event capture control
const { handleWheel, shouldHandleNodePointerEvents } = useCanvasInteractions()

View File

@@ -72,6 +72,7 @@ import EditableText from '@/components/common/EditableText.vue'
import type { VueNodeData } from '@/composables/graph/useGraphNodeManager'
import { useErrorHandling } from '@/composables/useErrorHandling'
import { st } from '@/i18n'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useNodeTooltips } from '@/renderer/extensions/vueNodes/composables/useNodeTooltips'
import { app } from '@/scripts/app'
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
@@ -126,25 +127,34 @@ const tooltipConfig = computed(() => {
return createTooltipConfig(description)
})
// Header style that replicates LiteGraph's ColorOption and drawNode logic
// Header style that exactly replicates LiteGraph's drawNode monkey patch logic
const headerStyle = computed(() => {
if (!nodeData?.color) {
return { backgroundColor: '' } // Explicitly clear background color
}
const colorPaletteStore = useColorPaletteStore()
const settingStore = useSettingStore()
// Start with the original color (same as old_color in drawNode)
let headerColor = nodeData.color
// Apply base header darkening to replicate LiteGraph's ColorOption system
// When header and body colors are the same/similar, darken the header
if (nodeData.bgcolor && nodeData.color === nodeData.bgcolor) {
// Darken header relative to body (opposite of light theme adjustment)
headerColor = adjustColor(nodeData.color, { lightness: -0.15 })
// Apply the exact same adjustments as the drawNode monkey patch
const adjustments: { lightness?: number; opacity?: number } = {}
// 1. Apply opacity setting (same as drawNode)
const opacity = settingStore.get('Comfy.Node.Opacity')
if (opacity) adjustments.opacity = opacity
// 2. Apply light theme adjustments (same as drawNode)
if (colorPaletteStore.completedActivePalette.light_theme) {
// This matches: "if (old_color) { node.color = adjustColor(old_color, { lightness: 0.5 }) }"
adjustments.lightness = 0.5
}
// Apply light theme lightening on top of base darkening (same as drawNode monkey patch)
if (colorPaletteStore.completedActivePalette.light_theme) {
headerColor = adjustColor(headerColor, { lightness: 0.5 })
// Apply all adjustments at once (matching drawNode's approach)
if (Object.keys(adjustments).length > 0) {
headerColor = adjustColor(headerColor, adjustments)
}
return { backgroundColor: headerColor }