DynaTree: How do you expand all children ( downstream node levels) from a active node? - dynatree

I've got a 4 level tree and would like to expand all of its children (and children's children) when a level 2 node is activated. I can determine the current activate node level with:
if(node.getLevel() == 2)...
I thought something like:
if(node.getLevel() == 2) node.expand(true)
But that doesn't work.

You could implement the onActivate event handler to expand all nodes recursively.
onActivate(node){
if(node.getLevel() == 2){
node.visit(function(n){
n.expand(true);
});
}
}

Related

How to use eles.components() to filter direct neighbours of one node?

I want to filter all nodes not further away then one edge of a given node. I dont have a compound graph. I tried
var children = cy.$('#1').components()
But this only returns the node #1. I also tried
var allEles = cy.elements()
var myChildren = allEles.componentsOf(cy.$('#1'))
But this seems to return all nodes again. The docs also state a selector syntax "> (child selector) Matches direct children of the parent node (e.g. node > node)." But I cant figure that one out either. I tried
var myChildren = cy.elements('node#1 > node')
getting an empty array.
So, how can filter for direct children (depth=1) of a given node?
Did you try use:
// outgoers return all elements (edges as well) comming out from $('#1')
// nodes() > select only nodes
var children = cy.$('#1').outgoers().nodes();
doc: https://js.cytoscape.org/#nodes.outgoers

recursive repeat tree structure in Aurelia should work like accordion [Aurelia]

I need some tree structure in Aurelia. I got some link for that. It's working fine. But My requirement is like accordion with tree view. Means when I clicked on closed parent all opened parents should close and clicked one should open same as bootstrap accordion. same thing should happen When ever I clicked on child parent element with in parent repeat.
Below is my image for tree structure.
Gist run Link: Gist
The above gist is just tree structure with open and collapse. From that when I clicked on closed tree node , that should open and remaining tree nodes should be closed.
In the above gist "node-model.js" is having events for open and close. So when ever I clicked on icon the clicked event inside this variable will get only clicked node. How can I get other node in that method to hide.
Answer:
Inside your tree-view.js, add the following code (3 methods):
attached() {
window.addEventListener('goCollapseAll', (e) => {
this.closeOtherBranches(e.detail);
}, false);
}
closeOtherBranches(exceptNode) {
// traverse node tree to find current one
var found = null;
for(var i = 0; i < this.nodes.length; i++){
if (this.subSearch(this.nodes[i], exceptNode)) {
found = i;
}
}
if (found !== null) {
for(var i = 0; i < this.nodes.length; i++){
if ((i != found) && (this.nodes[i].expanded)) {
this.nodes[i].toggleNode();
}
}
}
}
subSearch(node, findNode) {
// recursive search of tree for findNode
var match = null;
if (node === findNode) {
match = node;
} else {
for(var i = 0; i < node.children.length; i++){
if (node.children[i] === findNode) {
match = node;
} else {
match = this.subSearch(node.children[i], findNode);
}
}
}
return match;
}
Then, inside your node-model.js, add the following lines at the beginning of toggleNode():
// close other node branches
if (!this.expanded) {
var event = new CustomEvent('goCollapseAll', { 'detail': this });
window.dispatchEvent(event);
}
Explanation:
When a node is expanded, it publishes a custom event to trigger the recursive search to close all nodes that are part of a different branch. It's not the prettiest solution and I think there might be a cleaner way if you adopt a different structure for the tree, but this solution definitely works well and accomplishes your purpose.
GistRun:
I've updated your GistRun to demonstrate the functionality. You can see it working here:
https://gist.run/?id=828c3c79bff0dfbaffec3252ed376c8c

prevent node overlap on add new node

how do i prevent from overlapping new added nodes in cytoscape js graph?
i do not want change position of existing nodes
i want new adding nodes do automatically position by this rule that preventing existing node overlap
when i use add API to add nodes to graph added nodes overlap others
how can i change this behavior?
is there a solution for prevent node overlap in adding mode (new node do not overlap existing node)?
cy.add([
{ data: {label:"aaa" ,id:"bbb" } },
{ data: {label:"aaa333" ,id:"rrrr"} },
]);
There is no built in solution. I just look for an empty spot using this code for testing overlap (this is given a fixed node size, you could adapt it for using bounding boxes, but that slows things down).
function overlap(pos, size) {
var overlap = false;
cy.nodes(':visible').forEach(function (node) {
var npos = node.position();
if ((pos.x - size) < npos.x && (pos.x + size) > npos.x && (pos.y - size) < npos.y && (pos.y + size) > npos.y) {
overlap = true;
return false; //break
}
});
return overlap;
}
I use this with the prefered position as first argument ({x:..,y:..}), and when that fails I just add 10 to y to see if it fitst. Wether this is the best solution for you depends on the specific problem.
If you want an automated way of doing this, your best bet is a force-directed/physics layout.
Lock all but the new nodes when you run the layout.
You'll have to experiment with different layouts to see which particular one suits your app/data best.

