add CanvasNavigationMode (#4533)

Co-authored-by: bymyself <cbyrne@comfy.org>
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Terry Jia
2025-07-25 22:01:43 -04:00
committed by GitHub
parent 271643aa93
commit e3628ed156
24 changed files with 297 additions and 46 deletions

View File

@@ -803,3 +803,222 @@ test.describe('Viewport settings', () => {
)
})
})
test.describe('Canvas Navigation', () => {
test.describe('Legacy Mode', () => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.Canvas.NavigationMode', 'legacy')
})
test('Left-click drag in empty area should pan canvas', async ({
comfyPage
}) => {
await comfyPage.dragAndDrop({ x: 50, y: 50 }, { x: 150, y: 150 })
await expect(comfyPage.canvas).toHaveScreenshot(
'legacy-left-drag-pan.png'
)
})
test('Middle-click drag should pan canvas', async ({ comfyPage }) => {
await comfyPage.page.mouse.move(50, 50)
await comfyPage.page.mouse.down({ button: 'middle' })
await comfyPage.page.mouse.move(150, 150)
await comfyPage.page.mouse.up({ button: 'middle' })
await comfyPage.nextFrame()
await expect(comfyPage.canvas).toHaveScreenshot(
'legacy-middle-drag-pan.png'
)
})
test('Mouse wheel should zoom in/out', async ({ comfyPage }) => {
await comfyPage.page.mouse.move(400, 300)
await comfyPage.page.mouse.wheel(0, -120)
await comfyPage.nextFrame()
await expect(comfyPage.canvas).toHaveScreenshot(
'legacy-wheel-zoom-in.png'
)
await comfyPage.page.mouse.wheel(0, 240)
await comfyPage.nextFrame()
await expect(comfyPage.canvas).toHaveScreenshot(
'legacy-wheel-zoom-out.png'
)
})
test('Left-click on node should not pan canvas', async ({ comfyPage }) => {
await comfyPage.clickTextEncodeNode1()
const selectedCount = await comfyPage.getSelectedGraphNodesCount()
expect(selectedCount).toBe(1)
await expect(comfyPage.canvas).toHaveScreenshot(
'legacy-click-node-select.png'
)
})
})
test.describe('Standard Mode', () => {
test.beforeEach(async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.Canvas.NavigationMode', 'standard')
})
test('Left-click drag in empty area should select nodes', async ({
comfyPage
}) => {
const clipNodes = await comfyPage.getNodeRefsByType('CLIPTextEncode')
const clipNode1Pos = await clipNodes[0].getPosition()
const clipNode2Pos = await clipNodes[1].getPosition()
const offset = 64
await comfyPage.dragAndDrop(
{
x: Math.min(clipNode1Pos.x, clipNode2Pos.x) - offset,
y: Math.min(clipNode1Pos.y, clipNode2Pos.y) - offset
},
{
x: Math.max(clipNode1Pos.x, clipNode2Pos.x) + offset,
y: Math.max(clipNode1Pos.y, clipNode2Pos.y) + offset
}
)
const selectedCount = await comfyPage.getSelectedGraphNodesCount()
expect(selectedCount).toBe(clipNodes.length)
await expect(comfyPage.canvas).toHaveScreenshot(
'standard-left-drag-select.png'
)
})
test('Middle-click drag should pan canvas', async ({ comfyPage }) => {
await comfyPage.page.mouse.move(50, 50)
await comfyPage.page.mouse.down({ button: 'middle' })
await comfyPage.page.mouse.move(150, 150)
await comfyPage.page.mouse.up({ button: 'middle' })
await comfyPage.nextFrame()
await expect(comfyPage.canvas).toHaveScreenshot(
'standard-middle-drag-pan.png'
)
})
test('Ctrl + mouse wheel should zoom in/out', async ({ comfyPage }) => {
await comfyPage.page.mouse.move(400, 300)
await comfyPage.page.keyboard.down('Control')
await comfyPage.page.mouse.wheel(0, -120)
await comfyPage.page.keyboard.up('Control')
await comfyPage.nextFrame()
await expect(comfyPage.canvas).toHaveScreenshot(
'standard-ctrl-wheel-zoom-in.png'
)
await comfyPage.page.keyboard.down('Control')
await comfyPage.page.mouse.wheel(0, 240)
await comfyPage.page.keyboard.up('Control')
await comfyPage.nextFrame()
await expect(comfyPage.canvas).toHaveScreenshot(
'standard-ctrl-wheel-zoom-out.png'
)
})
test('Left-click on node should select node (not start selection box)', async ({
comfyPage
}) => {
await comfyPage.clickTextEncodeNode1()
const selectedCount = await comfyPage.getSelectedGraphNodesCount()
expect(selectedCount).toBe(1)
await expect(comfyPage.canvas).toHaveScreenshot(
'standard-click-node-select.png'
)
})
test('Space + left-click drag should pan canvas', async ({ comfyPage }) => {
// Click canvas to focus it
await comfyPage.page.click('canvas')
await comfyPage.nextFrame()
await comfyPage.page.keyboard.down('Space')
await comfyPage.dragAndDrop({ x: 50, y: 50 }, { x: 150, y: 150 })
await comfyPage.page.keyboard.up('Space')
await expect(comfyPage.canvas).toHaveScreenshot(
'standard-space-drag-pan.png'
)
})
test('Space key overrides default left-click behavior', async ({
comfyPage
}) => {
const clipNodes = await comfyPage.getNodeRefsByType('CLIPTextEncode')
const clipNode1Pos = await clipNodes[0].getPosition()
const offset = 64
await comfyPage.dragAndDrop(
{
x: clipNode1Pos.x - offset,
y: clipNode1Pos.y - offset
},
{
x: clipNode1Pos.x + offset,
y: clipNode1Pos.y + offset
}
)
const selectedCountAfterDrag =
await comfyPage.getSelectedGraphNodesCount()
expect(selectedCountAfterDrag).toBeGreaterThan(0)
await comfyPage.clickEmptySpace()
const selectedCountAfterClear =
await comfyPage.getSelectedGraphNodesCount()
expect(selectedCountAfterClear).toBe(0)
await comfyPage.page.keyboard.down('Space')
await comfyPage.dragAndDrop(
{
x: clipNode1Pos.x - offset,
y: clipNode1Pos.y - offset
},
{
x: clipNode1Pos.x + offset,
y: clipNode1Pos.y + offset
}
)
await comfyPage.page.keyboard.up('Space')
const selectedCountAfterSpaceDrag =
await comfyPage.getSelectedGraphNodesCount()
expect(selectedCountAfterSpaceDrag).toBe(0)
})
})
test.describe('Edge Cases', () => {
test('Multiple modifier keys work correctly in legacy mode', async ({
comfyPage
}) => {
await comfyPage.setSetting('Comfy.Canvas.NavigationMode', 'legacy')
await comfyPage.page.keyboard.down('Alt')
await comfyPage.page.keyboard.down('Shift')
await comfyPage.dragAndDrop({ x: 50, y: 50 }, { x: 150, y: 150 })
await comfyPage.page.keyboard.up('Shift')
await comfyPage.page.keyboard.up('Alt')
await expect(comfyPage.canvas).toHaveScreenshot(
'legacy-alt-shift-drag.png'
)
})
test('Cursor changes appropriately in different modes', async ({
comfyPage
}) => {
const getCursorStyle = async () => {
return await comfyPage.page.evaluate(() => {
return (
document.getElementById('graph-canvas')!.style.cursor || 'default'
)
})
}
await comfyPage.setSetting('Comfy.Canvas.NavigationMode', 'legacy')
await comfyPage.page.mouse.move(50, 50)
await comfyPage.page.mouse.down()
expect(await getCursorStyle()).toBe('grabbing')
await comfyPage.page.mouse.up()
})
})
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View File

