aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/App.vue5
-rw-r--r--src/components/TileTree.vue86
2 files changed, 71 insertions, 20 deletions
diff --git a/src/App.vue b/src/App.vue
index b1efd4b..26ae610 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -14,8 +14,9 @@ import TileTree from "./components/TileTree.vue";
export default {
data() {
return {
- //tree: tol.map(e => ({...e, children:[]})),
- tree: tol,
+ //tree: {...tol, children:[]},
+ tree: {...tol, children:tol.children.map(e => ({...e, children:[]}))},
+ //tree: tol,
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
}
diff --git a/src/components/TileTree.vue b/src/components/TileTree.vue
index 46da28e..8170ad7 100644
--- a/src/components/TileTree.vue
+++ b/src/components/TileTree.vue
@@ -26,13 +26,27 @@ export default {
}
},
methods: {
+ //determines layout for squares in a specified rectangle, with spacing
basicSquaresLayout(nodes, x0, y0, w, h){
- //determine layout for squares in a specified rectangle, with spacing
- let numCols = this.pickNumCols(nodes.length, w/h);
- let numRows = Math.ceil(nodes.length / numCols);
+ //get number-of-columns with highest occupied-fraction of rectangles with aspect-ratio w/h
+ //account for tile-spacing?
+ let numTiles = nodes.length, ar = w/h;
+ let numCols, numRows, bestFrac = 0;
+ for (let nc = 1; nc <= numTiles; nc++){
+ let nr = Math.ceil(numTiles/nc);
+ let ar2 = nc/nr;
+ let frac = ar > ar2 ? ar2/ar : ar/ar2;
+ if (frac > bestFrac){
+ bestFrac = frac;
+ numCols = nc;
+ numRows = nr;
+ }
+ }
+ //compute other parameters
let tileSz = Math.min(
((w - this.TILE_SPACING) / numCols) - this.TILE_SPACING,
((h - this.TILE_SPACING) / numRows) - this.TILE_SPACING);
+ //determine layout
return Object.fromEntries(
nodes.map((el, idx) => [el.name, {
x: x0 + (idx % numCols)*(tileSz + this.TILE_SPACING) + this.TILE_SPACING,
@@ -42,19 +56,54 @@ export default {
}])
);
},
- pickNumCols(numTiles, aspectRatio){ //account for tile-spacing?
- //look for number of columns with highest occupied-fraction of rectangles with aspectRatio
- let bestNum, bestFrac = 0;
- for (let numCols = 1; numCols <= numTiles; numCols++){
- let numRows = Math.ceil(numTiles/numCols);
- let ar = numCols/numRows;
- let frac = aspectRatio > ar ? ar/aspectRatio : aspectRatio/ar;
- if (frac > bestFrac){
- bestFrac = frac;
- bestNum = numCols;
+ basicRectsLayout(nodes, x0, y0, w, h){
+ //get number-of-columns with highest tileCount-proportions-alignment
+ let numTiles = nodes.length;
+ let tileCounts = nodes.map(e => e.tileCount);
+ let tileCountTotal = tileCounts.reduce((x, y) => x+y);
+ let numCols, bestScore = Number.NEGATIVE_INFINITY, rowProportions, colProportions;
+ for (let nc = 1; nc <= numTiles; nc++){
+ let nr = Math.ceil(numTiles/nc);
+ //create grid representing each tile's tileCount (0 for no tile)
+ let grid = Array(nr).fill().map(e => Array(nc).fill(0));
+ for (let i = 0; i < tileCounts.length; i++){
+ grid[Math.floor(i / nc)][i % nc] = tileCounts[i];
}
+ //get totals across each row/column divided by tileCountTotal
+ let rowProp = grid.map(e => e.reduce((x, y) => x+y) / tileCountTotal);
+ let colProp = [...Array(nc).keys()].map(c =>
+ [...Array(nr).keys()].map(r => grid[r][c]).reduce((x,y) => x+y) / tileCountTotal);
+ //get score
+ let score = 0;
+ for (let r = 0; r < nr; r++){
+ for (let c = 0; c < nc; c++){
+ score -= Math.abs(grid[r][c] - (rowProp[r] * colProp[c]));
+ }
+ }
+ if (score > bestScore){
+ bestScore = score;
+ numCols = nc;
+ rowProportions = rowProp;
+ colProportions = colProp;
+ }
+ }
+ //determine layout
+ let rowNetProps = [0];
+ for (let i = 0; i < rowProportions.length-1; i++){
+ rowNetProps.push(rowNetProps[i] + rowProportions[i]);
+ }
+ let colNetProps = [0];
+ for (let i = 0; i < colProportions.length-1; i++){
+ colNetProps.push(colNetProps[i] + colProportions[i]);
}
- return bestNum;
+ let retVal = Object.fromEntries(
+ nodes.map((el, idx) => [el.name, {
+ x: x0 + colNetProps[idx % numCols]*(w - this.TILE_SPACING) + this.TILE_SPACING,
+ y: y0 + rowNetProps[Math.floor(idx / numCols)]*(h - this.TILE_SPACING) + this.TILE_SPACING,
+ w: colProportions[idx % numCols]*(w - this.TILE_SPACING) - this.TILE_SPACING,
+ h: rowProportions[Math.floor(idx / numCols)]*(h - this.TILE_SPACING) - this.TILE_SPACING
+ }]));
+ return retVal;
},
sweepToSideLayout(nodes, x0, y0, w, h){
//separate leaf and non-leaf nodes
@@ -68,10 +117,11 @@ export default {
if (leaves.length > 0){
let ratio = leaves.length / this.tree.tileCount;
retVal = this.basicSquaresLayout(leaves, x0, y0, w*ratio, h);
- x0 += w*ratio;
- w -= w*ratio;
+ x0 += w*ratio - this.TILE_SPACING;
+ w -= (w*ratio - this.TILE_SPACING);
}
- return {...retVal, ...this.basicSquaresLayout(nonLeaves, x0, y0, w, h)};
+ //return {...retVal, ...this.basicSquaresLayout(nonLeaves, x0, y0, w, h)};
+ return {...retVal, ...this.basicRectsLayout(nonLeaves, x0, y0, w, h)};
}
}
}
@@ -82,7 +132,7 @@ export default {
<div v-if="tree.children && tree.children.length > 0" class="border border-black"
:style="{position: 'absolute', left: x + 'px', top: y + 'px', width: + width + 'px', height: height + 'px'}">
<div v-if="!isRoot" :style="{height: HEADER_SZ + 'px'}" class="text-center">{{tree.name}}</div>
- <tile-tree v-for="child in tree.children" :tree="child"
+ <tile-tree v-for="child in tree.children" :key="child.name" :tree="child"
:x="layout[child.name].x" :y="layout[child.name].y" :width="layout[child.name].w" :height="layout[child.name].h"
></tile-tree>
</div>