I'm trying to make a grid of divs that, when mouseentered change color. Then, when the a button is clicked and new number is entered to then generate a new grid with a side length of that many divs. I'm new to javascript and jQuery and can't figure out why my code won't generate the divs.
here's my script
$('.block').mouseenter(function () {
$(this).css('background-color', 'black');
});
function newGrid(x) {
for (i = 0; i > x * x; i++) {
$('.container').append('<div class="block"></div>');
}
$('.block').height(960 / );
$('.block').width(960 / );
}
function clearContainer() {
$('.block').remove();
}
function askGrid() {
var num = prompt("enter box length");
clearContainer();
newGrid(num);
}
function firstGrid() {
newGrid(16);
$('#reset').click(function () {
askGrid();
});
}
$(document).ready(firstGrid);
here's my css
.container {
margin: 30px auto 0px auto;
height: 960px;
width: 960px;
border: 1px solid black;
}
.block {
border:0px;
margin:0px;
padding:0px;
float:left;
background-color: yellow;
}
#reset {
display:block;
padding:5px 20px;
margin:0 auto;
}
html has a css reset and in the body i have a button with id="reset" and a div with class="container"
thanks!
Several problems:
The slash when setting height and width is wrong (either is 960 divided by something or just 960)
The for loop is wrong: it should be
for (i = 0; i < x * x; i++)
And the css thing is not going to apply since there are no .block elements when executed. You should probably move it into newGrid
You have a bug here for (i = 0; i > x * x; i++) it should be i < x.
And im not sure what this is
$('.block').height(960 / );
$('.block').width(960 / );
you can set the height and width respectively in the css
Also you need to this for the mouseenter event to work
$('.container').on('mouseenter','.block',function () {
$(this).css('background-color', 'black');
});
Since the items added are dynamic.
Welcome to jquery, a world of excitement and pain!
This code
$('.block').mouseenter(function () {
$(this).css('background-color', 'black');
});
binds the hover function to all existing .block elements on the page when it is run. It's at the top of your script so it'll execute once, binding this property to all .block elements when the page loads, but not to .block elements created after. To fix this add it inside your "newGrid" function so it rebinds each new element as they are created.
In your loop, you want for (i = 1; i < x * x; i++), starting index from 1 rather than 0, or else you'll have an off by 1 error and create an extra box.
To set the proper heights of .block, you want to divide your .container's dimentions by x, the size of block:
$('.block').height(960 / x);
$('.block').width(960 / x);
The following are general programming tips:
As a good practice, functions should have a specific job and only do that job. I moved the clearContainer call to inside newGrid, because it should be the function that builds the new grid that clears the old one, not the one called askGrid. askGrid should do as it is named, and only ask for your new grid dimension.
You should do a validation on the number received through askGrid. If the user types something that isn't a number, or a negative number, or 0, you shouldn't start making boxes or newGrid will break. I added a loop to keep asking for a size until a proper dimension is provided, but you can chose your behaviour.
I changed the variable "x" to "block_length" since variables should be given names indicative of that they mean, so that there aren't a bunch of mysterious variables all over the place called x, y, z that you can't tell what they mean from a glance.
Demo in this fiddle!
Related
I have a block with a few inline-blocks inside. These all have varying heights and widths. I have line wrap enabled.
What I'm trying to do is if I have a reference to one of the inline-blocks to
find out what line it is in and
how high that line is. (I can't change the HTML)
2 has the obvious solution of getting the bounding boxes of all blocks in the line and using the highest height as the height of the line. Here I'm just wondering if there is a more performant solution for that.
My main interest lies in a). My idea of an incredibly imperformant solution would be doing b) for all lines in the parent block and then comparing the offset-top of the searched element to the line-heights. I was hoping maybe someone can come up with a better idea?
edit:
relevant part of the html, css and js i'm using:
<div>
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
div {
display: block;
background-color: yellow;
height: 600px;
width: 2000px;
}
div > div {
display: inline-block;
padding: 10px;
margin: 5px;
}
document.addEventListener("DOMContentLoaded", function() {
const nodes = document.querySelectorAll("div > div");
for(let i = 0; i < nodes.length; i++) {
nodes[i].style.width = `${5 + Math.random() * 200}px`;
nodes[i].style.height = `${5 + Math.random() * 200}px`;
nodes[i].style.backgroundColor = `hsl(${(Math.random() * 360)}, 100%, 50%)`;
}
const nodeiwanttogetdescribeddataof = nodes[4];
//code to get the data
});
i did not implement the ideas described as i was hoping to not need to. the purpose of the question was to find out whether there is some easy way to do what i need, for example (pseudocode) let theline = node.line.
I am attempting to write some JavaScript code that will allow me to center a child element within it's parent using padding. Then using the same function to recalculate the spacing using the 'resize' event. Before you start asking me why i am not doing this with CSS, this code is only a small part of a larger project. I have simplified the code as the rest of the code works and would only serve to confuse the subject.
Calculating the space - This is the function that caculates the amount of space to be used on either side of the child element.
($outer.outerWidth() - $inner.outerWidth()) / 2;
($outer.outerHeight() - $inner.outerHeight()) / 2;
The problem
Although i have successfully managed to get the desired results with margin. Padding is causing me problems.
It appears to be increasing the width on the outer element when resized
It does not center the child element perfectly (there appears to be an offset)
The inner element collapses on resize and becomes invisible.
I realize that there may be some fundamentals regarding padding that are causing my problems however after numerous console logs and observing the data returned i still can't put my finger on the problem. Any suggestion would be very welcome. It may turn out that this is not feasible at all.
HTML
<div id="demo" class="outer">
<div class="inner">
</div>
</div>
CSS
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
.outer {
width:97%;
height:400px;
border:1px solid black;
margin:20px;
}
.inner {
width:40%;
height:100px;
background-color:grey;
}
JAVASCRIPT
var $outer = $(".outer");
var $inner = $(".inner");
var getSpace = function(axis) {
if (axis.toLowerCase() == "x") {
return ($outer.outerWidth() - $inner.outerWidth()) / 2;
} else if (axis.toLowerCase() == "y") {
return ($outer.outerHeight() - $inner.outerHeight()) / 2;
}
}
var renderStyle = function(spacingType) {
var lateralSpace = getSpace("x");
var verticalSpace = getSpace("y");
var $element;
if (spacingType == "padding") {
$element = $outer;
} else if (spacingType == "margin") {
$element = $inner;
}
$.each(["top", "right", "bottom", "left"], function(index, direction) {
if (direction == "top" || direction == "bottom") {
$element.css(spacingType + "-" + direction, verticalSpace);
}
else if (direction == "right" || direction == "left") {
$element.css(spacingType + "-" + direction, lateralSpace);
}
});
};
var renderInit = function() {
$(document).ready(function() {
renderStyle("padding");
});
$(window).on("resize", function() {
renderStyle("padding");
});
}
renderInit();
EXAMPLE - link
Although I completely disagree with this approach to horizontally centring an element, hopefully this will help you on your way.
Fiddle: https://jsfiddle.net/0uxx2ujg/
JavaScript:
var outer = $('.outer'), inner = $('.inner');
function centreThatDiv(){
var requiredPadding = outer.outerWidth() / 2 - (inner.outerWidth() / 2);
console.log(requiredPadding);
outer.css('padding', '0 ' + requiredPadding + 'px').css('width','auto');
}
$(document).ready(function(){
// fire on page load
centreThatDiv();
});
$(window).resize(function(){
// fire on window resize
centreThatDiv();
});
HTML:
<div class="outer">
<div class="inner">Centre me!</div>
</div>
CSS:
.outer{ width:80%; height:300px; margin:10%; background: tomato; }
.inner{ width:60px; height:60px; background:white; }
Furthered on from why I disagree with this approach - JavaScript shouldn't be used to lay things out. Sure - it can be, if it really needs to be used; but for something as simple as centring an element, it's not necessary at all. Browsers handle resizing CSS elements themselves, so by using JS you introduce more headaches for yourself further down the line.
Here's a couple of examples of how you can achieve this in CSS only:
text-align:center & display:inline-block https://jsfiddle.net/0uxx2ujg/1/
position:absolute & left:50% https://jsfiddle.net/0uxx2ujg/2/ (this can be used for vertically centring too which is trickier than horizontal)
You can create the new CSS class to adjust for elements size on $window.onresize = function () {
//add your code
};
The closest solution I found is Show div on scrollDown after 800px.
I'm learning HTML, CSS, and JS, and I decided to try to make a digital flipbook: a simple animation that would play (ie, load frame after frame) on the user's scroll.
I figured I would add all the images to the HTML and then use CSS to "stack them" in the same position, then use JS or jQuery to fade one into the next at different points in the scroll (ie, increasing pixel distances from the top of the page).
Unfortunately, I can't produce the behavior I'm looking for.
HTML (just all the frames of the animation):
<img class="frame" id="frame0" src="images/hand.jpg">
<img class="frame" id="frame1" src="images/frame_0_delay-0.13s.gif">
CSS:
body {
height: 10000px;
}
.frame {
display: block;
position: fixed;
top: 0px;
z-index: 1;
transition: all 1s;
}
#hand0 {
padding: 55px 155px 55px 155px;
background-color: white;
}
.frameHide {
opacity: 0;
left: -100%;
}
.frameShow {
opacity: 1;
left: 0;
}
JS:
frame0 = document.getElementById("frame0");
var myScrollFunc = function() {
var y = window.scrollY;
if (y >= 800) {
frame0.className = "frameShow"
} else {
frame0.className = "frameHide"
}
};
window.addEventListener("scroll", myScrollFunc);
};
One of your bigger problems is that setting frame0.className = "frameShow" removes your initial class frame, which will remove a bunch of properties. To fix this, at least in a simple way, we can do frame0.className = "frame frameShow", etc. Another issue is that frame0 is rendered behind frame1, which could be fixed a variety of ways. ie. Putting frame0's <img> after frame1, or setting frame0's CSS to have a z-index:2;, and then setting frame0's class to class="frame frameHide" so it doesn't show up to begin with. I also removed the margin and padding from the body using CSS, as it disturbs the location of the images. I have made your code work the way I understand you wanted it to, here is a JSFiddle.
It depends on your case, for example, in this jsFiddle 1 I'm showing the next (or previous) frame depending on the value of the vertical scroll full window.
So for my case the code is:
var jQ = $.noConflict(),
frames = jQ('.frame'),
win = jQ(window),
// this is very important to be calculated correctly in order to get it work right
// the idea here is to calculate the available amount of scrolling space until the
// scrollbar hits the bottom of the window, and then divide it by number of frames
steps = Math.floor((jQ(document).height() - win.height()) / frames.length),
// start the index by 1 since the first frame is already shown
index = 1;
win.on('scroll', function() {
// on scroll, if the scroll value equal or more than a certain number, fade the
// corresponding frame in, then increase index by one.
if (win.scrollTop() >= index * steps) {
jQ(frames[index]).animate({'opacity': 1}, 50);
index++;
} else {
// else if it's less, hide the relative frame then decrease the index by one
// thus it will work whether the user scrolls up or down
jQ(frames[index]).animate({'opacity': 0}, 50);
index--;
}
});
Update:
Considering another scenario, where we have the frames inside a scroll-able div, then we wrap the .frame images within another div .inner.
jsFiddle 2
var jQ = $.noConflict(),
cont = jQ('#frames-container'),
inner = jQ('#inner-div'),
frames = jQ('.frame'),
frameHeight = jQ('#frame1').height(),
frameWidth = jQ('#frame1').width() + 20, // we add 20px because of the horizontal scroll
index = 0;
// set the height of the outer container div to be same as 1 frame height
// and the inner div height to be the sum of all frames height, also we
// add some pixels just for safety, 20px here
cont.css({'height': frameHeight, 'width': frameWidth});
inner.css({'height': frameHeight * frames.length + 20});
cont.on('scroll', function() {
var space = index * frameHeight;
if (cont.scrollTop() >= space) {
jQ(frames[index]).animate({'opacity': 1}, 0);
index++;
} else {
jQ(frames[index]).animate({'opacity': 0}, 0);
index--;
}
});
** Please Note that in both cases all frames must have same height.
I tried do make a Webpage like this(Fullscreen):
And the color of each of them should change randomly every second.
This is the JS that I have:
<script>
var tid = setInterval(chngColor, 1000);
function chngColor()
{
document.body.style.backgroundColor = '#'+(Math.random()*0xFFFFFF<<0).toString(16);
}
</script>
Now I tried to make a fullscreen div(as big as the body) and place other divs inside the first div with the margin:10px on each side. I cant figure out the style of the divs.
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
background-color="myFunction();";
z-index: 10;
margin-bottom:10px;
margin-top:10px;
margin-left:10px;
margin-right:10px;
This doesn't work?
You can't use a JavaScript function inside CSS code. What you should do instead is to use your chngColor function on every element that you want to change it's background.
Changing you function to take an dom element as a parameter
function chngColor(el)
{
el.style.backgroundColor = '#' + (Math.random()*0xFFFFFF<<0).toString(16);
}
And supposing your elements have a common specific class, let's say "foo", you can iterate all of them and use the function for every one of them:
var foos = document.getElementsByClassName('foo');
for(var i=0; i <foos.length;i++){
chngColor(foos[i]);
}
Put that in a function so you can use in setInterval and you are good to go.
I've been trying to solve this problem for a week now and it seems basic, so maybe I'm missing something.
I want to have a div centered on the screen (or its container), and then insert a second div to the right of it, so that afterwards the two of them are centered (space on each side is equal).
Inserting the second div is not a problem, but I need the first block to slide over to where its going to be after the new block is inserted.
http://jsfiddle.net/rdbLbnw1/
.container {
width:100%;
text-align:center;
}
.inside {
border:solid 1px black;
width:100px;
height:100px;
display:inline-block;
}
$(document).ready(function() {
$("#add").click(function() {
$(".container").append("<div class='inside'></div>");
});
});
<div class="container">
<div class="inside"></div>
</div>
<input id="add" type="button" value="add"/>
Do I need to explicitly calculate where the original box is going to end up and then animate that, or is there a better way to do it?
I like your question so decide to write this:
$(document).ready(function() {
var isInAction = false;
var intNumOfBoxes = 1;
var intMargin = 10;
$containerWidth = $(".container").width();
$insideWidth = $(".inside").width();
$(".inside").css('margin-left',($containerWidth - $insideWidth - intMargin)/2 + 'px');
$("#add").click(function() {
if (!isInAction){
isInAction = true;
intNumOfBoxes +=1;
$(".current").removeClass("current");
$(".container").append("<div class='inside current'></div>");
$('.inside').animate({
'margin-left': '-=' + ($insideWidth + intMargin)/2 + 'px'
}, 300, function () {
$(".current").css('margin-left',($containerWidth + ((intNumOfBoxes - 2) * ($insideWidth + intMargin)))/2 + 'px');
$(".current").fadeIn(500,function(){
isInAction = false;
});
});
}
});
});
Also add this class in CSS:
.current {
display:none;
}
You don't need to change variables in JS code except intMargin. you can change this var to set margin between boxes.
Note: This code works fine on older browsers too and not need to support CSS3 features like transition.
Update: Some bugs like repeated clicks fixed.
Check JSFiddle Demo
First, we can animate only things that have explicit numerical values such as width, left or margin. We can't animate things like alignment (which actually use the same margin property but implicitly, never mind). So if we know width of inserted div let's just add it to our container.
1) Let's centre container itself and add transition to it
.container {
width: 102px; /* set explicit width; 102 - because of borders */
margin: auto; /* set margin to 'auto' - that will centre the div */
transition: width 0.5s;
}
2) Then increase the width when add div
$(".container").width($(".container").width() + 102);
3) But wait! If we add div to too narrow container it will be added to bottom not to right. So we need another container set to appropriate width before.
See final example on JSFiddle.
BTW, remove all line breaks and tabs from your code when you use inline-block, because it will cause spaces between your blocks.