How to make a grid in html and css - javascript

I'm trying to make a square grid that's n by n. at the moment I'm just doing it in js with translate but I'd like to have a way to have the grid contained within another element and scale as that element scales so it can be responsive. Ideally I'd like a solution that will allow me to remove set sizes for the grid squares and have them instead auto-adjust to fit the container. This is the code I have right now but it's obviously not a good solution:
let n = 6;
for(let i=0;i<(n*n);i++){
let k = document.createElement("div");
k.className += "tile";
k.style.transform = "translate("+(100*(i%n)).toString()+"%, "+(100*Math.floor(i/n)).toString()+"%)";
document.getElementById("tiles").appendChild(k);
}
and this is the css:
.tile{
width:100px;
height:100px;
position: absolute;
background-image: url("Tiles/tile_01.png");
}
.tile:hover {
opacity: 0.85;
}

In the end I got it working by creating n row flexboxes nested in a column flexbox

Related

JS/jQuery fit all images inside div (without whitespace)

I have a div call it #container,
Inside this #container I have n amount of img tags call it images
n can be 2, 10, 40 and so on.
I am wondering how I can fit n amount of images inside a #container to close all white spaces stretch the images. Quality doesn't matter
This is what I tried until now:
var amount = $("#container > img").length;
var amount_w = amount*200; //200 width of 1 image
var amount_h = amount*130; //120 height image
var refH = $("#container").height();
var refW = $("#container").width();
var refRatio = refW/refH;
$("#container img").each(function(){
$(this).height((amount_h-130)-refH);
$(this).width((amount_w-230)-refW);
});
First of all, it IS possible to achieve what you need even while maintaining the aspect ratio of the images - however the row height will be calculated, but it is not a trivial task (well, at least not as trivial as a single line formula).
There is a jQuery plugin called jPictura which I have developed. I believe the plugin does exactly what you need.
Here is a working fiddle.
You can find the plugin source codes and documentation on GitHub.
Simple example how to use the plugin:
$(document).ready(function () {
$('#my-gallery').jpictura({
layout: { itemSpacing: 0, justifyLastRow: true, idealRowHeight: 200}
});
});
itemSpacing - amount of space between the images in pixels
justifyLastRow - if true, the images in last row will be stretched to take the full width of the row
idealRowHeight - The desired height of the rows in pixels. The plugin will do its best to arrange the items so the row heights are as close as possible to this value.
there are a lot more options documented on GitHub
Beside the JS stuff that calculates the correct widths and heights of the images, there is one more thing to be considered regarding the blank space between images. Images are by default inline-blocks which means they behave like words and words do have some white space inbetween, right? Make them display: block; float: left; or use the flex box layout to get rid of the blank space. The plugin uses float: left; by default.
I created something that might interest you
var container = $('#container');
var height = container.outerHeight();
var width = container.outerWidth();
function populate(n){
var rem_items = n;
var rows = Math.round(Math.sqrt(n));
var row_items = Math.ceil(n/rows);
for (var i=0; i<rows; i++){
// this prevents us from generating a lonely single box in a row
if( (rem_items%(rows-i))===0 ){
row_items = rem_items/(rows-i);
}
if(rem_items<row_items){
row_items = rem_items;
}
rem_items = rem_items-row_items;
for (var j=0; j<row_items; j++){
var img_height = height/rows;
var img_width = width/row_items;
var img_left = j*img_width;
var img_top = i*img_height;
var img = $('<div class="cell"></div>');
img.css({
width: img_width,
height: img_height,
left: img_left,
top: img_top
});
container.append(img);
}
}
}
populate(40);
https://jsfiddle.net/jLq4hgaa/1/
Basically, it calculates the "most balanced" distribution of the images horizontally and vertically.
It does what you're asking for in the plainest sense. It distributes images/containers inside a container evenly regardless of aspect ratio.
$(document).on("pageload",function(){
$('.container').addClass('stretch');
});
Then make a css element called "stretch" defining width:100%
Height:100% and if need be define layout, i.e relative

Programmatically Resizing Divs

