mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-04 21:22:07 +00:00
Fix/vue nodes snap to grid (#5973)
## Summary Enable node snap to grid in vue nodes mirroring the same behavior as litegraph. - Show node snap preview (semi transparent white box target behind node) - Resize snap to grid - Shift + drag / Auto snap - Multi select + group snap ## Changes - **What**: useNodeSnap.ts useShifyKeySync.ts setups the core hooks into both the vue node positioning/resizing system and the event forwarding technique for communicating to litegraph. ## Review Focus Both new composables and specifically the useNodeLayout modifications to batch the mutations when snapping. A key tradeoff/note is why we are using the useShifyKeySync.ts which dispatches a new shift event to the canvas layer. This approach is the cleaner / more declaritive method mimicking how other vue node -> litegraph realtime events are passed. <!-- If this PR fixes an issue, uncomment and update the line below --> <!-- Fixes #ISSUE_NUMBER --> ## Screenshots (if applicable) <!-- Add screenshots or video recording to help explain your changes --> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5973-Fix-vue-nodes-snap-to-grid-2866d73d365081c1a058d223c8c52576) by [Unito](https://www.unito.io)
This commit is contained in:
73
src/renderer/extensions/vueNodes/composables/useNodeSnap.ts
Normal file
73
src/renderer/extensions/vueNodes/composables/useNodeSnap.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { snapPoint } from '@/lib/litegraph/src/measure'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
|
||||
/**
|
||||
* Composable for node snap-to-grid functionality
|
||||
*
|
||||
* Provides reactive access to snap settings and utilities for applying
|
||||
* snap-to-grid behavior to Vue nodes during drag and resize operations.
|
||||
*/
|
||||
export function useNodeSnap() {
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
// Reactive snap settings
|
||||
const gridSize = computed(() => settingStore.get('Comfy.SnapToGrid.GridSize'))
|
||||
const alwaysSnap = computed(() => settingStore.get('pysssss.SnapToGrid'))
|
||||
|
||||
/**
|
||||
* Determines if snap-to-grid should be applied based on shift key and settings
|
||||
* @param event - The pointer event to check for shift key
|
||||
* @returns true if snapping should be applied
|
||||
*/
|
||||
function shouldSnap(event: PointerEvent): boolean {
|
||||
return event.shiftKey || alwaysSnap.value
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies snap-to-grid to a position
|
||||
* @param position - Position object with x, y coordinates
|
||||
* @returns The snapped position as a new object
|
||||
*/
|
||||
function applySnapToPosition(position: { x: number; y: number }): {
|
||||
x: number
|
||||
y: number
|
||||
} {
|
||||
const size = gridSize.value
|
||||
if (!size) return { ...position }
|
||||
|
||||
const posArray: [number, number] = [position.x, position.y]
|
||||
if (snapPoint(posArray, size)) {
|
||||
return { x: posArray[0], y: posArray[1] }
|
||||
}
|
||||
return { ...position }
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies snap-to-grid to a size (width/height)
|
||||
* @param size - Size object with width, height
|
||||
* @returns The snapped size as a new object
|
||||
*/
|
||||
function applySnapToSize(size: { width: number; height: number }): {
|
||||
width: number
|
||||
height: number
|
||||
} {
|
||||
const gridSizeValue = gridSize.value
|
||||
if (!gridSizeValue) return { ...size }
|
||||
|
||||
const sizeArray: [number, number] = [size.width, size.height]
|
||||
if (snapPoint(sizeArray, gridSizeValue)) {
|
||||
return { width: sizeArray[0], height: sizeArray[1] }
|
||||
}
|
||||
return { ...size }
|
||||
}
|
||||
|
||||
return {
|
||||
gridSize,
|
||||
alwaysSnap,
|
||||
shouldSnap,
|
||||
applySnapToPosition,
|
||||
applySnapToSize
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user