Skip to content

Commit 344afa2

Browse files
jtydhr88github-actionschristian-byrne
authored
minimap (#4520)
Co-authored-by: github-actions <[email protected]> Co-authored-by: Christian Byrne <[email protected]>
1 parent ab8bcc9 commit 344afa2

31 files changed

+2044
-1
lines changed
416 Bytes
Loading
466 Bytes
Loading

browser_tests/tests/interaction.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,11 @@ test.describe('Viewport settings', () => {
768768
comfyMouse
769769
}) => {
770770
// Screenshot the canvas element
771+
await comfyPage.setSetting('Comfy.Graph.CanvasMenu', true)
772+
const toggleButton = comfyPage.page.getByTestId('toggle-minimap-button')
773+
774+
await toggleButton.click()
775+
771776
await comfyPage.menu.topbar.saveWorkflow('Workflow A')
772777
await comfyPage.nextFrame()
773778
const screenshotA = (await comfyPage.canvas.screenshot()).toString('base64')
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { expect } from '@playwright/test'
2+
3+
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
4+
5+
test.describe('Minimap', () => {
6+
test.beforeEach(async ({ comfyPage }) => {
7+
await comfyPage.setSetting('Comfy.UseNewMenu', 'Top')
8+
await comfyPage.setSetting('Comfy.Minimap.Visible', true)
9+
await comfyPage.setSetting('Comfy.Graph.CanvasMenu', true)
10+
await comfyPage.loadWorkflow('default')
11+
await comfyPage.page.waitForFunction(
12+
() => window['app'] && window['app'].canvas
13+
)
14+
})
15+
16+
test('Validate minimap is visible by default', async ({ comfyPage }) => {
17+
const minimapContainer = comfyPage.page.locator('.litegraph-minimap')
18+
19+
await expect(minimapContainer).toBeVisible()
20+
21+
const minimapCanvas = minimapContainer.locator('.minimap-canvas')
22+
await expect(minimapCanvas).toBeVisible()
23+
24+
const minimapViewport = minimapContainer.locator('.minimap-viewport')
25+
await expect(minimapViewport).toBeVisible()
26+
27+
await expect(minimapContainer).toHaveCSS('position', 'absolute')
28+
await expect(minimapContainer).toHaveCSS('z-index', '1000')
29+
})
30+
31+
test('Validate minimap toggle button state', async ({ comfyPage }) => {
32+
const toggleButton = comfyPage.page.getByTestId('toggle-minimap-button')
33+
34+
await expect(toggleButton).toBeVisible()
35+
36+
await expect(toggleButton).toHaveClass(/minimap-active/)
37+
38+
const minimapContainer = comfyPage.page.locator('.litegraph-minimap')
39+
await expect(minimapContainer).toBeVisible()
40+
})
41+
42+
test('Validate minimap can be toggled off and on', async ({ comfyPage }) => {
43+
const minimapContainer = comfyPage.page.locator('.litegraph-minimap')
44+
const toggleButton = comfyPage.page.getByTestId('toggle-minimap-button')
45+
46+
await expect(minimapContainer).toBeVisible()
47+
await expect(toggleButton).toHaveClass(/minimap-active/)
48+
49+
await toggleButton.click()
50+
await comfyPage.nextFrame()
51+
52+
await expect(minimapContainer).not.toBeVisible()
53+
await expect(toggleButton).not.toHaveClass(/minimap-active/)
54+
55+
await toggleButton.click()
56+
await comfyPage.nextFrame()
57+
58+
await expect(minimapContainer).toBeVisible()
59+
await expect(toggleButton).toHaveClass(/minimap-active/)
60+
})
61+
62+
test('Validate minimap keyboard shortcut Alt+M', async ({ comfyPage }) => {
63+
const minimapContainer = comfyPage.page.locator('.litegraph-minimap')
64+
65+
await expect(minimapContainer).toBeVisible()
66+
67+
await comfyPage.page.keyboard.press('Alt+KeyM')
68+
await comfyPage.nextFrame()
69+
70+
await expect(minimapContainer).not.toBeVisible()
71+
72+
await comfyPage.page.keyboard.press('Alt+KeyM')
73+
await comfyPage.nextFrame()
74+
75+
await expect(minimapContainer).toBeVisible()
76+
})
77+
})

src/components/graph/GraphCanvas.vue

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
/>
1919
</div>
2020
<GraphCanvasMenu v-if="canvasMenuEnabled" class="pointer-events-auto" />
21+
22+
<MiniMap
23+
v-if="comfyAppReady && minimapEnabled"
24+
ref="minimapRef"
25+
class="pointer-events-auto"
26+
/>
2127
</template>
2228
</LiteGraphCanvasSplitterOverlay>
2329
<GraphCanvasMenu v-if="!betaMenuEnabled && canvasMenuEnabled" />
@@ -51,6 +57,7 @@ import LiteGraphCanvasSplitterOverlay from '@/components/LiteGraphCanvasSplitter
5157
import BottomPanel from '@/components/bottomPanel/BottomPanel.vue'
5258
import DomWidgets from '@/components/graph/DomWidgets.vue'
5359
import GraphCanvasMenu from '@/components/graph/GraphCanvasMenu.vue'
60+
import MiniMap from '@/components/graph/MiniMap.vue'
5461
import NodeTooltip from '@/components/graph/NodeTooltip.vue'
5562
import SelectionOverlay from '@/components/graph/SelectionOverlay.vue'
5663
import SelectionToolbox from '@/components/graph/SelectionToolbox.vue'
@@ -65,6 +72,7 @@ import { useContextMenuTranslation } from '@/composables/useContextMenuTranslati
6572
import { useCopy } from '@/composables/useCopy'
6673
import { useGlobalLitegraph } from '@/composables/useGlobalLitegraph'
6774
import { useLitegraphSettings } from '@/composables/useLitegraphSettings'
75+
import { useMinimap } from '@/composables/useMinimap'
6876
import { usePaste } from '@/composables/usePaste'
6977
import { useWorkflowAutoSave } from '@/composables/useWorkflowAutoSave'
7078
import { useWorkflowPersistence } from '@/composables/useWorkflowPersistence'
@@ -111,6 +119,10 @@ const selectionToolboxEnabled = computed(() =>
111119
settingStore.get('Comfy.Canvas.SelectionToolbox')
112120
)
113121
122+
const minimapRef = ref<InstanceType<typeof MiniMap>>()
123+
const minimapEnabled = computed(() => settingStore.get('Comfy.Minimap.Visible'))
124+
const minimap = useMinimap()
125+
114126
watchEffect(() => {
115127
nodeDefStore.showDeprecated = settingStore.get('Comfy.Node.ShowDeprecated')
116128
})
@@ -346,6 +358,13 @@ onMounted(async () => {
346358
}
347359
)
348360
361+
whenever(
362+
() => minimapRef.value,
363+
(ref) => {
364+
minimap.setMinimapRef(ref)
365+
}
366+
)
367+
349368
whenever(
350369
() => useCanvasStore().canvas,
351370
(canvas) => {

src/components/graph/GraphCanvasMenu.vue

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@
5656
data-testid="toggle-link-visibility-button"
5757
@click="() => commandStore.execute('Comfy.Canvas.ToggleLinkVisibility')"
5858
/>
59+
<Button
60+
v-tooltip.left="t('graphCanvasMenu.toggleMinimap') + ' (Alt + m)'"
61+
severity="secondary"
62+
:icon="'pi pi-map'"
63+
:aria-label="$t('graphCanvasMenu.toggleMinimap')"
64+
:class="{ 'minimap-active': minimapVisible }"
65+
data-testid="toggle-minimap-button"
66+
@click="() => commandStore.execute('Comfy.Canvas.ToggleMinimap')"
67+
/>
5968
</ButtonGroup>
6069
</template>
6170

@@ -75,6 +84,7 @@ const commandStore = useCommandStore()
7584
const canvasStore = useCanvasStore()
7685
const settingStore = useSettingStore()
7786
87+
const minimapVisible = computed(() => settingStore.get('Comfy.Minimap.Visible'))
7888
const linkHidden = computed(
7989
() => settingStore.get('Comfy.LinkRenderMode') === LiteGraph.HIDDEN_LINK
8090
)
@@ -107,4 +117,15 @@ const stopRepeat = () => {
107117
margin: 0;
108118
border-radius: 0;
109119
}
120+
121+
.p-button.minimap-active {
122+
background-color: var(--p-button-primary-background);
123+
border-color: var(--p-button-primary-border-color);
124+
color: var(--p-button-primary-color);
125+
}
126+
127+
.p-button.minimap-active:hover {
128+
background-color: var(--p-button-primary-hover-background);
129+
border-color: var(--p-button-primary-hover-border-color);
130+
}
110131
</style>

src/components/graph/MiniMap.vue

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<template>
2+
<div
3+
v-if="visible && initialized"
4+
ref="containerRef"
5+
class="litegraph-minimap absolute bottom-[20px] right-[90px] z-[1000]"
6+
:style="containerStyles"
7+
@mousedown="handleMouseDown"
8+
@mousemove="handleMouseMove"
9+
@mouseup="handleMouseUp"
10+
@mouseleave="handleMouseUp"
11+
@wheel="handleWheel"
12+
>
13+
<canvas
14+
ref="canvasRef"
15+
:width="width"
16+
:height="height"
17+
class="minimap-canvas"
18+
/>
19+
<div class="minimap-viewport" :style="viewportStyles" />
20+
</div>
21+
</template>
22+
23+
<script setup lang="ts">
24+
import { onMounted, onUnmounted, watch } from 'vue'
25+
26+
import { useMinimap } from '@/composables/useMinimap'
27+
import { useCanvasStore } from '@/stores/graphStore'
28+
29+
const minimap = useMinimap()
30+
const canvasStore = useCanvasStore()
31+
32+
const {
33+
initialized,
34+
visible,
35+
containerRef,
36+
canvasRef,
37+
containerStyles,
38+
viewportStyles,
39+
width,
40+
height,
41+
init,
42+
destroy,
43+
handleMouseDown,
44+
handleMouseMove,
45+
handleMouseUp,
46+
handleWheel
47+
} = minimap
48+
49+
watch(
50+
() => canvasStore.canvas,
51+
async (canvas) => {
52+
if (canvas && !initialized.value) {
53+
await init()
54+
}
55+
},
56+
{ immediate: true }
57+
)
58+
59+
onMounted(async () => {
60+
if (canvasStore.canvas) {
61+
await init()
62+
}
63+
})
64+
65+
onUnmounted(() => {
66+
destroy()
67+
})
68+
</script>
69+
70+
<style scoped>
71+
.litegraph-minimap {
72+
overflow: hidden;
73+
}
74+
75+
.minimap-canvas {
76+
display: block;
77+
width: 100%;
78+
height: 100%;
79+
pointer-events: none;
80+
}
81+
82+
.minimap-viewport {
83+
position: absolute;
84+
top: 0;
85+
left: 0;
86+
pointer-events: none;
87+
}
88+
</style>

0 commit comments

Comments
 (0)