mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-21 07:14:11 +00:00
A major, full rewrite of linear mode, now under the name "Simple Mode". - Fixes widget styling - Adds a new simplified history - Adds support for non-image outputs - Supports right sidebar - Allows and panning on the output image preview - Provides support for drag and drop zones - Moves workflow notes into a popover. - Allows scrolling through outputs with Ctrl+scroll or arrow keys The primary means of accessing Simple Mode is a toggle button on the bottom right. This button is only shown if a feature flag is enabled, or the user has already seen linear mode during the current session. Simple Mode can also be accessed by - Using the toggle linear mode keybind - Loading a workflow that that was saved in Simple Mode workflow - Loading a template url with appropriate parameter <img width="1790" height="1387" alt="image" src="https://github.com/user-attachments/assets/d86a4a41-dfbf-41e7-a6d9-146473005606" /> Known issues: - Outputs on cloud are not filtered to those produced by the current workflow. - Output filtering has been globally disabled for consistency - Outputs will load more items on scroll, but does not unload - Performance may be reduced on weak devices with very large histories. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7734-linear-v2-2d16d73d3650819b8a10f150ff12ea22) by [Unito](https://www.unito.io)
60 lines
1.5 KiB
Vue
60 lines
1.5 KiB
Vue
<script setup lang="ts">
|
|
import { computed, ref, useTemplateRef } from 'vue'
|
|
|
|
const zoomPane = useTemplateRef('zoomPane')
|
|
|
|
const zoom = ref(1.0)
|
|
const panX = ref(0.0)
|
|
const panY = ref(0.0)
|
|
|
|
function handleWheel(e: WheelEvent) {
|
|
const zoomPaneEl = zoomPane.value
|
|
if (!zoomPaneEl) return
|
|
|
|
zoom.value -= e.deltaY
|
|
const { x, y, width, height } = zoomPaneEl.getBoundingClientRect()
|
|
const offsetX = e.clientX - x - width / 2
|
|
const offsetY = e.clientY - y - height / 2
|
|
const scaler = 1.1 ** (e.deltaY / -30)
|
|
|
|
panY.value = panY.value * scaler - offsetY * (scaler - 1)
|
|
panX.value = panX.value * scaler - offsetX * (scaler - 1)
|
|
}
|
|
|
|
let dragging = false
|
|
function handleDown(e: PointerEvent) {
|
|
if (e.button !== 0) return
|
|
|
|
const zoomPaneEl = zoomPane.value
|
|
if (!zoomPaneEl) return
|
|
zoomPaneEl.parentElement?.focus()
|
|
|
|
zoomPaneEl.setPointerCapture(e.pointerId)
|
|
dragging = true
|
|
}
|
|
function handleMove(e: PointerEvent) {
|
|
if (!dragging) return
|
|
panX.value += e.movementX
|
|
panY.value += e.movementY
|
|
}
|
|
|
|
const transform = computed(() => {
|
|
const scale = 1.1 ** (zoom.value / 30)
|
|
const matrix = [scale, 0, 0, scale, panX.value, panY.value]
|
|
return `matrix(${matrix.join(',')})`
|
|
})
|
|
</script>
|
|
<template>
|
|
<div
|
|
ref="zoomPane"
|
|
class="contain-size flex place-content-center"
|
|
@wheel="handleWheel"
|
|
@pointerdown.prevent="handleDown"
|
|
@pointermove="handleMove"
|
|
@pointerup="dragging = false"
|
|
@pointercancel="dragging = false"
|
|
>
|
|
<slot :style="{ transform }" />
|
|
</div>
|
|
</template>
|