aboutsummaryrefslogtreecommitdiff
path: root/src/layout.ts
diff options
context:
space:
mode:
authorTerry Truong <terry06890@gmail.com>2022-05-06 18:42:59 +1000
committerTerry Truong <terry06890@gmail.com>2022-05-06 18:42:59 +1000
commitc2aeb45c9e5f6e849728fc6ac674d85759361962 (patch)
tree2c8581b7ce5d68efbfb14bc3435e3d5a5f74fabf /src/layout.ts
parent58ee74ad06f00f9043a15d9f1ac855ddc61fe3b5 (diff)
Remove redundant layout-retry in sweepLayout()
Diffstat (limited to 'src/layout.ts')
-rw-r--r--src/layout.ts320
1 files changed, 158 insertions, 162 deletions
diff --git a/src/layout.ts b/src/layout.ts
index e023619..fe17b01 100644
--- a/src/layout.ts
+++ b/src/layout.ts
@@ -554,7 +554,7 @@ let rectLayout: LayoutFn = function (node, pos, dims, showHeader, allowCollapse,
// Lays out nodes by pushing leaves to one side, and using rectLayout() for the non-leaves
// With layout option 'sweepToParent', leaves from child nodes may occupy a parent's leaf-section
// 'sepArea' represents a usable leaf-section area from a direct parent,
- //and is changed to represent the area used, with changes visibile to the parent for reducing empty space
+ //and is changed to represent the area used, with changes visible to the parent for reducing empty space
let sweepLayout: LayoutFn = function (node, pos, dims, showHeader, allowCollapse, opts,
ownOpts?: {sepArea?: SepSweptArea}){
// Separate leaf and non-leaf nodes
@@ -573,9 +573,8 @@ let sweepLayout: LayoutFn = function (node, pos, dims, showHeader, allowCollapse
let leavesLyt: LayoutNode | null = null, nonLeavesLyt: LayoutNode | null = null, sweptLeft = false;
let sepArea: SepSweptArea | null = null, sepAreaUsed = false; // Represents leaf-section area provided for a child
// Try using parent-provided area
- let parentArea = (opts.sweepToParent && ownOpts) ? ownOpts.sepArea : null; // Represents area provided by parent
- let usingParentArea = false;
- if (parentArea != null){
+ if (opts.sweepToParent && ownOpts != null && ownOpts.sepArea != null){
+ let parentArea = ownOpts.sepArea;
// Attempt leaves layout
sweptLeft = parentArea.sweptLeft;
leavesLyt = new LayoutNode('SWEEP_' + node.name, leaves);
@@ -590,11 +589,10 @@ let sweepLayout: LayoutFn = function (node, pos, dims, showHeader, allowCollapse
// Attempt non-leaves layout
let newDims: [number,number] = [dims[0], dims[1] - (sweptLeft ? headerSz : 0)];
nonLeavesLyt = new LayoutNode('SWEEP_REM_' + node.name, nonLeaves);
- let tempTree: LayoutNode = nonLeavesLyt.cloneNodeTree();
let sepAreaLen = 0;
let nonLeavesSuccess: boolean;
if (nonLeaves.length > 1){
- nonLeavesSuccess = rectLayout(tempTree, [0,0], newDims, false, false, opts, {subLayoutFn:
+ nonLeavesSuccess = rectLayout(nonLeavesLyt, [0,0], newDims, false, false, opts, {subLayoutFn:
((n,p,d,h,a,o) => sweepLayout(n,p,d,h,allowCollapse,o,{sepArea:sepArea})) as LayoutFn});
} else {
// Get leftover area usable by non-leaf child
@@ -615,188 +613,186 @@ let sweepLayout: LayoutFn = function (node, pos, dims, showHeader, allowCollapse
sepAreaLen = sepArea.dims[0];
}
// Attempt layout
- nonLeavesSuccess = rectLayout(tempTree, [0,0], newDims, false, false, opts, {subLayoutFn:
+ nonLeavesSuccess = rectLayout(nonLeavesLyt, [0,0], newDims, false, false, opts, {subLayoutFn:
((n,p,d,h,a,o) => sweepLayout(n,p,d,h,allowCollapse,o,{sepArea:sepArea})) as LayoutFn});
}
- if (nonLeavesSuccess){
- usingParentArea = true;
- tempTree.copyTreeForRender(nonLeavesLyt);
- // Adjust child positions
- if (sweptLeft){
- nonLeavesLyt.children.forEach(lyt => {lyt.pos[1] += headerSz});
+ if (!nonLeavesSuccess){
+ if (allowCollapse){
+ node.children = [];
+ LayoutNode.updateDCounts(node, 1 - node.dCount);
+ return oneSqrLayout(node, pos, dims, false, false, opts);
}
- // Update parentArea to represent space used
- if (sweptLeft){
- parentArea.dims[1] = leavesLyt.dims[1];
- if (sepArea != null && sepAreaLen > sepArea.dims[1]){ // If space used by child
- parentArea.dims[1] += sepArea.dims[1] + opts.tileSpacing;
- }
- } else {
- parentArea.dims[0] = leavesLyt.dims[0];
- if (sepArea != null && sepAreaLen > sepArea.dims[0]){
- parentArea.dims[0] += sepArea.dims[0] + opts.tileSpacing;
- }
+ return false;
+ }
+ // Adjust child positions
+ if (sweptLeft){
+ nonLeavesLyt.children.forEach(lyt => {lyt.pos[1] += headerSz});
+ }
+ // Update parentArea to represent space used
+ if (sweptLeft){
+ parentArea.dims[1] = leavesLyt.dims[1];
+ if (sepArea != null && sepAreaLen > sepArea.dims[1]){ // If space used by child
+ parentArea.dims[1] += sepArea.dims[1] + opts.tileSpacing;
}
- // Align parentArea size with non-leaves area
- if (sweptLeft){
- if (parentArea.pos[1] + parentArea.dims[1] > nonLeavesLyt.dims[1] + headerSz){
- nonLeavesLyt.dims[1] = parentArea.pos[1] + parentArea.dims[1] - headerSz;
- } else {
- parentArea.dims[1] = nonLeavesLyt.dims[1] + headerSz - parentArea.pos[1];
- }
+ } else {
+ parentArea.dims[0] = leavesLyt.dims[0];
+ if (sepArea != null && sepAreaLen > sepArea.dims[0]){
+ parentArea.dims[0] += sepArea.dims[0] + opts.tileSpacing;
+ }
+ }
+ // Align parentArea size with non-leaves area
+ if (sweptLeft){
+ if (parentArea.pos[1] + parentArea.dims[1] > nonLeavesLyt.dims[1] + headerSz){
+ nonLeavesLyt.dims[1] = parentArea.pos[1] + parentArea.dims[1] - headerSz;
} else {
- if (parentArea.pos[0] + parentArea.dims[0] > nonLeavesLyt.dims[0]){
- nonLeavesLyt.dims[0] = parentArea.pos[0] + parentArea.dims[0];
- } else {
- parentArea.dims[0] = nonLeavesLyt.dims[0] - parentArea.pos[0];
- }
+ parentArea.dims[1] = nonLeavesLyt.dims[1] + headerSz - parentArea.pos[1];
}
- // Adjust area to avoid overlap with non-leaves
- if (sweptLeft){
- parentArea.dims[0] -= opts.tileSpacing;
+ } else {
+ if (parentArea.pos[0] + parentArea.dims[0] > nonLeavesLyt.dims[0]){
+ nonLeavesLyt.dims[0] = parentArea.pos[0] + parentArea.dims[0];
} else {
- parentArea.dims[1] -= opts.tileSpacing;
+ parentArea.dims[0] = nonLeavesLyt.dims[0] - parentArea.pos[0];
}
}
+ // Adjust area to avoid overlap with non-leaves
+ if (sweptLeft){
+ parentArea.dims[0] -= opts.tileSpacing;
+ } else {
+ parentArea.dims[1] -= opts.tileSpacing;
+ }
+ // Return with updated layout
+ let usedDims: [number,number] = [nonLeavesLyt.dims[0], nonLeavesLyt.dims[1] + (sweptLeft ? headerSz : 0)];
+ node.assignLayoutData(pos, usedDims, {showHeader, empSpc: nonLeavesLyt.empSpc, sepSweptArea: parentArea});
+ return true;
}
}
- // Try using own area
- if (!usingParentArea){
- // Choose proportion of area to use for leaves
- let ratio: number; // area-for-leaves / area-for-non-leaves
- let nonLeavesTiles = arraySum(nonLeaves.map(n => n.dCount));
- switch (opts.sweptNodesPrio){
- case 'linear':
- ratio = leaves.length / (leaves.length + nonLeavesTiles);
- break;
- case 'sqrt':
- ratio = Math.sqrt(leaves.length) / (Math.sqrt(leaves.length) + Math.sqrt(nonLeavesTiles));
- break;
- case 'pow-2/3':
- ratio = Math.pow(leaves.length, 2/3) /
- (Math.pow(leaves.length, 2/3) + Math.pow(nonLeavesTiles, 2/3));
- break;
- }
- // Attempt leaves layout
- let newPos = [0, headerSz];
- let newDims: [number,number] = [dims[0], dims[1] - headerSz];
- leavesLyt = new LayoutNode('SWEEP_' + node.name, leaves);
- let minSz = opts.minTileSz + opts.tileSpacing*2;
- let sweptW = Math.max(minSz, newDims[0] * ratio), sweptH = Math.max(minSz, newDims[1] * ratio);
- let leavesSuccess: boolean;
- switch (opts.sweepMode){
- case 'left':
+ // Choose proportion of area to use for leaves
+ let ratio: number; // area-for-leaves / area-for-non-leaves
+ let nonLeavesTiles = arraySum(nonLeaves.map(n => n.dCount));
+ switch (opts.sweptNodesPrio){
+ case 'linear':
+ ratio = leaves.length / (leaves.length + nonLeavesTiles);
+ break;
+ case 'sqrt':
+ ratio = Math.sqrt(leaves.length) / (Math.sqrt(leaves.length) + Math.sqrt(nonLeavesTiles));
+ break;
+ case 'pow-2/3':
+ ratio = Math.pow(leaves.length, 2/3) /
+ (Math.pow(leaves.length, 2/3) + Math.pow(nonLeavesTiles, 2/3));
+ break;
+ }
+ // Attempt leaves layout
+ let newPos = [0, headerSz];
+ let newDims: [number,number] = [dims[0], dims[1] - headerSz];
+ leavesLyt = new LayoutNode('SWEEP_' + node.name, leaves);
+ let minSz = opts.minTileSz + opts.tileSpacing*2;
+ let sweptW = Math.max(minSz, newDims[0] * ratio), sweptH = Math.max(minSz, newDims[1] * ratio);
+ let leavesSuccess: boolean;
+ switch (opts.sweepMode){
+ case 'left':
+ leavesSuccess = sqrLayout(leavesLyt, [0,0], [sweptW, newDims[1]], false, false, opts);
+ sweptLeft = true;
+ break;
+ case 'top':
+ leavesSuccess = sqrLayout(leavesLyt, [0,0], [newDims[0], sweptH], false, false, opts);
+ sweptLeft = false;
+ break;
+ case 'shorter':
+ let documentAR = document.documentElement.clientWidth / document.documentElement.clientHeight;
+ if (documentAR >= 1){
leavesSuccess = sqrLayout(leavesLyt, [0,0], [sweptW, newDims[1]], false, false, opts);
sweptLeft = true;
- break;
- case 'top':
+ } else {
leavesSuccess = sqrLayout(leavesLyt, [0,0], [newDims[0], sweptH], false, false, opts);
sweptLeft = false;
- break;
- case 'shorter':
- let documentAR = document.documentElement.clientWidth / document.documentElement.clientHeight;
- if (documentAR >= 1){
- leavesSuccess = sqrLayout(leavesLyt, [0,0], [sweptW, newDims[1]], false, false, opts);
- sweptLeft = true;
- } else {
- leavesSuccess = sqrLayout(leavesLyt, [0,0], [newDims[0], sweptH], false, false, opts);
- sweptLeft = false;
- }
- break;
- case 'auto':
- // Attempt left-sweep, then top-sweep on a copy, and copy over if better
- leavesSuccess = sqrLayout(leavesLyt, [0,0], [sweptW, newDims[1]], false, false, opts);
- sweptLeft = true;
- let tempTree = leavesLyt.cloneNodeTree();
- let sweptTopSuccess = sqrLayout(tempTree, [0,0], [newDims[0], sweptH], false, false, opts);;
- if (sweptTopSuccess && (!leavesSuccess || tempTree.empSpc < leavesLyt.empSpc)){
- tempTree.copyTreeForRender(leavesLyt);
- sweptLeft = false;
- leavesSuccess = true;
- }
- break;
- }
- if (!leavesSuccess){
- if (allowCollapse){
- node.children = [];
- LayoutNode.updateDCounts(node, 1 - node.dCount);
- return oneSqrLayout(node, pos, dims, false, false, opts);
}
- return false;
+ break;
+ case 'auto':
+ // Attempt left-sweep, then top-sweep on a copy, and copy over if better
+ leavesSuccess = sqrLayout(leavesLyt, [0,0], [sweptW, newDims[1]], false, false, opts);
+ sweptLeft = true;
+ let tempTree = leavesLyt.cloneNodeTree();
+ let sweptTopSuccess = sqrLayout(tempTree, [0,0], [newDims[0], sweptH], false, false, opts);;
+ if (sweptTopSuccess && (!leavesSuccess || tempTree.empSpc < leavesLyt.empSpc)){
+ tempTree.copyTreeForRender(leavesLyt);
+ sweptLeft = false;
+ leavesSuccess = true;
+ }
+ break;
+ }
+ if (!leavesSuccess){
+ if (allowCollapse){
+ node.children = [];
+ LayoutNode.updateDCounts(node, 1 - node.dCount);
+ return oneSqrLayout(node, pos, dims, false, false, opts);
}
- leavesLyt.children.forEach(lyt => {lyt.pos[1] += headerSz});
- // Attempt non-leaves layout
+ return false;
+ }
+ leavesLyt.children.forEach(lyt => {lyt.pos[1] += headerSz});
+ // Attempt non-leaves layout
+ if (sweptLeft){
+ newPos[0] += leavesLyt.dims[0] - opts.tileSpacing;
+ newDims[0] += -leavesLyt.dims[0] + opts.tileSpacing;
+ } else {
+ newPos[1] += leavesLyt.dims[1] - opts.tileSpacing;
+ newDims[1] += -leavesLyt.dims[1] + opts.tileSpacing
+ }
+ nonLeavesLyt = new LayoutNode('SWEEP_REM_' + node.name, nonLeaves);
+ let nonLeavesSuccess: boolean;
+ if (nonLeaves.length > 1){
+ nonLeavesSuccess = rectLayout(nonLeavesLyt, [0,0], newDims, false, false, opts, {subLayoutFn:
+ ((n,p,d,h,a,o) => sweepLayout(n,p,d,h,allowCollapse,o,{sepArea:sepArea})) as LayoutFn});
+ } else {
+ // Get leftover area usable by non-leaf child
+ let sepAreaLen;
if (sweptLeft){
- newPos[0] += leavesLyt.dims[0] - opts.tileSpacing;
- newDims[0] += -leavesLyt.dims[0] + opts.tileSpacing;
- } else {
- newPos[1] += leavesLyt.dims[1] - opts.tileSpacing;
- newDims[1] += -leavesLyt.dims[1] + opts.tileSpacing
- }
- nonLeavesLyt = new LayoutNode('SWEEP_REM_' + node.name, nonLeaves);
- let nonLeavesSuccess: boolean;
- if (nonLeaves.length > 1){
- nonLeavesSuccess = rectLayout(nonLeavesLyt, [0,0], newDims, false, false, opts, {subLayoutFn:
- ((n,p,d,h,a,o) => sweepLayout(n,p,d,h,allowCollapse,o,{sepArea:sepArea})) as LayoutFn});
+ sepAreaLen = newDims[1] - leavesLyt.dims[1] - opts.tileSpacing;
+ sepArea = new SepSweptArea(
+ [-leavesLyt.dims[0] + opts.tileSpacing, leavesLyt.dims[1] - opts.tileSpacing], // Relative to child
+ [leavesLyt.dims[0], sepAreaLen],
+ sweptLeft
+ );
} else {
- // Get leftover area usable by non-leaf child
- let sepAreaLen;
- if (sweptLeft){
- sepAreaLen = newDims[1] - leavesLyt.dims[1] - opts.tileSpacing;
- sepArea = new SepSweptArea(
- [-leavesLyt.dims[0] + opts.tileSpacing, leavesLyt.dims[1] - opts.tileSpacing], // Relative to child
- [leavesLyt.dims[0], sepAreaLen],
- sweptLeft
- );
- } else {
- sepAreaLen = newDims[0] - leavesLyt.dims[0] - opts.tileSpacing;
- sepArea = new SepSweptArea(
- [leavesLyt.dims[0] - opts.tileSpacing, -leavesLyt.dims[1] + opts.tileSpacing],
- [sepAreaLen, leavesLyt.dims[1]],
- sweptLeft
- );
- }
- // Attempt layout
- nonLeavesSuccess = rectLayout(nonLeavesLyt, [0,0], newDims, false, false, opts, {subLayoutFn:
- ((n,p,d,h,a,o) => sweepLayout(n,p,d,h,allowCollapse,o,{sepArea:sepArea})) as LayoutFn});
- if ((sweptLeft && sepAreaLen > sepArea.dims[1]) || (!sweptLeft && sepAreaLen > sepArea.dims[0])){
- sepAreaUsed = true;
- }
+ sepAreaLen = newDims[0] - leavesLyt.dims[0] - opts.tileSpacing;
+ sepArea = new SepSweptArea(
+ [leavesLyt.dims[0] - opts.tileSpacing, -leavesLyt.dims[1] + opts.tileSpacing],
+ [sepAreaLen, leavesLyt.dims[1]],
+ sweptLeft
+ );
}
- if (!nonLeavesSuccess){
- if (allowCollapse){
- node.children = [];
- LayoutNode.updateDCounts(node, 1 - node.dCount);
- return oneSqrLayout(node, pos, dims, false, false, opts);
- }
- return false;
+ // Attempt layout
+ nonLeavesSuccess = rectLayout(nonLeavesLyt, [0,0], newDims, false, false, opts, {subLayoutFn:
+ ((n,p,d,h,a,o) => sweepLayout(n,p,d,h,allowCollapse,o,{sepArea:sepArea})) as LayoutFn});
+ if ((sweptLeft && sepAreaLen > sepArea.dims[1]) || (!sweptLeft && sepAreaLen > sepArea.dims[0])){
+ sepAreaUsed = true;
}
- nonLeavesLyt.children.forEach(lyt => {
- lyt.pos[0] += newPos[0];
- lyt.pos[1] += newPos[1];
- });
}
- // Create combined layout
- if (leavesLyt == null || nonLeavesLyt == null){ //hint for typescript
+ if (!nonLeavesSuccess){
+ if (allowCollapse){
+ node.children = [];
+ LayoutNode.updateDCounts(node, 1 - node.dCount);
+ return oneSqrLayout(node, pos, dims, false, false, opts);
+ }
return false;
}
+ nonLeavesLyt.children.forEach(lyt => {
+ lyt.pos[0] += newPos[0];
+ lyt.pos[1] += newPos[1];
+ });
+ // Create combined layout
let usedDims: [number, number];
- if (usingParentArea){
- usedDims = [nonLeavesLyt.dims[0], nonLeavesLyt.dims[1] + (sweptLeft ? headerSz : 0)];
+ if (sweptLeft){
+ usedDims = [
+ leavesLyt.dims[0] + nonLeavesLyt.dims[0] - opts.tileSpacing,
+ Math.max(leavesLyt.dims[1] + (sepAreaUsed ? sepArea!.dims[1] : 0), nonLeavesLyt.dims[1]) + headerSz
+ ];
} else {
- if (sweptLeft){
- usedDims = [
- leavesLyt.dims[0] + nonLeavesLyt.dims[0] - opts.tileSpacing,
- Math.max(leavesLyt.dims[1] + (sepAreaUsed ? sepArea!.dims[1] : 0), nonLeavesLyt.dims[1]) + headerSz
- ];
- } else {
- usedDims = [
- Math.max(leavesLyt.dims[0] + (sepAreaUsed ? sepArea!.dims[0] : 0), nonLeavesLyt.dims[0]),
- leavesLyt.dims[1] + nonLeavesLyt.dims[1] - opts.tileSpacing + headerSz
- ];
- }
+ usedDims = [
+ Math.max(leavesLyt.dims[0] + (sepAreaUsed ? sepArea!.dims[0] : 0), nonLeavesLyt.dims[0]),
+ leavesLyt.dims[1] + nonLeavesLyt.dims[1] - opts.tileSpacing + headerSz
+ ];
}
- let empSpc = (!usingParentArea ? leavesLyt.empSpc : 0) + nonLeavesLyt.empSpc;
- node.assignLayoutData(pos, usedDims, {showHeader, empSpc, sepSweptArea: usingParentArea ? parentArea! : null});
+ let empSpc = leavesLyt.empSpc + nonLeavesLyt.empSpc;
+ node.assignLayoutData(pos, usedDims, {showHeader, empSpc, sepSweptArea: null});
return true;
}