minor fixes & mix node sample
This commit is contained in:
@@ -86,6 +86,7 @@ function onConnect(connection: Connection) {
|
||||
const srcHandle = connection.sourceHandle ?? ''
|
||||
const tgtHandle = connection.targetHandle ?? ''
|
||||
if (srcHandle.startsWith('video') !== tgtHandle.startsWith('video')) return
|
||||
if (!srcHandle.includes('-out') || !tgtHandle.includes('-in')) return
|
||||
const kind = srcHandle.startsWith('video') ? 'video' : 'audio'
|
||||
edges.value = [
|
||||
...edges.value,
|
||||
|
||||
@@ -12,6 +12,7 @@ interface PaletteGroup {
|
||||
|
||||
const groups: PaletteGroup[] = [
|
||||
{ label: 'SOURCES', types: ['testpattern', 'ndiin', 'decklinkin', 'videoin'] },
|
||||
{ label: 'PROCESS', types: ['mix'] },
|
||||
{ label: 'SINKS', types: ['ndiout', 'decklinkout', 'fakesink'] },
|
||||
]
|
||||
|
||||
@@ -23,6 +24,7 @@ const iconMap: Record<string, string> = {
|
||||
ndiout: '◬',
|
||||
decklinkout: '◧',
|
||||
fakesink: '◯',
|
||||
mix: '⊕',
|
||||
}
|
||||
|
||||
function onDragStart(event: DragEvent, nodeType: string) {
|
||||
|
||||
@@ -12,7 +12,10 @@ const typeDef = computed(() => NODE_TYPES[props.data.nodeType] ?? null)
|
||||
const inputs = computed(() => typeDef.value?.ports.filter(p => p.direction === 'in') ?? [])
|
||||
const outputs = computed(() => typeDef.value?.ports.filter(p => p.direction === 'out') ?? [])
|
||||
|
||||
const isSource = computed(() => outputs.value.length > 0)
|
||||
function portLabel(portId: string): string {
|
||||
const parts = portId.split('-')
|
||||
return parts.slice(0, -1).join(' ').toUpperCase()
|
||||
}
|
||||
|
||||
const iconMap: Record<string, string> = {
|
||||
testpattern: '▦',
|
||||
@@ -22,6 +25,7 @@ const iconMap: Record<string, string> = {
|
||||
ndiout: '◬',
|
||||
decklinkout: '◧',
|
||||
fakesink: '◯',
|
||||
mix: '⊕',
|
||||
}
|
||||
|
||||
const nodeIcon = computed(() => iconMap[props.data.nodeType] ?? '◯')
|
||||
@@ -91,12 +95,12 @@ function onDeleteNode() {
|
||||
<div v-if="inputs.length || outputs.length" class="node-ports">
|
||||
<div class="ports-side ports-left">
|
||||
<div v-for="port in inputs" :key="port.id" class="port-row">
|
||||
<span :class="['port-name', `port-${port.kind}`]">{{ port.kind }}</span>
|
||||
<span :class="['port-name', `port-${port.kind}`]">{{ portLabel(port.id) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ports-side ports-right">
|
||||
<div v-for="port in outputs" :key="port.id" class="port-row port-row-right">
|
||||
<span :class="['port-name', `port-${port.kind}`]">{{ port.kind }}</span>
|
||||
<span :class="['port-name', `port-${port.kind}`]">{{ portLabel(port.id) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+2
-1
@@ -25,8 +25,9 @@ function parseRes(res: string): { width: number; height: number } {
|
||||
|
||||
// Converts a Vue Flow handle id to the NODE_CONFIG port key used in graph JSON
|
||||
function handleToPort(handle: string): string {
|
||||
return handle.replace(/-(?:in|out)$/, '_flow_id')
|
||||
return handle.replace(/-(?:in|out)(?:-\d+)?$/, '_flow_id')
|
||||
// 'video-out' → 'video_flow_id', 'audio-in' → 'audio_flow_id'
|
||||
// 'video-in-1' → 'video_flow_id', 'audio-in-2' → 'audio_flow_id'
|
||||
}
|
||||
|
||||
export function buildGraph(vfNodes: Node[], vfEdges: Edge[]): GraphJson {
|
||||
|
||||
@@ -31,6 +31,20 @@ export const PATTERN_OPTIONS = [
|
||||
{ label: 'White solid', value: 'white' },
|
||||
]
|
||||
|
||||
export const MIX_MODE_OPTIONS = [
|
||||
{ label: 'Fade', value: 'fade' },
|
||||
{ label: 'Dissolve', value: 'dissolve' },
|
||||
{ label: 'Wipe', value: 'wipe' },
|
||||
{ label: 'A/B', value: 'ab' },
|
||||
]
|
||||
|
||||
export const TRANSITION_OPTIONS = [
|
||||
{ label: 'Cut', value: 'cut' },
|
||||
{ label: 'Cross', value: 'cross' },
|
||||
{ label: 'Slide', value: 'slide' },
|
||||
{ label: 'Push', value: 'push' },
|
||||
]
|
||||
|
||||
// Format params shown on source nodes; values go into edge format (not node params)
|
||||
const FORMAT_PARAMS: ParamDef[] = [
|
||||
{ key: 'res', label: 'Resolution', type: 'select', options: RESOLUTION_OPTIONS, default: '1920x1080', isFormat: true },
|
||||
@@ -114,6 +128,23 @@ export const NODE_TYPES: Record<string, NodeTypeDef> = {
|
||||
{ key: 'file', label: 'File', type: 'input', default: '0.ts' }
|
||||
],
|
||||
},
|
||||
mix: {
|
||||
type: 'mix',
|
||||
label: 'Mix',
|
||||
ports: [
|
||||
{ id: 'video-in-1', kind: 'video', direction: 'in' },
|
||||
{ id: 'video-in-2', kind: 'video', direction: 'in' },
|
||||
{ id: 'audio-in-1', kind: 'audio', direction: 'in' },
|
||||
{ id: 'audio-in-2', kind: 'audio', direction: 'in' },
|
||||
{ id: 'video-out', kind: 'video', direction: 'out' },
|
||||
{ id: 'audio-out', kind: 'audio', direction: 'out' },
|
||||
],
|
||||
params: [
|
||||
{ key: 'mode', label: 'Mode', type: 'select', options: MIX_MODE_OPTIONS, default: 'fade' },
|
||||
{ key: 'transition', label: 'Transition', type: 'select', options: TRANSITION_OPTIONS, default: 'cut' },
|
||||
{ key: 'duration', label: 'Duration', type: 'number', default: 500, min: 0, max: 10000 },
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
// Default params for a new node of the given type
|
||||
|
||||
Reference in New Issue
Block a user