mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-05 15:40:10 +00:00
Feat/adaptive lod threshold (#5249)
* feat: use a physical min font size as the LOD threshold instead of an abritrary zoom level that is different on different screens * feat: min 1px font size, max 24ox font size * refactor: settings text * refactor: settings text * refactor: version * fix: default font size from 10 to 8 * feat: cache the threshold and move it's calculation out of the render loop * refactor: comments * refactor: removed package-lock * refactor: improve how we manage deprecated settings, and removed any types * refactor: how the migration settings formula works so we get prev settings closer to the new font size setting * test: add in zoom and settings test for LOD * refactor: tests to use best practices * Update test expectations [skip ci] --------- Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -63,12 +63,11 @@ export const useLitegraphSettings = () => {
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
const lowQualityRenderingZoomThreshold = settingStore.get(
|
||||
'LiteGraph.Canvas.LowQualityRenderingZoomThreshold'
|
||||
const minFontSizeForLOD = settingStore.get(
|
||||
'LiteGraph.Canvas.MinFontSizeForLOD'
|
||||
)
|
||||
if (canvasStore.canvas) {
|
||||
canvasStore.canvas.low_quality_zoom_threshold =
|
||||
lowQualityRenderingZoomThreshold
|
||||
canvasStore.canvas.min_font_size_for_lod = minFontSizeForLOD
|
||||
canvasStore.canvas.setDirty(/* fg */ true, /* bg */ true)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -776,19 +776,36 @@ export const CORE_SETTINGS: SettingParams[] = [
|
||||
type: 'boolean',
|
||||
versionAdded: '1.8.8'
|
||||
},
|
||||
|
||||
{
|
||||
id: 'LiteGraph.Canvas.LowQualityRenderingZoomThreshold',
|
||||
name: 'Low quality rendering zoom threshold',
|
||||
type: 'hidden',
|
||||
deprecated: true,
|
||||
name: 'Low quality rendering zoom threshold (deprecated)',
|
||||
tooltip:
|
||||
'Zoom level threshold for performance mode. Lower values (0.1) = quality at all zoom levels. Higher values (1.0) = performance mode even when zoomed in. Performance mode simplifies rendering by hiding text labels, shadows, and details.',
|
||||
type: 'slider',
|
||||
attrs: {
|
||||
min: 0.1,
|
||||
max: 1,
|
||||
step: 0.01
|
||||
},
|
||||
defaultValue: 0.6,
|
||||
versionAdded: '1.9.1'
|
||||
versionAdded: '1.9.1',
|
||||
versionModified: '1.26.7'
|
||||
},
|
||||
{
|
||||
id: 'LiteGraph.Canvas.MinFontSizeForLOD',
|
||||
name: 'Zoom Node Level of Detail - font size threshold',
|
||||
tooltip:
|
||||
'Controls when the nodes switch to low quality LOD rendering. Uses font size in pixels to determine when to switch. Set to 0 to disable. Values 1-24 set the minimum font size threshold for LOD - higher values (24px) = switch nodes to simplified rendering sooner when zooming out, lower values (1px) = maintain full node quality longer.',
|
||||
type: 'slider',
|
||||
attrs: {
|
||||
min: 0,
|
||||
max: 24,
|
||||
step: 1
|
||||
},
|
||||
defaultValue: 8,
|
||||
versionAdded: '1.26.7'
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Canvas.NavigationMode',
|
||||
|
||||
@@ -441,11 +441,38 @@ export class LGraphCanvas
|
||||
LiteGraph.ROUND_RADIUS = value
|
||||
}
|
||||
|
||||
// Cached LOD threshold values for performance
|
||||
private _lowQualityZoomThreshold: number = 0
|
||||
private _isLowQuality: boolean = false
|
||||
|
||||
/**
|
||||
* Render low quality when zoomed out.
|
||||
* Updates the low quality zoom threshold based on current settings.
|
||||
* Called when min_font_size_for_lod or DPR changes.
|
||||
*/
|
||||
private updateLowQualityThreshold(): void {
|
||||
if (this._min_font_size_for_lod === 0) {
|
||||
// LOD disabled
|
||||
this._lowQualityZoomThreshold = 0
|
||||
this._isLowQuality = false
|
||||
return
|
||||
}
|
||||
|
||||
const baseFontSize = LiteGraph.NODE_TEXT_SIZE // 14px
|
||||
const dprAdjustment = Math.sqrt(window.devicePixelRatio || 1) //Using sqrt here because higher DPR monitors do not linearily scale the readability of the font, instead they increase the font by some heurisitc, and to approximate we use sqrt to say bascially a DPR of 2 increases the readibility by 40%, 3 by 70%
|
||||
|
||||
// Calculate the zoom level where text becomes unreadable
|
||||
this._lowQualityZoomThreshold =
|
||||
this._min_font_size_for_lod / (baseFontSize * dprAdjustment)
|
||||
|
||||
// Update current state based on current zoom
|
||||
this._isLowQuality = this.ds.scale < this._lowQualityZoomThreshold
|
||||
}
|
||||
|
||||
/**
|
||||
* Render low quality when zoomed out based on minimum readable font size.
|
||||
*/
|
||||
get low_quality(): boolean {
|
||||
return this.ds.scale < this.low_quality_zoom_threshold
|
||||
return this._isLowQuality
|
||||
}
|
||||
|
||||
options: {
|
||||
@@ -516,8 +543,21 @@ export class LGraphCanvas
|
||||
/** Shape of the markers shown at the midpoint of links. Default: Circle */
|
||||
linkMarkerShape: LinkMarkerShape = LinkMarkerShape.Circle
|
||||
links_render_mode: number
|
||||
/** Zoom threshold for low quality rendering. Zoom below this threshold will render low quality. */
|
||||
low_quality_zoom_threshold: number = 0.6
|
||||
/** Minimum font size in pixels before switching to low quality rendering.
|
||||
* This intializes first and if we cant get the value from the settings we default to 8px
|
||||
*/
|
||||
private _min_font_size_for_lod: number = 8
|
||||
|
||||
get min_font_size_for_lod(): number {
|
||||
return this._min_font_size_for_lod
|
||||
}
|
||||
|
||||
set min_font_size_for_lod(value: number) {
|
||||
if (this._min_font_size_for_lod !== value) {
|
||||
this._min_font_size_for_lod = value
|
||||
this.updateLowQualityThreshold()
|
||||
}
|
||||
}
|
||||
/** mouse in canvas coordinates, where 0,0 is the top-left corner of the blue rectangle */
|
||||
readonly mouse: Point
|
||||
/** mouse in graph coordinates, where 0,0 is the top-left corner of the blue rectangle */
|
||||
@@ -700,6 +740,14 @@ export class LGraphCanvas
|
||||
this.ds = new DragAndScale(canvas)
|
||||
this.pointer = new CanvasPointer(canvas)
|
||||
|
||||
// Set up zoom change handler for efficient LOD updates
|
||||
this.ds.onChanged = (scale: number, _offset: Point) => {
|
||||
// Only check LOD threshold if it's enabled
|
||||
if (this._lowQualityZoomThreshold > 0) {
|
||||
this._isLowQuality = scale < this._lowQualityZoomThreshold
|
||||
}
|
||||
}
|
||||
|
||||
this.linkConnector.events.addEventListener('link-created', () =>
|
||||
this.#dirty()
|
||||
)
|
||||
@@ -885,6 +933,8 @@ export class LGraphCanvas
|
||||
}
|
||||
|
||||
this.autoresize = options.autoresize
|
||||
|
||||
this.updateLowQualityThreshold()
|
||||
}
|
||||
|
||||
static onGroupAdd(
|
||||
|
||||
@@ -388,9 +388,9 @@
|
||||
"Topbar (2nd-row)": "Topbar (2nd-row)"
|
||||
}
|
||||
},
|
||||
"LiteGraph_Canvas_LowQualityRenderingZoomThreshold": {
|
||||
"name": "Low quality rendering zoom threshold",
|
||||
"tooltip": "Zoom level threshold for performance mode. Lower values (0.1) = quality at all zoom levels. Higher values (1.0) = performance mode even when zoomed in. Performance mode simplifies rendering by hiding text labels, shadows, and details."
|
||||
"LiteGraph_Canvas_MinFontSizeForLOD": {
|
||||
"name": "Zoom Node Level of Detail - font size threshold",
|
||||
"tooltip": "Controls when the nodes switch to low quality LOD rendering. Uses font size in pixels to determine when to switch. Set to 0 to disable. Values 1-24 set the minimum font size threshold for LOD - higher values (24px) = switch nodes to simplified rendering sooner when zooming out, lower values (1px) = maintain full node quality longer."
|
||||
},
|
||||
"LiteGraph_Canvas_MaximumFps": {
|
||||
"name": "Maximum FPS",
|
||||
|
||||
@@ -460,11 +460,12 @@ const zSettings = z.object({
|
||||
'Comfy.Workflow.AutoSaveDelay': z.number(),
|
||||
'Comfy.Workflow.AutoSave': z.enum(['off', 'after delay']),
|
||||
'Comfy.RerouteBeta': z.boolean(),
|
||||
'LiteGraph.Canvas.LowQualityRenderingZoomThreshold': z.number(),
|
||||
'LiteGraph.Canvas.MinFontSizeForLOD': z.number(),
|
||||
'Comfy.Canvas.SelectionToolbox': z.boolean(),
|
||||
'LiteGraph.Node.TooltipDelay': z.number(),
|
||||
'LiteGraph.ContextMenu.Scaling': z.boolean(),
|
||||
'LiteGraph.Reroute.SplineOffset': z.number(),
|
||||
'LiteGraph.Canvas.LowQualityRenderingZoomThreshold': z.number(),
|
||||
'Comfy.Toast.DisableReconnectingToast': z.boolean(),
|
||||
'Comfy.Workflow.Persist': z.boolean(),
|
||||
'Comfy.TutorialCompleted': z.boolean(),
|
||||
|
||||
@@ -188,6 +188,48 @@ export const useSettingStore = defineStore('setting', () => {
|
||||
)
|
||||
}
|
||||
settingValues.value = await api.getSettings()
|
||||
|
||||
// Migrate old zoom threshold setting to new font size setting
|
||||
await migrateZoomThresholdToFontSize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate the old zoom threshold setting to the new font size setting.
|
||||
* Preserves the exact zoom threshold behavior by converting it to equivalent font size.
|
||||
*/
|
||||
async function migrateZoomThresholdToFontSize() {
|
||||
const oldKey = 'LiteGraph.Canvas.LowQualityRenderingZoomThreshold'
|
||||
const newKey = 'LiteGraph.Canvas.MinFontSizeForLOD'
|
||||
|
||||
// Only migrate if old setting exists and new setting doesn't
|
||||
if (
|
||||
settingValues.value[oldKey] !== undefined &&
|
||||
settingValues.value[newKey] === undefined
|
||||
) {
|
||||
const oldValue = settingValues.value[oldKey] as number
|
||||
|
||||
// Convert zoom threshold to equivalent font size to preserve exact behavior
|
||||
// The threshold formula is: threshold = font_size / (14 * sqrt(DPR))
|
||||
// For DPR=1: threshold = font_size / 14
|
||||
// Therefore: font_size = threshold * 14
|
||||
//
|
||||
// Examples:
|
||||
// - Old 0.6 threshold → 0.6 * 14 = 8.4px → rounds to 8px (preserves ~60% zoom threshold)
|
||||
// - Old 0.5 threshold → 0.5 * 14 = 7px (preserves 50% zoom threshold)
|
||||
// - Old 1.0 threshold → 1.0 * 14 = 14px (preserves 100% zoom threshold)
|
||||
const mappedFontSize = Math.round(oldValue * 14)
|
||||
const clampedFontSize = Math.max(1, Math.min(24, mappedFontSize))
|
||||
|
||||
// Set the new value
|
||||
settingValues.value[newKey] = clampedFontSize
|
||||
|
||||
// Remove the old setting to prevent confusion
|
||||
delete settingValues.value[oldKey]
|
||||
|
||||
// Store the migrated setting
|
||||
await api.storeSetting(newKey, clampedFontSize)
|
||||
await api.storeSetting(oldKey, undefined)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user