mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 18:52:19 +00:00
fix: improve painter cursor performance by bypassing Vue reactivity (#9339)
## Summary Previously painter has node performance issue. Use direct DOM manipulation for cursor position updates instead of reactive refs, and add will-change-transform for GPU layer promotion. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9339-fix-improve-painter-cursor-performance-by-bypassing-Vue-reactivity-3176d73d365081d88b23d26e774cebf5) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -28,8 +28,9 @@
|
|||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-show="cursorVisible"
|
v-show="cursorVisible"
|
||||||
class="pointer-events-none absolute left-0 top-0 rounded-full border border-black/60 shadow-[0_0_0_1px_rgba(255,255,255,0.8)]"
|
ref="cursorEl"
|
||||||
:style="cursorStyle"
|
class="pointer-events-none absolute left-0 top-0 rounded-full border border-black/60 shadow-[0_0_0_1px_rgba(255,255,255,0.8)] will-change-transform"
|
||||||
|
:style="cursorSizeStyle"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -281,6 +282,7 @@ const { nodeId } = defineProps<{
|
|||||||
const modelValue = defineModel<string>({ default: '' })
|
const modelValue = defineModel<string>({ default: '' })
|
||||||
|
|
||||||
const canvasEl = useTemplateRef<HTMLCanvasElement>('canvasEl')
|
const canvasEl = useTemplateRef<HTMLCanvasElement>('canvasEl')
|
||||||
|
const cursorEl = useTemplateRef<HTMLElement>('cursorEl')
|
||||||
const controlsEl = useTemplateRef<HTMLDivElement>('controlsEl')
|
const controlsEl = useTemplateRef<HTMLDivElement>('controlsEl')
|
||||||
const { width: controlsWidth } = useElementSize(controlsEl)
|
const { width: controlsWidth } = useElementSize(controlsEl)
|
||||||
const compact = computed(
|
const compact = computed(
|
||||||
@@ -296,8 +298,6 @@ const {
|
|||||||
backgroundColor,
|
backgroundColor,
|
||||||
canvasWidth,
|
canvasWidth,
|
||||||
canvasHeight,
|
canvasHeight,
|
||||||
cursorX,
|
|
||||||
cursorY,
|
|
||||||
cursorVisible,
|
cursorVisible,
|
||||||
displayBrushSize,
|
displayBrushSize,
|
||||||
inputImageUrl,
|
inputImageUrl,
|
||||||
@@ -309,7 +309,7 @@ const {
|
|||||||
handlePointerLeave,
|
handlePointerLeave,
|
||||||
handleInputImageLoad,
|
handleInputImageLoad,
|
||||||
handleClear
|
handleClear
|
||||||
} = usePainter(nodeId, { canvasEl, modelValue })
|
} = usePainter(nodeId, { canvasEl, cursorEl, modelValue })
|
||||||
|
|
||||||
const canvasContainerStyle = computed(() => ({
|
const canvasContainerStyle = computed(() => ({
|
||||||
aspectRatio: `${canvasWidth.value} / ${canvasHeight.value}`,
|
aspectRatio: `${canvasWidth.value} / ${canvasHeight.value}`,
|
||||||
@@ -318,16 +318,10 @@ const canvasContainerStyle = computed(() => ({
|
|||||||
: backgroundColor.value
|
: backgroundColor.value
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const cursorStyle = computed(() => {
|
const cursorSizeStyle = computed(() => ({
|
||||||
const size = displayBrushSize.value
|
width: `${displayBrushSize.value}px`,
|
||||||
const x = cursorX.value - size / 2
|
height: `${displayBrushSize.value}px`
|
||||||
const y = cursorY.value - size / 2
|
}))
|
||||||
return {
|
|
||||||
width: `${size}px`,
|
|
||||||
height: `${size}px`,
|
|
||||||
transform: `translate(${x}px, ${y}px)`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const brushOpacityPercent = computed({
|
const brushOpacityPercent = computed({
|
||||||
get: () => Math.round(brushOpacity.value * 100),
|
get: () => Math.round(brushOpacity.value * 100),
|
||||||
|
|||||||
@@ -27,11 +27,12 @@ export const PAINTER_TOOLS: Record<string, PainterTool> = {
|
|||||||
|
|
||||||
interface UsePainterOptions {
|
interface UsePainterOptions {
|
||||||
canvasEl: Ref<HTMLCanvasElement | null>
|
canvasEl: Ref<HTMLCanvasElement | null>
|
||||||
|
cursorEl: Ref<HTMLElement | null>
|
||||||
modelValue: Ref<string>
|
modelValue: Ref<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function usePainter(nodeId: string, options: UsePainterOptions) {
|
export function usePainter(nodeId: string, options: UsePainterOptions) {
|
||||||
const { canvasEl, modelValue } = options
|
const { canvasEl, cursorEl, modelValue } = options
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const nodeOutputStore = useNodeOutputStore()
|
const nodeOutputStore = useNodeOutputStore()
|
||||||
const toastStore = useToastStore()
|
const toastStore = useToastStore()
|
||||||
@@ -41,8 +42,6 @@ export function usePainter(nodeId: string, options: UsePainterOptions) {
|
|||||||
const canvasWidth = ref(512)
|
const canvasWidth = ref(512)
|
||||||
const canvasHeight = ref(512)
|
const canvasHeight = ref(512)
|
||||||
|
|
||||||
const cursorX = ref(0)
|
|
||||||
const cursorY = ref(0)
|
|
||||||
const cursorVisible = ref(false)
|
const cursorVisible = ref(false)
|
||||||
|
|
||||||
const inputImageUrl = ref<string | null>(null)
|
const inputImageUrl = ref<string | null>(null)
|
||||||
@@ -518,8 +517,10 @@ export function usePainter(nodeId: string, options: UsePainterOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateCursorPos(e: PointerEvent) {
|
function updateCursorPos(e: PointerEvent) {
|
||||||
cursorX.value = e.offsetX
|
const el = cursorEl.value
|
||||||
cursorY.value = e.offsetY
|
if (!el) return
|
||||||
|
const size = displayBrushSize.value
|
||||||
|
el.style.transform = `translate(${e.offsetX - size / 2}px, ${e.offsetY - size / 2}px)`
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePointerDown(e: PointerEvent) {
|
function handlePointerDown(e: PointerEvent) {
|
||||||
@@ -760,8 +761,6 @@ export function usePainter(nodeId: string, options: UsePainterOptions) {
|
|||||||
canvasWidth,
|
canvasWidth,
|
||||||
canvasHeight,
|
canvasHeight,
|
||||||
|
|
||||||
cursorX,
|
|
||||||
cursorY,
|
|
||||||
cursorVisible,
|
cursorVisible,
|
||||||
displayBrushSize,
|
displayBrushSize,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user