I've been working on a project using jQuery where i have a div element that says "click," and when you try to click on it, it moves to a random location within the window. The issue I'm having is that every once in a while the div will move only a little bit, leaving the cursor still inside of the div, allowing the user to click on the link.
I'm fairly new at javascript and I'm not too sure how I should go about doing something like this.
I was thinking I could do something like subtracting the new position from the old one and checking to see if they have a difference of less than 200px, and if they do, recalculating the numbers. If that isn't how you would do it, I'm completely open to other methods.
function setPosition() {
var randY = Math.floor(Math.random() * (window.innerHeight - 200));
var randX = Math.floor(Math.random() * (window.innerWidth - 200));
$('#square').animate({
top: randY + 'px',
left: randX + 'px'
}, 200);
}
$(document).ready(function() {
setPosition()
var tries = 0;
//tries is just to stop it after it reaches 1000.
//I'm planning to make some kind of page to congradulate you on wasting your time.
$('#square').mouseenter(function() {
if (tries < 1000) {
setPosition();
tries += 1;
console.log(tries)
}
});
});
#square {
background: orange;
height: 115px;
width: 150px;
position: relative;
text-align: center;
padding-top: 35px;
}
h3,
h3 * {
font-family: "Comic Sans MS", cursive, sans-serif;
font-size: 20px;
vertical-align: middle;
position: relative;
color: black;
text-decoration: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
<link rel=stylesheet type=text/css href=square.css>
<script src=jquery-1.11.3.min.js></script>
<script src=square.js></script>
</head>
<body>
<div id=square>
<h3><a href=''>Click</a></h3>
</div>
</body>
</html>
I'm thinking you might want to run your randomization logic until it finds a combination that is more than 200 pixels away from it's current location.
Off the top of my head, that'd be something like this:
function setPosition() {
var $square = $('#square');
var prevY = $square.offset().top;
var prevX = $square.offset().left;
var randY, randX;
do {
randY = Math.floor(Math.random() * (window.innerHeight - 200));
randX = Math.floor(Math.random() * (window.innerWidth - 200));
} while( Math.abs(randY - prevY) < 200 || Math.abs(randX - prevX) < 200 );
$square.animate({
top: randY + 'px',
left: randX + 'px'
}, 200);
}
Related
To preface, this is my first time using JQuery so i dont really know the syntax and i'm a beginning programmer in javascript and I'm new to stackoverflow too. So apologies in advance.
Also apologies in advance if this has been asked before. This should be simple, yet somehow i can't figure it out and it's a little hard to search for.
Problem: I need my animation to be moving within a div boundry that it's in.
i tried changing the window in var h and var w to the id of my container, it doesn't work:
var h = $(#ghosts).height() - 75;
var w = $(#ghosts).height() - 75;
// html
<div id="playBoxProperties">
<div id="playBox"> // play area
<div id="ghosts"> // container for all 8 ghosts
<div id='g1' class="boo"> // one of the moving ghosts
</div>
</div>
</div>
</div>
// to randomize the movement
function randomPos() {
var h = $(window).height() - 75; // i need to change the window, to something else.
var w = $(window).width() - 75; // But i dont know what.
var newH = Math.floor(Math.random() * h);
var newW = Math.floor(Math.random() * w);
return [newH, newW];
}
// animation to move around
function animateDiv(divID) {
var newPos = randomPos();
$(divID).animate({ top: newPos[0], left: newPos[1] }, 4000, function () {
animateDiv(divID);
});
I expect it to be inside the black box
Subtract the currently iterating ghost element size from the random coordinate relative to the parent wrapper:
pass the parent and the animating child like randomPos($chi, $par)
Use Strings as your selectors. $(#ghosts); should be $('#ghosts');
Create a small jQuery plugin if you want: $.fn.animateGhosts. Use it like $ghosts.animateGhosts();
const rand = (min, max) => Math.random() * (max - min) + min;
const $ghostsWrapper = $('#ghosts');
const randomPos = ($chi, $par) => ({ // Randomize position
x: ~~(Math.random() * ($par.width() - $chi.width())),
y: ~~(Math.random() * ($par.height() - $chi.height()))
});
$.fn.animateGhosts = function() {
function anim() {
const pos = randomPos($(this), $ghostsWrapper);
$(this).stop().delay(rand(100, 500)).animate({
left: pos.x,
top: pos.y,
}, rand(1000, 4000), anim.bind(this));
}
return this.each(anim);
};
$('.boo').animateGhosts();
#ghosts {
position: relative;
height: 180px;
outline: 2px solid #000;
}
.boo {
position: absolute;
background: fuchsia;
width: 50px;
height: 50px;
}
<div id="ghosts">
<div class="boo">1</div>
<div class="boo">2</div>
<div class="boo">3</div>
<div class="boo">4</div>
<div class="boo">5</div>
<div class="boo">6</div>
</div>
<script src="//code.jquery.com/jquery-3.4.1.js"></script>
Better performance using CSS transition and translate
Here's an example that will use the power of CSS3 to move our elements in a hardware (GPU) accelerated fashion. Notice how, when slowing down, the elements are not zigzagging to the round pixel value (since jQuery animates top and left).
Instead we'll use transition for the CSS3 animation timing and translate(x, y) for the positions:
const rand = (min, max) => Math.random() * (max - min) + min;
const $ghostsWrapper = $('#ghosts');
const randomPos = ($chi, $par) => ({ // Randomize position
x: ~~(Math.random() * ($par.width() - $chi.width())),
y: ~~(Math.random() * ($par.height() - $chi.height()))
});
$.fn.animateGhosts = function() {
function anim() {
const pos = randomPos($(this), $ghostsWrapper);
$(this).css({
transition: `${rand(1, 4)}s ${rand(0.1, 0.4)}s ease`, // Speed(s) Pause(s)
transform: `translate(${pos.x}px, ${pos.y}px)`
}).one('transitionend', anim.bind(this));
}
return this.each(anim);
};
$('.boo').animateGhosts();
#ghosts {
position: relative;
height: 180px;
outline: 2px solid #000;
}
.boo {
position: absolute;
background: fuchsia;
width: 50px;
height: 50px;
}
<div id="ghosts">
<div class="boo">1</div>
<div class="boo">2</div>
<div class="boo">3</div>
<div class="boo">4</div>
<div class="boo">5</div>
<div class="boo">6</div>
</div>
<script src="//code.jquery.com/jquery-3.4.1.js"></script>
I try to create a running infotext on an infoscreen. The Text starts running from the right corner of the screen and leaves on the left side. This process repeats without a limit recursively.
Everything seems to work great, but when I remove the alert after debugging, the text don't start running from the right corner but from the left. Also the programm runs only one time.
HTML:
function setStaticData() {
sessionStorage.setItem('headerWidth', document.getElementById('header').scrollWidth);
}
function getStaticData() {
return sessionStorage.getItem('headerWidth');
}
function animation() {
//get element, its width & time param
var header = document.getElementById('header');
var headerWidth = getStaticData();
var headerTime = header.innerHTML.length * 0.3;
var windowWidth = window.innerWidth;
//clean all
header.style.transition = 'none';
header.style.marginLeft = windowWidth + 'px';
alert("baba"); //BAD BOY
//animate text
header.style.transition = 'margin linear ' + headerTime + 's';
header.style.marginLeft = '-' + headerWidth + 'px';
//wait and repeat
var delay = headerTime * 1000 + 1000;
setTimeout(animation, delay);
}
//first call
window.onload = function() {
setStaticData();
animation();
};
html {
width: 100%;
overflow: hidden;
}
body {
height: 100%;
width: 100%;
position: relative;
display: block;
margin: 0;
padding: 0;
top: 50vh;
transform: translateY(-50%);
color: black;
background-color: #bbc8d9;
}
header {
font-family: calibri, arial;
font-weight: 400;
font-size: 100px;
white-space: nowrap;
}
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<header id="header">+++ News, More News, Another Thing & something else +++</header>
<script src="functions.js"></script>
</body>
</html>
If I remove the bad boy [alert("baba");] it doesn't work, like I mentioned above.
I going crazy! Can you pls help me?
The problem is that changes to the style of an element are not processed until the Javascript returns to the main event loop and the page is rendered. If you make two assignments to a style, the browser only sees the final result. So when you set marginLeft to the window width and then set it to "-" + headerWidth + "px", only the second change is processed, so that's where the animation starts from.
The alert() causes the page to be rendered while it's waiting for your response (although I think this may be browser-dependent), which is why it works with that.
A simple solution is to put the second assignment in a setTimeout(), so it will be executed asynchronously after returning.
function setStaticData() {
//sessionStorage.setItem('headerWidth', document.getElementById('header').scrollWidth);
}
function getStaticData() {
return document.getElementById('header').scrollWidth; //sessionStorage.getItem('headerWidth');
}
function animation() {
//get element, its width & time param
var header = document.getElementById('header');
var headerWidth = getStaticData();
var headerTime = header.innerHTML.length * 0.3;
var windowWidth = window.innerWidth;
//clean all
header.style.transition = 'none';
header.style.marginLeft = windowWidth + 'px';
//alert("baba"); //BAD BOY
//animate text
setTimeout(function() {
header.style.transition = 'margin linear ' + headerTime + 's';
header.style.marginLeft = '-' + headerWidth + 'px';
}, 0);
//wait and repeat
var delay = headerTime * 1000 + 1000;
setTimeout(animation, delay);
}
//first call
window.onload = function() {
setStaticData();
animation();
};
html {
width: 100%;
overflow: hidden;
}
body {
height: 100%;
width: 100%;
position: relative;
display: block;
margin: 0;
padding: 0;
top: 50vh;
transform: translateY(-50%);
color: black;
background-color: #bbc8d9;
}
header {
font-family: calibri, arial;
font-weight: 400;
font-size: 100px;
white-space: nowrap;
}
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<header id="header">+++ News, More News, Another Thing & something else +++</header>
<script src="functions.js"></script>
</body>
</html>
Ok I think i fixed it. Its the timing problem just delay the animate call. 1s
function animation() {
//get element, its width & time param
var header = document.getElementById('header');
var headerWidth = getStaticData();
var headerTime = header.innerHTML.length * 0.3;
var windowWidth = window.innerWidth;
//clean all
header.style.transition = 'none';
header.style.marginLeft = windowWidth+'px';
// delay it for 1000ms
setTimeout(
function(){
//animate text
header.style.transition = 'margin linear '+headerTime+'s';
header.style.marginLeft = '-'+headerWidth+'px';
//wait and repeat
var delay = headerTime * 1000 + 1000;
setTimeout(animation, delay);
}, 1000);
}
Please look at the snippet below. I don't use sessionStorage as it is designed for a different purpose. I don't use setTimeout to wait for the styles to be applied.
I start the animation then restart it on transitionend event.
window.onload = function() {
var header = document.getElementById('header');
animation();
header.addEventListener('transitionend', function() {
header.style.transition = 'none';
header.style.transform = 'translateX(0)';
animation();
});
function animation() {
var t = header.offsetWidth / 70,
tx = header.scrollWidth;
header.style.transition = 'transform ' + t + 's linear';
header.style.transform = 'translateX(-' + tx + 'px)';
}
};
html {
width: 100%;
overflow: hidden;
background-color: #bbc8d9;
}
header {
font: 100px sans-serif;
white-space: nowrap;
padding-left: 100%;
}
<header id="header">+++ News, More News, Another Thing & something else +++</header>
I have a square, when clicked it appears in a random location and it also change size (so for example if I have a 30px box but it is 10px from the left border I still get 10px outside the gamespace).
sometimes the square exceed his container border
How can I make sure that the square will never exceed his container?
function position() {
var positionTop = Math.random() * 100;
var positionLeft = Math.random() * 100;
var position = "position:relative;top:" + positionTop + "%;left:" + positionLeft + "%;"
return position;
}
document.getElementById("shape").onclick = function() {
document.getElementById("shape").style.cssText = position();
}
#gameSpace {
width: 100%;
height: 470px;
background: blue;
margin: 0;
padding-top: 30px;
}
#playSpace {
width: 90%;
height: 90%;
margin: 0 auto;
margin-top: 10px;
border: 1px black solid;
}
#shape {
width: 100px;
height: 100px;
background-color: red;
}
<div id="gameSpace">
<div id="playSpace">
<!-- here we put the shape -->
<div id="shape"></div>
</div>
</div>
You need to set position: relative; to the parent element and position: absolute; to the shape element. Then use max min value for random where max is the parent width/height and subtract the shape width/height ...
This is snippet before update
function position() {
var playSpace = document.querySelector('#playSpace');
var shape = document.getElementById("shape");
var maxHeight = playSpace.offsetHeight - shape.offsetHeight;
var maxWidth = playSpace.offsetWidth - shape.offsetWidth;
var positionTop = Math.random() * (maxHeight - 0) + 0;
var positionLeft = Math.random() * (maxWidth - 0) + 0;
// think of this like so:
// var positionTop = Math.random() * (max - min) + min;
// more information about it https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
var position = "position:absolute;top:" + positionTop + "px;left:" + positionLeft + "px;"
return position;
}
document.getElementById("shape").onclick = function() {
document.getElementById("shape").style.cssText = position();
}
#gameSpace {
width: 100%;
height: 470px;
background: blue;
margin:0;
padding-top: 30px;
}
#playSpace {
position: relative; /* add this line */
width: 90%;
height: 90%;
margin: 0 auto;
border: 1px black solid;
}
#shape {
width: 100px;
height: 100px;
background-color: red;
}
<div id="gameSpace">
<div id="playSpace">
<!-- here we put the shape -->
<div id="shape"></div>
</div>
</div>
Updated after comment
Not sure how you added the size() function but probably the problem was with using ...cssText that you overwrote the changes. So now I changed the code with passing the element to the functions and then only change the single CSS statements which need to be changed.
function position(element) {
var playSpace = document.querySelector('#playSpace');
var shape = document.getElementById("shape");
var maxHeight = playSpace.offsetHeight - shape.offsetHeight;
var maxWidth = playSpace.offsetWidth - shape.offsetWidth;
var positionTop = Math.random() * (maxHeight - 0) + 0;
var positionLeft = Math.random() * (maxWidth - 0) + 0;
// think of this like so:
// var positionTop = Math.random() * (max - min) + min;
// more information about it https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
element.style.position = 'absolute';
element.style.top = positionTop + "px";
element.style.left = positionLeft + "px";
}
function size(element) {
var sizeMath = (Math.random() * 200) + 50;
element.style.width = sizeMath + "px";
element.style.height = sizeMath + "px";
}
document.getElementById("shape").onclick = function() {
size(document.getElementById("shape"));
position(document.getElementById("shape"));
}
#gameSpace {
width: 100%;
height: 470px;
background: blue;
margin:0;
padding-top: 30px;
}
#playSpace {
position: relative; /* add this line */
width: 90%;
height: 90%;
margin: 0 auto;
border: 1px black solid;
}
#shape {
width: 100px;
height: 100px;
background-color: red;
}
<div id="gameSpace">
<div id="playSpace">
<!-- here we put the shape -->
<div id="shape"></div>
</div>
</div>
You can use a specify the range (min/max) in Math.random function and then use this function Math.floor(Math.random() * (max - min + 1)) + min; to limit the returned value of the random function between min and max.
maxTop : height of the container - height of shape
maxLeft : width of the container - width of shape
minTop : 0
minLeft : 0
You need to use position:absolute and px value on shape for this to work
See code snippet:
function position() {
var minTop = 0;
var maxTop = document.getElementById("playSpace").clientHeight - document.getElementById("shape").clientHeight;
var minLeft = 0;
var maxLeft = document.getElementById("playSpace").clientWidth - document.getElementById("shape").clientWidth ;
var positionTop = Math.floor(Math.random() * (maxTop - minTop + 1) + minTop);
var positionLeft = Math.floor(Math.random() * (maxLeft - minLeft + 1) + minLeft);
var position = "position:absolute;top:" + positionTop + "px;left:" + positionLeft + "px;"
return position;
}
document.getElementById("shape").onclick = function() {
document.getElementById("shape").style.cssText = position();
}
#gameSpace {
width: 100%;
height: 470px;
background: blue;
margin: 0;
padding-top: 30px;
text-align:center;
}
#playSpace {
width: 90%;
height: 90%;
border: 1px black solid;
position:relative;
display:inline-block;
}
#shape {
width: 100px;
height: 100px;
background-color: red;
}
<div id="gameSpace">
<div id="playSpace">
<!-- here we put the shape -->
<div id="shape"></div>
</div>
</div>
With CSS calc, limit the position inside playSpace area (you can use different units, here % and px).
Then with offsetTop/offsetLeft, get the real position of the square and avoid negative positions (when positionTop < 100px or positionLeft < 100px).
function position() {
var positionTop = Math.random() * 100;
var positionLeft = Math.random() * 100;
var position = "position:relative;top: calc(" + positionTop + "% - 100px);left: calc(" + positionLeft + "% - 100px);";
return position;
}
document.getElementById("shape").onclick = function() {
var shapeDiv = document.getElementById("shape");
shapeDiv.style.cssText = position();
var top = shapeDiv.offsetTop;// Result of calc(" + positionTop + "% - 100px) in px
if(top < 0) {
shapeDiv.style.top = '0px';
}
var left = shapeDiv.offsetLeft;// Result of calc(" + positionLeft + "% - 100px) in px
if(left < 0) {
shapeDiv.style.left = '0px';
}
}
Don't forget to add position: relative to #playSpace, to get offsetTop/left correct
#playSpace {
position:relative;/* mandatory */
}
You can get the parent element size, so that in your scirpt, use a condition to prevent the square to exceed.
function position() {
var maxWidth = document.getElementById("playSpace").offsetWidth;
var maxTop = document.getElementById("playSpace").offsetHeight;
var positionTop = Math.random() * 100;
var positionLeft = Math.random() * 100;
if (positionTop > maxTop) { positionTop = maxTop;)
if (positionLeft > maxWidth) { positionLeft = maxWidth;)
var position = "position:relative;top:" + positionTop + "%;left:" + positionLeft + "%;"
return position;
}
I'm not sure if .offsetWidth and .offsetHeight works well, but you got the idea :)
By tweaking just a little your positionTop and positionLeft variable, I managed to keep the square inside. You just need to change the maximum % that it needs to have to not exceed the container. I found that 75% for the top and 80% for the left seems to be the max!
var positionTop = Math.floor(Math.random() * 75) ;
var positionLeft = Math.random() * 80;
Here's a fiddle
If you set the containing element to position: relative; and the inner element with position: absolute; the inner elements top left right and bottom properties will calculate from the borders of the containing element.
Here is a good source of css positioning.
In your case additional validation should be set to positionTop and positionLeft.
positionTop should be in the interval [( shapeHeight/2 ) - (100 - shapeHeight/2 ) ]
positionLeft should be in the interval [( shapeWidth/2 ) - (100 - shapeWeight/2 ) ]
I found this rather cool Js fiddle and have been editing the animation a bit and think its something I can use on a current project. However im not the best with Javascript. All I really need to know to accomplish the rest of my goal is how to make the animation not start until you click a button.
Here is the animation for the js fiddle.
http://jsfiddle.net/apipkin/qUTwQ/
Here is the css.
#o {
width: 200px;
height: 400px;
position: relative;
border-bottom: 1px solid blue;}
.bubble {
border: 1px solid
#f40009; display: block;
position: absolute;
border-radius: 20px;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
}
The rest is in the JS fiddle.
Thanks fo any help!
You can simply wrap it in a function and call that function on click.
DEMO
Create a button:
<button id="btn">Click</button>
And this js:
document.getElementById('btn').addEventListener('click', startAnimation);
function startAnimation() {
YUI().use('node', 'anim', 'anim-node-plugin', function(Y) {
var o = Y.one('#o'),
oW = o.get('offsetWidth'),
oH = o.get('offsetHeight'),
max = 12,
min = 4,
bubbles = 20,
timerDelay = 4000;
function makeBubble() {
var b = Y.Node.create('<span class="bubble"></span>');
b.plug(Y.Plugin.NodeFX, {
duration: 7,
easing: Y.Easing.easeOut,
to: {
top: 0,
opacity: 0
},
on: {
end: function() {
Y.later(10000, this, function(){
animBubble(this.get('node'));
});
}
}
});
o.append(b);
animBubble(b);
}
function animBubble(b) {
var v = Math.floor(Math.random() * (max - min)) + min;
b.setStyles({
height: v + 'px',
width: v + 'px',
borderRadius: v + 'px',
top: (oH + 2) + 'px',
opacity: 1
});
b.setStyle('left', Math.floor(Math.random() * (oW - v)));
b.fx.set('duration', Math.floor(Math.random() * 2 + 3));
b.fx.set('to.top', Math.floor(Math.random() * (oH / 2)));
b.fx.run();
}
for (i = 0; i < bubbles; i++) {
Y.later(Math.random() * timerDelay, this, function() {
makeBubble();
});
}
});
}
I have an unordred list which acts as a chat platform. With each "message" appended to the list by the user, I have it appear with a chat bubble behind, however, the chat bubble remains the same size with every message appended, meaning that if the message contains a certain amount of characters, it appears outside of the bubble. Is there a way for a chat bubble to resize itself due to the size of the message? Preferrably after about 25 characters, I'd like the message to start a new line and the bubble to expand in height. On the other side, if a message is only 5 characters long, the chat bubble would resize to fit that.
A picture to illustrate the problm is here: http://imgur.com/uzzjpQw
Here is my Jquery/ Javascript
$('#submit').click(function(){
var message = $('#typetextbox').val();
if (message.replace(/ /g, '')){
var positions = makeNewPosition();
var el = $('<li>'+message+'</li>');
el.attr('gridpos', positions[0].toString()+"x"+positions[1].toString())
el.css('left', positions[1] * window.li_width);
el.css('top', positions[0] * window.li_height);
$('#messagebox').append(el);
setTimeout(function() {
el.fadeOut();
var gridpos = el.attr('gridpos');
delete window.grid[gridpos];
}, 4000 );
}
$("#typetextbox").val("");
});
});
window.grid = {};
window.li_height = 20;
window.li_width = 200;
function makeNewPosition(){
var h = Math.floor($(window).height()/window.li_height);
var w = Math.floor($(window).width()/window.li_width);
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
var gridpos = nh.toString() + "x" + nw.toString();
if(typeof window.grid[gridpos] == 'undefined'){
return [nh,nw];
}else{
return makeNewPosition();
}
Here's my CSS:
li{
height: 24px;
width: 220px;
margin: 2px;
padding: 5px;
position: absolute;
z-index: -2;
font-family: Verdana, Geneva, sans-serif;
color: #FFF;
background-image: url(Images/chat-bubble-left-flick.png);
background-repeat: no-repeat;
background-position: -25px center;
}
ul{
list-style:none;
}
Sorry for providing a lot of code, but I'm not sure where my problem lies/fits. I'm assuming it's something to correct in Javascript rather than using a background image? Any help is appreciated.
height: 24px; is the reason, use min-height: 24px; instead.
Is position: absolute; required?