Issue
How can I create the following behaviour using CSS or Javascript:
- I want to have container (probably flex\grid) that have children
- The container children should be the same size, distributed evenly and cover all the container space (as much as possible)
- The children must keep ratio of 3:4
- The container width, height and the amount of children are dynamic
- The children size should be dynamic based on the height width and the children amount
Partial solution: https://codepen.io/lerman01/pen/poGNmry
the problem with my solution is that each time you change the container width, height or amount of children you need to recalculate the value of the container's grid-template-columns
value
For example
container 550x260 px with 2 children:
container 550x260 px with 20 children:
Solution
A possible approach is to start by setting the height of child div to its maximum available value (=parent_height - vertical_gap - 2*child_border) and then calculate the child div width by the aspect-ratio condition.
Then we can calculate total-width of divs and check if total-width and total-height are in parent-div bounds. Loop this check by decrementing div height until it fits.
window.addEventListener('load', calc());
var rows, cols, child_width, child_height, child_gap;
function total_width() {
return cols * (child_width + 2 + child_gap);
}
function total_height() {
return rows * (child_height + 2 + child_gap);
}
function calc() {
const container = document.querySelector('.container');
const container_width = document.getElementById('ct_width').valueAsNumber;
const container_height = document.getElementById('ct_height').valueAsNumber;
const number_of_childs = document.getElementById('ch_count').valueAsNumber;
child_gap = document.getElementById('ch_gap').valueAsNumber;
container.innerHTML = '';
container.style.width = container_width + 'px';
container.style.height = container_height + 'px';
container.style.gap = child_gap + 'px';
rows = 1;
cols = number_of_childs;
child_height = Math.floor((container_height - rows * (child_gap + 2)) / rows);
child_width = Math.floor(child_height * 3 / 4);
while (total_height() > container_height || total_width() > container_width) {
child_height--;
child_width = Math.floor(child_height * 3 / 4);
rows = Math.floor(container_height / (child_height + 2 + child_gap));
cols = Math.ceil(number_of_childs / rows);
}
document.getElementById("ch_width").value = child_width;
document.getElementById("ch_height").value = child_height;
document.getElementById("ch_aspect_ratio").value = ((child_width / child_height) * 4).toFixed(2) + ' To 4';
document.getElementById("coverage").value = Math.round(number_of_childs * (child_width + 2) * (child_height + 2) * 100 / container_width / container_height) + '%';
for (i = 0; i < number_of_childs; i++) {
var child = document.createElement('div');
child.classList.add('child');
child.style.width = child_width + 'px';
child.style.height = child_height + 'px';
child.innerText = i;
container.appendChild(child);
}
}
#params {
width: 300px;
display: grid;
grid-template-columns: auto 100px;
grid-gap: 4px;
margin: 15px;
}
#params label {
grid-column: 1 / 2;
text-align: right;
}
#params input {
grid-column: 2 / 2;
}
.container {
display: flex;
align-content: flex-start;
flex-wrap: wrap;
border: solid 1px red;
padding: 0px;
}
.child {
border: solid 1px blue;
background-color: burlywood;
}
<div id="params">
<label for="ct_width">Container Width =</label>
<input type="number" id="ct_width" value="550" max="1000" min="200" onchange="calc()" />
<label for="ct_height">Container Height =</label>
<input type="number" id="ct_height" value="260" max="700" min="100" onchange="calc()" />
<label for="ch_count">Count of Childs =</label>
<input type="number" id="ch_count" value="20" max="100" min="1" onchange="calc()" />
<label for="ch_gap">Child Gap =</label>
<input type="number" id="ch_gap" value="3" max="10" min="0" onchange="calc()" />
<label for="ch_width">Child Width =</label>
<input type="text" id="ch_width" readonly="readonly" />
<label for="ch_height">Child Height =</label>
<input type="text" id="ch_height" readonly="readonly" />
<label for="ch_aspect_ratio">Aspect Ratio =</label>
<input type="text" id="ch_aspect_ratio" readonly="readonly" />
<label for="coverage">Total Childs Coverage =</label>
<input type="text" id="coverage" readonly="readonly" />
</div>
<div class="container"></div>
Answered By - Shahram Alemzadeh
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.