81 lines
3.7 KiB
EmacsLisp
81 lines
3.7 KiB
EmacsLisp
// serializer.el — Export graph as SVG string or portable JSON.
|
|
//
|
|
// Public API:
|
|
// graph_to_svg(graph_json, width, height) -> String
|
|
// graph_json: { "nodes": [...], "edges": [...] }
|
|
// Full pipeline: parse -> layout -> render -> SVG string.
|
|
//
|
|
// graph_to_json(nodes_json, edges_json, positions_json) -> String
|
|
// Portable export combining node data with computed positions.
|
|
// Useful for saving layouts to disk or sending to other tools.
|
|
|
|
// ── graph_to_svg ──────────────────────────────────────────────────────────────
|
|
//
|
|
// Convenience wrapper: accepts a combined graph JSON object and returns SVG.
|
|
|
|
fn graph_to_svg(graph_json: String, width: Int, height: Int) -> String {
|
|
let nodes_raw: String = json_get_raw(graph_json, "nodes")
|
|
let edges_raw: String = json_get_raw(graph_json, "edges")
|
|
let nodes_json: String = if str_eq(nodes_raw, "") { "[]" } else { nodes_raw }
|
|
let edges_json: String = if str_eq(edges_raw, "") { "[]" } else { edges_raw }
|
|
graph_svg_endpoint(nodes_json, edges_json, width, height)
|
|
}
|
|
|
|
// ── graph_to_json ─────────────────────────────────────────────────────────────
|
|
//
|
|
// Merge node metadata with computed positions into a portable export format.
|
|
// Output: { "nodes": [{...node fields..., "x": 123.0, "y": 456.0}], "edges": [...] }
|
|
|
|
fn graph_to_json(nodes_json: String, edges_json: String, positions_json: String) -> String {
|
|
// Index positions by id
|
|
build_position_index(positions_json)
|
|
|
|
let node_count: Int = json_array_len(nodes_json)
|
|
let nodes_out: String = "["
|
|
let i: Int = 0
|
|
while i < node_count {
|
|
let n: String = json_array_get(nodes_json, i)
|
|
let id: String = json_get_string(n, "id")
|
|
let x: Float = get_pos_x(id)
|
|
let y: Float = get_pos_y(id)
|
|
// Inject x/y into the node JSON
|
|
let n_with_pos: String = json_set(json_set(n, "x", format_float(x, 1)), "y", format_float(y, 1))
|
|
if i == 0 {
|
|
let nodes_out = nodes_out + n_with_pos
|
|
} else {
|
|
let nodes_out = nodes_out + "," + n_with_pos
|
|
}
|
|
let i = i + 1
|
|
}
|
|
let nodes_out = nodes_out + "]"
|
|
|
|
"{\"nodes\":" + nodes_out + ",\"edges\":" + edges_json + "}"
|
|
}
|
|
|
|
// ── graph_snapshot_svg ────────────────────────────────────────────────────────
|
|
//
|
|
// Render a snapshot of the current in-process Engram graph as SVG.
|
|
// Uses engram_scan_nodes_json and reads edges from the snapshot file.
|
|
// This is the function called by the CGI Studio /api/graph/svg endpoint.
|
|
|
|
fn graph_snapshot_svg(width: Int, height: Int, snap_path: String) -> String {
|
|
let nodes_json: String = engram_scan_nodes_json(9999, 0)
|
|
let n_count: Int = json_array_len(nodes_json)
|
|
|
|
// Read edges from snapshot file
|
|
let snap: String = fs_read(snap_path)
|
|
let edges_raw: String = if str_eq(snap, "") { "[]" } else { json_get_raw(snap, "edges") }
|
|
let edges_json: String = if str_eq(edges_raw, "") { "[]" } else { edges_raw }
|
|
|
|
if n_count == 0 {
|
|
// Return an empty SVG with a "no data" message
|
|
return svg_open(width, height) +
|
|
"<text x=\"" + int_to_str(width / 2) + "\" y=\"" + int_to_str(height / 2) + "\" " +
|
|
"text-anchor=\"middle\" fill=\"#8b9aaa\" font-size=\"14\" " +
|
|
"font-family=\"IBM Plex Mono,monospace\">No nodes in graph</text>" +
|
|
svg_close()
|
|
}
|
|
|
|
graph_svg_endpoint(nodes_json, edges_json, width, height)
|
|
}
|