diff --git a/browser_tests/tests/minimap.spec.ts b/browser_tests/tests/minimap.spec.ts
index 9275107cb2..366a6634d5 100644
--- a/browser_tests/tests/minimap.spec.ts
+++ b/browser_tests/tests/minimap.spec.ts
@@ -24,8 +24,14 @@ test.describe('Minimap', () => {
const minimapViewport = minimapContainer.locator('.minimap-viewport')
await expect(minimapViewport).toBeVisible()
- await expect(minimapContainer).toHaveCSS('position', 'absolute')
- await expect(minimapContainer).toHaveCSS('z-index', '1000')
+ await expect(minimapContainer).toHaveCSS('position', 'relative')
+
+ // position and z-index validation moved to the parent container of the minimap
+ const minimapMainContainer = comfyPage.page.locator(
+ '.minimap-main-container'
+ )
+ await expect(minimapMainContainer).toHaveCSS('position', 'absolute')
+ await expect(minimapMainContainer).toHaveCSS('z-index', '1000')
})
test('Validate minimap toggle button state', async ({ comfyPage }) => {
diff --git a/src/components/graph/MiniMap.vue b/src/components/graph/MiniMap.vue
index 2e0fb1a3c1..0e47595f02 100644
--- a/src/components/graph/MiniMap.vue
+++ b/src/components/graph/MiniMap.vue
@@ -1,39 +1,68 @@
diff --git a/src/composables/useMinimap.ts b/src/composables/useMinimap.ts
index 6eada5b6c2..c329769c41 100644
--- a/src/composables/useMinimap.ts
+++ b/src/composables/useMinimap.ts
@@ -2,13 +2,14 @@ import { useRafFn, useThrottleFn } from '@vueuse/core'
import { computed, nextTick, ref, watch } from 'vue'
import { useCanvasTransformSync } from '@/composables/canvas/useCanvasTransformSync'
-import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
+import { LGraphEventMode, LGraphNode } from '@/lib/litegraph/src/litegraph'
import type { NodeId } from '@/schemas/comfyWorkflowSchema'
import { api } from '@/scripts/api'
import { app } from '@/scripts/app'
import { useCanvasStore } from '@/stores/graphStore'
import { useSettingStore } from '@/stores/settingStore'
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
+import { adjustColor } from '@/utils/colorUtil'
interface GraphCallbacks {
onNodeAdded?: (node: LGraphNode) => void
@@ -16,6 +17,13 @@ interface GraphCallbacks {
onConnectionChange?: (node: LGraphNode) => void
}
+export type MinimapOptionKey =
+ | 'Comfy.Minimap.NodeColors'
+ | 'Comfy.Minimap.ShowLinks'
+ | 'Comfy.Minimap.ShowGroups'
+ | 'Comfy.Minimap.RenderBypassState'
+ | 'Comfy.Minimap.RenderErrorState'
+
export function useMinimap() {
const settingStore = useSettingStore()
const canvasStore = useCanvasStore()
@@ -27,6 +35,27 @@ export function useMinimap() {
const visible = ref(true)
+ const nodeColors = computed(() =>
+ settingStore.get('Comfy.Minimap.NodeColors')
+ )
+ const showLinks = computed(() => settingStore.get('Comfy.Minimap.ShowLinks'))
+ const showGroups = computed(() =>
+ settingStore.get('Comfy.Minimap.ShowGroups')
+ )
+ const renderBypass = computed(() =>
+ settingStore.get('Comfy.Minimap.RenderBypassState')
+ )
+ const renderError = computed(() =>
+ settingStore.get('Comfy.Minimap.RenderErrorState')
+ )
+
+ const updateOption = async (key: MinimapOptionKey, value: boolean) => {
+ await settingStore.set(key, value)
+
+ needsFullRedraw.value = true
+ updateMinimap()
+ }
+
const initialized = ref(false)
const bounds = ref({
minX: 0,
@@ -63,10 +92,19 @@ export function useMinimap() {
const nodeColor = computed(
() => (isLightTheme.value ? '#3DA8E099' : '#0B8CE999') // lighter blue for light theme
)
+ const nodeColorDefault = computed(
+ () => (isLightTheme.value ? '#D9D9D9' : '#353535') // this is the default node color when using nodeColors setting
+ )
const linkColor = computed(
- () => (isLightTheme.value ? '#FFB347' : '#F99614') // lighter orange for light theme
+ () => (isLightTheme.value ? '#616161' : '#B3B3B3') // lighter orange for light theme
)
const slotColor = computed(() => linkColor.value)
+ const groupColor = computed(() =>
+ isLightTheme.value ? '#A2D3EC' : '#1F547A'
+ )
+ const bypassColor = computed(() =>
+ isLightTheme.value ? '#DBDBDB' : '#4B184B'
+ )
const containerRect = ref({
left: 0,
@@ -116,6 +154,14 @@ export function useMinimap() {
borderRadius: '8px'
}))
+ const panelStyles = computed(() => ({
+ width: `210px`,
+ height: `${height}px`,
+ backgroundColor: isLightTheme.value ? '#FAF9F5' : '#15161C',
+ border: `1px solid ${isLightTheme.value ? '#ccc' : '#333'}`,
+ borderRadius: '8px'
+ }))
+
const viewportStyles = computed(() => ({
transform: `translate(${viewportTransform.value.x}px, ${viewportTransform.value.y}px)`,
width: `${viewportTransform.value.width}px`,
@@ -189,6 +235,25 @@ export function useMinimap() {
return Math.min(scaleX, scaleY) * 0.9
}
+ const renderGroups = (
+ ctx: CanvasRenderingContext2D,
+ offsetX: number,
+ offsetY: number
+ ) => {
+ const g = graph.value
+ if (!g || !g._groups || g._groups.length === 0) return
+
+ for (const group of g._groups) {
+ const x = (group.pos[0] - bounds.value.minX) * scale.value + offsetX
+ const y = (group.pos[1] - bounds.value.minY) * scale.value + offsetY
+ const w = group.size[0] * scale.value
+ const h = group.size[1] * scale.value
+
+ ctx.fillStyle = groupColor.value
+ ctx.fillRect(x, y, w, h)
+ }
+ }
+
const renderNodes = (
ctx: CanvasRenderingContext2D,
offsetX: number,
@@ -203,9 +268,29 @@ export function useMinimap() {
const w = node.size[0] * scale.value
const h = node.size[1] * scale.value
+ let color = nodeColor.value
+
+ if (renderBypass.value && node.mode === LGraphEventMode.BYPASS) {
+ color = bypassColor.value
+ } else if (nodeColors.value) {
+ color = nodeColorDefault.value
+
+ if (node.bgcolor) {
+ color = isLightTheme.value
+ ? adjustColor(node.bgcolor, { lightness: 0.5 })
+ : node.bgcolor
+ }
+ }
+
// Render solid node blocks
- ctx.fillStyle = nodeColor.value
+ ctx.fillStyle = color
ctx.fillRect(x, y, w, h)
+
+ if (renderError.value && node.has_errors) {
+ ctx.strokeStyle = '#FF0000'
+ ctx.lineWidth = 0.3
+ ctx.strokeRect(x, y, w, h)
+ }
}
}
@@ -218,9 +303,9 @@ export function useMinimap() {
if (!g) return
ctx.strokeStyle = linkColor.value
- ctx.lineWidth = 1.4
+ ctx.lineWidth = 0.3
- const slotRadius = 3.7 * Math.max(scale.value, 0.5) // Larger slots that scale
+ const slotRadius = Math.max(scale.value, 0.5) // Larger slots that scale
const connections: Array<{
x1: number
y1: number
@@ -304,8 +389,15 @@ export function useMinimap() {
const offsetX = (width - bounds.value.width * scale.value) / 2
const offsetY = (height - bounds.value.height * scale.value) / 2
+ if (showGroups.value) {
+ renderGroups(ctx, offsetX, offsetY)
+ }
+
+ if (showLinks.value) {
+ renderConnections(ctx, offsetX, offsetY)
+ }
+
renderNodes(ctx, offsetX, offsetY)
- renderConnections(ctx, offsetX, offsetY)
needsFullRedraw.value = false
updateFlags.value.nodes = false
@@ -690,9 +782,16 @@ export function useMinimap() {
canvasRef,
containerStyles,
viewportStyles,
+ panelStyles,
width,
height,
+ nodeColors,
+ showLinks,
+ showGroups,
+ renderBypass,
+ renderError,
+
init,
destroy,
toggle,
@@ -701,6 +800,7 @@ export function useMinimap() {
handlePointerMove,
handlePointerUp,
handleWheel,
- setMinimapRef
+ setMinimapRef,
+ updateOption
}
}
diff --git a/src/constants/coreSettings.ts b/src/constants/coreSettings.ts
index 0765bf61a7..621d6b38c6 100644
--- a/src/constants/coreSettings.ts
+++ b/src/constants/coreSettings.ts
@@ -830,6 +830,41 @@ export const CORE_SETTINGS: SettingParams[] = [
defaultValue: true,
versionAdded: '1.25.0'
},
+ {
+ id: 'Comfy.Minimap.NodeColors',
+ name: 'Display node with its original color on minimap',
+ type: 'hidden',
+ defaultValue: false,
+ versionAdded: '1.26.0'
+ },
+ {
+ id: 'Comfy.Minimap.ShowLinks',
+ name: 'Display links on minimap',
+ type: 'hidden',
+ defaultValue: true,
+ versionAdded: '1.26.0'
+ },
+ {
+ id: 'Comfy.Minimap.ShowGroups',
+ name: 'Display node groups on minimap',
+ type: 'hidden',
+ defaultValue: true,
+ versionAdded: '1.26.0'
+ },
+ {
+ id: 'Comfy.Minimap.RenderBypassState',
+ name: 'Render bypass state on minimap',
+ type: 'hidden',
+ defaultValue: true,
+ versionAdded: '1.26.0'
+ },
+ {
+ id: 'Comfy.Minimap.RenderErrorState',
+ name: 'Render error state on minimap',
+ type: 'hidden',
+ defaultValue: true,
+ versionAdded: '1.26.0'
+ },
{
id: 'Comfy.Workflow.AutoSaveDelay',
name: 'Auto Save Delay (ms)',
diff --git a/src/locales/en/main.json b/src/locales/en/main.json
index 891a50402a..cfd240d21f 100644
--- a/src/locales/en/main.json
+++ b/src/locales/en/main.json
@@ -1647,5 +1647,12 @@
"view": "View",
"panelControls": "Panel Controls"
}
+ },
+ "minimap": {
+ "nodeColors": "Node Colors",
+ "showLinks": "Show Links",
+ "showGroups": "Show Frames/Groups",
+ "renderBypassState": "Render Bypass State",
+ "renderErrorState": "Render Error State"
}
}
\ No newline at end of file
diff --git a/src/locales/es/main.json b/src/locales/es/main.json
index c168c0e36e..4803c6c757 100644
--- a/src/locales/es/main.json
+++ b/src/locales/es/main.json
@@ -831,6 +831,13 @@
"Zoom In": "Acercar",
"Zoom Out": "Alejar"
},
+ "minimap": {
+ "nodeColors": "Colores de nodos",
+ "renderBypassState": "Mostrar estado de omisión",
+ "renderErrorState": "Mostrar estado de error",
+ "showGroups": "Mostrar marcos/grupos",
+ "showLinks": "Mostrar enlaces"
+ },
"missingModelsDialog": {
"doNotAskAgain": "No mostrar esto de nuevo",
"missingModels": "Modelos faltantes",
diff --git a/src/locales/fr/main.json b/src/locales/fr/main.json
index 5bf0434137..f04336fcc9 100644
--- a/src/locales/fr/main.json
+++ b/src/locales/fr/main.json
@@ -831,6 +831,13 @@
"Zoom In": "Zoom avant",
"Zoom Out": "Zoom arrière"
},
+ "minimap": {
+ "nodeColors": "Couleurs des nœuds",
+ "renderBypassState": "Afficher l’état de contournement",
+ "renderErrorState": "Afficher l’état d’erreur",
+ "showGroups": "Afficher les cadres/groupes",
+ "showLinks": "Afficher les liens"
+ },
"missingModelsDialog": {
"doNotAskAgain": "Ne plus afficher ce message",
"missingModels": "Modèles manquants",
diff --git a/src/locales/ja/main.json b/src/locales/ja/main.json
index 739c86491a..73a4f904c5 100644
--- a/src/locales/ja/main.json
+++ b/src/locales/ja/main.json
@@ -831,6 +831,13 @@
"Zoom In": "ズームイン",
"Zoom Out": "ズームアウト"
},
+ "minimap": {
+ "nodeColors": "ノードの色",
+ "renderBypassState": "バイパス状態を表示",
+ "renderErrorState": "エラー状態を表示",
+ "showGroups": "フレーム/グループを表示",
+ "showLinks": "リンクを表示"
+ },
"missingModelsDialog": {
"doNotAskAgain": "再度表示しない",
"missingModels": "モデルが見つかりません",
diff --git a/src/locales/ko/main.json b/src/locales/ko/main.json
index 25ec517383..ec0999a0b2 100644
--- a/src/locales/ko/main.json
+++ b/src/locales/ko/main.json
@@ -831,6 +831,13 @@
"Zoom In": "확대",
"Zoom Out": "축소"
},
+ "minimap": {
+ "nodeColors": "노드 색상",
+ "renderBypassState": "바이패스 상태 렌더링",
+ "renderErrorState": "에러 상태 렌더링",
+ "showGroups": "프레임/그룹 표시",
+ "showLinks": "링크 표시"
+ },
"missingModelsDialog": {
"doNotAskAgain": "다시 보지 않기",
"missingModels": "모델이 없습니다",
diff --git a/src/locales/ru/main.json b/src/locales/ru/main.json
index dd222dc2f2..ae4599a86b 100644
--- a/src/locales/ru/main.json
+++ b/src/locales/ru/main.json
@@ -831,6 +831,13 @@
"Zoom In": "Увеличить",
"Zoom Out": "Уменьшить"
},
+ "minimap": {
+ "nodeColors": "Цвета узлов",
+ "renderBypassState": "Отображать состояние обхода",
+ "renderErrorState": "Отображать состояние ошибки",
+ "showGroups": "Показать фреймы/группы",
+ "showLinks": "Показать связи"
+ },
"missingModelsDialog": {
"doNotAskAgain": "Больше не показывать это",
"missingModels": "Отсутствующие модели",
diff --git a/src/locales/zh-TW/main.json b/src/locales/zh-TW/main.json
index 47edf5bb8a..d27f38f935 100644
--- a/src/locales/zh-TW/main.json
+++ b/src/locales/zh-TW/main.json
@@ -831,6 +831,13 @@
"Zoom In": "放大",
"Zoom Out": "縮小"
},
+ "minimap": {
+ "nodeColors": "節點顏色",
+ "renderBypassState": "顯示繞過狀態",
+ "renderErrorState": "顯示錯誤狀態",
+ "showGroups": "顯示框架/群組",
+ "showLinks": "顯示連結"
+ },
"missingModelsDialog": {
"doNotAskAgain": "不要再顯示此訊息",
"missingModels": "缺少模型",
diff --git a/src/locales/zh/main.json b/src/locales/zh/main.json
index 189eb1f913..72c8e4d743 100644
--- a/src/locales/zh/main.json
+++ b/src/locales/zh/main.json
@@ -831,6 +831,13 @@
"Zoom In": "放大画面",
"Zoom Out": "缩小画面"
},
+ "minimap": {
+ "nodeColors": "節點顏色",
+ "renderBypassState": "顯示繞過狀態",
+ "renderErrorState": "顯示錯誤狀態",
+ "showGroups": "顯示框架/群組",
+ "showLinks": "顯示連結"
+ },
"missingModelsDialog": {
"doNotAskAgain": "不再显示此消息",
"missingModels": "缺少模型",
diff --git a/src/schemas/apiSchema.ts b/src/schemas/apiSchema.ts
index 887d165379..7c90292656 100644
--- a/src/schemas/apiSchema.ts
+++ b/src/schemas/apiSchema.ts
@@ -471,6 +471,11 @@ const zSettings = z.object({
'Comfy.InstalledVersion': z.string().nullable(),
'Comfy.Node.AllowImageSizeDraw': z.boolean(),
'Comfy.Minimap.Visible': z.boolean(),
+ 'Comfy.Minimap.NodeColors': z.boolean(),
+ 'Comfy.Minimap.ShowLinks': z.boolean(),
+ 'Comfy.Minimap.ShowGroups': z.boolean(),
+ 'Comfy.Minimap.RenderBypassState': z.boolean(),
+ 'Comfy.Minimap.RenderErrorState': z.boolean(),
'Comfy.Canvas.NavigationMode': z.string(),
'Comfy-Desktop.AutoUpdate': z.boolean(),
'Comfy-Desktop.SendStatistics': z.boolean(),