Creating row and column as per no. of images coming dynamically - javascript

I'm currently trying to dynamically create a table using jQuery, JavaScript and HTML. In my application images are coming dynamically.
**CASE:**If 9 images are coming dynamically then there must 3 rows and 3 columns, and if 16 image coming then 4 rows and 4 columns and so on. I also want some solution if odd number images(eg: 17, 19, 91..etc). I have searched lot but I didn't got proper answer. I am not looking for plugins.

Again, I'm not sure if this is what you wanted since your question is vague, no one has any idea how your markup looks like or how are you getting the images but I guess one of the solutions might be something like this:
http://jsfiddle.net/Udf3D/
$(document).ready(function(){
var count = $("#container img").size();
var columns = Math.sqrt(count);
columns = parseInt(columns);
$("#container img").css('width', $("#container").width() / columns);
});
The idea is to get the number of images, find square root of that number and then simply set the width of the image to fit nicely in the container. (if you have 25 images, you'll have 5 columns and image width would be 1/5 of the contaier width).
Again no idea if this fits your needs but it's a direction in which I would go.

Here's another possibility that assumes fixed with of images. This means as the number of images gets large, you may go over the edge of the page. Maybe that is ok.
http://jsfiddle.net/C4WpQ/14/
function createImages (n)
{
var images = [];
for (i = 0; i < n; i++)
{
var imageUrl = "http://images.fake.com/" + i + ".png";
images.push(imageUrl);
}
return images;
}
function leastSquareRoot (n)
{
// maybe use ceil if you want a wider rectangle vs a taller one
// when a square is not possible
var sr = Math.sqrt(n);
return Math.floor(sr);
}
function createRowsAndCols (images, width)
{
var result = "<table>\n";
var lsr = leastSquareRoot(images.length);
for (i = 0; i < images.length; i++)
{
if (i % width == 0)
{
result += "\t<tr>\n";
}
result += "\t\t<td><img src=\"" + images[i] + "\"></td>\n";
if (i % width == width - 1 || i == images.length - 1)
{
result += "\t</tr>\n";
}
}
result += "</table>\n";
return result;
}
function showTags(markup)
{
return markup.replace(/\</g, '<').replace(/\>/g, '>');
}
$( document ).ready(function() {
$("#canvas").html("Creating images...");
var images = createImages(17);
$("#canvas").append(" created " + images.length + " images.<br/>");
var width = leastSquareRoot(images.length);
$("#canvas").append("The proposed width is " + width + ".<br/>" );
var result = createRowsAndCols(images, width);
$("#canvas").append(result);
$("#canvas").append("<pre><code>" + showTags(result) + "</code></pre>");
});

Related

JS: How to make a for loop out of this?

I have to create a 20 column bar-chart. The bar on the very right gets updated every second with a random number which gives the bar its height. After one second the value gets transferred to its neighbour on the left and so on. To connect the values from the array to css, I created this piece of code. On the left (barchart) is connected to the div via querySelectorAll and then indexed with [i], on the right i take the corresponding value from the array. Since I need to do 20 bars, it would make sense to use a for loop, but I don't really know how to create it... Any ideas?
const arr = [];
let number = "";
function timer() {
setInterval(function () {
number = Math.floor((Math.random() * 100) + 1);
const barchart = document.querySelectorAll(".bar");
barchart[4].style.height = number + "%";
barchart[3].style.height = arr[4] + "%";
barchart[2].style.height = arr[3] + "%";
barchart[1].style.height = arr[2] + "%";
barchart[0].style.height = arr[1] + "%";
arr.push(number);
if (arr.length > 5) {
arr.shift();
}
console.log(arr);
}, 1000);
}
How to shorten this into a loop?
barchart[4].style.height = number + "%";
barchart[3].style.height = arr[4] + "%";
barchart[2].style.height = arr[3] + "%";
barchart[1].style.height = arr[2] + "%";
barchart[0].style.height = arr[1] + "%";
Looking at what you have so far the first time the code runs arr is only initialized with no elements at all and you are attempting to reach out of bound indices which returns undefined
Moreover, you should not use initialize an array as a const if you are planning on changing the values it stores.
Now for the problem at hand:
Considering the bar on the far right is positioned at the last index of barchart and that arr contains the corresponding bar's heights:
//give the bar on the far right a random height.
barchart[barchart.length-1].style.height = number + "%";
//loop through barcharts array from end to start excluding the last bar.
for(let i=barchart.length-2; i>=0; i--)
{
//give each bar the height of his right neighbour
barchart[i].style.height = arr[i+1] + "%";
}
How about just making sure arr has what you want before updating the bar chart, then you can just iterate over it.
Adding the new number and then making sure there are at most 5 numbers allows you to just iterate over all the elements in the array and it will only update the bars for the values it contains - no index out of bounds issues (you just get undefined with JS though.)
NOTE, I replaced querySelectorAll with querySelector as querySelectorAll returns a collection of matched elements rather than a single element.
const arr = [];
let number = "";
function timer() {
setInterval(function() {
number = Math.floor((Math.random() * 100) + 1);
arr.push(number);
// make sure arr max's out at 5 numbers
if (arr.length > 5)
arr.shift();
// update the bar chart(s)
const barchart = document.querySelector(".bar");
for (let i = 0; i < arr.length; i++)
barchart[i].style.height = arr[i] + "%";
console.log(arr);
}, 1000);
}
for(var i = 0;i < 5;i++){
barchart[i].style.height = arr[i+1] + "%";
}

Making divs fill up a containing div?

I've been searching the site for an answer, and nothing I've come across seems to help. I'm trying to make it so that a default (and eventually user-specified) number of divs fill up the containing div like a grid. I'm trying to figure out how to make the size of the boxes I append to the parent change depending on how many are added, while always filling up the div, if that makes sense. So for instance, if I specify 9, I should have 3 rows and 3 columns. If I specify 62, then I'm looking for 16 rows and 16 columns, always filling up (or coming close to, anyway) the containing div. Here's a JSfiddle I have so far: https://jsfiddle.net/psyonix/1g9p59bx/1/ Here's the code as it is:
var d = ("<div class='square'></div>");
function createGrid(numSquares){
for(var i = 0; i < numSquares; i++){
$('#g_area').append(d);
}
var squareSize = Math.floor(580/numSquares );
$('.square').height(squareSize);
$('.square').width(squareSize);
};
$(document).ready(function(){
createGrid(64);
});
The only issue you had was setting the square size to 1/64th of the height instead of 1/(64^.5) of the height. Essentially you where just making one row. https://jsfiddle.net/1g9p59bx/7/
var d = ("<div class='square'></div>");
function createGrid(numSquares){
var gridContainer = $('#g_area');
for(var i = 0; i < numSquares; i++){
gridContainer.append(d);
}
var squareSize = Math.floor(580/(Math.sqrt(numSquares)) );
$('.square').height(squareSize);
$('.square').width(squareSize);
};
$(document).ready(function(){
createGrid(64);
});
I would create a little jqueryplugin for that. You can call it in every container you like: containerForGrid.createGrid(cols, rows)
(function($){
$.fn.createGrid = function(cols, rows) {
// get width and height of sorrounding container
var w = this.width()
var h = this.height()
// calculate width and height of one cell
var colWidth = w / cols
var rowHeight = h / rows
// loop over all rows
for(var i = rows; --i;){
// loop over all cols
for(var j = cols; --j;){
$('<div>').css({
width:colWidth,
height:rowHeight,
float:'left'
}).appendTo(this)
}
}
}
})(jQuery)
jQuery('div').createGrid(10,10)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="width:1000px;height:500px">
</div>

How to cover every square in a grid in a single for loop?

I am implementing dynamic map tiles and have come across a bit of a puzzling issue. Suppose I have a grid of 8x8 squares, like a chessboard. I need to place an image on each of these squares, preferably starting in the centre and working out from there.
Is this possible to accomplish in a single for loop, or will it take several loops? As I said, these images are squares, and are being placed on a map. They are all 0.025° in latitude/longitude.
Here's my initial thought:
for (var i=-0.25; i<=0.25; i+=0.025) {
var adjustedLatitude = (requestedLatitude + i);
var adjustedLongitude = (requestedLongitude + i);
}
Of course, this will only fill the grid in a diagonal pattern. What is the best way to do this?
Personally I think it's most readable to use a nested loop:
for (var i=-0.25; i<=0.25; i+=0.025) {
for (var j=-0.25; j<=0.25; j+=0.025) {
var adjustedLatitude = (requestedLatitude + i);
var adjustedLongitude = (requestedLongitude + j);
doStuffWithAxes(adjustedLatitude, adjustedLongitude);
}
}
However, you could accomplish it using a single loop as so:
for (var i=0; i<=20*20; i++) {
var xoffset = (i % 20 - 10) / 40;
var yoffset = (i / 20 - 10) / 40;
var adjustedLatitude = (requestedLatitude + xoffset);
var adjustedLongitude = (requestedLongitude + yoffset);
doStuffWithAxes(adjustedLatitude, adjustedLongitude);
}

Improving speed of generating HTML table

Using jQuery .append I write some html to form a 10,000px grid of 125px X 80px. Where the pixels are numbered first down then across. Now this works fine but is slow enough that there's noticeable lag loading the page compared to writing it straight in html. Is it possible to speed this up at all while still maintaining the pixel numbering?
My html is:
<div id="grid">
</div>
Javascript:
function createGrid() {
var counter = 1;
var rowCounter = 1;
var divs = 10000;
$('<table width="625px"><tr>').appendTo('#grid');
for (var i = 1; i <= divs; i++) {
if (i % 125 == 0 ){
$('</ tr><tr>').appendTo('#grid');
rowCounter++;
counter = rowCounter;
}
else
$('<td id="pixel_' + counter + '" class="pixel"></td>').appendTo('#grid');
counter =+ 80;
}
$('</tr></table>').appendTo('#grid');
}
Your code won't work as you expect it to, because .append() creates complete DOM elements. $('<table width="625px"><tr>').appendTo('#grid') will automatically close both tags, and you'll have to append the next row to the table, and the cell to the row.
As it happens, it's inefficient to constantly append elements to the DOM anyway. Instead, build the table as a single string and write it out all at once. This is more efficient since you're only adding to the DOM one time.
function createGrid() {
var counter = 1;
var rowCounter = 1;
var divs = 10000;
var tstr = '<table width="625px"><tr>';
for (var i = 1; i <= divs; i++) {
if (i % 125 == 0) {
tstr += '</ tr><tr>';
rowCounter++;
counter = rowCounter;
} else
tstr += '<td id="pixel_' + counter + '" class="pixel"></td>';
counter = +80;
}
tstr += '</tr></table>';
$('#grid').append(tstr);
}
http://jsfiddle.net/mblase75/zuCCx/
$('<table width="625px"><tr>')
is not the same as writing and appending an HTML string! jQuery will evaluate that <table><tr> string and create a DOMElement from it. I.e., with just this tiny bit of code, you have created a whole table in the DOM. The closing tags are auto-completed and the table is instantiated. From then on you need to work with it as a DOM object, not as a string to append to.
Your code is probably slow because you're creating tons of incomplete/autocompleted tiny DOM objects which are all somehow being bunched together, probably not even in the correct structure. Either manipulate DOM objects, which should be pretty fast, or construct a complete string and have it evaluated once.
One of the first steps towards improving performance would be generating the complete HTML and appending to the DOM in one step.
function createGrid() {
var counter = 1;
var rowCounter = 1;
var divs = 10000;
var html = '<table width="625px"><tr>';
for (var i = 1; i <= divs; i++) {
if (i % 125 == 0 ){
html += '</ tr><tr>';
rowCounter++;
counter = rowCounter;
}
else
html += '<td id="pixel_' + counter + '" class="pixel"></td>';
counter =+ 80;
}
html += '</tr></table>';
$('#grid').html(html);
}

Read and Write JQuery Statements in One Loop

I have the following jQuery statement in a loop. #MainContent_gvDemographic and #tblFreez are two tables in a page.
$("#MainContent_gvDemographic").find(str)
.css("height", $("#tblFreez")
.find(str)
.css("height"))
When there are many steps in the loop, it takes a very long time to complete. To fix the problem, I then use two loops, one for reading the height of $("#tblFreez").find(str), the other for writing the height into $("#MainContent_gvDemographic").find(str), and use an array to carry the height data between the two loops. It becomes much faster now. Does anyone know why the two solutions have such big difference in performance? The computational complexity looks the same to me.
All right, here are the two complete version.
Original:
function FixHeight() {
var rowCount = $('#tblFreez tr').length;
for (var i = 0; i < rowCount; i++) {
var str = "";
if ($.browser.msie) {
str = "tr:eq(" + i + ") td";
}
else {
str = "tr:eq(" + i + ")";
}
$("#MainContent_gvDemographic").find(str).css("height", $("#tblFreez").find(str).css("height"));
}
}
New:
function FixHeight() {
var rowCount = $('#tblFreez tr').length;
var hei = new Array();
for (var i = 0; i < rowCount; i++) {
var str = "";
if ($.browser.msie) {
str = "tr:eq(" + i + ") td";
}
else {
str = "tr:eq(" + i + ")";
}
hei[i] = $("#tblFreez").find(str).css("height");
}
for (var i = 0; i < rowCount; i++) {
var str = "";
if ($.browser.msie) {
str = "tr:eq(" + i + ") td";
}
else {
str = "tr:eq(" + i + ")";
}
$("#MainContent_gvDemographic").find(str).css("height", hei[i]);
}
}
Why not use only one loop and not for but jQuery .each(). I haven't tested code below, but should work.
function FixHeight() {
var $MainContent = $("#MainContent_gvDemographic");
var $tblFreezRows = $("#tblFreez tr");
var hei, $row;
$tblFreezRows.each(function(index, elem){
$row = $(this);
if ($.browser.msie) {
hei = $row.find('td').css("height");
$MainContent.find("tr:eq(" + index + ") td").css("height", hei);
}
else {
hei = $row.css("height");
$MainContent.find("tr:eq(" + index + ")").css("height", hei);
}
});
}
The DOM operations are usually the expensive operations.
Your first version has heavy DOM operation, but your second version has the count. It looks like load vs number.
Ideally, your first version should be faster as it is just one loop and the number of iteration is half than the second version.. but it is not always the case.
Assume your memory is like 1000M in which 300M can be garbage collected meaning it can be cleaned up. So the Operating systems memory model would call the garbage collector whenever your memory gets closer to 1000M. With those conditions in mind, lets say in your first version, every 5 iterate takes 1000M, which would end up calling garbage collector to clean up or free up resources for next iteration. So if you end up running for 100 iteration which is equals to 100 iteration + 20 times GC processing.
In your second case, assume it take 50 iteration to fill up 1000M, so you would end up calling 4 time GC processing which is basically 20 vs 4 times calling some other process inbetween each of your iterate.
Above is just a speculation and the actual memory modules are much smarter than what I have explained, but that is just to give an idea of load vs numbers.
Anyways..Try below code and see if it fixes your problem,
Setting height at TR level
var fTable = document.getElementById('#tblFreez');
$("#MainContent_gvDemographic tr").each(function(ridx) {
$(this).height($(fTable.rows[ridx]).height());
});
Setting height at TD level
var fTable = document.getElementById('#tblFreez');
$("#MainContent_gvDemographic tr").each(function(ridx) {
$(this).find('td').each(function (cidx) {
$(this).height($(fTable.rows[ridx].cols[cidx]).height());
});
});
Try detaching the elements before you alter/search them. Then re-append them. DOM-operations are costly.

Categories