mirror of
https://github.com/Azornes/Comfyui-LayerForge.git
synced 2026-03-21 12:52:10 -03:00
Add documentation for core modules and update Canvas.js
Added documentation files for ComfyApi, ComfyApp, LitegraphService, and MaskEditor, summarizing their main functions and usage. Refactored js/Canvas.js to improve mask processing logic, using viewport pan for cropping and applying mask color only to non-transparent pixels. Also made minor formatting and logging consistency improvements throughout Canvas.js.
This commit is contained in:
96
Doc/ComfyApi
Normal file
96
Doc/ComfyApi
Normal file
@@ -0,0 +1,96 @@
|
||||
# ComfyApi - Function Documentation Summary import { api } from "../../scripts/api.js";
|
||||
|
||||
## Basic Information
|
||||
|
||||
ComfyApi is a class for communication with ComfyUI backend via WebSocket and REST API.
|
||||
|
||||
## Main Functions:
|
||||
|
||||
### Connection and Initialization
|
||||
|
||||
- constructor() - Initializes API, sets host and base path
|
||||
- init() - Starts WebSocket connection for real-time updates
|
||||
- #createSocket() - Creates and manages WebSocket connection
|
||||
|
||||
### URL Management
|
||||
|
||||
- internalURL(route) - Generates URL for internal endpoints
|
||||
- apiURL(route) - Generates URL for public API endpoints
|
||||
- fileURL(route) - Generates URL for static files
|
||||
- fetchApi(route, options) - Performs HTTP requests with automatic user headers
|
||||
|
||||
### Event Handling
|
||||
|
||||
- addEventListener(type, callback) - Listens for API events (status, executing, progress, etc.)
|
||||
- removeEventListener(type, callback) - Removes event listeners
|
||||
- dispatchCustomEvent(type, detail) - Emits custom events
|
||||
|
||||
### Queue and Prompt Management
|
||||
|
||||
- queuePrompt(number, data) - Adds prompt to execution queue
|
||||
- getQueue() - Gets current queue state (Running/Pending)
|
||||
- interrupt() - Interrupts currently executing prompt
|
||||
- clearItems(type) - Clears queue or history
|
||||
- deleteItem(type, id) - Removes item from queue or history
|
||||
|
||||
### History and Statistics
|
||||
|
||||
- getHistory(max_items) - Gets history of executed prompts
|
||||
- getSystemStats() - Gets system statistics (Python, OS, GPU, etc.)
|
||||
- getLogs() - Gets system logs
|
||||
- getRawLogs() - Gets raw logs
|
||||
- subscribeLogs(enabled) - Enables/disables log subscription
|
||||
|
||||
### Model and Resource Management
|
||||
|
||||
- getNodeDefs(options) - Gets definitions of available nodes
|
||||
- getExtensions() - List of installed extensions
|
||||
- getEmbeddings() - List of available embeddings
|
||||
- getModelFolders() - List of model folders
|
||||
- getModels(folder) - List of models in given folder
|
||||
- viewMetadata(folder, model) - Metadata of specific model
|
||||
|
||||
### Workflow Templates
|
||||
|
||||
- getWorkflowTemplates() - Gets workflow templates from custom nodes
|
||||
- getCoreWorkflowTemplates() - Gets core workflow templates
|
||||
|
||||
### User Management
|
||||
|
||||
- getUserConfig() - Gets user configuration
|
||||
- createUser(username) - Creates new user
|
||||
- getSettings() - Gets all user settings
|
||||
- getSetting(id) - Gets specific setting
|
||||
- storeSettings(settings) - Saves settings dictionary
|
||||
- storeSetting(id, value) - Saves single setting
|
||||
|
||||
### User Data
|
||||
|
||||
- getUserData(file) - Gets user data file
|
||||
- storeUserData(file, data, options) - Saves user data
|
||||
- deleteUserData(file) - Deletes user data file
|
||||
- moveUserData(source, dest) - Moves data file
|
||||
- listUserDataFullInfo(dir) - Lists files with full information
|
||||
|
||||
### Other
|
||||
|
||||
- getFolderPaths() - Gets system folder paths
|
||||
- getCustomNodesI18n() - Gets internationalization data for custom nodes
|
||||
|
||||
## Important Properties
|
||||
|
||||
- clientId - Client ID from WebSocket
|
||||
- authToken - Authorization token for ComfyOrg account
|
||||
- apiKey - API key for ComfyOrg account
|
||||
- socket - Active WebSocket connection
|
||||
|
||||
## WebSocket Event Types
|
||||
|
||||
- status - System status
|
||||
- executing - Currently executing node
|
||||
- progress - Execution progress
|
||||
- executed - Node executed
|
||||
- execution_start/success/error/interrupted/cached - Execution events
|
||||
- logs - System logs
|
||||
- b_preview - Image preview (binary)
|
||||
- reconnecting/reconnected - Connection events
|
||||
72
Doc/ComfyApp
Normal file
72
Doc/ComfyApp
Normal file
@@ -0,0 +1,72 @@
|
||||
## __Main ComfyApp Functions__ import { app, ComfyApp } from "../../scripts/app.js";
|
||||
|
||||
### __Application Management__
|
||||
|
||||
- `setup(canvasEl)` - Initializes the application on the page, loads extensions, registers nodes
|
||||
- `resizeCanvas()` - Adjusts canvas size to window
|
||||
- `clean()` - Clears application state (node outputs, image previews, errors)
|
||||
|
||||
### __Workflow Management__
|
||||
|
||||
- `loadGraphData(graphData, clean, restore_view, workflow, options)` - Loads workflow data from JSON
|
||||
- `loadApiJson(apiData, fileName)` - Loads workflow from API format
|
||||
- `graphToPrompt(graph, options)` - Converts graph to prompt for execution
|
||||
- `handleFile(file)` - Handles file loading (PNG, WebP, JSON, MP3, MP4, SVG, etc.)
|
||||
|
||||
### __Execution__
|
||||
|
||||
- `queuePrompt(number, batchCount, queueNodeIds)` - Queues prompt for execution
|
||||
- `registerNodes()` - Registers node definitions from backend
|
||||
- `registerNodeDef(nodeId, nodeDef)` - Registers single node definition
|
||||
- `refreshComboInNodes()` - Refreshes combo lists in nodes
|
||||
|
||||
### __Node Management__
|
||||
|
||||
- `registerExtension(extension)` - Registers ComfyUI extension
|
||||
- `updateVueAppNodeDefs(defs)` - Updates node definitions in Vue app
|
||||
- `revokePreviews(nodeId)` - Frees memory for node previews
|
||||
|
||||
### __Clipboard__
|
||||
|
||||
- `copyToClipspace(node)` - Copies node to clipboard
|
||||
- `pasteFromClipspace(node)` - Pastes data from clipboard to node
|
||||
|
||||
### __Position Conversion__
|
||||
|
||||
- `clientPosToCanvasPos(pos)` - Converts client position to canvas position
|
||||
- `canvasPosToClientPos(pos)` - Converts canvas position to client position
|
||||
|
||||
### __Error Handling__
|
||||
|
||||
- `showErrorOnFileLoad(file)` - Displays file loading error
|
||||
- `#showMissingNodesError(missingNodeTypes)` - Shows missing nodes error
|
||||
- `#showMissingModelsError(missingModels, paths)` - Shows missing models error
|
||||
|
||||
### __Internal Handlers__
|
||||
|
||||
- `#addDropHandler()` - Handles drag and drop of files
|
||||
- `#addProcessKeyHandler()` - Handles keyboard input
|
||||
- `#addDrawNodeHandler()` - Modifies node drawing behavior
|
||||
- `#addApiUpdateHandlers()` - Handles API updates
|
||||
- `#addConfigureHandler()` - Graph configuration flag
|
||||
- `#addAfterConfigureHandler()` - Post-configuration handling
|
||||
|
||||
### __Deprecated Properties__
|
||||
|
||||
Many properties are marked as deprecated and redirect to appropriate stores:
|
||||
|
||||
- `lastNodeErrors` → `useExecutionStore().lastNodeErrors`
|
||||
- `lastExecutionError` → `useExecutionStore().lastExecutionError`
|
||||
- `runningNodeId` → `useExecutionStore().executingNodeId`
|
||||
- `shiftDown` → `useWorkspaceStore().shiftDown`
|
||||
- `widgets` → `useWidgetStore().widgets`
|
||||
- `extensions` → `useExtensionStore().extensions`
|
||||
|
||||
### __Utility Functions__
|
||||
|
||||
- `sanitizeNodeName(string)` - Cleans node name from dangerous characters
|
||||
- `getPreviewFormatParam()` - Returns preview format parameter
|
||||
- `getRandParam()` - Returns random parameter for refresh
|
||||
- `isApiJson(data)` - Checks if data is in API JSON format
|
||||
|
||||
This application uses Vue and TypeScript composition pattern, where many functionalities are separated into different services and stores (e.g., `useExecutionStore`, `useWorkflowService`, `useExtensionService`, etc.).
|
||||
75
Doc/LitegraphService
Normal file
75
Doc/LitegraphService
Normal file
@@ -0,0 +1,75 @@
|
||||
LitegraphService Documentation
|
||||
|
||||
Main functions of useLitegraphService()
|
||||
|
||||
Node Registration and Creation Functions:
|
||||
|
||||
registerNodeDef(nodeId: string, nodeDefV1: ComfyNodeDefV1)
|
||||
|
||||
- Registers node definition in LiteGraph system
|
||||
- Creates ComfyNode class with inputs, outputs and widgets
|
||||
- Adds context menu, background drawing and keyboard handling
|
||||
- Invokes extensions before registration
|
||||
|
||||
addNodeOnGraph(nodeDef, options)
|
||||
|
||||
- Adds new node to graph at specified position
|
||||
- By default places node at canvas center
|
||||
|
||||
Navigation and View Functions:
|
||||
|
||||
getCanvasCenter(): Vector2
|
||||
|
||||
- Returns canvas center coordinates accounting for DPI
|
||||
|
||||
goToNode(nodeId: NodeId)
|
||||
|
||||
- Animates transition to specified node on canvas
|
||||
|
||||
resetView()
|
||||
|
||||
- Resets canvas view to default settings (scale 1, offset [0,0])
|
||||
|
||||
fitView()
|
||||
|
||||
- Fits canvas view to show all nodes
|
||||
|
||||
Node Handling Functions (internal):
|
||||
|
||||
addNodeContextMenuHandler(node)
|
||||
|
||||
- Adds context menu with options:
|
||||
|
||||
- Open/Copy/Save image (for image nodes)
|
||||
- Bypass node
|
||||
- Copy/Paste to Clipspace
|
||||
- Open in MaskEditor (for image nodes)
|
||||
|
||||
addDrawBackgroundHandler(node)
|
||||
|
||||
- Adds node background drawing logic
|
||||
- Handles image, animation and video previews
|
||||
- Manages thumbnail display
|
||||
|
||||
addNodeKeyHandler(node)
|
||||
|
||||
- Adds keyboard handling:
|
||||
|
||||
- Left/Right arrows: navigate between images
|
||||
- Escape: close image preview
|
||||
|
||||
ComfyNode Class (created by registerNodeDef):
|
||||
|
||||
Main methods:
|
||||
|
||||
- #addInputs() - adds inputs and widgets to node
|
||||
- #addOutputs() - adds outputs to node
|
||||
- configure() - configures node from serialized data
|
||||
- #setupStrokeStyles() - sets border styles (errors, execution, etc.)
|
||||
|
||||
Properties:
|
||||
|
||||
- comfyClass - ComfyUI class name
|
||||
- nodeData - node definition
|
||||
- Automatic yellow coloring for API nodes
|
||||
|
||||
76
Doc/MaskEditor
Normal file
76
Doc/MaskEditor
Normal file
@@ -0,0 +1,76 @@
|
||||
MASKEDITOR.TS FUNCTION DOCUMENTATION
|
||||
|
||||
MaskEditorDialog - Main mask editor class
|
||||
|
||||
- getInstance() - Singleton pattern, returns editor instance
|
||||
- show() - Opens the mask editor
|
||||
- save() - Saves mask to server
|
||||
- destroy() - Closes and cleans up editor
|
||||
- isOpened() - Checks if editor is open
|
||||
|
||||
CanvasHistory - Change history management
|
||||
|
||||
- saveState() - Saves current canvas state
|
||||
- undo() - Undo last operation
|
||||
- redo() - Redo undone operation
|
||||
- clearStates() - Clears history
|
||||
|
||||
BrushTool - Brush tool
|
||||
|
||||
- setBrushSize(size) - Sets brush size
|
||||
- setBrushOpacity(opacity) - Sets brush opacity
|
||||
- setBrushHardness(hardness) - Sets brush hardness
|
||||
- setBrushType(type) - Sets brush shape (circle/square)
|
||||
- startDrawing() - Starts drawing
|
||||
- handleDrawing() - Handles drawing during movement
|
||||
- drawEnd() - Ends drawing
|
||||
|
||||
PaintBucketTool - Fill tool
|
||||
|
||||
- floodFill(point) - Fills area with color from point
|
||||
- setTolerance(tolerance) - Sets color tolerance
|
||||
- setFillOpacity(opacity) - Sets fill opacity
|
||||
- invertMask() - Inverts mask
|
||||
|
||||
ColorSelectTool - Color selection tool
|
||||
|
||||
- fillColorSelection(point) - Selects similar colors
|
||||
- setTolerance(tolerance) - Sets selection tolerance
|
||||
- setLivePreview(enabled) - Enables/disables live preview
|
||||
- setComparisonMethod(method) - Sets color comparison method
|
||||
- setApplyWholeImage(enabled) - Applies to whole image
|
||||
- setSelectOpacity(opacity) - Sets selection opacity
|
||||
|
||||
UIManager - Interface management
|
||||
|
||||
- updateBrushPreview() - Updates brush preview
|
||||
- setBrushVisibility(visible) - Shows/hides brush
|
||||
- screenToCanvas(coords) - Converts screen coordinates to canvas
|
||||
- getMaskColor() - Returns mask color
|
||||
- setSaveButtonEnabled(enabled) - Enables/disables save button
|
||||
|
||||
ToolManager - Tool management
|
||||
|
||||
- setTool(tool) - Sets active tool
|
||||
- getCurrentTool() - Returns active tool
|
||||
- handlePointerDown/Move/Up() - Handles mouse/touch events
|
||||
|
||||
PanAndZoomManager - View management
|
||||
|
||||
- zoom(event) - Zooms in/out canvas
|
||||
- handlePanStart/Move() - Handles canvas panning
|
||||
- initializeCanvasPanZoom() - Initializes canvas view
|
||||
- smoothResetView() - Smoothly resets view
|
||||
|
||||
MessageBroker - Communication system
|
||||
|
||||
- publish(topic, data) - Publishes message
|
||||
- subscribe(topic, callback) - Subscribes to topic
|
||||
- pull(topic, data) - Pulls data from topic
|
||||
- createPullTopic/PushTopic() - Creates communication topics
|
||||
|
||||
KeyboardManager - Keyboard handling
|
||||
|
||||
- addListeners() - Adds keyboard listeners
|
||||
- removeListeners() - Removes listeners
|
||||
- isKeyDown(key) - Checks if key is pressed
|
||||
78
js/Canvas.js
78
js/Canvas.js
@@ -26,7 +26,7 @@ export class Canvas {
|
||||
this.node = node;
|
||||
this.widget = widget;
|
||||
this.canvas = document.createElement('canvas');
|
||||
this.ctx = this.canvas.getContext('2d', { willReadFrequently: true });
|
||||
this.ctx = this.canvas.getContext('2d', {willReadFrequently: true});
|
||||
this.width = 512;
|
||||
this.height = 512;
|
||||
this.layers = [];
|
||||
@@ -60,7 +60,7 @@ export class Canvas {
|
||||
log.debug('Canvas widget element:', this.node);
|
||||
log.info('Canvas initialized', {
|
||||
nodeId: this.node.id,
|
||||
dimensions: { width: this.width, height: this.height },
|
||||
dimensions: {width: this.width, height: this.height},
|
||||
viewport: this.viewport
|
||||
});
|
||||
|
||||
@@ -187,7 +187,7 @@ export class Canvas {
|
||||
* @param {boolean} replaceLast - Czy zastąpić ostatni stan w historii
|
||||
*/
|
||||
saveState(replaceLast = false) {
|
||||
log.debug('Saving canvas state', { replaceLast, layersCount: this.layers.length });
|
||||
log.debug('Saving canvas state', {replaceLast, layersCount: this.layers.length});
|
||||
this.canvasState.saveState(replaceLast);
|
||||
this.incrementOperationCount();
|
||||
this._notifyStateChange();
|
||||
@@ -683,7 +683,7 @@ export class Canvas {
|
||||
throw new Error("Old mask editor canvas not found");
|
||||
}
|
||||
|
||||
const maskCtx = maskCanvas.getContext('2d', { willReadFrequently: true });
|
||||
const maskCtx = maskCanvas.getContext('2d', {willReadFrequently: true});
|
||||
|
||||
const maskColor = {r: 255, g: 255, b: 255};
|
||||
const processedMask = await this.processMaskForEditor(maskData, maskCanvas.width, maskCanvas.height, maskColor);
|
||||
@@ -699,59 +699,58 @@ export class Canvas {
|
||||
* @param {number} targetHeight - Docelowa wysokość
|
||||
* @param {Object} maskColor - Kolor maski {r, g, b}
|
||||
* @returns {HTMLCanvasElement} Przetworzona maska
|
||||
*/
|
||||
async processMaskForEditor(maskData, targetWidth, targetHeight, maskColor) {
|
||||
const originalWidth = maskData.width || maskData.naturalWidth || this.width;
|
||||
const originalHeight = maskData.height || maskData.naturalHeight || this.height;
|
||||
*/async processMaskForEditor(maskData, targetWidth, targetHeight, maskColor) {
|
||||
// Współrzędne przesunięcia (pan) widoku edytora
|
||||
const panX = this.maskTool.x;
|
||||
const panY = this.maskTool.y;
|
||||
|
||||
log.info("Processing mask for editor:", {
|
||||
originalSize: {width: originalWidth, height: originalHeight},
|
||||
sourceSize: {width: maskData.width, height: maskData.height},
|
||||
targetSize: {width: targetWidth, height: targetHeight},
|
||||
canvasSize: {width: this.width, height: this.height}
|
||||
viewportPan: {x: panX, y: panY}
|
||||
});
|
||||
|
||||
const tempCanvas = document.createElement('canvas');
|
||||
tempCanvas.width = targetWidth;
|
||||
tempCanvas.height = targetHeight;
|
||||
const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true });
|
||||
const tempCtx = tempCanvas.getContext('2d', {willReadFrequently: true});
|
||||
|
||||
tempCtx.clearRect(0, 0, targetWidth, targetHeight);
|
||||
const sourceX = -panX;
|
||||
const sourceY = -panY;
|
||||
|
||||
tempCtx.drawImage(
|
||||
maskData, // Źródło: pełna maska z "output area"
|
||||
sourceX, // sx: Prawdziwa współrzędna X na dużej masce (np. 1000)
|
||||
sourceY, // sy: Prawdziwa współrzędna Y na dużej masce (np. 1000)
|
||||
targetWidth, // sWidth: Szerokość wycinanego fragmentu
|
||||
targetHeight, // sHeight: Wysokość wycinanego fragmentu
|
||||
0, // dx: Gdzie wkleić w płótnie docelowym (zawsze 0)
|
||||
0, // dy: Gdzie wkleić w płótnie docelowym (zawsze 0)
|
||||
targetWidth, // dWidth: Szerokość wklejanego obrazu
|
||||
targetHeight // dHeight: Wysokość wklejanego obrazu
|
||||
);
|
||||
|
||||
const scaleToOriginal = Math.min(originalWidth / this.width, originalHeight / this.height);
|
||||
|
||||
const scaledWidth = this.width * scaleToOriginal;
|
||||
const scaledHeight = this.height * scaleToOriginal;
|
||||
|
||||
const offsetX = (targetWidth - scaledWidth) / 2;
|
||||
const offsetY = (targetHeight - scaledHeight) / 2;
|
||||
|
||||
tempCtx.drawImage(maskData, offsetX, offsetY, scaledWidth, scaledHeight);
|
||||
|
||||
log.info("Mask drawn scaled to original image size:", {
|
||||
originalSize: {width: originalWidth, height: originalHeight},
|
||||
targetSize: {width: targetWidth, height: targetHeight},
|
||||
canvasSize: {width: this.width, height: this.height},
|
||||
scaleToOriginal: scaleToOriginal,
|
||||
finalSize: {width: scaledWidth, height: scaledHeight},
|
||||
offset: {x: offsetX, y: offsetY}
|
||||
log.info("Mask viewport cropped correctly.", {
|
||||
source: "maskData",
|
||||
cropArea: {x: sourceX, y: sourceY, width: targetWidth, height: targetHeight}
|
||||
});
|
||||
|
||||
// Reszta kodu (zmiana koloru) pozostaje bez zmian
|
||||
const imageData = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||
const data = imageData.data;
|
||||
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
const alpha = data[i + 3]; // Oryginalny kanał alpha
|
||||
|
||||
data[i] = maskColor.r; // R
|
||||
data[i + 1] = maskColor.g; // G
|
||||
data[i + 2] = maskColor.b; // B
|
||||
data[i + 3] = alpha; // Zachowaj oryginalny alpha
|
||||
const alpha = data[i + 3];
|
||||
if (alpha > 0) {
|
||||
data[i] = maskColor.r;
|
||||
data[i + 1] = maskColor.g;
|
||||
data[i + 2] = maskColor.b;
|
||||
}
|
||||
}
|
||||
|
||||
tempCtx.putImageData(imageData, 0, 0);
|
||||
|
||||
log.info("Mask processing completed - full size scaling applied");
|
||||
log.info("Mask processing completed - color applied.");
|
||||
return tempCanvas;
|
||||
}
|
||||
|
||||
@@ -784,6 +783,7 @@ export class Canvas {
|
||||
setTimeout(this.waitWhileMaskEditing.bind(this), 100);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zapisuje obecny stan maski przed otwarciem editora
|
||||
* @returns {Object} Zapisany stan maski
|
||||
@@ -797,7 +797,7 @@ export class Canvas {
|
||||
const savedCanvas = document.createElement('canvas');
|
||||
savedCanvas.width = maskCanvas.width;
|
||||
savedCanvas.height = maskCanvas.height;
|
||||
const savedCtx = savedCanvas.getContext('2d', { willReadFrequently: true });
|
||||
const savedCtx = savedCanvas.getContext('2d', {willReadFrequently: true});
|
||||
savedCtx.drawImage(maskCanvas, 0, 0);
|
||||
|
||||
return {
|
||||
@@ -893,7 +893,7 @@ export class Canvas {
|
||||
const tempCanvas = document.createElement('canvas');
|
||||
tempCanvas.width = this.width;
|
||||
tempCanvas.height = this.height;
|
||||
const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true });
|
||||
const tempCtx = tempCanvas.getContext('2d', {willReadFrequently: true});
|
||||
|
||||
tempCtx.drawImage(resultImage, 0, 0, this.width, this.height);
|
||||
|
||||
@@ -920,7 +920,7 @@ export class Canvas {
|
||||
const destX = -this.maskTool.x;
|
||||
const destY = -this.maskTool.y;
|
||||
|
||||
log.debug("Applying mask to canvas", { destX, destY });
|
||||
log.debug("Applying mask to canvas", {destX, destY});
|
||||
|
||||
maskCtx.globalCompositeOperation = 'source-over';
|
||||
maskCtx.clearRect(destX, destY, this.width, this.height);
|
||||
|
||||
Reference in New Issue
Block a user