140 lines
4.0 KiB
TypeScript
140 lines
4.0 KiB
TypeScript
/**
|
|
* Module: Graph of Terms graphical representation.
|
|
*/
|
|
import { type Edge, type Node } from 'reactflow';
|
|
import dagre from '@dagrejs/dagre';
|
|
|
|
import { PARAMETER } from '@/utils/constants';
|
|
|
|
import { CstType } from '../backend/types';
|
|
import { type GraphFilterParams, type GraphType } from '../stores/term-graph';
|
|
|
|
import { type IConstituenta, type IRSForm } from './rsform';
|
|
|
|
export interface TGNodeState {
|
|
cst: IConstituenta;
|
|
focused: boolean;
|
|
}
|
|
|
|
/** Represents graph node. */
|
|
export interface TGNodeData extends Node {
|
|
id: string;
|
|
data: TGNodeState;
|
|
}
|
|
|
|
/** Represents graph node internal data. */
|
|
export interface TGNodeInternal {
|
|
id: string;
|
|
data: TGNodeState;
|
|
selected: boolean;
|
|
dragging: boolean;
|
|
xPos: number;
|
|
yPos: number;
|
|
}
|
|
|
|
export function applyLayout(nodes: Node<TGNodeState>[], edges: Edge[], subLabels: boolean) {
|
|
const dagreGraph = new dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
|
|
dagreGraph.setGraph({
|
|
rankdir: 'TB',
|
|
ranksep: subLabels ? 60 : 40,
|
|
nodesep: subLabels ? 100 : 20,
|
|
ranker: 'network-simplex'
|
|
});
|
|
nodes.forEach(node => {
|
|
dagreGraph.setNode(node.id, { width: 2 * PARAMETER.graphNodeRadius, height: 2 * PARAMETER.graphNodeRadius });
|
|
});
|
|
|
|
edges.forEach(edge => {
|
|
dagreGraph.setEdge(edge.source, edge.target);
|
|
});
|
|
|
|
dagre.layout(dagreGraph);
|
|
|
|
nodes.forEach(node => {
|
|
const nodeWithPosition = dagreGraph.node(node.id);
|
|
node.position.x = nodeWithPosition.x - PARAMETER.graphNodeRadius;
|
|
node.position.y = nodeWithPosition.y - PARAMETER.graphNodeRadius;
|
|
});
|
|
}
|
|
|
|
export function inferEdgeType(schema: IRSForm, source: number, target: number): GraphType {
|
|
const isDefinition = schema.graph.hasEdge(source, target);
|
|
const isAttribution = schema.attribution_graph.hasEdge(source, target);
|
|
if (!isDefinition && !isAttribution) {
|
|
return 'definition';
|
|
} else if (isDefinition && isAttribution) {
|
|
return 'full';
|
|
} else if (isDefinition) {
|
|
return 'definition';
|
|
} else {
|
|
return 'attribution';
|
|
}
|
|
}
|
|
|
|
export function produceFilteredGraph(schema: IRSForm, params: GraphFilterParams, focusCst: IConstituenta | null) {
|
|
const filtered =
|
|
params.graphType === 'full'
|
|
? schema.full_graph.clone()
|
|
: params.graphType === 'attribution'
|
|
? schema.attribution_graph.clone()
|
|
: schema.graph.clone();
|
|
const allowedTypes: CstType[] = (() => {
|
|
const result: CstType[] = [];
|
|
if (params.allowBase) result.push(CstType.BASE);
|
|
if (params.allowStruct) result.push(CstType.STRUCTURED);
|
|
if (params.allowTerm) result.push(CstType.TERM);
|
|
if (params.allowAxiom) result.push(CstType.AXIOM);
|
|
if (params.allowFunction) result.push(CstType.FUNCTION);
|
|
if (params.allowPredicate) result.push(CstType.PREDICATE);
|
|
if (params.allowConstant) result.push(CstType.CONSTANT);
|
|
if (params.allowTheorem) result.push(CstType.THEOREM);
|
|
if (params.allowNominal) result.push(CstType.NOMINAL);
|
|
return result;
|
|
})();
|
|
|
|
if (params.noTemplates) {
|
|
schema.items.forEach(cst => {
|
|
if (cst !== focusCst && cst.is_template) {
|
|
filtered.foldNode(cst.id);
|
|
}
|
|
});
|
|
}
|
|
if (allowedTypes.length < Object.values(CstType).length) {
|
|
schema.items.forEach(cst => {
|
|
if (cst !== focusCst && !allowedTypes.includes(cst.cst_type)) {
|
|
filtered.foldNode(cst.id);
|
|
}
|
|
});
|
|
}
|
|
if (!focusCst && params.foldDerived) {
|
|
schema.items.forEach(cst => {
|
|
if (cst.spawner) {
|
|
filtered.foldNode(cst.id);
|
|
}
|
|
});
|
|
}
|
|
if (params.noHermits) {
|
|
filtered.removeIsolated();
|
|
}
|
|
|
|
if (focusCst) {
|
|
const includes: number[] = [
|
|
focusCst.id,
|
|
...focusCst.spawn,
|
|
...(params.focusShowInputs ? schema.graph.expandInputs([focusCst.id]) : []),
|
|
...(params.focusShowOutputs ? schema.graph.expandOutputs([focusCst.id]) : [])
|
|
];
|
|
schema.items.forEach(cst => {
|
|
if (!includes.includes(cst.id)) {
|
|
filtered.foldNode(cst.id);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (params.noTransitive) {
|
|
filtered.transitiveReduction();
|
|
}
|
|
|
|
return filtered;
|
|
}
|