I'm in a javascript project, and I have to draw a tree using canvas. Like this: http://en.wikipedia.org/wiki/Binary_search_tree#Types
Each node represents a window in my project, and each sub-node is a child of the previous node.
I'm sure that I have to use an array, like:
var node = {
windowId,
childs{}
}
That is, the node would be the root, with its id (windowId) and childs{} is another array that will have the same structure.
For example:
var node = {
windowId,
childs{
windowId //windowId of the child
childs{}
}
}
.
.
.
I'm creating a recursive function, but I haven't almost nothing...could you help me,please?
If each node can become top-level, then all you have to do is figure out a structure that always allows childs. Extending your example, it would be pretty easy to make each list of childs an array.
{
id: 0,
childs: [
{
id: 0.1,
childs: [ ... ]
},
{
id: 0.2,
childs: [ ... ]
},
...
]
}
For the rest, store the current object in a variable, then go through each leaf and add the corresponding indent. If you do it right, you can have a single draw function and call it as many times as you need; you just need to keep track of the level.
Related
I'm using the tabulator tree js library (http://tabulator.info/). But why is the tree show the expand symbol even if the children array is empty? This is very annoying! Is it a bug?
This:
var tdata = [{id:1, name:"Billy Bob", age:"12", "_children":[]},];
Results in this:
as far as have seen , if you have a "_children" array (even if its empty) and your "dataTree" is set to true , then you will have the expand button always visible .
actually it is an opened issue in the tabulator repo ...
so there is only one solution here or work arround ,
you can try to not provide the _children array when there is no children ( backend )
or adjust it in the front end using js
var tdata = [
{
id: 1,
name: "Billy Bob",
age: "12",
_children: []
}
];
tdata.forEach((e) => {
if (!e._children.length) delete e._children; //this will delete any empty _children element
});
here is a working example ( it has two rows one with children one without , try and remove the for each and expriment with it )
I found what is the cause. You need to remove "dataTree:true," part from creating new Tabulator object.
I have an array of objects, which contains more array of objects (with the same structure) with unknown depth.
sTree = [{
Tree: [{
Tree: [{
}],
Leafs:[{},{},{}]
}],
Leafs:[{},{},{}]
}
it's a classic (and actual) tree.
Each Object has a reference in a DOM object (using $(obj).data("ref",obj)).
|this part is done|
The UI is flagging some of the objects with obj.deleted = true.
|this part is done|
When the user is done, i want to get back the sTree, without the deleted=true flagged items.
How can it be done?
thanks
Do it with recursion. Loop over the structure and check every item like this:
function cleanTree(tree){
for(var i in tree){
if(tree[i].deleted){
// debug output
console.log('delete '+tree[i].toString());
delete tree[i];
}else{
// debug output
console.log('look at '+tree[i].toString());
tree[i] = cleanTree(tree[i]);
}
}
return tree;
}
You have to change the inside of the for-loop a bit to work with your structure.
I try to do something like this:
var obj = {id: id, items: "asdf", items: "sdff", test: varTest};
BUT I need to add the two same named items called 'items' dynamically. Because it won't be always the same number of these elements. How can I add them to this object, without overwriting them itselfs?
Thank you very much.
PS: I know that this is probably not a good idea, but I use an API so I can't change this. I need to give them the same name.
You cannot use same key multiple times in an object. You can use array.
var obj = {id: id, items:["asdf", "sdff"], test: varTest};
This will be easy to access the elements having same semantics.
To add items use,
if (obj.hasOwnProperty(items)) {
obj.items.push(newVal);
} else {
obj.items = [newVal];
}
I have some data which I want to display in html tables using d3. My data is laid out like this:
var dataset = [
{
'name': 'foo',
'children': [
{
'var1': 'hello',
'var2': 87,
...
},
{...},
{...}
]
},
{
'name': 'bar',
'children': [
{
'var1': 'howdy',
...
},
{...},
]
},
{
// and so on...
}
]
Ultimately, I would like to have something similar in style/functionality to this example, where the user can click on the 'foo' row and see everything in the 'foo' group. But for now I'm struggling to display the data at all.
I've made a little jsfiddle to show where I am now. As you can see, I have so far been unsuccessful at showing any of the actual numbers from my data. Does anyone have any ideas on how I should go about this? Should I restructure dataset? Thank you
== EDIT ==
I must apologise for maybe being vague about what I'm trying to do. Here is a mock up of what I ultimately want to achieve, although I stress that this question is more about binding data than layout/transition stuff.
Here's what I would do: http://jsfiddle.net/j43Nb/
Looking at your data, it seems more appropriate to have one table per parent and one row per child, and not wrap the whole thing in one big table. If you really need one big table, just replace the div.section/h4 bits with another table/tr/td sequence.
The key to understanding how "child" objects become an array of cell data is in this bit at the end:
var cells = rows.selectAll('td')
.data(function(d) {
// return cell data as an array of prop values,
// ordered according to prop names in cols
return cols.map(function(prop) {
return d[prop];
})
});
where the field names in cols are used to build a corresponding array of cell values for each given row (child).
I'm trying to generate a tree structure in JavaScript from a flat array. This would usually be a fairly straightforward proposition - simply retain a 'stack' array with references to ancestor objects of the current working scope ordered by nesting depth - push a new element onto the stack when entering another nested level, and pop it off when leaving one, replacing the current working element with the object referenced by the (new) last array item.
Unfortunately this requires the capability to pass-by-reference, which JavaScript doesn't have (well, doesn't have in any meaningful way that I know how I could use for this problem.)
To give a bit of background, I'm trying to turn an arbitrarily long/complicated string containing nested XML-style (but not XML, so an XML parser can't be used instead) tokens into a structure similar to the one below:
Expected Input:
[
"<token>",
"<my non compliant token>",
"some text at this level",
"<some other token>",
"some more text",
"<yet another token>",
"more text",
"</yet another token>",
"blah!",
"</some other token>",
"</token>",
"more text"
]
Expected Output
[
{
"token": "<token>",
"children": [
{
"token": "<my non compliant token>",
"children": [
"some text at this level",
{
"token": "<some other token>",
"children": [
"some more text",
{
"token": "<yet another token>",
"children": [ "more text" ]
},
"blah!"
]
}
]
}
]
},
"more text"
]
To clarify - I'm not after an entire algorithm (but I'd be interested if you want to provide your implementation) - just a good method for maintaining current position in the outputted tree (or an entirely different/better way of generating tree objects!) Don't get too caught up on how the tokens work - they're not XML and for the purpose of the exercise could be formatted entirely differently.
Any input would be greatly appreciated!
Your strings look easy to parse. I think I would do something like this:
var stack = [];
var array = [];
for (var i in strings) {
var s = strings[i];
if (s.indexOf("</") == 0) {
array = stack.pop();
} else if (s.indexOf("<") == 0) {
var obj = {token: s, children: []};
array.push(obj);
stack.push(array);
array = obj.children;
} else {
array.push(s);
}
}
Idea #1
Here's an answer you probably weren't anticipating.
Looking at your expect output, I was wondering if it's easiest to just generate JSON and then eval it when you're done. No references at all.
When going through your flat array, you basically have three operations:
You add more data to the current object
You close off the current object
You create a new child object
You can do all three of those fairly easily by just appending the appropriate text onto a JSON string you're building as you iterate through your source array to literally just generate the text you show in your expected output. When done, run that JSON string through eval. You may need a few safety checks to verify that each array and object is closed properly if there are errors in the input, but it should work fine.
Idea #2
You can still use your stack array. I'm not sure exactly why you need to pass by reference, but you can just pass an index into the array around and have everyone modify the master copy of the array that way via index. Using local functions, the master array can be a common data value that is local to your main function, but essentially global to all your sub-functions so they can all shared access to it.
This would look something like this:
function ParseRawData(rawData)
{
var parentScopeArray = []; // main parent scope of objects
function processTag(x)
{
// you can access parentScopeArray directly here and
// and be accessing it by reference
}
// other code or local functions here
}
Idea #3
If you want to pass the array into a function and have the master copy modified (perhaps the reason you're thinking of pass by reference), the javascript design pattern is to pass the array in and return a modified array, replacing the entire original array with the modified one that is returned.