mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-05 05:00:03 +00:00
Add optional icon to LGraphBadge and use for API nodes (#930)
Adds option to include an icon when creating an `LGraphBadge`. Then, adds the icon to the title of nodes whose `constructor.nodeData` has a non-null `credits_cost` property (API nodes that ComfyUI_frontend was able to successfully query a credit cost for).  - https://github.com/Comfy-Org/ComfyUI-private/pull/2 - https://github.com/Comfy-Org/litegraph.js/pull/930 - https://github.com/Comfy-Org/ComfyUI_frontend/pull/3470 --------- Co-authored-by: filtered <176114999+webfiltered@users.noreply.github.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { LGraphIcon, LGraphIconOptions } from "./LGraphIcon"
|
||||
|
||||
export enum BadgePosition {
|
||||
TopLeft = "top-left",
|
||||
TopRight = "top-right",
|
||||
@@ -11,6 +13,9 @@ export interface LGraphBadgeOptions {
|
||||
padding?: number
|
||||
height?: number
|
||||
cornerRadius?: number
|
||||
iconOptions?: LGraphIconOptions
|
||||
xOffset?: number
|
||||
yOffset?: number
|
||||
}
|
||||
|
||||
export class LGraphBadge {
|
||||
@@ -21,6 +26,9 @@ export class LGraphBadge {
|
||||
padding: number
|
||||
height: number
|
||||
cornerRadius: number
|
||||
icon?: LGraphIcon
|
||||
xOffset: number
|
||||
yOffset: number
|
||||
|
||||
constructor({
|
||||
text,
|
||||
@@ -30,6 +38,9 @@ export class LGraphBadge {
|
||||
padding = 6,
|
||||
height = 20,
|
||||
cornerRadius = 5,
|
||||
iconOptions,
|
||||
xOffset = 0,
|
||||
yOffset = 0,
|
||||
}: LGraphBadgeOptions) {
|
||||
this.text = text
|
||||
this.fgColor = fgColor
|
||||
@@ -38,20 +49,29 @@ export class LGraphBadge {
|
||||
this.padding = padding
|
||||
this.height = height
|
||||
this.cornerRadius = cornerRadius
|
||||
if (iconOptions) {
|
||||
this.icon = new LGraphIcon(iconOptions)
|
||||
}
|
||||
this.xOffset = xOffset
|
||||
this.yOffset = yOffset
|
||||
}
|
||||
|
||||
get visible() {
|
||||
return this.text.length > 0
|
||||
return this.text.length > 0 || !!this.icon
|
||||
}
|
||||
|
||||
getWidth(ctx: CanvasRenderingContext2D) {
|
||||
if (!this.visible) return 0
|
||||
|
||||
const { font } = ctx
|
||||
let iconWidth = 0
|
||||
if (this.icon) {
|
||||
ctx.font = `${this.icon.fontSize}px '${this.icon.fontFamily}'`
|
||||
iconWidth = ctx.measureText(this.icon.unicode).width + this.padding
|
||||
}
|
||||
ctx.font = `${this.fontSize}px sans-serif`
|
||||
const textWidth = ctx.measureText(this.text).width
|
||||
const textWidth = this.text ? ctx.measureText(this.text).width : 0
|
||||
ctx.font = font
|
||||
return textWidth + this.padding * 2
|
||||
return iconWidth + textWidth + this.padding * 2
|
||||
}
|
||||
|
||||
draw(
|
||||
@@ -61,7 +81,11 @@ export class LGraphBadge {
|
||||
): void {
|
||||
if (!this.visible) return
|
||||
|
||||
const { fillStyle } = ctx
|
||||
x += this.xOffset
|
||||
y += this.yOffset
|
||||
|
||||
const { font, fillStyle, textBaseline, textAlign } = ctx
|
||||
|
||||
ctx.font = `${this.fontSize}px sans-serif`
|
||||
const badgeWidth = this.getWidth(ctx)
|
||||
const badgeX = 0
|
||||
@@ -77,14 +101,26 @@ export class LGraphBadge {
|
||||
}
|
||||
ctx.fill()
|
||||
|
||||
// Draw badge text
|
||||
ctx.fillStyle = this.fgColor
|
||||
ctx.fillText(
|
||||
this.text,
|
||||
x + badgeX + this.padding,
|
||||
y + this.height - this.padding,
|
||||
)
|
||||
let drawX = x + badgeX + this.padding
|
||||
const centerY = y + this.height / 2
|
||||
|
||||
// Draw icon if present
|
||||
if (this.icon) {
|
||||
this.icon.draw(ctx, drawX, centerY)
|
||||
drawX += this.icon.fontSize + this.padding / 2 + 4
|
||||
}
|
||||
|
||||
// Draw badge text
|
||||
if (this.text) {
|
||||
ctx.fillStyle = this.fgColor
|
||||
ctx.textBaseline = "middle"
|
||||
ctx.textAlign = "left"
|
||||
ctx.fillText(this.text, drawX, centerY + 1)
|
||||
}
|
||||
|
||||
ctx.font = font
|
||||
ctx.fillStyle = fillStyle
|
||||
ctx.textBaseline = textBaseline
|
||||
ctx.textAlign = textAlign
|
||||
}
|
||||
}
|
||||
|
||||
68
src/LGraphIcon.ts
Normal file
68
src/LGraphIcon.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
export interface LGraphIconOptions {
|
||||
unicode: string
|
||||
fontFamily?: string
|
||||
color?: string
|
||||
bgColor?: string
|
||||
fontSize?: number
|
||||
circlePadding?: number
|
||||
xOffset?: number
|
||||
yOffset?: number
|
||||
}
|
||||
|
||||
export class LGraphIcon {
|
||||
unicode: string
|
||||
fontFamily: string
|
||||
color: string
|
||||
bgColor?: string
|
||||
fontSize: number
|
||||
circlePadding: number
|
||||
xOffset: number
|
||||
yOffset: number
|
||||
|
||||
constructor({
|
||||
unicode,
|
||||
fontFamily = "PrimeIcons",
|
||||
color = "#e6c200",
|
||||
bgColor,
|
||||
fontSize = 16,
|
||||
circlePadding = 2,
|
||||
xOffset = 0,
|
||||
yOffset = 0,
|
||||
}: LGraphIconOptions) {
|
||||
this.unicode = unicode
|
||||
this.fontFamily = fontFamily
|
||||
this.color = color
|
||||
this.bgColor = bgColor
|
||||
this.fontSize = fontSize
|
||||
this.circlePadding = circlePadding
|
||||
this.xOffset = xOffset
|
||||
this.yOffset = yOffset
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D, x: number, y: number) {
|
||||
x += this.xOffset
|
||||
y += this.yOffset
|
||||
|
||||
const { font, textBaseline, textAlign, fillStyle } = ctx
|
||||
|
||||
ctx.font = `${this.fontSize}px '${this.fontFamily}'`
|
||||
ctx.textBaseline = "middle"
|
||||
ctx.textAlign = "center"
|
||||
const iconRadius = this.fontSize / 2 + this.circlePadding
|
||||
// Draw icon background circle if bgColor is set
|
||||
if (this.bgColor) {
|
||||
ctx.beginPath()
|
||||
ctx.arc(x + iconRadius, y, iconRadius, 0, 2 * Math.PI)
|
||||
ctx.fillStyle = this.bgColor
|
||||
ctx.fill()
|
||||
}
|
||||
// Draw icon
|
||||
ctx.fillStyle = this.color
|
||||
ctx.fillText(this.unicode, x + iconRadius, y)
|
||||
|
||||
ctx.font = font
|
||||
ctx.textBaseline = textBaseline
|
||||
ctx.textAlign = textAlign
|
||||
ctx.fillStyle = fillStyle
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user