In JavaScript you can get the current location of an element in a variety of ways. One of those is element.getBoundingClientRect()
. Once you can have the Y location on the page for the element, <button>
elements in this case, you can determine where the row breaks are.
In the code below, the row breaks are determined when the Y location value changes by more than slopY
from one element being changed to the next. We know that we start at the top row and proceed right to left, top to bottom. It will also work for left to right display. Only the top to bottom traversal matters. The key is that we know we handle all buttons in the first row prior to encountering any in the second row, etc.
The code applies a different class to the elements (<buttons>
) in each row. In addition, for testing, it changes the height and applies a different background color to the buttons in each row.
The buttons are not automatically maintained with the correct class (or the size and color applied for testing) when the layout changes. Thus, you will need to re-run applyRowClassesMultipleTimes()
if the buttons change layout (e.g. the container they are in is resized). This can be dealt with by adding an appropriate event handler.
In briefly trying, I did not get ReactJS to run with your code in a Stack Overflow snippet. Thus, for the snippet below, I just copied the DOM that your code generates in the JSFiddle you linked.
The code below is also available as a JSFiddle, which includes your ReactJS code.
function applyRowClasses(buttonSelector,rowClassBase){
//The selector passed as the first argument should select all elements for which
// it is desired to have the class applied.
//The second argument is the text portion of the class to be applied. The row
// number (0 at the top) will be appended to that text for the class of each row.
// (e.g. 'row' will result in classes 'row0', 'row1', 'row2', etc.)
var children = document.querySelectorAll(buttonSelector);
var replaceRowRegExp = new RegExp('\\s*' + rowClassBase + '\\d+(\\b|$)','g');
var child;
var testColor = ['red','orange','yellow','green','blue','purple','crimson'
,'cyan','lightgreen','lightblue','Fuchsia'];
var row = -1;
var rowY = 0;
var slopY = 5;
var newHeight = 120;
var newHeightDelta = -10;
for(var i=0,numChildren=children.length;i<numChildren;i++) {
child = children[i];
var rect = child.getBoundingClientRect();
if(rect.top > rowY+slopY){
//New row
row++;
rowY = rect.top;
newHeight += newHeightDelta;
}
var childClass = child.className;
//Remove any old row class. Need to do this because we would need to re-apply
// these classes when the window size changes, or if the layout changes
// in response to the changes we are making here.
childClass = childClass.replace(replaceRowRegExp,'');
childClass += ' ' + rowClassBase + row;
child.className = childClass;
//For testing change background color and height
child.style.backgroundColor = testColor[(row % testColor.length)];
child.style.height = newHeight + 'px';
}
}
function applyRowClassesMultipleTimes(buttonSelector,rowClassBase,count){
//Our changes may affect the button layout. Change
// multiple times giving the browser a chance to re-draw.
// We could calculate what our changes will be, but it's just as
// easy to iterate a few times.
if(count<=1){
return;
}
applyRowClasses(buttonSelector,rowClassBase);
count--;
setTimeout(applyRowClassesMultipleTimes,0,buttonSelector,rowClassBase,count);
}
applyRowClassesMultipleTimes('#root button','row',4);
#root {
display:flex;
color:#444;
}
.buttonContainer {
display:flex;
flex-flow: row wrap;
justify-content: space-around;
margin-top:1.5rem;
}
<body>
<div xmlns="http://www.w3.org/1999/xhtml" id="root"><div data-reactroot=""><div>Popular Genres</div><div class="buttonContainer"><button class="singleButton">Jazz</button><button class="singleButton">Top 40</button><button class="singleButton">Country</button><button class="singleButton">Blues</button><button class="singleButton">Easy Listening</button><button class="singleButton">Rock</button><button class="singleButton">Classical</button><button class="singleButton">Chillout</button><button class="singleButton">80s</button><button class="singleButton">Oldies</button><button class="singleButton">Dance</button><button class="singleButton">Ambient</button><button class="singleButton">Reggae</button><button class="singleButton">Trance</button><button class="singleButton">Hip Hop</button><button class="singleButton">Smooth Jazz</button><button class="singleButton">70s</button><button class="singleButton">House</button><button class="singleButton">Lounge</button><button class="singleButton">Drum and Bass</button><button class="singleButton">Metal</button><button class="singleButton">Meditation</button><button class="singleButton">Heavy Metal</button><button class="singleButton">60s</button><button class="singleButton">Techno</button><button class="singleButton">Pop</button><button class="singleButton">Soul</button><button class="singleButton">90s</button><button class="singleButton">Psytrance</button><button class="singleButton">Latin</button><button class="singleButton">Funk</button><button class="singleButton">Rap</button><button class="singleButton">Bollywood</button><button class="singleButton">50s</button><button class="singleButton">Hindi</button><button class="singleButton">Rockabilly</button><button class="singleButton">Minimal</button><button class="singleButton">Greek</button><button class="singleButton">Comedy</button><button class="singleButton">Alternative</button><button class="singleButton">Reggaeton</button><button class="singleButton">New Age</button><button class="singleButton">Salsa</button><button class="singleButton">Bluegrass</button><button class="singleButton">edm</button><button class="singleButton">Manele</button><button class="singleButton">Indie</button><button class="singleButton">Japanese</button><button class="singleButton">Dancehall</button><button class="singleButton">Classic Rock</button><button class="singleButton">Disco</button><button class="singleButton">Dubstep</button><button class="singleButton">Folk</button><button class="singleButton">goth</button><button class="singleButton">Punk</button><button class="singleButton">Garage</button><button class="singleButton">New Wave</button></div></div></div>
</body>
The following is what the buttons look like without applying the color and sizes:
#root {
display:flex;
color:#444;
}
.buttonContainer {
display:flex;
flex-flow: row wrap;
justify-content: space-around;
margin-top:1.5rem;
}
<body>
<div xmlns="http://www.w3.org/1999/xhtml" id="root"><div data-reactroot=""><div>Popular Genres</div><div class="buttonContainer"><button class="singleButton">Jazz</button><button class="singleButton">Top 40</button><button class="singleButton">Country</button><button class="singleButton">Blues</button><button class="singleButton">Easy Listening</button><button class="singleButton">Rock</button><button class="singleButton">Classical</button><button class="singleButton">Chillout</button><button class="singleButton">80s</button><button class="singleButton">Oldies</button><button class="singleButton">Dance</button><button class="singleButton">Ambient</button><button class="singleButton">Reggae</button><button class="singleButton">Trance</button><button class="singleButton">Hip Hop</button><button class="singleButton">Smooth Jazz</button><button class="singleButton">70s</button><button class="singleButton">House</button><button class="singleButton">Lounge</button><button class="singleButton">Drum and Bass</button><button class="singleButton">Metal</button><button class="singleButton">Meditation</button><button class="singleButton">Heavy Metal</button><button class="singleButton">60s</button><button class="singleButton">Techno</button><button class="singleButton">Pop</button><button class="singleButton">Soul</button><button class="singleButton">90s</button><button class="singleButton">Psytrance</button><button class="singleButton">Latin</button><button class="singleButton">Funk</button><button class="singleButton">Rap</button><button class="singleButton">Bollywood</button><button class="singleButton">50s</button><button class="singleButton">Hindi</button><button class="singleButton">Rockabilly</button><button class="singleButton">Minimal</button><button class="singleButton">Greek</button><button class="singleButton">Comedy</button><button class="singleButton">Alternative</button><button class="singleButton">Reggaeton</button><button class="singleButton">New Age</button><button class="singleButton">Salsa</button><button class="singleButton">Bluegrass</button><button class="singleButton">edm</button><button class="singleButton">Manele</button><button class="singleButton">Indie</button><button class="singleButton">Japanese</button><button class="singleButton">Dancehall</button><button class="singleButton">Classic Rock</button><button class="singleButton">Disco</button><button class="singleButton">Dubstep</button><button class="singleButton">Folk</button><button class="singleButton">goth</button><button class="singleButton">Punk</button><button class="singleButton">Garage</button><button class="singleButton">New Wave</button></div></div></div>
</body>