I'm working on an HTML5 browser game that can be divided into 3 parts: two UI panels on the left and right of a center set of square canvases for the playing surface. The three panels need to be horizontally aligned, and the total game needs to keep an aspect ratio of 16:9. The left and right panels should be of equal widths, and all three panels must be of equal height. I have specified a minimum width and height inside a resize() function called when an onresize event is detected.
Currently, each panel is a div, and all three are contained inside a section. Right now, the section isn't necessary, but I want to keep the game separated from extra content at the bottom of the screen that I might choose to add later.
The CSS style is as follows:
* {
vertical-align: baseline;
font-weight: inherit;
font-family: inherit;
font-style: inherit;
font-size: 100%;
border: 0 none;
outline: 0;
padding: 0;
margin: 0;
}
#gameSection {
white-space: nowrap;
overflow-x: hide;
overflow-y: hide;
}
#leftPanel, #centerPanel, #rightPanel {
display: inline-block;
}
#leftPanel {
background-color: #6495ed;
}
#centerPanel {
background-color: #e0ffff;
}
#rightPanel {
background-color: #b0c4de;
Right now, I have set the background color of each div just to show me when I'm correctly setting the size of each div.
The body of my HTML document is as follows:
<body onresize="resize()">
<section id="gameSection">
<div id="leftPanel">Left Panel.</div>
<div id="centerPanel">Center Panel.</div>
<div id="rightPanel">Right Panel.</div>
</section>
</body>
And finally, my resize() function (I created a separate function for resizing the game in case I add more elements below later):
function resize() {
var MIN_GAME_WIDTH = 800;
var MIN_GAME_HEIGHT = 450;
var GAME_ASPECT_RATIO = 16 / 9;
var width = window.innerWidth;
var height = window.innerHeight;
var gWidth, gHeight;
if(width < MIN_GAME_WIDTH || height < MIN_GAME_HEIGHT) {
gWidth = MIN_GAME_WIDTH;
gHeight = MIN_GAME_HEIGHT;
}
else if ((width / height) > GAME_ASPECT_RATIO) {
<!-- width is too large for height -->
gHeight = height;
gWidth = height * GAME_ASPECT_RATIO;
}
else {
<!-- height is too large for width -->
gWidth = width;
gHeight = width / GAME_ASPECT_RATIO;
}
resizeGame(gWidth, gHeight, GAME_ASPECT_RATIO);
}
function resizeGame(var gWidth, var gHeight, var aspectRatio) {
var gSection = document.getElementById("gameSection");
var lPanel = document.getElementById("leftPanel");
var cPanel = document.getElementById("centerPanel");
var rPanel = document.getElementById("rightPanel");
gSection.height = gHeight;
gSection.width = gWidth;
<!-- should the below be taken care of in the CSS? -->
lPanel.height = gHeight;
cPanel.height = gHeight;
rPanel.height = gHeight;
cPanel.width = cPanel.height;
lPanel.width = (gWidth - cPanel.width) / 2;
rPanel.width = lPanel.width;
}
I've tried a number of different commands to resize the divs, but it just isn't working for me. When I try adding test canvases, color appears, but the boxes still aren't the correct size. I have also considered loading an invisible background image to each div and scaling it to the desired size; however, I was able to resize my canvas using the above method before and it seemed to work just fine.
Additional Notes
While I've already had pretty good success resizing a single canvas, I don't want to use just one canvas for the game because not all parts of the UI need to be drawn at the same time.
I'm trying to keep this solely in Javascript.
I suspect that I could just use CSS to handle resizing by fixing the aspect ratio to 16:9 and using width:56.25% for the center panel and width:21.875% for the side panels, but that limits me to one aspect ratio and doesn't explain why my above script isn't working.
I can provide the entire HTML file if needed. This is what it's supposed to look like:
End Goal (without right panel)
Thank you!
UDPATE:
jsfiddle
I got it kind of working here. I made a lot of changes/minor fixes to the code before finding what was wrong (other than various syntax errors):
You were using .width and .height instead of .style.width and .style.height, and you were applying integers to these instead of strings with "px" appended to them. Both of these things are completely understandable to miss.
I also moved the onresize from the body tag into the JS, don't know why it wasn't working on jsfiddle, but this is good practice anyways.
In the future: learn how to debug JS using the console and when you ask questions, use small examples, not your entire codebase. This question could have been simplified to "How do I resize a div?" with one line of JS and one div. You also should consider not doing this specific thing in JS, and using flexbox as redbmk said.

Generate 3 main colors gradient based on numeric array in Javascript or jQuery

