I want to make an event where .gridss change colors with mouseover event. Problem is gridss comes out as not definied,and if i try to move the mouseover event into the the gridss function it also does not work. So how can I successfully refer to .gridds?
My question is pretty simple yet i cant seem to get it right,so thanks in advance.
const container = document.querySelector('#container');
$(document).ready(function() {
for(var x = 0; x < 16; x++) {
for(var y = 0; y < 16; y++) {
let gridss = $("<div class='gridss'></div>");
gridss.appendTo('#container');
}
}
});
gridss.addEventListener("mouseover", function( event ){
event.target.style.color = "purple";
setTimeout(function(){
event.target.style.color = "";
}, 10);
}, false);
Use jQuery for events if you are using jQuery. I assume that you are not aware of mouseout or mouseleave because it looks like you are using setTimeout() to trigger a delay of text color reverting back to original color. I used mouseenter and mouseleave which are similar to mouseover and mouseout events.
You had an error which that gridss wasn't defined. The reason why moving in and out of functions didn't work is because you defined gridss with let.
let is limited scope to that of the block
var scope is the function which works as long as you have gridss in the function.
Demo
const container = document.querySelector('#container');
$(document).ready(function() {
for (let y = 0; y < 32; y++) {
var gridss = $("<div class='gridss'>TEST</div>");
gridss.appendTo('#container');
}
$('.gridss').on('mouseenter mouseleave', function(e) {
if (e.type === 'mouseenter') {
this.style.color = "purple";
} else {
this.style.color = "white";
}
});
});
#container {
border: 5px solid blue
}
.gridss {
border: 3px solid red;
height: 20px;
margin: 10px 5px;
text-align: center;
background: cyan;
font-weight: 900;
color: white;
transition: color .5s ease
}
<div id='container'></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Related
Im trying to create a 2 rows 3 columns puzzle using CSS and JavaScript. The idea is that the pieces of the puzzle will be all black cut in different shapes. The users has to drag the pieces to board to complete it.I wrote a javascript that creates the board and pieces. Made them draggable too but unable to proceed from here. Need help in changing the shape of pieces from square to other shapes.
var rows = 5;
var columns = 5;
var currTile;
var otherTile;
var turns = 0;
window.onload = function() {
//initialize the 5x5 board
for (let r = 0; r < rows; r++) {
for (let c = 0; c < columns; c++) {
//<img>
let tile = document.createElement("img");
tile.src = "blank.png";
//DRAG FUNCTIONALITY
tile.addEventListener("dragstart", dragStart); //click on image to drag
tile.addEventListener("dragover", dragOver); //drag an image
tile.addEventListener("dragenter", dragEnter); //dragging an image into another one
tile.addEventListener("dragleave", dragLeave); //dragging an image away from another one
tile.addEventListener("drop", dragDrop); //drop an image onto another one
tile.addEventListener("dragend", dragEnd); //after you completed dragDrop
document.getElementById("board").append(tile);
}
}
//pieces
let pieces = [];
for (let i = 1; i <= rows * columns; i++) {
pieces.push(i.toString()); //put "1" to "25" into the array (puzzle images names)
}
pieces.reverse();
for (let i = 0; i < pieces.length; i++) {
let j = Math.floor(Math.random() * pieces.length);
//swap
let tmp = pieces[i];
pieces[i] = pieces[j];
pieces[j] = tmp;
}
for (let i = 0; i < pieces.length; i++) {
let tile = document.createElement("img");
tile.src = "blank2.png";
//DRAG FUNCTIONALITY
tile.addEventListener("dragstart", dragStart); //click on image to drag
tile.addEventListener("dragover", dragOver); //drag an image
tile.addEventListener("dragenter", dragEnter); //dragging an image into another one
tile.addEventListener("dragleave", dragLeave); //dragging an image away from another one
tile.addEventListener("drop", dragDrop); //drop an image onto another one
tile.addEventListener("dragend", dragEnd); //after you completed dragDrop
document.getElementById("pieces").append(tile);
}
}
//DRAG TILES
function dragStart() {
currTile = this; //this refers to image that was clicked on for dragging
}
function dragOver(e) {
e.preventDefault();
}
function dragEnter(e) {
e.preventDefault();
}
function dragLeave() {
}
function dragDrop() {
otherTile = this; //this refers to image that is being dropped on
}
function dragEnd() {
if (currTile.src.includes("blank")) {
return;
}
let currImg = currTile.src;
let otherImg = otherTile.src;
currTile.src = otherImg;
otherTile.src = currImg;
turns += 1;
document.getElementById("turns").innerText = turns;
}
body {
font-family: Arial, Helvetica, sans-serif;
text-align: center;
}
#board {
width: 400px;
height: 400px;
border: 2px solid purple;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
}
#board img {
width: 79px;
height: 79px;
border: 0.5px solid lightblue;
}
#pieces {
width: 1040px;
height: 160px;
border: 2px solid purple;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
}
#pieces img {
width: 79px;
height: 79px;
border: 0.5px solid lightblue;
}
<body>
<br>
<div id="board"></div>
<div id="pieces">
</div>
</body>
now, you can add event lister to the puzzle to handle dragover event with preventDefault() method to allow the drop to occur.
Then, in the event handler, you can retrieve the ID of the puzzle piece being dropped using getdata() method of the datatransfer object with following code:
boardElement.addEventListener("drop", e => {
// Get the ID of the puzzle piece being dropped
const id = e.dataTransfer.getData("text/plain");
// Find the puzzle piece
const piece = puzzlePieces.find(piece => piece.id === id);
// Update the color of the puzzle piece
piece.color = "black";
// Render the puzzle board
render();
});
Then, you can add event dragenter in drag-over class in boardelemennt and dragleave to release the drag.
how does one get the cubes made in the grid to turn black with mouse running over? any help would be appreciated.
function Grid(z) {
for (y=0; y < z; y++) {
for (x=0; x < z; x++) {
size = 700 / z;
var div = document.querySelector('#container');
var block = document.createElement('div');
block.style.height = size + 'px';
block.style.width = size + 'px';
block.classList.add('cube');
div.appendChild(block);
}
}
}
function changeBlockColor() {
Grid(16);
var s = document.querySelector('.cube');
s.addEventListener('onmouseover', function(){
s.setAttribute('style', 'background: black');
});
}
changeBlockColor();
I would use CSS to achieve this effect.
.cube {
background-color:red;
}
.cube:hover {
background-color: black;
}
The following is for if you want the cubes to stay black after you finished hovering over them (and then hovered out).
First, your s = document.querySelector('.cube'); will make s only point to the first element with class cube. To solve that, make s an array of all elements of class cube, by using s = document.querySelectorAll('.cube'); instead.
Next, you need to loop through the array s and add the event listener to all its elements:
for(var i = 0; i < s.length; i++) {
s[i].addEventListener('mouseover', function(){
this.setAttribute('style', 'background: black');
});
}
Notice the use of this inside the handler. Inside handler code, this refers to the object that triggered the event (the cube moused over in your case).
No need to have hundred of mouseover Event Listener. Just one is enough
var
divContainer = document.getElementById('container'),
CubeClass = 'cube';
function Grid(z)
{
var sizePx = Math.floor(700 / z) + 'px';
for (let y = 0; y < z; y++)
{
for (let x = 0; x < z; x++)
{
let block = document.createElement('div');
block.style.height = sizePx;
block.style.width = sizePx;
block.className = CubeClass;
divContainer.appendChild(block);
};
};
}
divContainer.onmouseover = function(e)
{
if (!e.target.classList.contains( CubeClass )) return;
e.target.setAttribute('style', 'background: black');
}
divContainer.onmouseout = function(e) // if you need it...
{
if (!e.target.classList.contains( CubeClass )) return;
e.target.removeAttribute('style');
}
The event name you want is mouseover, not onmouseover
Also, querySelector will only find the first matching element, so you need to use querySelectorAll or getElementsByClassName instead
Finally, you need to iterate over all the elements you matched, which are returned in an Object, not an Array, so you need to use a for loop.
Solution
function createGrid(z) {
for (var y = 0; y < z; ++y) {
for (var x = 0; x < z; ++x) {
var size = 700 / z;
var div = document.getElementById('container');
var block = document.createElement('div');
block.style.height = size + 'px';
block.style.width = size + 'px';
block.classList.add('cube');
div.appendChild(block);
}
}
changeBlockColor()
}
function changeBlockColor(){
var cubes = document.querySelectorAll('.cube')
for (var i = 0; i < cubes.length; i++) {
cubes[i].addEventListener("mouseover", function(e) {
e.target.classList.add('active')
})
}
}
createGrid(16);
#container {
display: flex;
flex-wrap: wrap;
}
.cube {
background-color: red;
}
.active {
background-color: black;
}
<div id="container"></div>
Implementation Details
Naming is all preference in JS, but traditionally, names that start with a capital letter are for a class, so I renamed you function to createGrid
At the end of createGrid I call changeBlockColor, rather than call createGrid from inside changeBlockColor, logically it make more sense.
I created a CSS class called active to handle changing the color, as using setAttribute('style') was erasing the height and width styles you applied inside you Grid function.
Feedback
You use querySelector exclusively, you should get to know getElementById as well.
You use var a few times, but don't declare y, x, or size
You can define y and x in your for loop with for(var y=0 and for(var x=0
CSS Solution
Assuming you want the color to revert on mouseout, you can achieve this same effect with CSS using .cube:hover
.cube {
display: inline-block;
width: 50px;
height: 50px;
background-color: red;
}
.cube:hover {
background-color: black;
}
<div class="cube"></div>
<div class="cube"></div>
<div class="cube"></div>
<div class="cube"></div>
<div class="cube"></div>
Performance
A side note about using querySelector('#container') vs getElementById('container'). The first has to traverse the entire DOM looking for the selector, the latter can just go to the internal list of ids and return the reference.
https://jsperf.com/so53824751
Documentation
https://developer.mozilla.org/en-US/docs/Web/Events/mouseover
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById
Ok so I have a div with an animation:
var x = true;
function dynamicTaskbar(thumb) {
function anim1() {
thumb.style.backgroundColor = "green";
}
function anim2() {
thumb.style.backgroundColor = "blue";
}
if (x === false) {
thumb.style.backgroundColor = "red";
thumb.removeEventListener("mouseover", anim1);
thumb.removeEventListener("mouseleave", anim2);
x = true;
} else {
thumb.style.backgroundColor = "blue";
thumb.addEventListener("mouseover", anim1);
thumb.addEventListener("mouseleave", anim2);
x = false;
}
}
//Create window's thumbnail for taskbar
var thumbnail = document.createElement("div");
thumbnail.setAttribute("class", "thumbnail");
taskbar.append(thumbnail);
taskbar.style.width = taskbar.style.width + thumbnail.style.width + "px";
thumbnail.addEventListener("mousedown", function() {
dynamicTaskbar(thumbnail);
});
#taskbar {
background-color: red;
border: solid 1px black;
width: 50px;
height: 30px;
}
.thumbnail {
width: 50px;
height: 30px;
border: solid 1px black;
}
<div id="taskbar"></div>
By default, the div is red.
When it is clicked:
If x is true, it becomes false and the div turns blue. Two event listeners, mouseover (the div becomes green) and mouseleave (the div becomes red again) are added.
If x is false, it becomes true and the div turns red. But here is my problem: both event listeners (mouseover and mouseleave) are suppose to be removed, but it doesn't work. I searched over the Internet but found nothing that fixed my problem.
Any help?
The solution for this problem is extracting the anim1() and anim2() funtions from the dynamicTaskbar() function.
Since both functions are located inside the dynamicTaskbar() function they are created again and again with each execution of the function causing the instances to be different then the initial ones.
If for example in the first execution (1st click) of dynamicTaskbar() the "object id" of anim1() will be "1" and in the second execution it will be "2". Therefore when you're trying to remove the listener you're actually trying to remove it for a different object reference.
Take a look at the example:
var x = true;
function anim1(thumb) {
thumbnail.style.backgroundColor = "green";
}
function anim2(thumb) {
thumbnail.style.backgroundColor = "blue";
}
function dynamicTaskbar(thumb) {
if (x === false) {
thumbnail.style.backgroundColor = "red";
thumbnail.removeEventListener("mouseover", anim1);
thumbnail.removeEventListener("mouseleave", anim2);
x = true;
} else {
thumbnail.style.backgroundColor = "blue";
thumbnail.addEventListener("mouseover", anim1);
thumbnail.addEventListener("mouseleave", anim2);
x = false;
}
}
//Create window's thumbnail for taskbar
var thumbnail = document.createElement("div");
thumbnail.setAttribute("class", "thumbnail");
taskbar.append(thumbnail);
taskbar.style.width = taskbar.style.width + thumbnail.style.width + "px";
thumbnail.addEventListener("mousedown", function() {
dynamicTaskbar(thumbnail);
});
#taskbar {
background-color: red;
border: solid 1px black;
width: 50px;
height: 30px;
}
.thumbnail {
width: 50px;
height: 30px;
border: solid 1px black;
}
<div id="taskbar"></div>
Im trying to get the shapes to appear once after clicking. After 1.2 seconds it appears, then when clicked it disappears, then the whole process repeats. The problem is after a few clicks two shapes appear.
This is the link to the program.
https://jsfiddle.net/EyedFox/w98naLjx/2/
function show() {
var randomColor = colors[Math.floor(colors.length * Math.random())]; // Random color chosen
var randomX = Math.floor(Math.random() * 60); // random x axis margin
var randomY = Math.floor(Math.random() * 80); // random y axis margin
square = document.getElementById("square");
circle = document.getElementById("circle");
var shapeArray = [square, circle];
var randShape = shapeArray[Math.floor(shapeArray.length * Math.random())];
randShape.style.margin = randomX + "% " + randomY + "%";
randShape.style.backgroundColor = randomColor;
randShape.style.display = "block";
randShape.addEventListener("click", click);
function click() {
randShape.style.display = "none";
setTimeout(show, 1200);
}
}
setTimeout(show, 1200);
Your code keep adding click event listener to randShape, but it never cleans them those event. As a result, they keep being added and click (and thus show) will get executed several times per click. Try to add console.log('clicked on', randShape); at the beginning of your click function to see it. If by chance all the show execution selects the same shape, you'll see only this one on screen, but otherwise you'll get both.
Your click function should look like this:
function click() {
console.log('clicked on', randShape);
randShape.style.display = "none";
setTimeout(show, 1200);
randShape.removeEventListener('click', click); // cleaning after myself ;-)
}
(btw (function() { ... })() is not executed on load, but as soon as it is encountered by the javascript vm)
Here is a fiddle that fixes the issue.
Edited my response based on #autra response
I would probably completely clean the canvas before redrawing:
https://jsfiddle.net/c0L54uk3/
Essentially made a reset function like so:
function reset(){
square = document.getElementById("square").style.display = "none";
circle = document.getElementById("circle").style.display = "none";
randShape.removeEventListener("click", click);
}
And called it at the beginning of the click() function to reset the canvas like so:
function click() {
reset();
setTimeout(show, 1200);
}
Hope that helps.
Delegate Events Instead of Registering Them Individually
addEventListener() should be outside the callback function (i.e. show()). There's an event listener being added to the clicked tag but none of them are being removed. So when the 4th to 7th click occurs, the browser starts slowing down and that setTimeout is never 1.2 seconds because it will be cued to fire off which means it'll wait however long then wait 1.2 seconds. As the cue accumulates, the clicks will out race the setTimeout.
Register the parent tag, .container to listen to the click event event for all of its children tags. This pattern is called Event Delegation. In doing so, you can add the click event to an unlimited number of tags within .container using only one event listener instead of one for each shape.
The #triangle was never styled so it's an extra invisible div that floats around. In the demo I have styled the #triangle and added a .blank <div> outlined in gold (you can remove the .blank).
Demo
Fiddle
Details commented in demo
// Reference parent tag
var box = document.querySelector('.container');
function show() {
// Collect all .shape into a NodeList and convert into an array
var shapes = Array.from(document.querySelectorAll('.shape'));
var colors = ["yellow", "red", "green", "purple", "aqua", "chartreuse", "coral", "dodgerBlue", "deepPink"];
var rColor = colors[Math.floor(colors.length * Math.random())];
var rX = Math.floor(Math.random() * 60);
var rY = Math.floor(Math.random() * 80);
var rShape = shapes[Math.floor(shapes.length * Math.random())];
rShape.style.margin = rX + "% " + rY + "%";
// if #triangle change the border-bottom-color
if (rShape.id === 'triangle') {
rShape.style.borderBottomColor = rColor;
// otherwise change background-color
} else {
rShape.style.backgroundColor = rColor;
}
rShape.style.display = "block";
}
/*
Run show()
A setTimeout nor an IIFE is needed to initially run show()
Simply call it.
*/
show();
// Register box to click event...
box.addEventListener('click', function(e) {
// ...reference the clicked tag (i.e. .shape)...
var tgt = e.target;
// ...reference the registered parent tag...
var cur = e.currentTarget;
/*
...if the clicked tag IS NOT the registered parent tag...
*/
if (tgt !== cur) {
// ...then hide clicked element...
tgt.style.display = "none";
// ...and run show() in about 1.2 seconds
setTimeout(show(), 1200);
}
});
.container {
overflow: hidden;
height: 800px;
width: 80%;
background-color: rgb(0, 34, 85);
margin: 0 auto;
margin-top: 5em;
}
#square {
width: 80px;
height: 80px;
background-color: red;
margin-left: 0%;
margin-top: 10%;
display: none
}
#circle {
width: 100px;
height: 100px;
background: red;
border-radius: 50px;
display: none
}
#triangle {
width: 0;
height: 0;
border-left: 45px solid transparent;
border-right: 45px solid transparent;
border-bottom: 90px solid cyan;
display: none
}
.shape {
cursor: pointer
}
.blank {
outline: 10px solid gold
}
<div class="container">
<div id="square" class='shape'></div>
<div id="triangle" class='shape'></div>
<!--
This .blank represents what #triangle was before it
had any style.
-->
<div class='blank'></div>
<div id="circle" class='shape'></div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" />
here is my jsfiddle http://jsfiddle.net/9XdV7/, how to make when hover in - text scroll and infinite loop, out - back to start position? now it can't infinite loop scroll
for (var i = 0; i < $('.list').length; i++) {
var this_el = $('.list').eq(i);
var interval = null;
$(this_el).hover(function() {
var that = $(this);
var this_indent = 0;
interval = setInterval(function(){
this_indent--;
if (this_indent == -($(that).find('.text').width())) {
clearInterval(interval);
this_indent = 0;
// how to loop scroll
}
$(that).css('text-indent', this_indent);
},20);
}, function() {
clearInterval(interval);
$(this).css('text-indent', 0);
});
}
html & css
<div class="list"><div class="text">stringstringstringstring</div></div>
<div class="list"><div class="text">stringstringstring</div></div>
<div class="list"><div class="text">stringstringstringstring</div></div>
.list {
width: 100px;
overflow: hidden;
white-space:nowrap;
height: 15px;
background-color: red;
margin: 10px;
}
.text {
text-align: left;
background-color: purple;
display: inline;
}
Is this what you're looking for? Fiddle
I used mouseenter and mouseleave instead of hover.
$(elem).on("mouseenter",function() { ... });
I stored the identifier belonging to the element in its data: $(this).data("interval",interval);
I added
if(this_indent < -150) {
this_indent = 100;
}
to make the effect infinite. -150 is a value I got from the developer tools. 100 is pure testing.
This still wants some tweaking for determining the point at which to loop, but I think it's basically what you want:
$(function() {
for (var i = 0; i < $('.list').length; i++) {
var this_el = $('.list').eq(i);
var interval = null;
$(this_el).hover(function() {
var that = $(this);
var this_indent = 0;
interval = setInterval(function(){
this_indent--;
if (this_indent < that.width() * -1)
this_indent = that.width();
that.css('text-indent', this_indent);
},20);
}, function() {
clearInterval(interval);
$(this).css('text-indent', 0);
});
}
});
It's looping based on the width of the div, rather than the actual length of the text. If you want the text width, you could look here: Calculating text width