var Pivot = { Leaves:{}, Root:N.Create({Label:"All Pivots"}), Schema:N.Create({Label:"Column Details"}), Proto:N.Create({Label:"User Form"}), Init(inColumnNames, inColumnTypes, inRows) { for(let i=0; i N.Create({Row:r})); Pivot.Init = ()=>{}; }, Create(inPivotIndicies, inSumIndicies) { N.ID.Walk++; let columns = N.Step(Pivot.Schema, "all"); let label = inPivotIndicies.map( inPivotIndex => { return columns[inPivotIndex].Meta.Label; }); let pivotRoot = N.Create({Label:label.join("|"), Leaves:Pivot.Leaves}); N.Connect(Pivot.Root, pivotRoot, "Pivot"); return Pivot.Pivot(pivotRoot, pivotRoot, inPivotIndicies, inSumIndicies); }, Pivot(inRoot, inParent, inPivotIndicies, inSumIndicies, inDepth) { let depth = inDepth||0; let uniques = {}; let indexPivot = inPivotIndicies[depth]; if(!inParent.Meta.Leaves) { console.log("problem") } // create a set of new nodes off of the input node inParent.Meta.Leaves.forEach((inLeaf)=> { let row = inLeaf.Meta.Row; // shorthand for the raw "CSV" row in the leaf Node's Meta let value = row[indexPivot]; // get the pivot column let match = uniques[value]; // check in the uniques list if this pivot column exists if(!match) { // if not, store a value under that key that will be the meta object for a new child let clone = row.map(r=>null); inSumIndicies.forEach((inSumIndex, inIndex, inArray)=> { clone[inSumIndex] = row[inSumIndex] }); match = uniques[value] = { Label:value, Row:clone, IndexPivot:indexPivot, IndexSum:inSumIndicies, Leaves:[], Depth:depth }; // grow a child off of the parent using the meta object N.Connect(inParent, N.Create(match), "Hierarchy"); } else { // if a match does exist, sum the appropriate columns inSumIndicies.forEach((inSumIndex) => match.Row[inSumIndex] += row[inSumIndex]); } // move the leaves into the child match.Leaves.push(inLeaf); }); delete inParent.Meta.Leaves; let iterator = () => {}; if(depth >= inPivotIndicies.length-1) { iterator = inLastBranch => { inLastBranch.Meta.Leaves.forEach( inLeaf => { // collect modifiers effecting leaves let modifiers = []; let collectModifier = n => modifiers.push(n); let connectModifiers = n => { modifiers.forEach(inModifier => N.Connect(inModifier, n, "ModifyOut", true)); }; N.Walk(collectModifier, inLeaf, "ModifyAt", false); N.Walk(collectModifier, inLeaf, "ModifyDown", false); if(modifiers.length) { // apply them to the branch inLastBranch.ID.Walk = N.ID.Walk; connectModifiers(inLastBranch); // also walk them up and connect, but with "check unique" enabled console.log("walking modifiers up from", inLastBranch.Meta.Label); N.ID.Walk++; N.Walk(connectModifiers, inLastBranch, "Hierarchy", false); /* N.Walk((n)=> { console.log("going up", n); } , inLastBranch, "Hierarchy", false); */ } // lastly connect the leaf to the branch N.Connect(inLastBranch, inLeaf, "Leaf"); }); delete inLastBranch.Meta.Leaves; } } else { iterator = child => { if(child.Meta.Label == "b") { console.log("at b for some reason"); } Pivot.Pivot(inRoot, child, inPivotIndicies, inSumIndicies, depth+1); }; } N.Walk(iterator, inParent, "Hierarchy"); return inParent; }, Delete(inRoot) { // disconnect modifiers let check = N.Step(inRoot, "ModifyUp", false); if(check) { while(check.length>0) { Pivot.Unmodify(check[0]); } } // disconnect leaves from terminal branches N.Walk(()=>{}, inRoot, "Hierarchy", true, terminal=>{ N.Disconnect(terminal, null, "Leaf"); }); // disconnect from app N.Disconnect(null, inRoot, "Pivot"); }, Modify(inNode) { let modified = N.Create({Label:"Modifier"}); // traverse let gatherUp = n => N.Connect(modified, n, "ModifyUp"); let gatherDown = n => N.Connect(modified, n, "ModifyDown"); let gatherOut = n => N.Connect(modified, n, "ModifyOut"); N.ID.Walk++; inNode.ID.Walk = N.ID.Walk; // at N.Connect(modified, inNode, "ModifyAt"); // up N.Walk(gatherUp, inNode, "Hierarchy", false); // down 1 N.Walk(gatherDown, inNode, "Hierarchy", true, terminal=> { // down 2 // for each terminal node, step down into its leaves and gather down N.Walk(gatherDown, terminal, "Leaf", true, leaf=> { // out 1 // walk back up on the leaf connections on other trees N.Walk(gatherOut, leaf, "Leaf", false, terminal=> { // out 2 // and continueup the hierarchy N.Walk(gatherOut, terminal, "Hierarchy", false); }); }); }); return modified; }, Unmodify(inModifier) { N.Disconnect(inModifier, null, "ModifyUp"); N.Disconnect(inModifier, null, "ModifyDown"); N.Disconnect(inModifier, null, "ModifyOut"); N.Disconnect(inModifier, null, "ModifyAt"); N.Disconnect(null, inModifier, "Modifier"); } };