Cytoscape.js not setting compound node properties when exported as json - javascript

I am currently trying to export my Cytoscape.js graph as json to later import it into the Cytoscape application. For some nodes I need to add a compound node after the layout process, so they are not included in the layout process and do not affect the node positions.
After the layout I add the parent nodes via cy.add() and the child nodes are added to the parent nodes via ele.move().
When I debug the nodes the properties autoHeight and autoWidth are set but when I read them it results in undefinded and the positions are not set according to their child nodes.
var json = cy.json();
var jsonNodes = json.elements.nodes;
var graphNodes = cy.nodes(':parent');
jsonNodes.forEach(jsonNode => {
graphNodes.forEach(graphNode => {
if (jsonNode.data['id'] == graphNode._private.data['id']){
if(graphNode._private['autoHeight'] != undefined) {
let height = graphNode._private['autoHeight'];
let width = graphNode._private['autoWidth'];
jsonNode.data['height'] = height;
jsonNode.data['width'] = width;
jsonNode.data['opacity'] = 70;
}
}
}
)
});
I want the json to include the parents width, height and position (according to the position of their child node).

Related

How to Get React Element Props from HTML Element with Javascript?

I can inspect a component's props with the React developer tools. Is it possible to get the component's props from its corresponding HTML element from the console without using the developer tools?
The solution would be something like this:
const someElement = document.querySelector('.some-element')
getElementReactProps(someElement)
I tried to inspect the HTML element's properties __reactFiber$at69yqn7c1k and __reactProps$at69yqn7c1k but couldn't find any of its props that I see in the React developer tools.
I have also found other stack overflow threads but none of them worked. (React - getting a component from a DOM element for debugging, React - get React component from a child DOM element?, How do you inspect a react element's props & state in the console?)
Any ideas?
React does seem to store the correct properties in some parent elements, but not in child elements.
The code below works by walking down the path from the given parent to the target child in the react prop tree, after tracing it from the DOM tree. I've only tested it with a single app but I believe it works with all elements created by React 17+.
function getReactProps(parent: Element, target: Element): any {
const keyof_ReactProps = Object.keys(parent).find(k => k.startsWith("__reactProps$"));
const symof_ReactFragment = Symbol.for("react.fragment");
//Find the path from target to parent
let path = [];
let elem = target;
while (elem !== parent) {
let index = 0;
for (let sibling = elem; sibling != null;) {
if (sibling[keyof_ReactProps]) index++;
sibling = sibling.previousElementSibling;
}
path.push({ child: elem, index });
elem = elem.parentElement;
}
//Walk down the path to find the react state props
let state = elem[keyof_ReactProps];
for (let i = path.length - 1; i >= 0 && state != null; i--) {
//Find the target child state index
let childStateIndex = 0, childElemIndex = 0;
while (childStateIndex < state.children.length) {
let childState = state.children[childStateIndex];
if (childState instanceof Object) {
//Fragment children are inlined in the parent DOM element
let isFragment = childState.type === symof_ReactFragment && childState.props.children.length;
childElemIndex += isFragment ? childState.props.children.length : 1;
if (childElemIndex === path[i].index) break;
}
childStateIndex++;
}
let childState = state.children[childStateIndex] ?? (childStateIndex === 0 ? state.children : null);
state = childState?.props;
elem = path[i].child;
}
return state;
}
Example usage:
let itemRow = document.querySelectorAll("#item-row")[2];
let menuBtn = itemRow.querySelector("#more-button");
let props = getReactProps(itemRow, menuBtn);
//This may also work:
let props = getReactProps(menuBtn.parentElement, menuBtn);

JsTree how to get IDs of group node

I want to get IDs of all child, Surface nodes, and a higher level.
See the image below
When i click on C1 node :
1 - I want the IDs of all the lower level nodes contains : D1 , D2
2 - I want the IDs of node that is a higher direct level : B2
3 - And i want the IDs of all IDs of straight level : C2
jsTree's API provides with functions to identify and traverse between nodes. Here's a small script you could use to identify child, parent(direct level) & sibling nodes(straight level).
$('#jstree').bind('select_node.jstree', function (e, data) {
var tree = $('#jstree').jstree(true),
parentNode = tree.get_node(data.node.parent),
aChildren = data.node.children,
aSiblings = [];
parentNode.children.forEach(function(c){
if(c !== data.node.id) aSiblings.push(c);
});
console.log("1.)" + JSON.stringify(aChildren));
console.log("2.)" + JSON.stringify(parentNode.id));
console.log("3.)" + JSON.stringify(aSiblings));
});

How to get dbId of only visible objects in Viewer?

I can get the dbId of all items in the Viewer via
const tree = viewerApp.myCurrentViewer.model.getData().instanceTree;
const dbIndices = Object.values(tree.nodeAccess.dbIdToIndex).slice(1);
But for models imported from Revit, their number is much larger than the actually visible objects in the Viewer (for example, for a project consisting of only three walls, this number is approximately 3,500). How do I get a dbId of only visible objects?
By default all nodes (assets to render for Viewer) are visible when a model is loaded. Each node can be uniquely identified by an unique dbid in addition to its externalId that corresponds to the UniqueID of a Revit component.
So the extra dbids that you observed are actually parent nodes. To isolate them, see here to traverse all the leaf nodes (that is nodes representing a single visible components):
function getAllLeafComponents(viewer, callback) {
var cbCount = 0; // count pending callbacks
var components = []; // store the results
var tree; // the instance tree
function getLeafComponentsRec(parent) {
cbCount++;
if (tree.getChildCount(parent) != 0) {
tree.enumNodeChildren(parent, function (children) {
getLeafComponentsRec(children);
}, false);
} else {
components.push(parent);
}
if (--cbCount == 0) callback(components);
}
viewer.getObjectTree(function (objectTree) {
tree = objectTree;
var allLeafComponents = getLeafComponentsRec(tree.getRootId());
});
}

THREE JS position from matrixWorld is same as local position

I've imported a collada file from Cinema4D with a tree of parented objects. When I get an object's world position like so:
var thing = scene.getObjectByName("thing");
thing.updateMatrixWorld();
var worldPos = new THREE.Vector3();
worldPos.setFromMatrixPosition(thing.matrixWorld);
it is the same as thing.position, which the docs say is local position. I know this object has a parent with a non-zero position. When I try the same thing without updateMatrixWorld(), the world position is zero. How can I get the correct world position?
I needed to updateMatrixWorld() for each parent of my object, which I did like this:
function updateWorldMatrices (object)
{
var parent = object;
while (parent.parent != null)
{
parent.updateMatrixWorld();
parent = parent.parent;
}
}

Does a documentFragment element reset itself?

This is a strange behavior I noticed. I did not reset a document but immediately used it after I had appended it, and the previous elements it contained were not there.
Should I be clearing it as such?
frag_inner = '';
Are there side-effects I'm not aware of?
frag_outer = NS.createDocumentFragment();
frag_inner = NS.createDocumentFragment();
NS.eachIndex(obj, function(val) {
// fragment element - inner
// image element
val.view_picture = (val.picture === '0') ? this.A.images + 'generic_large.jpg' :
this.A.pictures + val.h_file + '-2.jpg';
img_element = $A.createElement('img');
img_element.className = 'tweet';
img_element.src = val.view_picture;
frag_inner.appendChild(img_element);
// link element
link_element = $A.createElement('a');
link_element.className = 'tweet';
link_element.innerHTML = val.name + ' posted ' +
this.prettyTime(val.time) + '<br>';
frag_inner.appendChild(link_element);
// paragraph element
par_element = $A.createElement('p');
par_element.className = 'tweet';
par_element.innerHTML = val.tweet;
frag_inner.appendChild(par_element);
// div element
div_element = $A.createElement('div');
div_element.className = 'tweet';
div_element.appendChild(frag_inner);
// append the div which is now populated
frag_outer.appendChild(div_element);
}, this);
I think it's actually the expected behaviour, as...
1) it's a well-known feature of Node.appendChild to move existing Nodes. As said in the docs (MDN)...
[Node.appendChild]... adds a node to the end of the list of children of a specified
parent node. If the node already exists it is removed from current
parent node, then added to new parent node.
2) when you append documentFragment, you actually append all its children (MDN again):
Various other methods can take a document fragment as an argument
(e.g., any Node interface methods such as Node.appendChild and
Node.insertBefore), in which case the children of the fragment are
appended or inserted, not the fragment itself.
The point is, when you do someNode.append(documentFragment), you remove all its children from it, then append them to someNode. That's why documentFragment is empty as result.
Note that when you do this...
frag_inner = '';
... you're not clearing the documentFragment stored in this variable - you store a new value (an empty string, obviously) in it instead. The very first attempt to work with it as with documentFragment should result in something like TypeError: Object has no method 'appendChild'.

Categories