I continuously keep getting this error, and I don't really understand why.
Uncaught TypeError: Cannot read property 'top' of undefined
I have gone back in and added a if statement to see if it exists before hand, but still error persists.
$(document).ready(function(){
//setTimeout(function(){
animateDiv();
// },2000);
});
function makeNewPosition(){
// Get viewport dimensions (remove the dimension of the div)
var h = $(window).height() - 50;
var w = $(window).width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh,nw];
}
function animateDiv(){
var newq = makeNewPosition();
var oldq = $('.MyContain a').offset();
var speed = calcSpeed([oldq.top, oldq.left], newq);
// if (oldq.length) {
$('.MyContain a').animate({ top: newq[0], left: newq[1] }, speed, function(){
animateDiv();
});
//}
};
function calcSpeed(prev, next) {
var x = Math.abs(prev[1] - next[1]);
var y = Math.abs(prev[0] - next[0]);
var greatest = x > y ? x : y;
var speedModifier = 0.009;
var speed = Math.ceil(greatest/speedModifier);
return speed;
}
My mark-up is a bunch of text anchor links within .MyContain element. That I am trying to get just to move around randomly.
<div class="MyContain">
Sample
Demo
Coffee
<!-- etc -->
</div>
Related
I am trying to get the script to run again after all the gifs have been clicked and changed to the png's. Once all the gifs are clicked I have to refresh the browser in order for the game to start again. I would preferably like to have the creation of a newDiv happen when one of the divs is clicked. So that way a new one appears when one is clicked, and is constantly adding the newDiv. Any ideas on how to do that would help.
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Shoo Fly</title>
<style>
div.a {
width: 200px;
height:200px;
position:absolute;
background-image: url("fly.gif");
}
html {
background: url("fly-background.png");
background-size: cover;
background-repeat: no-repeat;
margin: 0;
padding:0;
background-color: #50BBAD;
zoom: 80%;
}
</style>
<script src="jquery-3.1.1.js"></script>
<script src="please-work.js"></script>
</head>
<body>
<div class="animatedDivs"></div>
</body>
</html>
Javascript:
$(document).ready(function () {
newDiv();
newDiv();
newDiv();
newDiv();
newDiv(); //5
newDiv();
newDiv();
newDiv();
newDiv();
newDiv(); //10
});
function newDiv() {
var $div = $("<div class='a'>");
$(".animatedDivs").append($div);
animateDiv();
$div.click(function(){
$div.css('background-image','url(splatter-1.png)');
$div.css('zIndex' , '-1');
$div.css({'position': 'absolute'});
//$(this).data('clicked', true);
var offset = $div.position();
$div.stop();
$div.position({left:(offset.left), right: (offset.right)});
});
function animateDiv() {
var newq = makeNewPosition();
var oldq = $div.offset();
var speed = calcSpeed([oldq.top, oldq.left], newq);
$div.animate({
top: newq[0],
left: newq[1]
}, speed, function () {
animateDiv();
});
};
}
function makeNewPosition() {
// Get viewport dimensions (remove the dimension of the div)
var h = $(window).height() - 50;
var w = $(window).width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh, nw];
}
function calcSpeed(prev, next) {
var x = Math.abs(prev[1] - next[1]);
var y = Math.abs(prev[0] - next[0]);
var greatest = x > y ? x : y;
var speedModifier = .1;
var speed = Math.ceil(greatest / speedModifier);
return speed;
}
A bonus to skip a couple lines and get a new param.
var init = function(x){
for(i=0;i<x;i++){
newDiv();
};
// Onload initialisation
init(10); // OKAY! div amount as argument??
// So possibly a incrental or random amount?
//
// Thanks SO!
ACCEPTED ANSWER
I named your function, to be able to call it again from somewhere else in the code.
Then I added a loop to check if all images have been clicked...
On each click event.
I also changed your images sources... But it is just for my demo.
Here is the whole code working in this CodePen:
$(document).ready(function () {
// Named the init fonction
var init = function(){
newDiv();
newDiv();
newDiv();
newDiv();
newDiv(); //5
newDiv();
newDiv();
newDiv();
newDiv();
newDiv(); //10
};
// Onload initialisation
init();
function newDiv() {
var $div = $("<div class='a'>");
$(".animatedDivs").append($div);
animateDiv();
$div.click(function(){
console.log("Image clicked");
$div.css('background-image','url(https://media.licdn.com/mpr/mpr/shrink_200_200/AAEAAQAAAAAAAATsAAAAJDM0N2NjNzkxLWEyOGYtNDE5MS05OGQxLTRkMzFkMDA3ZmZjNw.png)');
$div.css('zIndex' , '-1');
$div.css({'position': 'absolute'});
//$(this).data('clicked', true);
var offset = $div.position();
$div.stop();
$div.position({left:(offset.left), right: (offset.right)});
// ===================================
// Check if all images are clicked.
var allClicked=true;
$(".a").each(function(){
if( $(this).css("z-index")!="-1" ){
allClicked=false;
}
});
console.log( allClicked ); // Is true when all images are clicked.
if(allClicked){
console.log("restarting!");
$(".a").remove();
// Re-init the game
init();
}
// ===================================
});
function animateDiv() {
var newq = makeNewPosition();
var oldq = $div.offset();
var speed = calcSpeed([oldq.top, oldq.left], newq);
$div.animate({
top: newq[0],
left: newq[1]
}, speed, function () {
animateDiv();
});
};
}
function makeNewPosition() {
// Get viewport dimensions (remove the dimension of the div)
var h = $(window).height() - 50;
var w = $(window).width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh, nw];
}
function calcSpeed(prev, next) {
var x = Math.abs(prev[1] - next[1]);
var y = Math.abs(prev[0] - next[0]);
var greatest = x > y ? x : y;
var speedModifier = .1;
var speed = Math.ceil(greatest / speedModifier);
return speed;
}
});
EDIT
To keep the "splats" there and load some new moving divs, only two lines have to be changed:
In CSS :
div.a {
becomes:
div.a, div.splatted {
And in JS :
$(".a").remove();
becomes:
$(".a").removeClass("a").addClass("splatted");
See this CodePen v2.
Well, if all what you want it is to create a new div when one is clicked, you just need to call to your newDiv function from inside the click function handler:
$div.click(function(){
newDiv();
// more code
});
And if, as the title suggests, you want to restart the animation once all divs are clicked, just check if all are already clicked inside the click function handler:
$div.click(function(){
$(this).data('clicked')
if ( allAreClicked() ) {
// code to restart the game
}
// more code
});
function allAreClicked() {
return $('.animatedDivs > div').lenght = $('.animatedDivs > div[data-cliked="true"]').lenght;
}
I'm making an animation that each list item will float randomly inside its wrapper. I'm trying to put together using prototypal inheritance pattern but it's not doing it. There are a couple of places that I think it may be cause to the problem but I need some advice to proceed.
function Menu($item) {
this.item = $item;
};
Menu.prototype.makeNewPosition = function ($container) {
var h = $container.height() - 50;
var w = $container.width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh, nw];
};
Menu.prototype.move = function () {
$.each(this.item, function(index, value) {
var newq = this.makeNewPosition(value.parent());
value.animate({
top: newq[0],
left: newq[1]
}, 400, function() {
this.move();
});
});
};
var $menu = new Menu($('.nav li'));
$menu.move();
Within move function, there is animate and within this I'm calling move again to run the animation indefinitely. If it's calling itself in prototypal structure, can it be called using this?
Not also sure about the use of $.each within move function.
Here is JSfiddle
Here's a cleaner version
uses self instead of that - I use that, most people use self - I'm different :p
set $value = $(value) ... DRY
.
function Menu($item) {
this.item = $item;
};
Menu.prototype.makeNewPosition = function ($container) {
var h = $container.height() - 50;
var w = $container.width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh, nw];
};
Menu.prototype.move = function () {
var self = this;
$.each(this.item, function(index, value) {
var $value = $(value);
var newq = self.makeNewPosition($value.parent());
$value.animate({
top: newq[0],
left: newq[1]
}, 400, function() {
self.move();
});
});
};
var $menu = new Menu($('.nav li'));
$menu.move();
original answer below - which contains explanation of changes
Here's ALL the errors fixed, not just the first
function Menu($item) {
this.item = $item;
};
Menu.prototype.makeNewPosition = function ($container) {
var h = $container.height() - 50;
var w = $container.width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh, nw];
};
Menu.prototype.move = function () {
var that = this; // added that because the this isn't the this you want in the $.each function
$.each(this.item, function(index, value) {
var newq = that.makeNewPosition($(value).parent());
// ^^^^ ^^ ^
// that instead of this
// $(value) instead of value
$(value).animate({
// ^^ ^
// $(value) instead of value
top: newq[0],
left: newq[1]
}, 400, function() {
that.move();
//^^^^ another this to that change
});
});
};
var $menu = new Menu($('.nav li'));
$menu.move();
There's ways to clean up the code even more, but these changes should get you working at least
The working changes to your fiddle http://jsfiddle.net/wzmh63xb/16/
There is your mistakes. Try this. it is working.
Menu.prototype.move = function () {
var self = this;
$.each(this.item, function(index, value) {
var newq = self.makeNewPosition($(value).parent());
$(value).animate({
top: newq[0],
left: newq[1]
}, 400, function() {
self.move();
});
});
};
DEMO
Please, play with teh fiddle below. ONE bug goes as it should - turns its "head" and crawls in proper direction. But several bugs (starting with two and up) destroy it all. Jquery "each" returns coordinates twice so instead of two sets of coordinates for two bugs FOUR are generated.
$(document).ready(function () {
function bug() {
$('.bug').each(function () {
//var bugs = $('.bug').length;
var h = $(window).height() / 2;
var w = $(window).width() / 2;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
//$this = $(this);
//var newCoordinates = makeNewPosition();
var p = $(this).offset();
var OldY = p.top;
var NewY = nh;
var OldX = p.left;
var NewX = nw;
var y = OldY - NewY;
var x = OldX - NewX;
angle = Math.atan2(y, x);
angle *= 180 / Math.PI
angle = Math.ceil(angle);
console.log(p);
$(this).delay(1000).rotate({
animateTo: angle
});
$(this).animate({
top: nh,
left: nw
}, 5000, "linear", function () {
bug();
});
});
};
bug();
});
http://jsfiddle.net/p400uhy2/
http://jsfiddle.net/p400uhy2/4/
As mentioned by #Noah B, the problem is that each "bug" is setting the loop for all "bugs".
I'd make bug() function per element, so that each "bug" can be set individually.
EDIT (#Roko C. Buljan comment)
function bug() {
// ... your code ...
// calculate animation time, so that each of bugs runs same fast in long and short distance:
var top_diff = Math.abs(OldY - nh),
left_diff = Math.abs(OldX - nw),
speed = Math.floor(Math.sqrt((top_diff * top_diff) + (left_diff * left_diff))) * 15;
$(this).animate({
top: nh,
left: nw
}, speed, "linear", function () {
// rerun bug() function only for that single element:
bug.call(this);
});
};
$('.bug').each(bug);
DEMO
The problem is that you had .each() calling a function with .each() in it...so each bug had the bug() callback. You just have to move the bug() call outside of the .each(){}. See fiddle: http://jsfiddle.net/p400uhy2/2/
I found this post really very helpful and it is almost what I want to achieve
The problem is I want multiple div moving around a page, how can this be modified to allow for multiple elements moving randomly?
$(document).ready(function(){
animateDiv();
});
function makeNewPosition(){
// Get viewport dimensions (remove the dimension of the div)
var h = $(window).height() - 50;
var w = $(window).width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh,nw];
}
function animateDiv(){
var newq = makeNewPosition();
var oldq = $('.a').offset();
var speed = calcSpeed([oldq.top, oldq.left], newq);
$('.a').animate({ top: newq[0], left: newq[1] }, speed, function(){
animateDiv();
});
};
function calcSpeed(prev, next) {
var x = Math.abs(prev[1] - next[1]);
var y = Math.abs(prev[0] - next[0]);
var greatest = x > y ? x : y;
var speedModifier = .8;
var speed = Math.ceil(greatest/speedModifier);
return speed;
}
In this codepen I've made a new function targeting a new class but its drawing out the same movement.
http://codepen.io/Alex/pen/OPPBmX
One possibility is to contain the functionality within a function, and call that function multiple times.
You can have a containing div which all divs will be appended to:
<div class="animatedDivs"></div>
Then inside the function you can create a div, append it to that div, and animate it:
function newDiv() {
//Create
var $div = $("<div class='a'>");
//Append
$(".animatedDivs").append($div);
//Animate
animateDiv();
function animateDiv(){
//same code with $('.a') replaced by $div
};
}
function makeNewPosition(){
//same code
}
function calcSpeed(prev, next) {
//same code
}
Then you can create as many as you want:
$(document).ready(function () {
newDiv();
newDiv();
//etc...
});
Fiddle Example: http://jsfiddle.net/9agtb339/1/
I made some modifications on your code pen page and came up with an solution I believe:
I made all the divs the same class.
http://codepen.io/anon/pen/NPPOXg
$(document).ready(function(){
animateDiv();
animateDivTwo();
});
function makeNewPosition(){
// Get viewport dimensions (remove the dimension of the div)
var h = $(window).height() - 50;
var w = $(window).width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh,nw];
}
function animateDiv(element){
var newq = makeNewPosition();
var oldq = $('.a').offset();
var speed = calcSpeed([oldq.top, oldq.left], newq);
$(element).animate({ top: newq[0], left: newq[1] }, speed, function(){
animateDiv(element);
});
};
function animateDivTwo(){
var newq = makeNewPosition();
var oldq = $('.a').offset();
var speed = calcSpeed([oldq.top, oldq.left], newq);
$('.a').animate({ top: newq[0], left: newq[1] }, speed, function(){
animateDiv(this);
});
};
function calcSpeed(prev, next) {
var x = Math.abs(prev[1] - next[1]);
var y = Math.abs(prev[0] - next[0]);
var greatest = x > y ? x : y;
var speedModifier = .4;
var speed = Math.ceil(greatest/speedModifier);
return speed;
}
Your wrong:
You animate ".a" in your animateDivTwo function, seems like you want target ".b" here
You call animateDiv in animateDivTwo function
So, animateDivTwo calls once only
I correct your codepen
Please look into this JSFiddle.
Updated
<div class='a' name="animate"></div>
<div class='b' name="animate"></div>
$(document).ready(function(){
$("div[name=animate]").each(function(){
animateDiv($(this));
});
});
function animateDiv(c){
var newq = makeNewPosition();
$(c).animate({ top: newq[0], left: newq[1] }, function(){
animateDiv(c);
});
};
css
div.a, div.b {
width: 50px;
height:50px;
background-color:red;
position:fixed;
}
div.b{
background-color:green;
}
This is just an Idea to start with.
UPDATE
In this following updated JSFiddle I have created three Div. So this is the best way to add any number of divs. All that you have to do is add css. Infact we can randomize that too.
I am looking for a way to implement the exact functionality from this answer using angularjs: Specifically, for a box (div) to move randomly around a screen, while being animated. Currently I have tried
myApp.directive("ngSlider", function($window) {
return {
link: function(scope, element, attrs){
var animateDiv = function(newq) {
var oldRect = element.getBoundingClientRect();
var oldq = [oldRect.top, oldRect.left];
if (oldq != newq){
var dir = calcDir([oldq.top, oldq.left], newq);
element.moveTo(oldq.left + dir[0], oldq.top + dir[1]);
setTimeout(animateDiv(newq), 100);
}
};
var makeNewPosition = function() {
// Get viewport dimensions (remove the dimension of the div)
var window = angular.element($window);
var h = window.height() - 50;
var w = window.width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh,nw];
};
function calcDir(prev, next) {
var x = prev[1] - next[1];
var y = prev[0] - next[0];
var norm = Math.sqrt(x * x + y * y);
return [x/norm, y/norm];
}
var newq = makeNewPosition();
animateDiv(newq);
}
};
});
There appears to be quite a bit wrong with this, from an angular point of view. Any help is appreciated.
I like to take advantage of CSS in situations like this.
absolutely position your div
use ng-style to bind top and left attributes to some in-scope variable
randomly change the top and left attributes of this in-scope variable
use CSS transitions on top and left attributes to animate it for you
I made a plnkr! Visit Kentucky!