Load real GraphFX serialized examples

This commit is contained in:
2026-06-19 00:29:19 +02:00
parent f27e0d07c4
commit 952f0b425a
5 changed files with 37 additions and 9 deletions

View File

@@ -22,7 +22,3 @@ dist-ssr
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
examples/*
# Local graph examples
examples/*

File diff suppressed because one or more lines are too long

View File

@@ -10,6 +10,7 @@ import GraphFxNode from './components/GraphFxNode.vue'
import { countSavedPositions, graphFxToVueFlow, parseGraphFxJson, type GraphFxFlowWarning, type GraphFxSerializedGraph } from './lib/graphfxToVueFlow' import { countSavedPositions, graphFxToVueFlow, parseGraphFxJson, type GraphFxFlowWarning, type GraphFxSerializedGraph } from './lib/graphfxToVueFlow'
import { layoutGraph } from './lib/layout' import { layoutGraph } from './lib/layout'
import { sampleGraph } from './lib/sampleGraph' import { sampleGraph } from './lib/sampleGraph'
import apiExampleJson from '../examples/api.json?raw'
const editorText = ref(JSON.stringify(sampleGraph, null, 2)) const editorText = ref(JSON.stringify(sampleGraph, null, 2))
const parseError = ref<string | null>(null) const parseError = ref<string | null>(null)
@@ -18,7 +19,7 @@ const nodes = ref<Node[]>([])
const edges = ref<Edge[]>([]) const edges = ref<Edge[]>([])
const warnings = ref<GraphFxFlowWarning[]>([]) const warnings = ref<GraphFxFlowWarning[]>([])
const layoutDirection = ref<'LR' | 'TB'>('LR') const layoutDirection = ref<'LR' | 'TB'>('LR')
const preferSavedPositions = ref(false) const preferSavedPositions = ref(true)
const selectedSaveSlot = ref(localStorage.getItem('GRAPHFX_UI_SELECTED_SAVE_SLOT') || 'My first graph') const selectedSaveSlot = ref(localStorage.getItem('GRAPHFX_UI_SELECTED_SAVE_SLOT') || 'My first graph')
const fileInput = ref<HTMLInputElement | null>(null) const fileInput = ref<HTMLInputElement | null>(null)
const { fitView } = useVueFlow() const { fitView } = useVueFlow()
@@ -53,6 +54,12 @@ function loadSample() {
refreshFlow() refreshFlow()
} }
function loadApiExample() {
editorText.value = JSON.stringify(parseGraphFxJson(apiExampleJson), null, 2)
selectedSaveSlot.value = 'api'
refreshFlow()
}
function saveSlotKey(name = selectedSaveSlot.value) { function saveSlotKey(name = selectedSaveSlot.value) {
return `GRAPHFX_UI_SAVE_${name}` return `GRAPHFX_UI_SAVE_${name}`
} }
@@ -129,6 +136,7 @@ refreshFlow()
<div class="toolbar"> <div class="toolbar">
<button type="button" @click="refreshFlow">Render JSON</button> <button type="button" @click="refreshFlow">Render JSON</button>
<button type="button" class="secondary" @click="loadSample">Load sample</button> <button type="button" class="secondary" @click="loadSample">Load sample</button>
<button type="button" class="secondary" @click="loadApiExample">Load api.json</button>
</div> </div>
<div class="savebar"> <div class="savebar">
@@ -150,7 +158,7 @@ refreshFlow()
</label> </label>
<label class="checkbox-row"> <label class="checkbox-row">
<input v-model="preferSavedPositions" type="checkbox" /> <input v-model="preferSavedPositions" type="checkbox" />
Prefer saved x/y when every node has coordinates Use saved x/y when every node has coordinates
</label> </label>
</div> </div>

View File

@@ -66,6 +66,15 @@ export function getOutputHandleId(nodeId: string, outputName: string) {
return `${nodeId}:out:${outputName}` return `${nodeId}:out:${outputName}`
} }
function serializedOutputIds(nodeId: string, outputName: string) {
return [
// GraphFX Output.id is `${outputsSet.id}-${name}` and Outputs.id is `${node.id}-out`.
`${nodeId}-out-${outputName}`,
// Keep accepting early graphfx-ui/sample shorthand.
`${nodeId}-${outputName}`,
]
}
const ioTypeColors: Record<GraphFxIoType, string> = { const ioTypeColors: Record<GraphFxIoType, string> = {
Image: '#4dd7ff', Image: '#4dd7ff',
Number: '#f6c85f', Number: '#f6c85f',
@@ -117,7 +126,7 @@ export function graphFxToVueFlow(graph: GraphFxSerializedGraph): GraphFxFlowMode
nodeIds.add(item.node.id) nodeIds.add(item.node.id)
for (const outputName of Object.keys(item.node.options?.out || {})) { for (const outputName of Object.keys(item.node.options?.out || {})) {
const serializedOutputId = `${item.node.id}-${outputName}` const [serializedOutputId, ...aliases] = serializedOutputIds(item.node.id, outputName)
if (outputBySerializedId.has(serializedOutputId)) { if (outputBySerializedId.has(serializedOutputId)) {
warnings.push({ warnings.push({
type: 'duplicate-output', type: 'duplicate-output',
@@ -128,6 +137,11 @@ export function graphFxToVueFlow(graph: GraphFxSerializedGraph): GraphFxFlowMode
}) })
} }
outputBySerializedId.set(serializedOutputId, { nodeId: item.node.id, outputName }) outputBySerializedId.set(serializedOutputId, { nodeId: item.node.id, outputName })
for (const alias of aliases) {
if (!outputBySerializedId.has(alias)) {
outputBySerializedId.set(alias, { nodeId: item.node.id, outputName })
}
}
} }
} }

View File

@@ -108,8 +108,17 @@ code {
.toolbar { .toolbar {
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.7rem; gap: 0.55rem;
}
.toolbar button {
padding-inline: 0.68rem;
white-space: nowrap;
}
.toolbar button:first-child {
grid-column: 1 / -1;
} }
.savebar { .savebar {