dynamically adding div's as columns in a row with Zurb Foundation - html

I am trying to dynamically add div's (which will be the target for jqplot graphs) to a tab panel using Foundation 6. I want the divs to be in a column layout in the row. I can get the divs in a row but each div ends up being in a row by itself instead of being a column element in the row.
I want this layout:
Layout I want
I have been using the code below to create the row div in the "graph1" panel:
var dynDivR1 = document.createElement("div");
dynDivR1.id = ("dynRow1");
dynDivR1.class = "row";
document.getElementById("graph1").appendChild(dynDivR1);
I then go into a loop to create the actual images (get the data, create the jqplot graph). Within the loop I create the graph div using the code below:
var dynDiv2 = document.createElement("div");
dynDiv2.id = ("dynDiv2" + divno2);
dynDiv2.class = "small-7 medium-3 large-3 columns";
dynDiv2.style.height = "200px";
dynDiv2.style.width = "200px";
dynDiv2.style.backgroundColor = 'white';
document.getElementById("dynRow1").appendChild(dynDiv2);
var plotInDiv2 = simplePlot(dynDiv2.id, lineDat2, sensorNames);
divno2 +=1;
simplePlot is a function that creates the graph using jqplot. This code works in the sense that divs are dynamically created, the graphs are placed in them. The problem I have is the layout: because I will have many graphs I want them in columns going across the page, not rows down the page (I will eventually have to have rows and columns but for now I am just trying to solve the column problem).
I tried removing the column width and height attributes in the image div but that also did not work (just got full width images / divs).
When I look at the resulting HTML the div's I have created do not seem to contain the class information. So for example the dynRow1 div looks like this (see actual HTML below):
<div id="dynRow1">
It does not have class = row attribute. When I look at the div (console.log) immediately after creation the class = row is there.
I tried inserting an additional column class div in the row like this (and then attach the plot div to that) but it did not work:
<div class="medium-6 columns">
I am stuck and would greatly appreciate any suggestions or pointers others can give.
Thank you very much.
Added 26/12/16 This is the HTML I am getting (I have not included the closing tags - they are there, the page loads and works without error in Firebug:
<div class="tabs-content" data-tabs-content="dy-tabs-2">
<div id="data1" class="tabs-panel" role="tabpanel" aria-hidden="true" aria-labelledby="data1-label">
<div id="graph1" class="tabs-panel is-active" role="tabpanel" aria-hidden="false" aria-labelledby="graph1-label">
<div id="dynRow1">
<div id="dynDiv21" class="jqplot-target" style="height: 200px; width: 200px; background-color: white; position: relative;">
<div id="dynDiv22" class="jqplot-target" style="height: 200px; width: 200px; background-color: white; position: relative;">
Then this is a clip of the screen shot of the resulting HTML
Clipped screen shot from HTML page
Thanks Again

Dear please check the snippet, i have added display:inline-block to your generated div, is this what you need ?
<div class="tabs-content" data-tabs-content="dy-tabs-2">
<div id="data1" class="tabs-panel" role="tabpanel" aria-hidden="true" aria-labelledby="data1-label">
<div id="graph1" class="tabs-panel is-active" role="tabpanel" aria-hidden="false" aria-labelledby="graph1-label">
<div id="dynRow1">
<div id="dynDiv21" class="jqplot-target" style="height: 200px; display:inline-block; width: 200px; background-color: orange; position: relative;"></div>
<div id="dynDiv22" class="jqplot-target" style="height: 200px; display:inline-block; width: 200px; background-color: black; position: relative;"></div>
</div>
</div>
</div>
</div>

Adding a row is <div class='row'> you have <div class='column row'>.
Using both column and row in the class creates a div that is a row 12 columns wide. Any new div columns you add will go to a new row.
Also, you will need to add the width (in grid blocks) that you want for your columns (up to 12 per row).
<div class='small-7 medium-3 large-3 columns'>
This code shows a column div that will be 7 grid spaces on small screen, 3 on medium and 3 on large.
Adding a new div should go as follows... (notice classList.add("row")):
// create a new ROW div
var dv = document.createElement("div");
dv.id = ("newDiv");
dv.classList.add("row");
Here is a codepen example of adding all the content to create a row with several columns and utilizing the foundation classes:
https://codepen.io/cmodesign/pen/woEpEd
http://foundation.zurb.com/sites/docs/grid.html

Thanks to Chris O for the useful suggestions. I have used Chris's suggestions as a basis for the following solution which works.
function staticPlots (selectDataSet) {
/* Function to create row and column div's for each variable in SelectDataSet and then plot
the data for each variable using jqplot line graph.
Temporary data in dataToPlot.
Temporary list of variables in selectVar
*/
// Temporary selection of variables to plot
selectVar = ["R1_","R2_","R3_","R4_","C1_","C2_","C3_","C4_","C5_","C6_","C7_","C8_","C9_","C10_","C11_","C12_"];
/* Create divs and place plots in them
First calculate the number of rows needed with four plots per row
lx is iterator to set unique col ids
*/
var x = selectVar.length;
var y = 4;
var z = Math.ceil(x / y);
var lx = 0;
for(var r=1; r<=z; r++) {
var dv = createRowColDivs();
dv.id = ("newRow"+r);
dv.classList.add("row");
document.getElementById("graph1").appendChild(dv);
var newCol;
for(var i=1; i<=4; i++) {
newCol = document.createElement("div");
newCol.classList.add("small-3");
newCol.classList.add("columns");
newCol.id = "col"+lx;
dv.appendChild(newCol);
var names = selectVar[lx];
// Temporary data for illustration so the database is not used
dataToPlot = [[1,4,5,6,8,2,3],[2,8,7,6,3,2,3]];
var plotInDiv2 = simplePlot(newCol.id, dataToPlot, names);
lx ++;
}
}
};
The createRowColDivs function just creates the row div so I can use it in other processes. Could easily have kept those processes in staticPlots function.
function createRowColDivs() {
// create a new ROW div
var dv = document.createElement("div");
dv.id = ("newDiv");
dv.classList.add("row");
return(dv);
};
This code gives me the row by column plot layout I was after.
Thanks Chris for the snippet that saw me on my way. One thing I had to change in your code was attaching the row div before I defined the col divs. it also took me way too long to figure out I needed to use lx to create unique id's for each plot.
Always appreciate suggestions for improving the code if anyone cares to.

Related

Border on page break of a div

I'm generating a pdf with wicked_pdf, and centain pages will have a div with a black border. This div may or may not be big enough to break between pages, which leads to the following effect:
Div with open bottom
The div breaks like it should, but it is open between pages, and i need it to have a closing border. I was able to achieve a border using a footer with the right width and height to match the bottom break, but there are pages that shouldn't have it. Besides, there is the problem that the top of the div on the next page remains open
Using footer to close the bottom
I was able to make the footer disappear, from specific pages, like the last one, but there isn't a way to know how many pages the pdf will have, or which pages should or should not have it. I used the following code to do so:
var vars = {};
var x = document.location.search.substring(1).split('&');
for (var i in x) {
var z = x[i].split('=', 2);
vars[z[0]] = unescape(z[1]);
}
var x = ['frompage', 'topage', 'page', 'webpage', 'section', 'subsection', 'subsubsection'];
for (var i in x) {
var y = document.getElementsByClassName(x[i]);
for (var j = 0; j < y.length; ++j) y[j].textContent = vars[x[i]];
if (vars["topage"] == vars["page"]) {
document.getElementById("footer-line").style.display = "none";
}
};
<div id="footer" style="display: inline-block; width: 100%">
<div id="footer-line" style="margin-left: 2px; width: 99.6%; height: 60px;border-top: 2px solid black;"><div>
</div>
But it doesn't solve the problem, since the footer with the line remains on pages which it shouldn't be or its not needed, cause the div itself migth have ended and is, therefore, already closed.
I also tried to use box-decoration-break, but it looks like the html is first rendered and then turned into pdf, so this rule doesn't work apparently
I guess it would make a lot of sense for css to have a border feature on page-breaks, but i couldn't find anything like that. How could a closement for it be made?

Find index of element within a list of elements with the same class

I have a div:
<div class="container">
<div class="info" style="display:block;"></div>
<div class="result-image-slides"></div>
<div class="result-image-slides"></div>
<div class="result-image-slides" style="display:block;"></div>
<div class="result-image-slides"></div>
<div class="prev_img"></div>
</div>
<div class="container">
<div class="info" style="display:block;"></div>
<div class="result-image-slides" style="display:block;"></div>
<div class="result-image-slides"></div>
<div class="result-image-slides"></div>
<div class="result-image-slides"></div>
<div class="prev_img"></div>
</div>
and I have a jquery onclick
$('.prev_img').on('click', function(e) {
// Get the count of siblings with the class 'result-image-slides'
var count = $(this).siblings('div.result-image-slides').length;
var slideIndex = $(this).siblings('div.result-image-slides:visible').index();
showSlides(-1, count, $(this).siblings('div.result-image-slides'), slideIndex);
})
that gets the count of the siblings and tries to get the index of the sibling that has been clicked. The issue is that when I do the index() it seems to count the firsat div (with the class "info") as well.
I've tried the following:
$(this).siblings('div.result-image-slides:visible').index()
and
$(this).siblings('div.result-image-slides').index('div.result-image-slides:visible')
however it always seems to include the first div, leading to the wrong index.
Am I missing something here? How can I only get the index of a div within a list of 'div's with the same class.
For example with the above html for the first container when I click prev_img the index of the visible element would be 2 not 3.
EDIT: By default the divs are hidden with display:none
Adding to this: I have the same functionality on a different page however that container doesn't have a child with the class info. When the above jquery runs, and (for example) the visible item is the first div, it returns an index of 0 however for above if the first element is visible, it returns 1. This makes me believe it's counting the first element as well as the ones with the classes I'm checking against;
EDIT 2: So I've figured out how to solve this issue but it's not really the best solution.
var arr = [];
var slideIndex = 0;
arr = $(this).siblings('div.result-image-slides');
for (var i = 0; i < arr.length; i++) {
if (arr[i].style.display == 'block') {
slideIndex = i;
break;
}
}
var count = $(this).siblings('div.result-image-slides').length;
showSlides(-1, count, $(this).siblings('div.result-image-slides'), slideIndex);
To only get the index of the visible div in regards to the classes I want to check against, I've added the siblings to an array and looped through it, setting the slideIndex based off that
In your snippet all <div>s were visible, so the first visible one had the index 1 which is the second child element in the parent's collection. I added some CSS to make the .result-image-slides divs invisible by default. Only the third .result-image-slides is visible now. Its index is 2. And this index is returned when we use the .index() function in a slightly different way:
$('.prev_img').on('click', function(e) {
// Get the count of siblings with the class 'result-image-slides'
var indx = $(this).siblings('.result-image-slides:visible').index(".result-image-slides");
console.log(indx);
// showSlides(-1, count, $(this).siblings('div.result-image-slides'), slideIndex);
})
.result-image-slides {display:none}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="info">info</div>
<div class="result-image-slides">one</div>
<div class="result-image-slides">two</div>
<div class="result-image-slides" style="display:block">three</div>
<div class="result-image-slides">four</div>
<div class="prev_img">click here</div>
</div>
$.index() returns the element's index within the parent's .children collection, irrespective of whether the siblings match the selector .result-image-slides or not. But when we do
$(this).siblings('.result-image-slides:visible').index(".result-image-slides");
We first look for the first .result-image-slides:visible div and get its index relative the the first occurrence of a .result-image-slides element in the parent's .children collection. The index here has to be and is: 2.
Since it's been a few days and no answer has been provided that corrects this issue, I will add this as the answer.
var arr = [];
var slideIndex = 0;
arr = $(this).siblings('div.result-image-slides');
for (var i = 0; i < arr.length; i++) {
if (arr[i].style.display == 'block') {
slideIndex = i;
break;
}
}
var count = $(this).siblings('div.result-image-slides').length;
showSlides(-1, count, arr, slideIndex);
We add the siblings to a js array and get the index that way. This means that it should never count any siblings that do not contain the correct class.

Creating a 'Zoom' like dynamic gallery view in CSS/HTML

I have an application where I want to create a full sized HTML page for displaying on a Kiosk.
Javascript will change the number of images depending on how many people are interacting with the kiosk (this side is all handled).
I could have one image, it could be two, three, four, anything up to 7x7 = 49.
I want to create a layout that looks very similar in how 'Zoom' creates the gallery view.
For instance:
One image: would be 100% width and height of the page
Two images: would do 50% width/height, showing eachother side by side with letterboxing top and bottom of the page
Three images: two on the top line, one on the bottom - with the bottom one horizontally centred
Four images: 2x2 grid
Five images: three on the top line, two on the bottom line
etc
Nine images: 3x3 grid
You get the picture!
I've spent a good few hours today trying to solve this. I don't really have working code to show any more as I have tried lots of options. I have tried pure CSS, jquery manipulating tables, utilities that create masonry galleries, etc. None seem to achieve what I want.
Does anyone have any bright ideas on how to make this happen?
It's running on Chrome in a controlled environment so don't need to worry about cross browser compatibility and can generally get away with using most options for technologies to get this to work.
Thanks
If you wanted the new people to come in at the bottom/left then grid would be the answer. But to get the bottom row centered we need to turn to flex.
As you will probably be using JS to insert or remove people you can calculate how many columns you need each time and reorganize the screen.
Here's a snippet showing the calculation. Change the number of divs in #container to see the effect. The aspect ratio for the person div is set in JS as variable personAspect. Currently set to 16:9 but can be altered as required.
<head>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#screen {
position: relative;
width: 100vw;
height: 100vh;
background-color: black;
overflow: hidden;
}
#container {
position: relative;
top: 50%;
margin: auto;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.person {
background-image: url(https://i.stack.imgur.com/ju8HY.jpg);
background-size: cover;
background-repeat: no-repeat;
}
</style>
<style id="person">
</style>
</head>
<div id="screen" >
<div id="container">
<div class="person"></div>
<div class="person"></div>
<div class="person"></div>
<div class="person"></div>
<div class="person"></div>
</div>
</div>
<script>
const personAspect = 16/9; /* SET TO WHAT YOU WANT IT TO BE FOR EACH PERSON DIV */
const maxCols = 7;
const screen = document.getElementById("screen");
const container = document.getElementById("container");
function reorganize() {
const people = container.querySelectorAll('.person');
const numPeople = people.length;
const screenAspect = window.innerWidth/window.innerHeight;
let cols = 1;
for (cols; cols <= maxCols; cols++) {
if (numPeople <= (cols * cols)) { break; }
}
let w = 0; //will be of the container in px
let h = 0; //will be height of the container in px
if (numPeople > (cols * (cols-1))) {// > OK for 5 and 6 not OK for 7
h = window.innerHeight;
w = h * personAspect;
} else {
w = window.innerWidth;
h = w / personAspect;
}
container.style.width = w + 'px';
document.getElementById('person').innerHTML = '.person {flex: 0 0 ' + (100/cols) + '%; height: ' + (h/cols) + 'px;}';
if (numPeople <= (cols * (cols-1))) {h = h- h/cols;}// for when last row is empty
container.style.marginTop = (- h)/2 + 'px';
}
reorganize();
window.onresize = reorganize;//not needed for final production but to make it easier to use the real window aspect ratio when developing
</script>
</body>

CSS set background image regarding class selector

I would like to set the background image of a div regarding its class. The web I am developing should show a set of game cards. Each card is contained in a div and have a class like this:
<div class="card value suit>
</div>
Being the suit and value for instance clubs and five respectively. So for instance, for a div container like this:
<div class="card seven clubs>
</div>
I wonder if there is a way via CSS to set its background-image to this attribute without writing this for each card:
.card.seven.clubs {
background-image: url("../../images/seven_clubs.png");
}
you can't really have dinamy classes with css only, you need some form or precompiler such as SASS to to convert from thing like
for every number do {
generate number properties
}
for every suite do {
generate suite css properties
}
to actual css code in the form of
.suite1{
property: value;
}
.suite2{
property:value
}
.number1{
property:value
}
or you can use Javascript and dynamically set styles on it
var cards = document.getElementsByClassName('card');
for (var i = 0; i++; i < cards.length){
var thisElementClasses = cards[i].classList;
let imageUrl = '../../images/'+thisElementClasses[0]+'_'+'thisElementClasses[1]'+'.png';
card[i].style.backgroundImage = imageUrl;
}

How to freeze header and left columns of the table

I want to fix header and 3 left columns of my table.
But I found only one suitable solution. Here is link: http://hazaa.com.au/blog/how-to-create-an-html-table-with-frozen-headers-and-columns/
I need to divide my table to 4 independent tables and that's not good.
Also I found plugin http://www.fixedheadertable.com/ (as suggestion in another such question on SO) unfortunately it can freeze only one left column (I need 3 columns).
Are there any other simple ways to implement this feature?
the standard html table does not support frozen columns, even with css.
if you can use a jquery plugin, i suggest you to use http://www.datatables.net/ with the fixedcolumns plugin (just configure and it works as supposed :) )
if not, you will end up with u solution where you havo to split up the table in the one or the other way, and if you want to have scrollable tables you will have to use javascript since css and html do not support such features yet.
Thought I'd share how I've done this. This code is surely somewhat based off other code found on this site but have long since lost exactly where. Requires jQuery. Potentially doesn't support various odd things you might want to do to a table.
<div class='tableFreeze'>
<table>
<thead>
<tr><th>Headers</th><th>Go</th><th>Here</th></tr>
</thead>
<tbody>
<!--table body stuff goes here-->
</tbody>
</table>
</div>
<style>
.tableFreeze {
width: 800px;
max-height: 500px;
position: relative;
overflow: scroll;
}
</style>
<script>
$(document).ready(function(){
//Sets a table to have frozen headers, or both headers and first column
//A div around the table must have a class of 'tableFreeze'
//can also add class 'tableFreeze_headersOnly' to the div to specify only headers should be frozen
//Table inside of div must have one thead and one tbody
//can set the div to have custom CSS defining the width and max height
$('.tableFreeze').each(function(){
var div=$(this);
//get the table in the DIV
var table=div.children('table');
// save original width to table object
var table_original_width=table.width();
//do the same for each td or th in the header
table.find('thead tr td,thead tr th').each(function(){
$(this).attr("data-item-original-width",$(this).width());
});
//do the same for the heights of each first cell on the left
var table_original_height=table.height();
table.find('tr').each(function(){
$(this).find('td,th').eq(0).attr("data-item-original-height",$(this).find('td,th').eq(0).height());
});
//need a copy of the table to strip away and make it just the header
var table_header=table.clone();
//set the whole copy of this table to have the proper width
table_header.width(table_original_width);
//set width of all cells in the header
table_header.find('thead tr td,thead tr th').each(function(){
$(this).width($(this).attr("data-item-original-width"));
});
//remove the tbody
table_header.find('tbody').remove();
//set the width and height of this header bar. add a header class
table_header.css({'width':table_original_width,'height':table_header.find("td,th").first().attr('data-item-original-height'),"position":"absolute","left":0,"top":0}).addClass('tableFreeze_header');
//add to div
div.append(table_header);
//if we have this class, we don't need to do the rest
if ($(this).hasClass('tableFreeze_headersOnly')) return;
//another copy of the table for just the left bar
var table_leftcol=table.clone();
//go through each row (in both tbody and thead)
table_leftcol.find('tr').each(function(){
//remove all but the first cell
$(this).children('td,th').slice(1).remove();
//set the height of each cell to be the original height
$(this).children('td,th').height(($(this).children('td,th').attr("data-item-original-height")*1)+1);
});
//set: the height of the whole table based on the original height we got, the width based on the width set of the first cell, absolutely position it on the left and right, and an id for finding later
table_leftcol.css({'height':table_original_height,'width':table_leftcol.find("td,th").first().attr('data-item-original-width'),"position":"absolute","left":0,"top":0}).addClass('tableFreeze_leftcol');
//add to div
div.append(table_leftcol);
//and finally a similar thing for just the top left cell (a1). That will need to always be on the top left.
var table_a1=table.clone();
//set copy to be original table width
table_a1.width(table_original_width);
//get the width and height of the a1 cell
var table_a1_width=table_a1.find("thead tr td,thead tr th").eq(0).attr("data-item-original-width");
var table_a1_height=table_a1.find("thead tr td,thead tr th").eq(0).attr("data-item-original-height");
//remove all but the first cell in the header
table_a1.find("thead tr td,thead tr th").slice(1).remove();
//and remove the entire tbody
table_a1.find('tbody').remove();
//set the first (and should be only remaining) cell to have the proper width/height
table_a1.find("thead tr td,thead tr th").eq(0).width(table_a1_width).height(table_a1_height);
//table positionin' stuff
table_a1.css({'width':table_a1_width,'height':table_a1_height,"position":"absolute","left":0,"top":0}).addClass('tableFreeze_a1');
//add to div
div.append(table_a1);
});
});
</script>