I have this code that after a while starts to slow down, I tried everything to reduce the script and increase performance but nothing works.
Here's a snippet with the code:
var rotated = false;
function load() {
setInterval(rain, 100);
function rain() {
var deg = rotated ? 0 : 20;
var variable = screen.width + screen.width;
var side = Math.floor((Math.random() * variable));
var pos = -20;
var element = document.createElement('div');
var position = Math.random() < 0.5 ? 1 : 3;
element.style.webkitTransform = 'rotate(' + deg + 'deg)';
element.style.mozTransform = 'rotate(' + deg + 'deg)';
element.style.msTransform = 'rotate(' + deg + 'deg)';
element.style.oTransform = 'rotate(' + deg + 'deg)';
element.style.transform = 'rotate(' + deg + 'deg)';
element.style.position = "absolute";
element.style.width = "1px";
element.style.height = "10px";
element.style.top = "-20px";
element.style.zIndex = position;
document.getElementById('body').appendChild(element);
if (position == 3) {
element.style.backgroundColor = "#0018FF";
}
if (position == 1) {
element.style.backgroundColor = "#8590FF";
}
element.style.left = side + 'px';
setInterval(frame, 1);
setInterval(frame2, 2);
setInterval(frameChecker, 100);
function frame() {
pos++;
element.style.top = pos + 'px';
}
function frame2() {
side--;
element.style.left = side + "px";
}
function frameChecker() {
element.id = pos;
if (element.id > screen.height + 500) {
element.remove();
}
}
}
}
body {
font-family: "Times New Roman", Times, serif;
}
html,
body {
padding: 0px;
margin: 0px;
width: 100%;
height: 100%;
overflow: hidden;
background-color: black
}
.center {
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: auto;
position: absolute;
text-align: center;
z-index: 2;
}
.center span {
position: relative;
font-size: 500%;
text-align: center;
top: 45%;
transform: translateY(-50%);
color: white
}
<!DOCTYPE html>
<html>
<head>
<!--CSS and SCRIPT here-->
<title>GOT 404 ERROR</title>
</head>
<body onload="load()" id="body">
<div style="width:100%; height:100%; position: relative;">
<div class="center"><span>ERROR 404</span></div>
</div>
</body>
</html>
The whole JavaScript code is to make it rain, I think the problem is in somewhere in the variables but when I set as global only one dot of "rain" shows up (by global i mean outside of any function)
so i done it:
every 100 miliseconds is added a dot, this dot start 3 functions/dot to move and check its location, so i just added a "interval cleaner",(the frameChecker() if settement here is the code:
<!DOCTYPE html>
<html>
<head>
<style>
body{
font-family: "Times New Roman", Times, serif;}
html, body{
padding: 0px;
margin: 0px;
width: 100%;
height: 100%;
overflow: hidden;
background-color: black}
.center {
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: auto;
position: absolute;
text-align: center;
z-index: 2;}
.center span{
position: relative;
font-size: 500%;
text-align: center;
top: 45%;
transform: translateY(-50%);
color: white}
</style>
<script type="text/javascript">
var rotated = false;
function load(){
setInterval(rain, 200);
function rain(){
var deg = rotated ? 0 : 20;
var variable = screen.width+screen.width;
var side = Math.floor((Math.random() * variable));
var pos = -20;
var element = document.createElement('div');
var position = Math.random() < 0.5 ? 1 : 3;
element.style.webkitTransform = 'rotate('+deg+'deg)';
element.style.mozTransform = 'rotate('+deg+'deg)';
element.style.msTransform = 'rotate('+deg+'deg)';
element.style.oTransform = 'rotate('+deg+'deg)';
element.style.transform = 'rotate('+deg+'deg)';
element.style.position = "absolute";
element.style.width = "1px";
element.style.height = "10px";
element.style.top = "-20px";
element.style.zIndex = position;
document.getElementById('body').appendChild(element);
if (position == 3){element.style.backgroundColor = "#0018FF";}
if (position == 1){element.style.backgroundColor = "#8590FF";}
element.style.left = side + 'px';
var framee = setInterval(frame, 1);
var framee2 = setInterval(frame2, 2);
var frameCheckerr = setInterval(frameChecker, 100);
function frame() {
pos++;
element.style.top = pos + 'px';}
function frame2() {
side--;
element.style.left = side + "px";}
function frameChecker(){
element.id = pos;
if (element.id > screen.height+20){element.remove();clearInterval(framee);clearInterval(framee2);clearInterval(frameCheckerr);}}}}
</script>
<title>GOT 404 ERROR</title>
</head>
<body onload="load()" id="body">
<div style="width:100%; height:100%; position: relative;">
<div class="center"><span>ERROR 404</span></div>
</div>
</body>
</html>
it was petty tuff to fund out, thanks to #Pointy for saying about the functions being allways on after called with setInterval() and also the first timer (rain()) can be used with timer set was 500 for better performace
Every time your rain() function runs because of its interval timer (every 100 milliseconds), it starts three new interval timers with even faster intervals. After a minute or so, therefore, you'll have hundreds of interval timers running. That's what is making everything slow down.
You might consider setTimeout() for those nested functions. The setTimeout function calls it's callback only once after a single delay.
Related
I made a basic javascript code so you can poke divs with you mouse.
Unfortunately I have to add them manualy but i wanna add so much of them with a pattern.
First i decided to use grid but i guessed it wont work because divs (which i call them squares from now on :D) can change their position.
So I was about to ask, how can I create a javascript code that i can spawn them until they fill the screen.
Also i have another question which is realted to this project, How can i make these squares just decors. I mean by decors i dont want them to effect the webside at all, when the blocks goes out of the screen the body starts to expend, is there any way to avoid that?
(Also it will be better if you make the snippet full screen!)
EDIT: I put the refresh-button on the top left on the main div so you can draw squares by clicking it!
let mouse = {
speedX: 0,
speedY: 0,
posX: 0,
posY: 0,
movement: 0,
speed: 0
}
//on mousemove update the moouse object
document.onmousemove = function(e) {
mouse.speedX = e.movementX;
mouse.speedY = e.movementY
mouse.posX = e.pageX;
mouse.posY = e.pageY;
}
//refresh the mouse movement and speed every 100ms
setInterval(() => {
mouse.movement =
Math.sqrt(Math.pow(mouse.speedX, 2) + Math.pow(mouse.speedY, 2));
mouse.speed = mouse.movement * 10;
}, 100);
//add a square div in parent element
function addSquare(parent) {
const newDiv = document.createElement("div");
newDiv.classList.add("square")
parent.appendChild(newDiv)
return newDiv;
}
//add squares in the parent element filling the available size
//gap is the space between squares, size is the edge of the square
//if skipbefore is false it will begin to draw the next square also if it won't fit entirely
function addSquares(parent, gap, size, skipbefore = true) {
const squares = [];
let rect = parent.getBoundingClientRect();
const availableWidth = rect.width;
const availableHeight = rect.height;
let top = 100;
while (top < availableHeight) {
let left = 0;
if (skipbefore && top + size > availableHeight)
break;
while (left < availableWidth) {
if (skipbefore && left + size > availableWidth)
break;
const square = addSquare(parent);
square.style.left = `${left}px`;
square.style.top = `${top}px`;
squares.push(square);
left += gap + size;
}
top += gap + size;
}
return squares;
}
//onmoveover event handler
const squareOnMouseOver = (event) => {
const element = event.target;
const y = mouse.speedY;
const x = mouse.speedX;
const rad = Math.atan2(y, x);
yAxis = mouse.movement * Math.sin(rad);
xAxis = mouse.movement * Math.cos(rad);
const rect = element.getBoundingClientRect();
const left = Math.round(rect.x + xAxis * 3);
const top = Math.round(rect.y + yAxis * 3);
element.style.left = `${left}px`;
element.style.top = `${top}px`;
const o = rad * (180 / Math.PI);
element.style.transform = `rotate(${o}deg)`;
}
//resets the .target parent and redraw the squares inside it
function drawSquares() {
const parent = document.querySelector('.target');
parent.innerHTML = '';
const squares = addSquares(parent, 25, 75);
const colors = [
'lightcoral',
'bisque',
'aquamarine',
'cadetblue',
'greenyellow',
'yellowgreen'
];
squares.forEach(square => {
const iColor = Math.floor(Math.random() * (colors.length - 1));
const color = colors[iColor];
square.style.background = color;
square.addEventListener('mouseover', squareOnMouseOver);
});
}
body{
margin: 0;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: rgb(242, 239, 231);
color: rgb(10, 10, 9);
}
.square{
background-color: lightcoral;
width: 75px;
height: 75px;
position: absolute;
transform: rotate(0deg);
transition: all ease-out 0.5s;
}
.background {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.container .row .col > * {
display: inline-block;
}
.target {
display: block;
width: 100%;
height: 100%;
}
#draw {
font-size: 20px;
padding: .2em 1em;
cursor: pointer;
}
.name{
font-size: 40px;
}
#main-container{
position: absolute;
padding: 35px 45px;
width: 950px;
height: 285px;
box-shadow: 0px 2px 5px 2px rgb(191, 188, 182);
}
.links{
display: flex;
justify-content: center;
align-items: center;
}
.icons{
width: 55px;
height: auto;
margin: 0px 25px;
padding: 10px;
border-radius: 5px;
transition: all ease-in 0.2s;
}
.icons:hover{
background-color: rgb(144, 144, 144);
}
.refresh{
position: absolute;
}
.refresh-button{
width: 25px;
height: auto;
}
.btn:hover{
background-color: rgb(144, 144, 144);
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="css.css">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="background">
<div class="target"></div>
<div class="container text-center" id="main-container">
<div class="">
<div class="refresh">
<button class="btn" id="draw" onclick="drawSquares()"><img class="refresh-button" src="SVG/arrow-clockwise.svg"></button>
</div>
<div class="name">Berk Efe Keskin</div>
<br>
<i>This website is working in progress right now...</i>
<br>
<i>Here is some useful links.</i>
<br>
<br>
<div class="links">
<img class="icons" src="SVG/github.svg">
<img class="icons" src="SVG/linkedin.svg">
<img class="icons" src="SVG/stack-overflow.svg">
</div>
</div>
</div>
</div>
<script type="text/javascript" src = "javascript.js"></script>
</body>
</html>
You may have a function that given a container will be filled with how many squares can fit inside as long as there is still avaiable width and available height in the target.
Here in this demo I better factored your code and added a main function called drawSquares that gets called when the button reDRAW is clicked. Each time the squares are redrawn, the target content is emptied.
I'm using a button to trigger the box drawing because the available space depends on the size of the area when the action is fired. For example you can expand the snippet and decide to redraw the squares to have the whole new area filled again.
You may decide to call the action on document ready or when the window gets resized.
let mouse = {
speedX: 0,
speedY: 0,
posX: 0,
posY: 0,
movement: 0,
speed: 0
}
//on mousemove update the moouse object
document.onmousemove = function(e) {
mouse.speedX = e.movementX;
mouse.speedY = e.movementY
mouse.posX = e.pageX;
mouse.posY = e.pageY;
}
//refresh the mouse movement and speed every 100ms
setInterval(() => {
mouse.movement =
Math.sqrt(Math.pow(mouse.speedX, 2) + Math.pow(mouse.speedY, 2));
mouse.speed = mouse.movement * 10;
}, 100);
//add a square div in parent element
function addSquare(parent) {
const newDiv = document.createElement("div");
newDiv.classList.add("square")
parent.appendChild(newDiv)
return newDiv;
}
//add squares in the parent element filling the available size
//gap is the space between squares, size is the edge of the square
//if skipbefore is false it will begin to draw the next square also if it won't fit entirely
function addSquares(parent, gap, size, skipbefore = true) {
const squares = [];
let rect = parent.getBoundingClientRect();
const availableWidth = rect.width;
const availableHeight = rect.height;
let top = 100;
while (top < availableHeight) {
let left = 0;
if (skipbefore && top + size > availableHeight)
break;
while (left < availableWidth) {
if (skipbefore && left + size > availableWidth)
break;
const square = addSquare(parent);
square.style.left = `${left}px`;
square.style.top = `${top}px`;
squares.push(square);
left += gap + size;
}
top += gap + size;
}
return squares;
}
//onmoveover event handler
const squareOnMouseOver = (event) => {
const element = event.target;
const y = mouse.speedY;
const x = mouse.speedX;
const rad = Math.atan2(y, x);
yAxis = mouse.movement * Math.sin(rad);
xAxis = mouse.movement * Math.cos(rad);
const rect = element.getBoundingClientRect();
const left = Math.round(rect.x + xAxis * 3);
const top = Math.round(rect.y + yAxis * 3);
element.style.left = `${left}px`;
element.style.top = `${top}px`;
const o = rad * (180 / Math.PI);
element.style.transform = `rotate(${o}deg)`;
}
//resets the .target parent and redraw the squares inside it
function drawSquares() {
const parent = document.querySelector('.target');
parent.innerHTML = '';
const squares = addSquares(parent, 25, 75);
const colors = [
'lightcoral',
'bisque',
'aquamarine',
'cadetblue',
'greenyellow',
'yellowgreen'
];
squares.forEach(square => {
const iColor = Math.floor(Math.random() * (colors.length - 1));
const color = colors[iColor];
square.style.background = color;
square.addEventListener('mouseover', squareOnMouseOver);
});
}
body {
margin: 0;
width: 100vw;
height: 100vh;
display: flex;
}
.square {
background-color: lightcoral;
width: 75px;
height: 75px;
position: absolute;
transform: rotate(0deg);
transition: all ease-out 0.5s;
}
#Header {
font-size: italic;
}
.background {
width: 100%;
height: 100%;
}
.target {
position: relative;
display: block;
width: 100%;
height: 100%;
z-index: -1;
}
#draw {
font-size: 20px;
padding: .2em 1em;
cursor: pointer;
}
.container .row .col > * {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<link el="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<body>
<div class="background">
<span>Work in progress...</span>
<div class="container text-center">
<div class="row">
<div class="col">
<h1 id="Header">Work in progress...</h1>
<button id="draw" onclick="drawSquares()">reDRAW</button>
</div>
</div>
</div>
<div class="target"></div>
</div>
</body>
I have some Javascript drawing random square elements in the DOM. I have a gif (Image) I want these elements to appear over but they keep appearing underneath the gif. I tried defining z-depth and layout parameters to move these elements on top of the image here, but this produced no difference.
Any assistance in achieving the result (drawing elements onclick, on top of this gif) would be much appreciated.
I ultimately want to draw various other images over this image onclick, restricted to this particular area on top of the gif. If someone can suggest a solution to this as well I would be very much grateful!
(Code features some unused elements from my past attempts)
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="div.css" />
</head>
<body>
<div style="cursor: pointer;" id="boxy" >
<img src="bg.gif" alt="unfinished bingo card" onclick="create()" />
</div>
</div>
<script>
var body = document.getElementsByTagName("body")[0];
var canvas = document.createElement("canvas");
canvas.height = 1300;
canvas.width = 1300;
var context = canvas.getContext("2d");
body.appendChild(canvas);
var rects = [];
function create() {
// Opacity
context.globalAlpha = 0.7;
var color = '#' + Math.round(0xffffff * Math.random()).toString(16);
context.fillStyle = color;
//Each rectangle's size is (20 ~ 100, 20 ~ 100)
var coordx = Math.random() * canvas.width;
var coordy = Math.random() * canvas.width;
var width = Math.random() * 80 + 20;
var height = Math.random() * 80 + 20;
var rect = {
x: coordx,
y: coordy,
w: width,
h: height
}
var ok = true;
rects.forEach(function (item) {
if (isCollide(rect, item)) {
console.log("collide");
ok = false;
} else {
console.log("no collision");
}
})
if (ok) {
context.fillRect(coordx, coordy, width, height);
rects.push(rect);
} else {
console.log('rect dropped');
}
console.log(rects);
}
function isCollide(a, b) {
return !(
((a.y + a.h) < (b.y)) ||
(a.y > (b.y + b.h)) ||
((a.x + a.w) < b.x) ||
(a.x > (b.x + b.w))
);
}
document.getElementById('boxy').addEventListener('click', create);
document.getElementById('canvas').style.position = "relative";
document.getElementById('canvas').style.zIndex = "10";
</script>
</body>
</html>
#my-div {
width: 1300x;
height: 1300px;
z-index: -1;
}
a.fill-div {
display: block;
height: 100%;
width: 100%;
text-decoration: none;
}
#boxy {
display: inline-block;
height: 100%;
width: 100%;
text-decoration: none;
z-index: -1;
}
.canvas {
display: inline-block;
height: 100%;
width: 100%;
text-decoration: none;
z-index: 10;
}
You have to use position:absolute; to take it out of the html flow.
Now anything added after the image will be placed like the image was never there.
img {
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
z-index: -10;
}
div {
font-size: 2rem;
color: white;
}
<img src="https://images.unsplash.com/photo-1664273107076-b6d1fbfb973b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1171&q=80">
<div>Hello i am on top of the image
</div>
I was tasked with creating an animation in javascript using an existing code and altering to do two things. Switch modes, and go on until the person closes the program. The four modes are:
mode 0 - left to right
mode 1 - top to bottom
mode 2 - right to left
mode 3 - bottom to top
Switching from mode 0 - 1 is where the trouble starts. It's supposed to slide, but it jumps when I get there.
Below is my code as is.
<!DOCTYPE html>
<html>
<style>
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
</style>
<body>
<p><button onclick="myMove()">Click Me</button></p>
<div id ="container">
<div id ="animate"></div>
</div>
<script>
function myMove() {
var elem = document.getElementById("animate");
var pos = 350;
var id = setInterval(frame, 5);
}
function frame() {
if (pos == 0) {
pos++;
elem.style.bottom= pos + 'px';
} else {
pos--;
elem.style.left = pos + "px";
if (pos == 49.985) {
pos++;
elem.style.left = pos + "px";
}
}
I suggest you use two variables for both x and y, and replace posBottom with a variable for top style.
The issue before was that when pos was equal to 0 and thus triggered the if statement, it immediately incremented, causing it to instead trigger the else, and then decremented, going back to if, and so on. It jumped because the style.bottom = 0px was causing it to go straight down to the bottom.
function myMove() {
var elem = document.getElementById("animate");
var posLeft = 350;
var posTop = 0;
var id = setInterval(frame, 5);
function frame() {
if (posLeft == 0 && posTop != 350) {
stage=1;
posTop++;
elem.style.top= posTop + 'px';
} else if (posTop == 0) {
posLeft--;
elem.style.left = posLeft + "px";
} else if (posLeft != 350) {
posLeft++;
elem.style.left = posLeft + "px";
} else if (posTop != 0) {
posTop--;
elem.style.top= posTop + 'px';
}
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<p><button onclick="myMove()">Click Me</button></p>
<div id ="container">
<div id ="animate"></div>
</div>
I have this code above who switch between CSS transform-origin and scale to CSS width and scrollbars.
I need to make this switch because I am having a pinch to zoom for a DIV wrap I'm using in my website.
I'm using CSS translateX and translateY and Scale for a smoother pinch zoom, but after the zoom take place, I need to return back to width and scrollbar so the user can move across the layout.
I have here an example of how I'm doing the switch and there is a bit margin on top that I can't really set mind my on.
what is the correct way to do so?
var isOrigin = false;
var originX = 500;
var originY = 200;
var scale = 1.5;
var deltaX = 0;
var deltaY = 0;
var from_origin_to_scroll = function () {
if (isOrigin) { from_scroll_to_origin(); return; }
var wrap = $('.containter .wrap');
//reset scroll
const el = document.scrollingElement || document.documentElement;
$('.containter')[0].scrollLeft = 0;
el.scrollTop = 0;
wrap.css({
transformOrigin: originX + "px " + originY + "px",
transform: "translate3d(" + deltaX + "px," + deltaY + "px, 0) " +
"scale3d(" + scale + "," + scale + ", 1) ",
width: 100 + '%'
});
isOrigin = true;
$('.info').html('layout set by origin and scale');
}
var from_scroll_to_origin = function () {
var wrap = $('.containter .wrap');
wrap.css({
transformOrigin: originX + "px " + originY + "px",
transform: "translate3d(" + 0 + "px," + 0 + "px, 0) " +
"scale3d(" + 1 + "," + 1 + ", 1) ",
width: (100 * scale) + '%'
});
$('.containter')[0].scrollLeft = originX * (scale - 1);
const el = document.scrollingElement || document.documentElement;
el.scrollTop = originY * (scale - 1);
isOrigin = false;
$('.info').html('layout set by width and scroll');
}
body {
margin: 0;
padding: 0;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
width:100vw;
}
.top{
position: fixed;
width: 100%;
background-color: #333;
line-height: 40pt;
text-align: center;
color: #f1f1f1;
font-size: 20pt;
left: 0;
top: 0;
z-index: 10;
}
.top .info{
}
.header_content
{
background-color: #e1e1e1;
line-height:130pt;
}
.containter {
width:100%;
box-sizing: border-box;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
.containter .wrap {
display: flex;
flex-direction: column;
width: 100%;
}
.containter .wrap img {
width: 100%;
margin-top: 30pt;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="top">
<div class="info" onclick="from_origin_to_scroll()">click to switch</div>
</div>
<div class="header_content">
this is a header content - needs to be added to overall calculation
</div>
<div class="containter">
<div class="wrap">
<img src="https://thumb7.shutterstock.com/display_pic_with_logo/91858/594887747/stock-photo-dreams-of-travel-child-flying-on-a-suitcase-against-the-backdrop-of-sunset-594887747.jpg" />
<img src="https://thumb9.shutterstock.com/display_pic_with_logo/1020994/556702975/stock-photo-portrait-of-a-happy-and-proud-pregnant-woman-looking-at-her-belly-in-a-park-at-sunrise-with-a-warm-556702975.jpg" />
<img src="https://thumb7.shutterstock.com/display_pic_with_logo/234100/599187701/stock-photo-funny-little-girl-plays-super-hero-over-blue-sky-background-superhero-concept-599187701.jpg" />
<img src="https://thumb1.shutterstock.com/display_pic_with_logo/1316512/661476343/stock-photo-funny-pineapple-in-sunglasses-near-swimming-pool-661476343.jpg" />
<img src="https://thumb1.shutterstock.com/display_pic_with_logo/2114402/689953639/stock-photo-adult-son-hugging-his-old-father-against-cloudy-sky-with-sunshine-689953639.jpg" />
<img src="https://thumb7.shutterstock.com/display_pic_with_logo/172762/705978841/stock-photo-businessman-looking-to-the-future-for-new-business-opportunity-705978841.jpg" />
</div>
</div>
In your case the possible solution is to detect when the user is trying to zoom, and when just to scroll.
const $container = $(".container");
$container.on('touchstart', function (e) {
if (e.touches.length > 1){
//more than one finger is detected on the screen,
//change mode to transform-origin
from_scroll_to_origin()
}
});
$container.on('touchend', function (e) {
//change mode to scrollbars
from_origin_to_scroll()
});
So I'm trying to make simple animation. When you press somewhere inside blue container, a circle should be created in this place and then go up. After some research I found how to put JS values into keyframes, but it's changing values for every object not just for freshly created. If you run snipped and press somewhere high and then somewhere low you will see what I'm talking about.
I found some AWESOME solution with Raphael library, but I'm a beginner and I'm trying to make something like this in JS. Is it even possible? How?
var bubble = {
posX: 0,
posY: 0,
size: 0
};
var aquarium = document.getElementById("container");
var ss = document.styleSheets;
var keyframesRule = [];
function findAnimation(animName) { //function to find keyframes and insert replace values in them
for (var i = 0; i < ss.length; i++) {
for (var j = 0; j < ss[i].cssRules.length; j++) {
if (window.CSSRule.KEYFRAMES_RULE == ss[i].cssRules[j].type && ss[i].cssRules[j].name == animName) {
keyframesRule.push(ss[i].cssRules[j]);
}
}
}
return keyframesRule;
}
function changeAnimation (nameAnim) { //changing top value to cursor position when clicked
var keyframesArr = findAnimation(nameAnim);
for (var i = 0; i < keyframesArr.length; i++) {
keyframesArr[i].deleteRule("0%");
keyframesArr[i].appendRule("0% {top: " + bubble.posY + "px}");
}
}
function createBubble(e) {
"use strict";
bubble.posX = e.clientX;
bubble.posY = e.clientY;
bubble.size = Math.round(Math.random() * 100);
var bubbleCircle = document.createElement("div");
aquarium.appendChild(bubbleCircle);
bubbleCircle.className = "bubble";
var bubbleStyle = bubbleCircle.style;
bubbleStyle.width = bubble.size + "px";
bubbleStyle.height = bubble.size + "px";
bubbleStyle.borderRadius = (bubble.size / 2) + "px";
//bubbleStyle.top = bubble.posY - (bubble.size / 2) + "px";
bubbleStyle.left = bubble.posX - (bubble.size / 2) + "px";
changeAnimation("moveUp");
bubbleCircle.className += " animate";
}
aquarium.addEventListener("click", createBubble);
//console.log(bubble);
body {
background-color: red;
margin: 0;
padding: 0;
}
#container {
width: 100%;
height: 100%;
position: fixed;
top: 80px;
left: 0;
background-color: rgb(20,255,200);
}
#surface {
width: 100%;
height: 40px;
position: fixed;
top: 40px;
opacity: 0.5;
background-color: rgb(250,250,250);
}
.bubble {
position: fixed;
border: 1px solid blue;
}
.animate {
animation: moveUp 5s linear;//cubic-bezier(1, 0, 1, 1);
-webkit-animation: moveUp 5s linear;//cubic-bezier(1, 0, 1, 1);
}
#keyframes moveUp{
0% {
top: 400px;
}
100% {
top: 80px;
}
}
#-webkit-keyframes moveUp{
0% {
top: 400px;
}
100% {
top: 80px;
}
}
<body>
<div id="container">
</div>
<div id="surface">
</div>
</body>
Here is a possible solution. What I did:
Remove your functions changeAnimation () and findAnimation() - we don't need them
Update the keyframe to look like - only take care for the 100%
#keyframes moveUp { 100% {top: 80px;} }
Assign top of the new bubble with the clientY value
After 5 seconds set top of the bubble to the offset of the #container(80px) - exactly when animation is over to keep the position of the bubble, otherwise it will return to initial position
var bubble = {
posX: 0,
posY: 0,
size: 0
};
var aquarium = document.getElementById("container");
function createBubble(e) {
"use strict";
bubble.posX = e.clientX;
bubble.posY = e.clientY;
bubble.size = Math.round(Math.random() * 100);
var bubbleCircle = document.createElement("div");
aquarium.appendChild(bubbleCircle);
bubbleCircle.className = "bubble";
var bubbleStyle = bubbleCircle.style;
bubbleStyle.width = bubble.size + "px";
bubbleStyle.height = bubble.size + "px";
bubbleStyle.borderRadius = (bubble.size / 2) + "px";
bubbleStyle.top = bubble.posY - (bubble.size / 2) + "px";
bubbleStyle.left = bubble.posX - (bubble.size / 2) + "px";
bubbleCircle.className += " animate";
// The following code will take care to reset top to the top
// offset of #container which is 80px, otherwise circle will return to
// the position of which it was created
(function(style) {
setTimeout(function() {
style.top = '80px';
}, 5000);
})(bubbleStyle);
}
aquarium.addEventListener("click", createBubble);
body {
background-color: red;
margin: 0;
padding: 0;
}
#container {
width: 100%;
height: 100%;
position: fixed;
top: 80px;
left: 0;
background-color: rgb(20, 255, 200);
}
#surface {
width: 100%;
height: 40px;
position: fixed;
top: 40px;
opacity: 0.5;
background-color: rgb(250, 250, 250);
}
.bubble {
position: fixed;
border: 1px solid blue;
}
.animate {
animation: moveUp 5s linear;
/*cubic-bezier(1, 0, 1, 1);*/
-webkit-animation: moveUp 5s linear;
/*cubic-bezier(1, 0, 1, 1);*/
}
#keyframes moveUp {
100% {
top: 80px;
}
}
#-webkit-keyframes moveUp {
100% {
top: 80px;
}
}
<body>
<div id="container"></div>
<div id="surface"></div>
</body>
The problem about your code was that it is globally changing the #keyframes moveUp which is causing all the bubbles to move.
The problem with your code is that you're updating keyframes which are applied to all bubbles. I tried another way of doing it by using transition and changing the top position after the element was added to the DOM (otherwise it wouldn't be animated).
The main problem here is to wait the element to be added to the DOM. I tried using MutationObserver but it seems to be called before the element is actually added to the DOM (or at least rendered). So the only way I found is using a timeout which will simulate this waiting, although there must be a better one (because it may be called too early, causing the bubble to directly stick to the top), which I would be happy to hear about.
var bubble = {
posX: 0,
posY: 0,
size: 0
};
var aquarium = document.getElementById("container");
function createBubble(e) {
"use strict";
bubble.posX = e.clientX;
bubble.posY = e.clientY;
bubble.size = Math.round(Math.random() * 100);
var bubbleCircle = document.createElement("div");
aquarium.appendChild(bubbleCircle);
bubbleCircle.classList.add("bubble");
var bubbleStyle = bubbleCircle.style;
bubbleStyle.width = bubble.size + "px";
bubbleStyle.height = bubble.size + "px";
bubbleStyle.borderRadius = (bubble.size / 2) + "px";
bubbleStyle.top = bubble.posY - (bubble.size / 2) + "px";
bubbleStyle.left = bubble.posX - (bubble.size / 2) + "px";
setTimeout(function() {
bubbleCircle.classList.add("moveUp");
}, 50);
}
aquarium.addEventListener("click", createBubble);
body {
background-color: red;
margin: 0;
padding: 0;
}
#container {
width: 100%;
height: 100%;
position: fixed;
top: 80px;
left: 0;
background-color: rgb(20, 255, 200);
}
#surface {
width: 100%;
height: 40px;
position: fixed;
top: 40px;
opacity: 0.5;
background-color: rgb(250, 250, 250);
}
.bubble {
position: fixed;
border: 1px solid blue;
transition: 5s;
}
.moveUp {
top: 80px !important;
}
<body>
<div id="container">
</div>
<div id="surface">
</div>
</body>
Also, I used the classList object instead of className += ... because it is more reliable.