Skip to content

Commit

Permalink
#36 parent child relationship logic moved to application
Browse files Browse the repository at this point in the history
  • Loading branch information
ddelpiano committed Oct 25, 2022
1 parent 556b1eb commit 1e1b144
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 31 deletions.
5 changes: 0 additions & 5 deletions installation.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@ function parse() {
parse "$@"

echo "=== Install / Update script for PsyNeuLinkViewer and meta-diagram ==="
#echo "Install is"
#echo $INSTALL
#echo "Update is"
#echo $UPDATE



if [ "$INSTALL" = true ]; then
Expand Down
21 changes: 11 additions & 10 deletions src/components/Main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import Composition from './views/compositions/Composition';
import GenericMechanism from './views/mechanisms/GenericMechanism';
import MetaDiagram, { CallbackTypes, ComponentsMap, EventTypes, Position } from "@metacell/meta-diagram";
import CustomLinkWidget from './views/projections/CustomLinkWidget';
import { generateMetaGraph } from '../model/utils';
const mockModel = require('../resources/model').mockModel;


const styles = () => ({
root: {
height: 'calc(100vh - 3.5rem)',
Expand Down Expand Up @@ -40,23 +42,22 @@ class Main extends React.Component {
this.handlePreUpdates = this.handlePreUpdates.bind(this);
this.handlePostUpdates = this.handlePostUpdates.bind(this);
this.mouseMoveCallback = this.mouseMoveCallback.bind(this);
}

calculateDelta(metaNode, metaNodeModel) {
let oldPosition = new Position(metaNode.position.x, metaNode.position.y);
let newPosition = new Position(metaNodeModel.position.x, metaNodeModel.position.y);
return oldPosition.sub(newPosition)
this.metaGraph = generateMetaGraph([...this.metaModel[PNLClasses.COMPOSITION], ...this.metaModel[PNLClasses.MECHANISM]]);
this.metaGraph.addLinks(this.metaModel[PNLClasses.PROJECTION]);
}

handlePostUpdates(event) {
switch(event.function) {
case CallbackTypes.POSITION_CHANGED: {
this.interpreter.updateModel(event.entity);
break;
const node = event.entity;
this.metaGraph.handleNodePositionChanged(node, this.mousePos.x, this.mousePos.y);
this.interpreter.updateModel(node);
return true;
}
default: {
console.log('Function callback type not yet implemented ' + event.function);
break;
return false;
}
}
}
Expand Down Expand Up @@ -94,8 +95,8 @@ class Main extends React.Component {
<MetaDiagram
metaCallback={this.metaCallback}
componentsMap={this.componentsMap}
metaLinks={this.metaModel[PNLClasses.PROJECTION]}
metaNodes={[...this.metaModel[PNLClasses.COMPOSITION], ...this.metaModel[PNLClasses.MECHANISM]]}
metaLinks={this.metaGraph.getLinks()}
metaNodes={this.metaGraph.getNodes()}
metaTheme={{
customThemeVariables: {},
canvasClassName: classes.canvasBG,
Expand Down
220 changes: 220 additions & 0 deletions src/components/graph/MetaGraph.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
// import {MetaNodeModel} from "../react-diagrams/MetaNodeModel";
import {MetaLink, MetaNodeModel, MetaLinkModel} from "@metacell/meta-diagram"

class Graph {
private readonly node: MetaNodeModel;
private readonly children: Map<string, Graph>;

constructor(metaNodeModel: MetaNodeModel) {
this.node = metaNodeModel;
this.children = new Map<string, Graph>()
}

getID() : string{
return this.node.getID()
}

getNode() : MetaNodeModel{
return this.node
}

getChild(id:string) {
return this.children.get(id)
}

addChild(graph: Graph) : void {
this.children.set(graph.getID(), graph)
}

getChildren(): MetaNodeModel[] {
return Array.from(this.children.values()).map(g => g.getNode())
}

getDescendancy(): MetaNodeModel[] {
const descendancy = this.getChildren()
for(const graph of Array.from(this.children.values())){
descendancy.push(...graph.getDescendancy())
}
return descendancy
}

dfs(id: string): MetaNodeModel | boolean {
if(this.getID() === id){
return this.node
}
for (let node of Array.from(this.children.values())) {
const found = node.dfs(id)
if(found){
return found
}
}
return false
}

getContainerBoundingBox() : any {
return this.node.getNodeBoundingBox();
}
}


export class MetaGraph {
private readonly roots: Map<string, Graph>;
private readonly links: MetaLinkModel[];

constructor() {
this.roots = new Map<string, Graph>()
this.links = [];
}

addLinks(links: MetaLink[]) {
links.forEach( (child: MetaLink) => {
const link = child.toModel();
const source = this.getNodeDFS(child.getSourceId());
const target = this.getNodeDFS(child.getTargetId());
if (source && target) {
link.setSourcePort(source.getPort(child.getSourcePortId()));
link.setTargetPort(target.getPort(child.getTargetPortId()));
this.links.push(link);
}
});
}

getLinks(): MetaLinkModel[] {
return this.links;
}

addNode(metaNodeModel:MetaNodeModel): void {
const path = metaNodeModel.getGraphPath()
if(path.length === 1){
this.roots.set(metaNodeModel.getID(), new Graph(metaNodeModel))
}else{
path.pop() // Removes own id from path
const parentGraph = this.findNodeGraph(path)
parentGraph.addChild(new Graph(metaNodeModel))
}
}

getNodes() : MetaNodeModel[] {
const nodes = []
for(const graph of Array.from(this.roots.values())){
nodes.push(graph.getNode())
nodes.push(...graph.getDescendancy())
}
return nodes
}

getAncestors(node : MetaNodeModel): MetaNodeModel[] {
const path = node.getGraphPath()
const oldestAncestor = this.getRoot(path[0])
return [oldestAncestor.getNode(), ...oldestAncestor.getChildren()]
}

getRoot(rootId: string) : Graph{
const root = this.roots.get(rootId)
if(root === undefined){
throw new Error('unknown parent ' + rootId);
}
return root
}

getChildren(parent : MetaNodeModel): MetaNodeModel[] {
const path = parent.getGraphPath()
if (path.length === 1) {
const root = this.getRoot(parent.getID())
return root.getChildren()
} else {
const graph = this.findNodeGraph(path)
return graph.getChildren()
}
}

getParent(node : MetaNodeModel): MetaNodeModel | undefined {
const path = node.getGraphPath()
if (path.length === 1) {
return undefined
} else {
path.pop() // removes own id from path
const parentGraph = this.findNodeGraph(path)
return parentGraph.getNode()
}
}

getNodeDFS(nodeId: string): MetaNodeModel | undefined {
for (let root of Array.from(this.roots.values())) {
const found = root.dfs(nodeId)
if(found){
// @ts-ignore
return found
}
}
return undefined
}

getNodeContainerBoundingBox(node: MetaNodeModel) : any {
const graph = this.findNodeGraph(node.getGraphPath())
return graph.getContainerBoundingBox()
}

private findNodeGraph(path: string[]) : Graph {
const rootId = path.shift()
// @ts-ignore
let parent = this.getRoot(rootId)
while(path.length > 0){
const next = path.shift()
// @ts-ignore
parent = parent.getChild(next)
if (parent === undefined){
throw new Error('unknown parent ' + rootId);
}
}
return parent
}

handleNodePositionChanged(metaNodeModel: MetaNodeModel, cursorX: number, cursorY: number){
// TODO: Update node parent (add or remove parent)
// update node graph path,
// bounding boxes of parents

// Update children position (children should move the same delta as node)
this.updateChildrenPosition(metaNodeModel)
// Update local position / relative position to the parent
this.updateNodeLocalPosition(metaNodeModel)
// update the graph for right parent children relationship
this.updateGraph(metaNodeModel, cursorX, cursorY);
}

updateGraph(metaNodeModel: MetaNodeModel, cursorX: number, cursorY: number) {
let parent = undefined;
let search = true;
this.roots.forEach((node, id) => {
if (node.getContainerBoundingBox().containsPoint(cursorX, cursorY)) {
parent = node;
}
});
// TODO add the new child to the graph and update graphPath for the metaNodeModel instance
}

private updateChildrenPosition(metaNodeModel: MetaNodeModel){
const children = this.getChildren(metaNodeModel);

children.forEach(n => {
/*
No need to explicitly call updateChildrenPosition for n children because it will happen automatically in
the event listener
*/
// @ts-ignore
const localPosition = n.getLocalPosition()
n.setPosition(metaNodeModel.getX() + localPosition.x, metaNodeModel.getY() + localPosition.y)

})
}

private updateNodeLocalPosition(metaNodeModel: MetaNodeModel){
const parent = this.getParent(metaNodeModel)
metaNodeModel.updateLocalPosition(parent)
}

updateNodesContainerBoundingBoxes(nodes: MetaNodeModel[]): void {
nodes.forEach(n => n.setContainerBoundingBox(this.getNodeContainerBoundingBox(n)))
}
}
9 changes: 2 additions & 7 deletions src/components/views/compositions/Composition.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ class Composition extends React.Component {
expanded: false,
width: props.model.options.width,
height: props.model.options.height,
x: props.model.options.x,
y: props.model.options.y
}
this.changeVisibility = this.changeVisibility.bind(this);
}
Expand All @@ -101,12 +99,9 @@ class Composition extends React.Component {
<Box className={`${classes.root} ${expanded ? classes.selected : ''}`}>
<Rnd
size={{ width: this.state.width, height: this.state.height }}
position={{ x: this.state.x, y: this.state.y }}
onDragStop={(e, d) => {
this.setState({ x: d.x, y: d.y });
}}
position={{ x: this.props.model.options.x, y: this.props.model.options.y }}
onResizeStop={(e, direction, ref, delta, position) => {
this.props.model.updateSize(ref.style.width, ref.style.height);
this.props.model.updateSize(parseFloat(ref.style.width), parseFloat(ref.style.height));
this.setState({
width: ref.style.width,
height: ref.style.height,
Expand Down
6 changes: 4 additions & 2 deletions src/model/Interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,11 @@ export default class ModelInterpreter {
}

updateModel(item: MetaNode|MetaLink) {
// TODO: here we sync the MetaModel node with the MetaNodeModel, question is, do we need it?
// the MetaNodeModel has already serialization implemented and we don't need anything else
// from the metamodel once it's passed to meta-diagram, to investigate whether we need this sync
// or we can simply rely on the metaNodeModel to be serialised and passed to the backend.
// if (this.metaModelMap[item.getShape()].has(item.getId())) {
console.log('this is where I update the node');
console.log(item);
// }
}

Expand Down
5 changes: 3 additions & 2 deletions src/model/nodes/composition/CompositionNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ export default class CompositionNode extends MechanismNode {
}

if (this.extra?.boundingBox) {
console.log(this.extra.boundingBox);
this.extra.position = {
x: this.extra.boundingBox.llx + 75,
y: this.extra.boundingBox.lly + 75
x: this.extra.boundingBox.llx,
y: this.extra.boundingBox.lly
}
}

Expand Down
21 changes: 16 additions & 5 deletions src/model/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PNLClasses } from '../constants';
// const html2json = require('html2json').html2json;

import {MetaNode} from '@metacell/meta-diagram';
import { MetaGraph } from '../components/graph/MetaGraph';

export function buildModel(frontendModel, coord, prevModel) {
let finalModel = {
Expand All @@ -18,8 +18,6 @@ export function buildModel(frontendModel, coord, prevModel) {
y: 150,
};

let linkCounter = 1;

if (coord) {
coordinates.x = coord.x;
coordinates.y = coord.y;
Expand Down Expand Up @@ -58,4 +56,17 @@ export function buildModel(frontendModel, coord, prevModel) {
});

return finalModel;
}
}

export function generateMetaGraph(metaNodes) {
const metaGraph = new MetaGraph()
metaNodes.sort(function(a, b) {
return a.getDepth() - b.getDepth();
});

for(const mn of metaNodes){
const metaNodeModel = mn.toModel()
metaGraph.addNode(metaNodeModel)
}
return metaGraph
}

0 comments on commit 1e1b144

Please sign in to comment.