mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-11 02:20:08 +00:00
[refactor] Move thumbnail functionality to renderer/core domain (#5586)
Move thumbnail functionality from src/renderer/thumbnail/ to src/renderer/core/thumbnail/ to align with domain-driven design architecture. Thumbnail generation is core rendering infrastructure and belongs alongside other core renderer utilities. Changes: - Move useWorkflowThumbnail.ts and graphThumbnailRenderer.ts to renderer/core/thumbnail/ - Update all import paths in consuming files - Fix relative imports within moved files 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
64
src/renderer/core/thumbnail/graphThumbnailRenderer.ts
Normal file
64
src/renderer/core/thumbnail/graphThumbnailRenderer.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import type { LGraph } from '@/lib/litegraph/src/litegraph'
|
||||
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
|
||||
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
|
||||
import {
|
||||
calculateMinimapScale,
|
||||
calculateNodeBounds
|
||||
} from '@/renderer/core/spatial/boundsCalculator'
|
||||
|
||||
import { renderMinimapToCanvas } from '../../extensions/minimap/minimapCanvasRenderer'
|
||||
|
||||
/**
|
||||
* Create a thumbnail of the current canvas's active graph.
|
||||
* Used by workflow thumbnail generation.
|
||||
*/
|
||||
export function createGraphThumbnail(): string | null {
|
||||
const canvasStore = useCanvasStore()
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
||||
const graph = workflowStore.activeSubgraph || canvasStore.canvas?.graph
|
||||
if (!graph || !graph._nodes || graph._nodes.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const width = 250
|
||||
const height = 200
|
||||
|
||||
// Calculate bounds using spatial calculator
|
||||
const bounds = calculateNodeBounds(graph._nodes)
|
||||
if (!bounds) {
|
||||
return null
|
||||
}
|
||||
|
||||
const scale = calculateMinimapScale(bounds, width, height)
|
||||
|
||||
// Create detached canvas
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
|
||||
// Render the minimap
|
||||
renderMinimapToCanvas(canvas, graph as LGraph, {
|
||||
bounds,
|
||||
scale,
|
||||
settings: {
|
||||
nodeColors: true,
|
||||
showLinks: false,
|
||||
showGroups: true,
|
||||
renderBypass: false,
|
||||
renderError: false
|
||||
},
|
||||
width,
|
||||
height
|
||||
})
|
||||
|
||||
const dataUrl = canvas.toDataURL()
|
||||
|
||||
// Explicit cleanup (optional but good practice)
|
||||
const ctx = canvas.getContext('2d')
|
||||
if (ctx) {
|
||||
ctx.clearRect(0, 0, width, height)
|
||||
}
|
||||
|
||||
return dataUrl
|
||||
}
|
||||
90
src/renderer/core/thumbnail/useWorkflowThumbnail.ts
Normal file
90
src/renderer/core/thumbnail/useWorkflowThumbnail.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { ComfyWorkflow } from '@/platform/workflow/management/stores/workflowStore'
|
||||
|
||||
import { createGraphThumbnail } from './graphThumbnailRenderer'
|
||||
|
||||
// Store thumbnails for each workflow
|
||||
const workflowThumbnails = ref<Map<string, string>>(new Map())
|
||||
|
||||
export const useWorkflowThumbnail = () => {
|
||||
/**
|
||||
* Capture a thumbnail of the canvas
|
||||
*/
|
||||
const createMinimapPreview = (): Promise<string | null> => {
|
||||
try {
|
||||
const thumbnailDataUrl = createGraphThumbnail()
|
||||
return Promise.resolve(thumbnailDataUrl)
|
||||
} catch (error) {
|
||||
console.error('Failed to capture canvas thumbnail:', error)
|
||||
return Promise.resolve(null)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a thumbnail for a workflow
|
||||
*/
|
||||
const storeThumbnail = async (workflow: ComfyWorkflow) => {
|
||||
const thumbnail = await createMinimapPreview()
|
||||
if (thumbnail) {
|
||||
// Clean up existing thumbnail if it exists
|
||||
const existingThumbnail = workflowThumbnails.value.get(workflow.key)
|
||||
if (existingThumbnail) {
|
||||
URL.revokeObjectURL(existingThumbnail)
|
||||
}
|
||||
workflowThumbnails.value.set(workflow.key, thumbnail)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a thumbnail for a workflow
|
||||
*/
|
||||
const getThumbnail = (workflowKey: string): string | undefined => {
|
||||
return workflowThumbnails.value.get(workflowKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a thumbnail for a workflow
|
||||
*/
|
||||
const clearThumbnail = (workflowKey: string) => {
|
||||
const thumbnail = workflowThumbnails.value.get(workflowKey)
|
||||
if (thumbnail) {
|
||||
URL.revokeObjectURL(thumbnail)
|
||||
}
|
||||
workflowThumbnails.value.delete(workflowKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all thumbnails
|
||||
*/
|
||||
const clearAllThumbnails = () => {
|
||||
for (const thumbnail of workflowThumbnails.value.values()) {
|
||||
URL.revokeObjectURL(thumbnail)
|
||||
}
|
||||
workflowThumbnails.value.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a thumbnail from one workflow key to another (useful for workflow renaming)
|
||||
*/
|
||||
const moveWorkflowThumbnail = (oldKey: string, newKey: string) => {
|
||||
// Don't do anything if moving to the same key
|
||||
if (oldKey === newKey) return
|
||||
|
||||
const thumbnail = workflowThumbnails.value.get(oldKey)
|
||||
if (thumbnail) {
|
||||
workflowThumbnails.value.set(newKey, thumbnail)
|
||||
workflowThumbnails.value.delete(oldKey)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
createMinimapPreview,
|
||||
storeThumbnail,
|
||||
getThumbnail,
|
||||
clearThumbnail,
|
||||
clearAllThumbnails,
|
||||
moveWorkflowThumbnail,
|
||||
workflowThumbnails
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user