mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-14 09:27:41 +00:00
Support display of multitype slots (#7457)
Example with forcibly modified types for testing <img width="736" height="425" alt="image" src="https://github.com/user-attachments/assets/e885a7d0-5946-41be-b9b4-b9b195f50c92" /> Vue mode doesn't currently seem to display optional inputs, but the SVGs here include support for being made hollow with `--shape: url(#hollow)` <img width="765" height="360" alt="image" src="https://github.com/user-attachments/assets/0ea57179-99a4-4001-aa18-856e172287c0" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7457-Support-display-of-multitype-slots-2c86d73d3650818594afd988e73827e3) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -30,6 +30,8 @@ export interface IDrawOptions {
|
||||
highlight?: boolean
|
||||
}
|
||||
|
||||
const ROTATION_OFFSET = -Math.PI / 2
|
||||
|
||||
/** Shared base class for {@link LGraphNode} input and output slots. */
|
||||
export abstract class NodeSlot extends SlotBase implements INodeSlot {
|
||||
pos?: Point
|
||||
@@ -130,6 +132,7 @@ export abstract class NodeSlot extends SlotBase implements INodeSlot {
|
||||
slot_type === SlotType.Array ? SlotShape.Grid : this.shape
|
||||
) as SlotShape
|
||||
|
||||
ctx.save()
|
||||
ctx.beginPath()
|
||||
let doFill = true
|
||||
|
||||
@@ -163,16 +166,52 @@ export abstract class NodeSlot extends SlotBase implements INodeSlot {
|
||||
if (lowQuality) {
|
||||
ctx.rect(pos[0] - 4, pos[1] - 4, 8, 8)
|
||||
} else {
|
||||
let radius: number
|
||||
if (slot_shape === SlotShape.HollowCircle) {
|
||||
const path = new Path2D()
|
||||
path.arc(pos[0], pos[1], 10, 0, Math.PI * 2)
|
||||
path.arc(pos[0], pos[1], highlight ? 2.5 : 1.5, 0, Math.PI * 2)
|
||||
ctx.clip(path, 'evenodd')
|
||||
}
|
||||
const radius = highlight ? 5 : 4
|
||||
const typesSet = new Set(
|
||||
`${this.type}`
|
||||
.split(',')
|
||||
.map(
|
||||
this.isConnected
|
||||
? (type) => colorContext.getConnectedColor(type)
|
||||
: (type) => colorContext.getDisconnectedColor(type)
|
||||
)
|
||||
)
|
||||
const types = [...typesSet].slice(0, 3)
|
||||
if (types.length > 1) {
|
||||
doFill = false
|
||||
doStroke = true
|
||||
ctx.lineWidth = 3
|
||||
ctx.strokeStyle = ctx.fillStyle
|
||||
radius = highlight ? 4 : 3
|
||||
} else {
|
||||
// Normal circle
|
||||
radius = highlight ? 5 : 4
|
||||
const arcLen = (Math.PI * 2) / types.length
|
||||
types.forEach((type, idx) => {
|
||||
ctx.moveTo(pos[0], pos[1])
|
||||
ctx.fillStyle = type
|
||||
ctx.arc(
|
||||
pos[0],
|
||||
pos[1],
|
||||
radius,
|
||||
arcLen * idx + ROTATION_OFFSET,
|
||||
Math.PI * 2 + ROTATION_OFFSET
|
||||
)
|
||||
ctx.fill()
|
||||
ctx.beginPath()
|
||||
})
|
||||
//add stroke dividers
|
||||
ctx.save()
|
||||
ctx.strokeStyle = 'black'
|
||||
ctx.lineWidth = 0.5
|
||||
types.forEach((_, idx) => {
|
||||
ctx.moveTo(pos[0], pos[1])
|
||||
const xOffset = Math.cos(arcLen * idx + ROTATION_OFFSET) * radius
|
||||
const yOffset = Math.sin(arcLen * idx + ROTATION_OFFSET) * radius
|
||||
ctx.lineTo(pos[0] + xOffset, pos[1] + yOffset)
|
||||
})
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
ctx.beginPath()
|
||||
}
|
||||
ctx.arc(pos[0], pos[1], radius, 0, Math.PI * 2)
|
||||
}
|
||||
@@ -180,6 +219,7 @@ export abstract class NodeSlot extends SlotBase implements INodeSlot {
|
||||
|
||||
if (doFill) ctx.fill()
|
||||
if (!lowQuality && doStroke) ctx.stroke()
|
||||
ctx.restore()
|
||||
|
||||
// render slot label
|
||||
const hideLabel = lowQuality || this.isWidgetInputSlot
|
||||
|
||||
Reference in New Issue
Block a user