Last active
March 21, 2016 16:42
-
-
Save cheton/21d4272d5e32505ff90f to your computer and use it in GitHub Desktop.
Flat Tree
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
import _ from 'lodash'; | |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray | |
const isArray = Array.isArray; | |
const extend = (target, ...sources) => { | |
sources.forEach((source) => { | |
for (let key in source) { | |
if (source.hasOwnProperty(key)) { | |
target[key] = source[key]; | |
} | |
} | |
}); | |
return target; | |
}; | |
class FlatTree { | |
isFolded(node = {}) { | |
const { state = {} } = node; | |
const { isFolded = false } = state; | |
return !!isFolded; | |
} | |
flatten(tree = []) { | |
let flatten = []; | |
let stack = []; | |
let current = null; | |
let depth = 0; | |
let index = 0; | |
if (isArray(tree)) { // Array format | |
let root = { _path: '', _depth: depth, _parent: null, children: tree }; | |
stack.push([root, depth, index]); | |
} else { // Object format | |
let root = extend({}, tree, { _path: '', _depth: depth, _parent: null }); | |
flatten.push(root); | |
stack.push([root, depth, index]); | |
} | |
while (stack.length > 0) { | |
[current, depth, index] = stack.pop(); | |
if (this.isFolded(current)) { | |
continue; | |
} | |
while (index < current.children.length) { | |
const node = current.children[index]; | |
node._path = current._path + '.' + index; | |
node._depth = depth + 1; | |
node._parent = current; | |
flatten.push(node); | |
++index; | |
if (this.isFolded(node)) { | |
continue; | |
} | |
if (node.children) { | |
// Push back parent node to the stack that will be able to continue | |
// the next iteration once all the child nodes of the current node | |
// have been completely explored. | |
stack.push([current, depth, index]); | |
index = 0; | |
depth = depth + 1; | |
current = node; | |
} | |
} | |
} | |
return flatten; | |
} | |
} | |
const ft = new FlatTree(); | |
const tree = { | |
label: 'ROOT', | |
state: { | |
isFolded: false | |
}, | |
children: [ | |
{ | |
label: 'A', | |
props: { | |
}, | |
state: { | |
isFolded: false | |
}, | |
children: [ | |
{ | |
label: 'B', | |
state: { | |
isFolded: false | |
}, | |
children: [ | |
{ | |
label: 'C', | |
state: { | |
isFolded: true | |
}, | |
children: [ | |
{ | |
label: 'D' | |
} | |
] | |
} | |
] | |
}, | |
{ | |
label: 'E', | |
children: [ | |
{ | |
label: 'F', | |
children: [ | |
{ | |
label: 'G' | |
} | |
] | |
} | |
] | |
} | |
] | |
}, | |
{ | |
label: 'H', | |
state: { | |
isFolded: false | |
}, | |
children: [ | |
{ | |
label: 'I', | |
children: [] | |
} | |
] | |
} | |
] | |
}; | |
bin.log(''); | |
bin.log('// Example #1: FlatTree - A flat list view'); | |
ft.flatten(tree).forEach((item, index) => { | |
const { _depth, _path, label = '', state = {}, children = [] } = item; | |
bin.log(JSON.stringify({ _depth, _path, label, folded: !!state.isFolded, children: children.length })); | |
}); | |
bin.log(''); | |
bin.log('// Example #2: FlatTree with root node'); | |
ft.flatten(tree).forEach((item, index) => { | |
const { _depth, _path, label = '', state = {}, children = [] } = item; | |
let padding = _.pad('', _depth, ' '); | |
if (item.state && item.state.isFolded){ | |
padding += '[+] '; | |
} else if (item.children && item.children.length > 0) { | |
padding += '[-] '; | |
} else { | |
padding += '(0) '; | |
} | |
bin.log(padding + JSON.stringify({ _path, label, folded: !!state.isFolded, children: children.length })); | |
}); | |
bin.log(''); | |
bin.log('// Example #3: FlatTree without root node'); | |
ft.flatten(tree.children).forEach((item, index) => { | |
const { _depth, _path, label = '', state = {}, children = [] } = item; | |
let padding = _.pad('', _depth - 1, ' '); | |
if (item.state && item.state.isFolded){ | |
padding += '[+] '; | |
} else if (item.children && item.children.length > 0) { | |
padding += '[-] '; | |
} else { | |
padding += '(0) '; | |
} | |
bin.log(padding + JSON.stringify({ _path, label, folded: !!state.isFolded, children: children.length })); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment