mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-12 08:30:08 +00:00
## 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)
74 lines
2.1 KiB
TypeScript
74 lines
2.1 KiB
TypeScript
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
|
|
}
|
|
}
|