@myrmidon/cadmus-graph-ui-ex
Version:
Cadmus - extensions to semantic graph components.
597 lines (587 loc) • 23 kB
TypeScript
import * as _angular_core from '@angular/core';
import { AfterViewInit, OnDestroy, ElementRef, OnInit, PipeTransform } from '@angular/core';
import { Subject, Observable } from 'rxjs';
import { DialogService } from '@myrmidon/ngx-mat-tools';
import { LinkedNodeFilter, LinkedLiteralFilter, TripleFilter, GraphService, NodeSourceType, UriNode } from '@myrmidon/cadmus-api';
import { FormControl, FormGroup, FormBuilder } from '@angular/forms';
import { PageEvent } from '@angular/material/paginator';
import { GraphNodeLookupService } from '@myrmidon/cadmus-graph-ui';
/**
* Graph interfaces to replace ngx-graph types
*/
interface GraphNode {
id: string;
label?: string;
data?: any;
position?: {
x: number;
y: number;
};
dimension?: {
width: number;
height: number;
};
meta?: any;
color?: string;
[key: string]: any;
}
interface Edge {
id?: string;
source: string;
target: string;
label?: string;
data?: any;
line?: string;
meta?: any;
color?: string;
[key: string]: any;
}
interface ZoomOptions {
center?: boolean;
scale?: number;
animationDuration?: number;
force?: boolean;
}
interface Graph {
nodes: GraphNode[];
edges: Edge[];
}
type GraphMode = '2d' | '3d';
/**
* Force graph renderer component that can display graphs in 2D or 3D
* using force-graph and 3d-force-graph libraries.
*/
declare class ForceGraphRendererComponent implements AfterViewInit, OnDestroy {
graphContainer: ElementRef<HTMLDivElement>;
readonly nodes: _angular_core.InputSignal<GraphNode[]>;
readonly edges: _angular_core.InputSignal<Edge[]>;
readonly mode: _angular_core.InputSignal<GraphMode>;
readonly update$: _angular_core.InputSignal<Subject<boolean> | undefined>;
readonly center$: _angular_core.InputSignal<Subject<boolean> | undefined>;
readonly zoomToFit$: _angular_core.InputSignal<Subject<any> | undefined>;
readonly nodeSelect: _angular_core.OutputEmitterRef<GraphNode>;
readonly nodeDoubleClick: _angular_core.OutputEmitterRef<GraphNode>;
readonly modeChange: _angular_core.OutputEmitterRef<GraphMode>;
private graph;
private currentMode;
private clickTimeout;
private resizeObserver?;
private destroy$;
constructor();
ngAfterViewInit(): void;
ngOnDestroy(): void;
private initGraph;
private createGraph;
private convertToForceGraphData;
private getNode3DLabel;
private getLink3DLabel;
private truncateLabelFor3D;
private updateGraphData;
private getNodeColor;
private getNodeSize;
private getNodeSizeValue;
private getLinkColor;
private getLinkWidth;
private getLinkLabel;
private drawNode;
private drawLink;
private onNodeClick;
private onNodeHover;
private onBackgroundClick;
private setupSubscriptions;
toggleMode(): void;
private switchMode;
centerView(): void;
zoomToFit(): void;
private createNode3DWithLabel;
private createTextSprite;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ForceGraphRendererComponent, never>;
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ForceGraphRendererComponent, "cadmus-force-graph-renderer", never, { "nodes": { "alias": "nodes"; "required": false; "isSignal": true; }; "edges": { "alias": "edges"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "update$": { "alias": "update$"; "required": false; "isSignal": true; }; "center$": { "alias": "center$"; "required": false; "isSignal": true; }; "zoomToFit$": { "alias": "zoomToFit$"; "required": false; "isSignal": true; }; }, { "nodeSelect": "nodeSelect"; "nodeDoubleClick": "nodeDoubleClick"; "modeChange": "modeChange"; }, never, never, true, never>;
}
interface PagedTripleFilter extends TripleFilter {
pageNumber: number;
pageSize: number;
}
interface PagedLinkedLiteralFilter extends LinkedLiteralFilter {
pageNumber: number;
pageSize: number;
}
interface PagedLinkedNodeFilter extends LinkedNodeFilter {
pageNumber: number;
pageSize: number;
}
/**
* Essential graph walker data.
*/
interface WalkerData {
originId: string;
customColor?: string;
hidden?: boolean;
}
/**
* Graph walker widget data, i.e. a node or a property group.
*/
interface WalkerWidgetData extends WalkerData {
selected?: boolean;
expanded?: boolean;
error?: string;
}
/**
* Graph walker node data.
* ID: "N" + nodeid (e.g. "N3").
*/
interface WalkerNodeData extends WalkerWidgetData {
uri: string;
sourceType: NodeSourceType;
isClass?: boolean;
sid?: string;
tag?: string;
outFilter: PagedTripleFilter;
inFilter: PagedTripleFilter;
outTotal?: number;
inTotal?: number;
}
/**
* Graph walker property group data.
* ID: "P" + propertyid + "N" + source nodeid ("P2N3").
*/
interface WalkerPropData extends WalkerWidgetData {
uri: string;
outFilter: PagedLinkedNodeFilter;
inFilter: PagedLinkedNodeFilter;
litFilter: PagedLinkedLiteralFilter;
outTotal?: number;
inTotal?: number;
litTotal?: number;
}
/**
* Graph walker literal node data.
* ID: "L" + tripleid (e.g. "L5").
*/
interface WalkerLitData extends WalkerWidgetData {
value: string;
type?: string;
language?: string;
number?: number;
}
/**
* The total counts of items fetched by each children graph nodes filter.
*/
interface NodeChildTotals {
pOut: number;
pIn: number;
pLit: number;
nOut: number;
nIn: number;
}
/**
* Graph walker.
* This class encapsulates data used for interactively exploring a graph
* starting from a designated origin node.
*/
declare class GraphWalker {
private _graphService;
private readonly _nodes$;
private readonly _edges$;
private readonly _loading$;
private readonly _error$;
private _rootNode?;
private readonly _selectedNode$;
private readonly _pOutFilter$;
private readonly _pInFilter$;
private readonly _pLitFilter$;
private readonly _nOutFilter$;
private readonly _nInFilter$;
private readonly _childTotals$;
/**
* The page size. Default is 10.
*/
pageSize: number;
/**
* Max length of literal value to show. Default is 30.
*/
maxLiteralLen: number;
/**
* The nodes of the walker graph, which can represent nodes, literals,
* or property groups. You can easily determine the type of each node
* by looking at the first character of its id (N=node, L=literal,
* P=property).
*/
get nodes$(): Observable<GraphNode[]>;
/**
* The edges connecting nodes.
*/
get edges$(): Observable<Edge[]>;
/**
* True if the walker is loading data.
*/
get loading$(): Observable<boolean>;
/**
* The last error occurred in communicating with the server, if any.
*/
get error$(): Observable<string | null>;
/**
* The selected node. Only one node at a time can be selected.
*/
get selectedNode$(): Observable<GraphNode | null>;
/**
* The outbound linked nodes filter for the selected P node.
*/
get pOutFilter$(): Observable<PagedLinkedNodeFilter | null>;
/**
* The inbound linked nodes filter for the selected P node.
*/
get pInFilter$(): Observable<PagedLinkedNodeFilter | null>;
/**
* The literal linked nodes filter for the selected P node.
*/
get pLitFilter$(): Observable<PagedLinkedLiteralFilter | null>;
/**
* The outbound triples filter for the selected N node.
*/
get nOutFilter$(): Observable<PagedTripleFilter | null>;
/**
* The inbound triples filter for the selected N node.
*/
get nInFilter$(): Observable<PagedTripleFilter | null>;
/**
* The total items fetched for each filter of the selected node.
*/
get childTotals$(): Observable<NodeChildTotals>;
constructor(_graphService: GraphService);
getSelectedNode(): GraphNode | null;
private toggleLoading;
private setError;
private buildNodeId;
/**
* Get the numeric ID of the data node being the source of the graph node
* with the specified ID.
*
* @param id The graph node ID (...N + its data node numeric ID)
* @returns The data node numeric ID.
*/
private getNodeNumericId;
private getPredicateNumericId;
private buildEdgeId;
private buildPropertyId;
private buildLiteralId;
private addEdgeIfAbsent;
private resetFilters;
/**
* Select the specified node. This also implies updating all the current
* filters, which depend on the selected node.
*
* @param id The node ID or null to deselect the selected node.
*/
selectNode(id: string | null): void;
/**
* Reset the graph setting its origin to the specified node.
*
* @param id The ID of the origin node to start from ("root origin").
*/
reset(id: number): void;
/**
* Get the source and target graph nodes IDs from the specified edge ID.
*
* @param edgeId The ID of the edge graph node.
* @returns IDs of the source and target graph nodes.
*/
private getEdgeEndIds;
/**
* Remove all the nodes with the specified origin node ID.
*
* @param originId The ID of the origin graph node.
* @param nodes The nodes array to remove nodes from.
* @param removedIds The IDs of all the removed nodes.
*/
private removeDescendantNodes;
/**
* Remove all the children graph nodes of the specified origin graph node.
*
* @param originId The ID of the origin graph node.
* @param nodes The nodes array to remove nodes from.
* @param edges The edges array to remove edges from.
*/
private removeChildren;
/**
* Build a new graph node representing a property.
*
* @param sourceId The source node ID.
* @param group The triple group emitting this node.
* @returns A new graph node.
*/
private buildPropertyNode;
/**
* Expand the specified node, by loading its property groups.
*
* @param node The node to expand.
* @param outFilter The properties to update for the output filter.
* @param inFilter The properties to update for the input filter.
*/
expandNode(node: GraphNode, outFilter?: Partial<PagedTripleFilter> | null, inFilter?: Partial<PagedTripleFilter> | null): void;
/**
* Expand the selected node, by loading its property groups.
*
* @param outFilter The properties to update for the output filter.
* @param inFilter The properties to update for the input filter.
*/
expandSelectedNode(outFilter?: Partial<PagedTripleFilter> | null, inFilter?: Partial<PagedTripleFilter> | null): void;
private buildLiteralLabel;
private buildNonLiteralNode;
private buildLiteralNode;
/**
* Expand the currently selected properties group node, by loading its
* outbound nodes, inbound nodes, and literal nodes.
*
* @param node The property group node to expand.
* @param outFilter The properties to update for the outbound nodes filter.
* @param inFilter The properties to update for the inbound nodes filter.
* @param litFilter The properties to update for the literal nodes filter.
*/
expandProperty(node: GraphNode, outFilter?: Partial<PagedLinkedNodeFilter> | null, inFilter?: Partial<PagedLinkedNodeFilter> | null, litFilter?: Partial<PagedLinkedLiteralFilter> | null): void;
/**
* Expand the currently selected properties group node, by loading its
* outbound nodes, inbound nodes, and literal nodes. If there is no
* selection, or the selected node is not a properties group node, nothing
* is done.
*
* @param outFilter The properties to update for the outbound nodes filter.
* @param inFilter The properties to update for the inbound nodes filter.
* @param litFilter The properties to update for the literal nodes filter.
*/
expandSelectedProperty(outFilter?: Partial<PagedLinkedNodeFilter> | null, inFilter?: Partial<PagedLinkedNodeFilter> | null, litFilter?: Partial<PagedLinkedLiteralFilter> | null): void;
/**
* Toggle the specified node by expanding or collapsing it.
*
* @param node The node to toggle.
*/
toggleNode(node: GraphNode): void;
}
/**
* Graph walker component. This starts from a given node, and let users
* walk along edges to discover new nodes.
*/
declare class GraphWalkerComponent implements OnInit, OnDestroy {
private _dialog;
private _sub?;
private _walker?;
/**
* The root origin node ID.
*/
readonly nodeId: _angular_core.InputSignal<number>;
/**
* The graph service instance to use.
*/
readonly graphService: _angular_core.InputSignal<GraphService | undefined>;
/**
* True if user can pick a node from the graph.
*/
readonly canPick: _angular_core.InputSignal<boolean | undefined>;
/**
* True if user can move to the source of a picked node when
* shift-clicking it.
*/
readonly canMoveToSource: _angular_core.InputSignal<boolean | undefined>;
/**
* The graph visualization mode (2D or 3D).
*/
readonly graphMode: _angular_core.WritableSignal<GraphMode>;
/**
* Emitted when a graph node is picked by user.
*/
readonly nodePick: _angular_core.OutputEmitterRef<GraphNode>;
/**
* Emitted when the user requests to move to the source of a picked node.
*/
readonly moveToSource: _angular_core.OutputEmitterRef<GraphNode>;
nodes$: Observable<GraphNode[]>;
edges$: Observable<Edge[]>;
loading$: Observable<boolean>;
error$: Observable<string | null>;
selectedNode$: Observable<GraphNode | null>;
pOutFilter$: Observable<PagedLinkedNodeFilter | null>;
pInFilter$: Observable<PagedLinkedNodeFilter | null>;
pLitFilter$: Observable<PagedLinkedLiteralFilter | null>;
nOutFilter$: Observable<PagedTripleFilter | null>;
nInFilter$: Observable<PagedTripleFilter | null>;
childTotals$: Observable<NodeChildTotals>;
update$: Subject<boolean>;
center$: Subject<boolean>;
zoomToFit$: Subject<ZoomOptions>;
constructor(_dialog: DialogService);
private setupObservables;
ngOnInit(): void;
ngOnDestroy(): void;
onNodeSelect(node: GraphNode): void;
private reset;
onReset(): void;
onNodeDblClick(node: GraphNode): void;
onGraphModeChange(mode: GraphMode): void;
onPOutFilterChange(filter: PagedLinkedNodeFilter): void;
onPInFilterChange(filter: PagedLinkedNodeFilter): void;
onPLitFilterChange(filter: PagedLinkedLiteralFilter): void;
onNOutFilterChange(filter: PagedTripleFilter): void;
onNInFilterChange(filter: PagedTripleFilter): void;
pickSelectedNode(event: MouseEvent): void;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<GraphWalkerComponent, never>;
static ɵcmp: _angular_core.ɵɵComponentDeclaration<GraphWalkerComponent, "cadmus-graph-walker", never, { "nodeId": { "alias": "nodeId"; "required": false; "isSignal": true; }; "graphService": { "alias": "graphService"; "required": false; "isSignal": true; }; "canPick": { "alias": "canPick"; "required": false; "isSignal": true; }; "canMoveToSource": { "alias": "canMoveToSource"; "required": false; "isSignal": true; }; }, { "nodePick": "nodePick"; "moveToSource": "moveToSource"; }, never, never, true, never>;
}
/**
* Linked literal filter.
*/
declare class LinkedLiteralFilterComponent {
lookupService: GraphNodeLookupService;
private _graphService;
/**
* True if this component is disabled.
*/
readonly disabled: _angular_core.InputSignal<boolean | undefined>;
/**
* True if this component should show a pager.
*/
readonly hasPager: _angular_core.InputSignal<boolean | undefined>;
/**
* The total number of triples returned from the last
* page fetch operation. Used when hasPager is true.
*/
readonly total: _angular_core.InputSignal<number>;
/**
* The filter.
*/
readonly filter: _angular_core.ModelSignal<PagedLinkedLiteralFilter>;
pageNumber: FormControl<number>;
pageSize: FormControl<number>;
litPattern: FormControl<string | null>;
litType: FormControl<string | null>;
litLanguage: FormControl<string | null>;
minLitNumber: FormControl<number | null>;
maxLitNumber: FormControl<number | null>;
subj: FormControl<UriNode | null>;
pred: FormControl<UriNode | null>;
form: FormGroup;
constructor(formBuilder: FormBuilder, lookupService: GraphNodeLookupService, _graphService: GraphService);
private updateForm;
private getFilter;
onSubjectNodeChange(node: unknown): void;
onPredicateNodeChange(node: unknown): void;
onPageChange(page: PageEvent): void;
reset(): void;
apply(): void;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LinkedLiteralFilterComponent, never>;
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LinkedLiteralFilterComponent, "cadmus-walker-linked-literal-filter", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "hasPager": { "alias": "hasPager"; "required": false; "isSignal": true; }; "total": { "alias": "total"; "required": false; "isSignal": true; }; "filter": { "alias": "filter"; "required": false; "isSignal": true; }; }, { "filter": "filterChange"; }, never, never, true, never>;
}
/**
* Linked non-literal node filter.
*/
declare class LinkedNodeFilterComponent {
lookupService: GraphNodeLookupService;
private _graphService;
/**
* True if this component is disabled.
*/
readonly disabled: _angular_core.InputSignal<boolean | undefined>;
/**
* True if this component should show a pager.
*/
readonly hasPager: _angular_core.InputSignal<boolean>;
/**
* The total number of nodes returned from the last
* page fetch operation. Used when hasPager is true.
*/
readonly total: _angular_core.InputSignal<number>;
/**
* The filter.
*/
readonly filter: _angular_core.ModelSignal<PagedLinkedNodeFilter>;
otherNodeId: number;
predicateId: number;
isObject: boolean;
pageNumber: FormControl<number>;
pageSize: FormControl<number>;
uid: FormControl<string | null>;
isClass: FormControl<boolean | null>;
tag: FormControl<string | null>;
label: FormControl<string | null>;
sourceType: FormControl<NodeSourceType | null>;
sid: FormControl<string | null>;
isSidPrefix: FormControl<boolean>;
classes: FormControl<UriNode[]>;
form: FormGroup;
constructor(formBuilder: FormBuilder, lookupService: GraphNodeLookupService, _graphService: GraphService);
private updateForm;
private getFilter;
onPageChange(page: PageEvent): void;
onClassAdd(node: unknown): void;
onClassRemove(node: UriNode): void;
reset(): void;
apply(): void;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LinkedNodeFilterComponent, never>;
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LinkedNodeFilterComponent, "cadmus-walker-linked-node-filter", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "hasPager": { "alias": "hasPager"; "required": false; "isSignal": true; }; "total": { "alias": "total"; "required": false; "isSignal": true; }; "filter": { "alias": "filter"; "required": false; "isSignal": true; }; }, { "filter": "filterChange"; }, never, never, true, never>;
}
/**
* Triples filter.
*/
declare class TripleFilterComponent {
lookupService: GraphNodeLookupService;
private _graphService;
/**
* True if this component is disabled.
*/
readonly disabled: _angular_core.InputSignal<boolean>;
/**
* True if this component should show a pager.
*/
readonly hasPager: _angular_core.InputSignal<boolean>;
/**
* The total number of triples returned from the last
* page fetch operation. Used when hasPager is true.
*/
readonly total: _angular_core.InputSignal<number>;
/**
* The filter.
*/
readonly filter: _angular_core.ModelSignal<PagedTripleFilter>;
pageNumber: FormControl<number>;
pageSize: FormControl<number>;
litPattern: FormControl<string | null>;
litType: FormControl<string | null>;
litLanguage: FormControl<string | null>;
minLitNumber: FormControl<number | null>;
maxLitNumber: FormControl<number | null>;
subj: FormControl<UriNode | null>;
isNotPred: FormControl<boolean>;
preds: FormControl<UriNode[]>;
notPreds: FormControl<UriNode[]>;
hasLiteralObj: FormControl<boolean | null>;
obj: FormControl<UriNode | null>;
sid: FormControl<string | null>;
isSidPrefix: FormControl<boolean>;
tag: FormControl<string | null>;
form: FormGroup;
constructor(formBuilder: FormBuilder, lookupService: GraphNodeLookupService, _graphService: GraphService);
private updateForm;
private getFilter;
onPageChange(page: PageEvent): void;
onSubjectNodeChange(node: unknown): void;
onObjectNodeChange(node: unknown): void;
onPredicateNodeChange(node: unknown): void;
deleteNotPred(node: UriNode): void;
deletePred(node: UriNode): void;
reset(): void;
apply(): void;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<TripleFilterComponent, never>;
static ɵcmp: _angular_core.ɵɵComponentDeclaration<TripleFilterComponent, "cadmus-walker-triple-filter", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "hasPager": { "alias": "hasPager"; "required": false; "isSignal": true; }; "total": { "alias": "total"; "required": false; "isSignal": true; }; "filter": { "alias": "filter"; "required": false; "isSignal": true; }; }, { "filter": "filterChange"; }, never, never, true, never>;
}
/**
* Get the extended label for the specified graph node. This returns the label
* for N nodes, and the uri + "=" + the label for P nodes. That's because P
* nodes label is just the count of the triples group, so the predicate ID is
* got from the property node's data uri.
*/
declare class GraphNodeLabelPipe implements PipeTransform {
transform(value: unknown, ...args: unknown[]): unknown;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<GraphNodeLabelPipe, never>;
static ɵpipe: _angular_core.ɵɵPipeDeclaration<GraphNodeLabelPipe, "graphNodeLabel", true>;
}
export { ForceGraphRendererComponent, GraphNodeLabelPipe, GraphWalker, GraphWalkerComponent, LinkedLiteralFilterComponent, LinkedNodeFilterComponent, TripleFilterComponent };
export type { Edge, Graph, GraphMode, GraphNode, NodeChildTotals, PagedLinkedLiteralFilter, PagedLinkedNodeFilter, PagedTripleFilter, WalkerData, WalkerLitData, WalkerNodeData, WalkerPropData, WalkerWidgetData, ZoomOptions };