@@ -124,9 +124,12 @@ export const useLitegraphSettings = () => {
})
watchEffect(() => {
LiteGraph.macTrackpadGestures = settingStore.get(
'LiteGraph.Pointer.TrackpadGestures'
)
const navigationMode = settingStore.get('Comfy.Canvas.NavigationMode') as
| 'standard'
| 'legacy'
LiteGraph.canvasNavigationMode = navigationMode
LiteGraph.macTrackpadGestures = navigationMode === 'standard'
})
watchEffect(() => {

View File

@@ -782,6 +782,21 @@ export const CORE_SETTINGS: SettingParams[] = [
defaultValue: 0.6,
versionAdded: '1.9.1'
},
{
id: 'Comfy.Canvas.NavigationMode',
category: ['LiteGraph', 'Canvas', 'CanvasNavigationMode'],
name: 'Canvas Navigation Mode',
defaultValue: 'legacy',
type: 'combo',
options: [
{ value: 'standard', text: 'Standard (New)' },
{ value: 'legacy', text: 'Left-Click Pan (Legacy)' }
],
versionAdded: '1.25.0',
defaultsByInstallVersion: {
'1.25.0': 'standard'
}
},
{
id: 'Comfy.Canvas.SelectionToolbox',
category: ['LiteGraph', 'Canvas', 'SelectionToolbox'],
@@ -852,17 +867,6 @@ export const CORE_SETTINGS: SettingParams[] = [
versionAdded: '1.20.4',
versionModified: '1.20.5'
},
{
id: 'LiteGraph.Pointer.TrackpadGestures',
category: ['LiteGraph', 'Pointer', 'Trackpad Gestures'],
experimental: true,
name: 'Enable trackpad gestures',
tooltip:
'This setting enables trackpad mode for the canvas, allowing pinch-to-zoom and panning with two fingers.',
type: 'boolean',
defaultValue: false,
versionAdded: '1.19.1'
},
// Release data stored in settings
{
id: 'Comfy.Release.Version',

View File

@@ -29,6 +29,13 @@
"name": "Canvas background image",
"tooltip": "Image URL for the canvas background. You can right-click an image in the outputs panel and select \"Set as Background\" to use it, or upload your own image using the upload button."
},
"Comfy_Canvas_NavigationMode": {
"name": "Canvas Navigation Mode",
"options": {
"Standard (New)": "Standard (New)",
"Left-Click Pan (Legacy)": "Left-Click Pan (Legacy)"
}
},
"Comfy_Canvas_SelectionToolbox": {
"name": "Show selection toolbox"
},
@@ -395,10 +402,6 @@
"LiteGraph_Node_TooltipDelay": {
"name": "Tooltip Delay"
},
"LiteGraph_Pointer_TrackpadGestures": {
"name": "Enable trackpad gestures",
"tooltip": "This setting enables trackpad mode for the canvas, allowing pinch-to-zoom and panning with two fingers."
},
"LiteGraph_Reroute_SplineOffset": {
"name": "Reroute spline offset",
"tooltip": "The bezier control point offset from the reroute centre point"

View File

@@ -29,6 +29,13 @@
"name": "Imagen de fondo del lienzo",
"tooltip": "URL de la imagen para el fondo del lienzo. Puedes hacer clic derecho en una imagen del panel de resultados y seleccionar \"Establecer como fondo\" para usarla."
},
"Comfy_Canvas_NavigationMode": {
"name": "Modo de navegación del lienzo",
"options": {
"Left-Click Pan (Legacy)": "Desplazamiento con clic izquierdo (Legado)",
"Standard (New)": "Estándar (Nuevo)"
}
},
"Comfy_Canvas_SelectionToolbox": {
"name": "Mostrar caja de herramientas de selección"
},
@@ -395,10 +402,6 @@
"LiteGraph_Node_TooltipDelay": {
"name": "Retraso de la información sobre herramientas"
},
"LiteGraph_Pointer_TrackpadGestures": {
"name": "Habilitar gestos del trackpad",
"tooltip": "Esta configuración activa el modo trackpad para el lienzo, permitiendo hacer zoom con pellizco y desplazar con dos dedos."
},
"LiteGraph_Reroute_SplineOffset": {
"name": "Desvío de la compensación de la spline",
"tooltip": "El punto de control bezier desplazado desde el punto central de reenrutamiento"

View File

@@ -29,6 +29,13 @@
"name": "Image de fond du canevas",
"tooltip": "URL de l'image pour le fond du canevas. Vous pouvez faire un clic droit sur une image dans le panneau de sortie et sélectionner « Définir comme fond » pour l'utiliser."
},
"Comfy_Canvas_NavigationMode": {
"name": "Mode de navigation sur le canvas",
"options": {
"Left-Click Pan (Legacy)": "Panoramique clic gauche (Hérité)",
"Standard (New)": "Standard (Nouveau)"
}
},
"Comfy_Canvas_SelectionToolbox": {
"name": "Afficher la boîte à outils de sélection"
},
@@ -395,10 +402,6 @@
"LiteGraph_Node_TooltipDelay": {
"name": "Délai d'infobulle"
},
"LiteGraph_Pointer_TrackpadGestures": {
"name": "Activer les gestes du trackpad",
"tooltip": "Ce paramètre active le mode trackpad pour le canevas, permettant le zoom par pincement et le déplacement à deux doigts."
},
"LiteGraph_Reroute_SplineOffset": {
"name": "Réacheminement décalage de spline",
"tooltip": "Le point de contrôle de Bézier est décalé par rapport au point central de réacheminement"

View File

@@ -29,6 +29,13 @@
"name": "キャンバス背景画像",
"tooltip": "キャンバスの背景画像のURLです。出力パネルで画像を右クリックし、「背景として設定」を選択すると使用できます。"
},
"Comfy_Canvas_NavigationMode": {
"name": "キャンバスナビゲーションモード",
"options": {
"Left-Click Pan (Legacy)": "左クリックパン(レガシー)",
"Standard (New)": "標準(新)"
}
},
"Comfy_Canvas_SelectionToolbox": {
"name": "選択ツールボックスを表示"
},
@@ -395,10 +402,6 @@
"LiteGraph_Node_TooltipDelay": {
"name": "ツールチップ遅延"
},
"LiteGraph_Pointer_TrackpadGestures": {
"name": "トラックパッドジェスチャーを有効にする",
"tooltip": "この設定を有効にすると、キャンバスでトラックパッドモードが有効になり、ピンチズームや2本指でのパン操作が可能になります。"
},
"LiteGraph_Reroute_SplineOffset": {
"name": "リルートスプラインオフセット",
"tooltip": "リルート中心点からのベジエ制御点のオフセット"

View File

@@ -29,6 +29,13 @@
"name": "캔버스 배경 이미지",
"tooltip": "캔버스 배경에 사용할 이미지 URL입니다. 출력 패널에서 이미지를 마우스 오른쪽 버튼으로 클릭한 후 \"배경으로 설정\"을 선택해 사용할 수 있습니다."
},
"Comfy_Canvas_NavigationMode": {
"name": "캔버스 내비게이션 모드",
"options": {
"Left-Click Pan (Legacy)": "왼쪽 클릭 이동(레거시)",
"Standard (New)": "표준(신규)"
}
},
"Comfy_Canvas_SelectionToolbox": {
"name": "선택 도구 상자 표시"
},
@@ -395,10 +402,6 @@
"LiteGraph_Node_TooltipDelay": {
"name": "툴팁 지연"
},
"LiteGraph_Pointer_TrackpadGestures": {
"name": "트랙패드 제스처 활성화",
"tooltip": "이 설정을 켜면 캔버스에서 트랙패드 모드를 사용할 수 있으며, 두 손가락으로 확대/축소 및 이동이 가능합니다."
},
"LiteGraph_Reroute_SplineOffset": {
"name": "경유점 스플라인 오프셋",
"tooltip": "경유점 중심에서 베지어 제어점까지의 오프셋"

View File

@@ -29,6 +29,13 @@
"name": "Фоновое изображение холста",
"tooltip": "URL изображения для фона холста. Вы можете кликнуть правой кнопкой мыши на изображении в панели результатов и выбрать «Установить как фон», чтобы использовать его."
},
"Comfy_Canvas_NavigationMode": {
"name": "Режим навигации по холсту",
"options": {
"Left-Click Pan (Legacy)": "Перемещение левой кнопкой (устаревший)",
"Standard (New)": "Стандартный (новый)"
}
},
"Comfy_Canvas_SelectionToolbox": {
"name": "Показать панель инструментов выбора"
},
@@ -395,10 +402,6 @@
"LiteGraph_Node_TooltipDelay": {
"name": "Задержка всплывающей подсказки"
},
"LiteGraph_Pointer_TrackpadGestures": {
"name": "Включить жесты трекпада",
"tooltip": "Эта настройка включает режим трекпада для холста, позволяя использовать масштабирование щипком и панорамирование двумя пальцами."
},
"LiteGraph_Reroute_SplineOffset": {
"name": "Перераспределение смещения сплайна",
"tooltip": "Смещение контрольной точки Безье от центральной точки перераспределения"

View File

@@ -29,6 +29,13 @@
"name": "畫布背景圖片",
"tooltip": "畫布背景的圖片網址。你可以在輸出面板中右鍵點擊圖片並選擇「設為背景」來使用,或是使用上傳按鈕上傳你自己的圖片。"
},
"Comfy_Canvas_NavigationMode": {
"name": "畫布導航模式",
"options": {
"Left-Click Pan (Legacy)": "左鍵拖曳平移(舊版)",
"Standard (New)": "標準(新)"
}
},
"Comfy_Canvas_SelectionToolbox": {
"name": "顯示選取工具箱"
},
@@ -395,10 +402,6 @@
"LiteGraph_Node_TooltipDelay": {
"name": "提示延遲"
},
"LiteGraph_Pointer_TrackpadGestures": {
"name": "啟用觸控板手勢",
"tooltip": "此設定可為畫布啟用觸控板模式,允許使用兩指縮放與平移。"
},
"LiteGraph_Reroute_SplineOffset": {
"name": "重導樣條偏移",
"tooltip": "貝茲控制點相對於重導中心點的偏移量"

View File

@@ -29,6 +29,13 @@
"name": "画布背景图像",
"tooltip": "画布背景的图像 URL。你可以在输出面板中右键点击一张图片并选择“设为背景”来使用它。"
},
"Comfy_Canvas_NavigationMode": {
"name": "畫布導航模式",
"options": {
"Left-Click Pan (Legacy)": "左鍵拖曳(舊版)",
"Standard (New)": "標準(新)"
}
},
"Comfy_Canvas_SelectionToolbox": {
"name": "显示选择工具箱"
},
@@ -395,10 +402,6 @@
"LiteGraph_Node_TooltipDelay": {
"name": "工具提示延迟"
},
"LiteGraph_Pointer_TrackpadGestures": {
"name": "启用触控板手势",
"tooltip": "此设置为画布启用触控板模式,允许使用双指捏合缩放和拖动。"
},
"LiteGraph_Reroute_SplineOffset": {
"name": "重新路由样条偏移",
"tooltip": "贝塞尔控制点从重新路由中心点的偏移"

View File

@@ -475,6 +475,7 @@ const zSettings = z.object({
'Comfy.TutorialCompleted': z.boolean(),
'Comfy.InstalledVersion': z.string().nullable(),
'Comfy.Node.AllowImageSizeDraw': z.boolean(),
'Comfy.Canvas.NavigationMode': z.string(),
'Comfy-Desktop.AutoUpdate': z.boolean(),
'Comfy-Desktop.SendStatistics': z.boolean(),
'Comfy-Desktop.WindowStyle': z.string(),