dynatree selectmode=3 is not honoured when using lazy loading

I was trying to use dynatree with lazy loading on in my project.
When I tried to combine the select functionality with the checkboxes and select mode 3 I was disappointed to see that the select rule for mode 3 which is select everything including children children .... children when the parent is selected.
This is because the children havent yet been loaded.
Does anyone have a workaround to get this working ? I would very much appreciate any suggestions.
Zank ya!!
When adding the children of the parent you selected, check if the parent has children. If TRUE, add each child and set each of those children to selected.
Here is some code below. The onLazyRead will go up top. Every time you click on a lazy node, this function will trigger. Inside this function should be a call to your function that fetches child data for the node you just selected.
The code below that is the way I solved this problem. Pretty much all it is doing is checking if the parent of the node you are adding is selected. If TRUE, you add the node, then .select() it.
This is much simpler when deselecting a node because all the nodes are already loaded. When deselecting, just go down the hierarchy of the tree from the node that is being deselected and simply un-check each node.
I know this is a lot of code to just throw at you, but hopefully you can grasp the idea out of it. If you cannot, I will try to check back to this thread during work. Maybe you can even post what you have so far?
onLazyRead: function(node){
jQuery("#tree2").dynatree("getTree").disable();
var pParentID = node.data.key;
//Select the Node
doChildReport(pParentID); //Get Children for this node's ID
},
///....
//Methods to grab data from a "XMLHttpRequest GET" go here
//....
//When you finally want to add the children that you fetched using the ID of the node you selected...
//treeArray is an array of node data that has been parsed out of a
//string returned by a "XMLHttpRequest GET"
//Contents of array in order, repeating: treeArray[0] = ParentID, [1] = nodeID [2] = nodeName
//Example, the array would return [111], [222], ["Child Node"]
if(){ //IF Next fetched node is on the last level, ie. no children
//add normally
}
else{ //If NOT, add lazy.
if(treeArray[1] != "nill" && treeArray[1] != undefined){
//IF THE PARENT NODE IS SELECTED
if(jQuery("#tree2").dynatree("getTree").getNodeByKey(treeArray[0]).isSelected() == true){
//AND IF the child node does not exist
if(jQuery("#tree2").dynatree("getTree").getNodeByKey(treeArray[1]) == null){
//Add the child node and then mark it selected
addChildNodeLazy(treeArray[1], treeArray[2], treeArray[0]);
jQuery("#tree2").dynatree("getTree").getNodeByKey(treeArray[1]).select();
}
}else{
if( jQuery("#tree2").dynatree("getTree").getNodeByKey(treeArray[1]) == null){
addChildNodeLazy(treeArray[1], treeArray[2], treeArray[0]);
}
}
}
}
Lazy load function...
function addChildNodeLazy(NodeID, NodeName, ParentID){
jQuery("#tree2").dynatree("getTree").getNodeByKey(ParentID).addChild({title: NodeName, key: NodeID, icon: false, isFolder: true, isLazy: true});
}
Admittedly, the following is a bit of a hack...but it solves this problem:
onSelect: function (flag, node) {
if (flag && node.childList == undefined) {
node.reloadChildren(function() {
node.select(false);
node.select(true);
});
}
If node is being selected (flag == true) AND the node has not been loaded yet (childList == undefined) then call reloadChildren with a callback function. The callback runs after the data is loaded and simply toggles the checkbox off/on. This causes all the child nodes (which now exist) to be selected.

Sencha Touch 2 How to Detect Top Level on Nestedlist

I would like to create an event listener to detect when my nestedlist is at the top level, and then hide a component on the page. For example:
onNestedlistActiveItemChange: function(container, value, oldValue, options) {
if (this.getMyNestedList().atLevel(0)) <-- seudo code, does not work
{
Ext.getCmp('myButton').hide();
}
}
Thanks in advance for your help
The _backButton._hidden property of the nested list will return true when the default back button is hidden and false when the button is displayed. The button is hidden only when the nested list is at the top level.
The trick is to use the nested list's "back" event, which returns the state of the toolbar after the back event has occurred:
onMynestedlistBack: function(nestedlist, node, lastActiveList, detailCardActive, options){
if(nestedlist._backButton._hidden) {
Ext.ComponentQuery.query('#myButton')[0].hide();
}
}
That is, if the nested list's back button is hidden, then the list is at the top level, so hide myButton.
There are certainly more rigorous ways to do it, but most of them would involve overriding the toolbar's default button handling.
You can get the list level by checking the index of the list
var idx = nestedlist.getInnerItems().indexOf(list);
if (idx === 0) {
// top level...
}
[UPDATE]
You can also check the depth level of the record
var depth = record.getData().depth;
if (depth === 1) {
// top level...
}