123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- // The React state and reducer of a D3Graph component showing an onion graph state.
- import {PrimitiveValue} from "onion/types";
- import {INodeState, IValueState, GraphStateListener} from "onion/graph_state";
- import {D3GraphData, D3NodeData, D3LinkData} from "../d3graph";
- export type D3OnionNodeData = D3NodeData<INodeState|IValueState>;
- export type D3OnionLinkData = D3LinkData<null>;
- export type D3OnionGraphData = D3GraphData<INodeState|IValueState,null>;
- interface AddNode {type:'addNode', ns: INodeState, x: number, y: number}
- interface RemoveNode {type:'removeNode', id: PrimitiveValue}
- interface AddValue {type:'addValue', vs: IValueState, x: number, y: number}
- interface RemoveValue {type:'removeValue', value: PrimitiveValue}
- interface AddLinkToNode {type:'addLinkToNode', sourceId: PrimitiveValue, label: string, targetId: PrimitiveValue}
- interface AddLinkToValue {type:'addLinkToValue', sourceId: PrimitiveValue, label: string, targetValue: PrimitiveValue}
- interface RemoveLink {type:'removeLink', sourceId: PrimitiveValue, label: string}
- export type D3OnionGraphAction =
- Readonly<AddNode>
- | Readonly<RemoveNode>
- | Readonly<AddValue>
- | Readonly<RemoveValue>
- | Readonly<AddLinkToNode>
- | Readonly<AddLinkToValue>
- | Readonly<RemoveLink>;
- export function onionGraphReducer(prevState: D3OnionGraphData, action: D3OnionGraphAction): D3OnionGraphData {
- switch (action.type) {
- case 'addNode': {
- return {
- nodes: [...prevState.nodes, {
- id: nodeNodeId(action.ns.creation.id.value),
- label: JSON.stringify(action.ns.creation.id.value),
- x: action.x,
- y: action.y,
- color: "darkturquoise",
- obj: action.ns,
- bold: false,
- }],
- links: prevState.links,
- };
- }
- case 'removeNode': {
- return {
- nodes: prevState.nodes.filter(n => !n.obj.isNode(action.id)),
- links: prevState.links,
- };
- }
- case 'addValue': {
- return {
- nodes: [...prevState.nodes, {
- id: valueNodeId(action.vs.value),
- label: JSON.stringify(action.vs.value),
- x: action.x,
- y: action.y,
- color: "darkorange",
- obj: action.vs,
- bold: false,
- }],
- links: prevState.links,
- };
- }
- case 'removeValue': {
- return {
- nodes: prevState.nodes.filter(n => !n.obj.isValue(action.value)),
- links: prevState.links,
- };
- }
- case 'addLinkToNode': {
- return {
- nodes: prevState.nodes,
- links: [...prevState.links, {
- source: prevState.nodes.find(n => n.obj.isNode(action.sourceId)), // AR: here is the problem!
- target: prevState.nodes.find(n => n.obj.isNode(action.targetId)),
- label: action.label,
- color: 'black',
- obj: null,
- }],
- };
- }
- case 'addLinkToValue': {
- return {
- nodes: prevState.nodes,
- links: [...prevState.links, {
- source: prevState.nodes.find(n => n.obj.isNode(action.sourceId)),
- target: prevState.nodes.find(n => n.obj.isValue(action.targetValue)),
- label: action.label,
- color: 'black',
- obj: null,
- }],
- };
- }
- case 'removeLink': {
- return {
- nodes: prevState.nodes,
- links: prevState.links.filter(l => l.source.obj.creation.id.value !== action.sourceId || l.label !== action.label),
- };
- }
- }
- }
- function nodeNodeId(nodeId: PrimitiveValue) {
- return "N"+JSON.stringify(nodeId);
- }
- function valueNodeId(value: PrimitiveValue) {
- return "V"+JSON.stringify(value);
- }
- // Responds to changes to a GraphState object by updating the React state of a d3Graph component.
- export class D3GraphUpdater implements GraphStateListener {
- readonly setGraph: (cb: (prevGraph: D3OnionGraphData) => D3OnionGraphData) => void;
- // SVG coordinates for newly created nodes
- // This information cannot be part of our NodeCreation deltas, but it must come from somewhere...
- x: number;
- y: number;
- constructor(setGraph: (cb: (prevGraph: D3OnionGraphData) => D3OnionGraphData) => void, x, y) {
- this.setGraph = setGraph;
- this.x = x;
- this.y = y;
- }
- createNode(ns: INodeState) {
- this.setGraph(prevGraph => onionGraphReducer(prevGraph, {type: 'addNode', ns, x: this.x, y: this.y}));
- }
- createValue(vs: IValueState) {
- this.setGraph(prevGraph => onionGraphReducer(prevGraph, {type: 'addValue', vs, x: this.x, y: this.y}));
- }
- deleteNode(id: PrimitiveValue) {
- this.setGraph(prevGraph => onionGraphReducer(prevGraph, {type: 'removeNode', id}));
- }
- deleteValue(value: PrimitiveValue) {
- this.setGraph(prevGraph => onionGraphReducer(prevGraph, {type: 'removeValue', value}));
- }
- createLinkToNode(sourceId: PrimitiveValue, label: string, targetId: PrimitiveValue) {
- this.setGraph(prevGraph => onionGraphReducer(prevGraph, {type: 'addLinkToNode', sourceId, label, targetId}));
- }
- createLinkToValue(sourceId: PrimitiveValue, label: string, targetValue: PrimitiveValue) {
- this.setGraph(prevGraph => onionGraphReducer(prevGraph, {type: 'addLinkToValue', sourceId, label, targetValue}));
- }
- deleteLink(sourceId: PrimitiveValue, label: string) {
- this.setGraph(prevGraph => onionGraphReducer(prevGraph, {type: 'removeLink', sourceId, label}));
- }
- }
|