There is a column from a table that contains numeric values unordered. Each td needs to be painted using solid colors in a way that the column forms a unordered gradient.
I created a numeric array which contains those values ordered and now I need to generate the gradient array based on that, so each value of the array will have a corresponding solid color.
Lower numbers must be red, medium numbers must be yellow and higher numbers must be green. All those colors smoothly transiting from itself to the next one.
So basically, the ordered array will have a ordered gradient, but when I paint the column the gradient will become unordered, because the columns values aren't ordered.
What I'm trying to reach is "crescent rank" gradient in that column.
How can I do that with javascript or jQuery?
Modified Answer After Update to Question
I still think I can help you with this. I forked and modified my original JSFiddle to show how this is applied. The CSS stays relatively the same.
It sounds like you want to have specific values for each level of gradient, but I still think the moving "bar" concept works best when applying multi-stop gradients. IE going from one color to a different to another different. This is because it is MUCH less work if you need to modify the gradient colors since you can just change out the background linear-gradient code in the CSS, as well as it gives you the smoothest and realest gradient no matter how many rows you have. The JSFiddle still has the input boxes so you can see each "step" of the gradient. As I said before you can go to a site like www.colorzilla.com/gradient-editor/ and modify the gradient to your needs and even add an in-between color stop if say you don't like the transition from yellow to green.
Here is the jQuery code you would need to input all your values from a table into a multidimensional array. After it is in the array, you can then order each column in the array (since each column is it's own array in the array) and move the background based on the "rank" or index in that array. Since my understanding is that you wanted to sort based on lowest value to highest value, and not say 0 to 100.
//jQuery for table
$("#someTable td").wrapInner("<span class='tdData'></span>");
$(".tdData").wrap("<div class='css3gradient'></div>");
var colVal = [];
var numCol = $("#someTable").find('tr')[0].cells.length;
var numRows = $("#someTable tr").length - 1; //subtract if header
var itemCount = 0;
var gradientWidth = $(".css3gradient").css("width").replace(/[^-\d\.]/g, '')-$(".tdData").css("width").replace(/[^-\d\.]/g, '');
//initialize array
for (var i = 0; i < numCol; i++) {
colVal[i] = new Array();
}
//fill multidimensional array
$("table tr td").each(function () {
curCol = itemCount % numCol;
colVal[curCol].push($(this).text());
itemCount++;
});
//sort values in array and assign value for gradient
for (i = 0; i < numCol; i++) {
//sort values as numbers
colVal[i] = colVal[i].sort(function (a, b) {
return a - b;
});
//match each value in the array in order with value in table
$.each(colVal[i], function (index, value) {
$("#someTable td:nth-child(" + (i + 1) + ")").each(function () {
if ($(this).text() == colVal[i][index]) {
//Multiply current index with
///Divide the total width of gradient box with
////Subtract total number of rows with one to make zero the first left position
////and the last number the final position
$(this).find(".css3gradient").css({ backgroundPosition: '-' + (index * (gradientWidth / (numRows - 1))) + 'px 0' });
}
});
});
}
Feel free to comment again if I've misunderstood something. This has been a really fun problem to solve, and I hope I helped or gave you at least a step in the right direction.
Original Answer
I made a JSFiddle for you that should get you started. Explanation below.
From what I understand, you want to have a background within a div/span/input change colors based on the value in that div/span/input. You would like lower numbers to represent red, and the a gradient to change the color from red > yellow > green, with green being the max color. You would also like this to be controlled by jQuery.
To do that we can stack a couple of divs, and utilize positioning and overflows to “hide” any excess of the div we are using for the background.
First, I’d recommend using a CSS Gradient Generator like the one at http://www.colorzilla.com/gradient-editor/ to generate your CSS code.
Next, lets look at the structure of your data. You’ll want to have 3 elements to get this to work.
The inner element which holds the data. For my example I used an input element so you can change the values and test.
The next element you want is a div which you can use as the “background”. This element will be positioned absolutely so we can move it left to right to get the gradient we want.
Finally you’ll want the outer wrapped div so you can utilize the overflow css rule to hide the excess from the background div.
So for a reference, here is what the html looks like for this particular task:
<div class=“data”><div class=“css3gradient”><input /></div></div>
If you don’t have access to the HTML, a quick fix is to use the .wrap() jQuery function. For instance, if you just had an outer div and input, you could “wrap” the input with
$(“.data input”).wrap(“<div class=“css3gradient”></div>”);
For the gradient div, mathematically, it can get a bit wonky trying to make it “line up”. For my example I just went with a total width to display the data of 100px, and a total width for the gradient background of 1100px;. The reason for the extra 100px on the background is because when you move the element over by 10, you need the extra width to fill the remaining div. IE zero position takes up 0-100, second position takes up 200-300, and the final tenth position takes up 1000-1100. You can apply this method to any width you have by making the width of the gradient div be (x * 10) + x.
This also looks at the data from the standpoint that you go from 0 to 100 as if you are doing %s.
So for my CSS this is what it looks like:
.css3gradient{
width:1100px;
height:100px;
position:absolute;
background: #ff0000; /* Old browsers */
background: -moz-linear-gradient(left, #ff0000 0%, #ffff00 50%, #00ff00 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, right top, color-stop(0%,#ff0000), color-stop(50%,#ffff00), color-stop(100%,#00ff00)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(left, #ff0000 0%,#ffff00 50%,#00ff00 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(left, #ff0000 0%,#ffff00 50%,#00ff00 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(left, #ff0000 0%,#ffff00 50%,#00ff00 100%); /* IE10+ */
background: linear-gradient(to right, #ff0000 0%,#ffff00 50%,#00ff00 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ff0000', endColorstr='#00ff00',GradientType=1 ); /* IE6-9 */
}
.data {
width: 100px;
height: 50px;
vertical-align: middle;
position: relative;
overflow: hidden;
border: 1px solid #000;
margin: 3px;
}
.data input {
width: 100px;
height: 50px;
background: transparent;
border: 0;
text-align: center;
}
Finally, the fun part. We have to actually move this background based on the value in the input. I’m not sure if you have some sort of input or dynamic way your changing the values within each element. At any rate, this jQuery will get you started.
$(".data input").each(function(){
var dataValue = $(this);
//call this initially set the background based on the value
changeColor(dataValue.val());
//this is what allows the background to change dynamically when you type into the input element
dataValue.bind("keyup change input",function(){
changeColor(dataValue.val());
});
function changeColor(e) {
var mulitplyColor = e * 10;
dataValue.parent(".css3gradient").css({backgroundPosition: '-' + mulitplyColor + 'px 0'});
}
});
Hope this helps!

X sections within a div

I saw this
And thought it would be cool if I can dynamically change the colors and width of the colors with JS. The problem is I can use divs, but prefer not to. I've already tried gradients, but it didn't seem to work as expected. Any ideas on how to go about this? Additionally I'm not asking you to code this for me, rather a step of help. When I use it the div way and say set it to 33%, only 33% of the gradient shows. Not the 33% that corresponds to the color.
.a{
background-image:
linear-gradient(
to right,
#fffdc2,
#009dff 15%,
#000 15%,
#000 85%,
#fffdc2 85%
);
position: fixed;
z-index: 1031;
top: 0;
height: 4px;
transition:all 1s;
}
Gradient is definitely the way to go. Use percentage positions for the colour stops.
For example, try this function:
function generateCSSGradient(colours) {
var l = colours.length, i;
for( i=0; i<l; i++) colours[i] = colours[i].join(" ");
return "linear-gradient( to right, "+colours.join(", ")+")";
}
var cols = [
["red","0%"],
["red","40%"],
["yellow","40%"], // note same percentage - this gives a crisp change
["yellow","60%"],
["green","60%"],
["green","80%"],
["blue","80%"],
["blue","100%"]
];
yourElement.style.background = generateCSSGradient(cols);
You can adjust and vary the colours however you want - add more, move them, change them, anything goes!

Javascript positioning center style

I wanted to set my second div element indside of my first div element center. I think somehow I managed to center it. But I think I made some mistakes and it seems to me it is not properly centered and also this JavaScript style seems to me bad. Is there any better way doing it? Is my JavaScript code is correct?
FIDDLE
HTML
<div class='first'>
<div class='second'>
</div>
</div>
JavaScript
var first = document.getElementsByClassName('first')[0];
var second = document.getElementsByClassName('second')[0];
var height = first.offsetHeight;
second.style.width = height/2+"px";
second.style.height = height/2+"px";
second.style.marginLeft = height/4+"px";
second.style.marginTop = height/4+"px";
offsetHeight will get the height of the element including borders, clientHeight won't. Instead of:
var height = first.offsetHeight;
Try:
var height = first.clientHeight;
JSFiddle
I've also used top and left with position:absolute for positioning, as this take the element out of the page flow and I assume this is the behaviour you are looking for.
References:
offsetHeight
clientHeight
(Follow the links and take a look at the box-model diagrams)
Reason is drawing round take 3px thats why not positioning but you divide 2.1 that result come that you need.
Check this Demo jsFiddle
JavaScript
var first = document.getElementsByClassName('first')[0];
var second = document.getElementsByClassName('second')[0];
var height = first.offsetHeight;
second.style.width = height/2.1+"px";
second.style.height = height/2.1+"px";
second.style.marginLeft = height/4+"px";
second.style.marginTop = height/4+"px";
var second = document.getElementsByClassName('second')[0];`
var left = (screen.width/2)-(100/2);
var top = (screen.height/2)-(100/2);
second.style.width = "100px"; //set as per your requirement
second.style.height = "100px"; //set as per your requirement
second.style.left= left +"px";
second.style.top = top +"px";
Just in case, you're interested, I tried to come up with a CSS only solution.
http://jsfiddle.net/53M6A/1/
Here's the changes I made to the .second class.
.second{
left: 50%; //move 50% to left
top: 50%; // move 50% down
margin-left: -50px; //move half of it's own size back to the left
margin-top: -50px; //move half of it's own size back to the top
position: relative; //make it relative, so it can be moved around by left/top
width:100px;
height:100px;
background: #fff;
border-radius:50%;
}
I've been playing a little in your fiddle and finally, I changed your 2 last lines for these:
first.style.display = "table-cell";
first.style.verticalAlign = "middle";
second.style.margin = "0 auto";
Fiddle
Seems perfectly centered to me.

Categories