I have this function
var flakeImage = new Image();
function loadImage(){
flakeImage.onload = drawFlake;
flakeImage.src = "game/snowflake.png";
}
and this one that initialises the image
function initFlake() {
flakex = Math.random()*(WIDTH-140)+70;
flakey = (Math.random()*20)+70;
flakes = Math.random()*40;
}
and this one that updates the image so it will look like it s actually falling
function updateFlake(){
flakey = flakey + 1;
}
and also the draw function
function drawFlake() {
context.drawImage(flakeImage, flakex, flakey, flakes, flakes);
}
I want to make it look like it s snowing in my canvas. I can't use a for loop because it will just modify the same picture . I tried making a big array with the same picture, but in the end I don't get that effect .. because the images have to keep falling randomly . How should I combine an array with that image stored at random positions with an interval to get that effect ?
You can use setInterval().
doSomething: function() {
clearInterval(myInterval);
myInterval = setInterval(function() {
// update flake position
updateFlake();
}, timeInMilliseconds);
},
This runs the function given as a parameter every timeInMilliseconds milliseconds. The setInterval() function returns an ID which you can pass to clearInterval() in order to stop updating.
You can also pass a function directly.
doSomething: function() {
clearInterval(myInterval);
myInterval = setInterval(updateFlake, timeInMilliseconds);
},
EDIT: OP, you can do this just fine without relying on HTML5 canvas, instead use DOM elements:
JS BIN
Javascript:
function update () {
var myInterval = null;
clearInterval(myInterval);
myInterval = setInterval(function() {
// update flake position
$("#holder > img").each(function() {
if ($(this).position().top >= $(window).height())
$(this).remove();
else
$(this).css({top: $(this).position().top+=3});
});
}, 50); //update each of the drawn children
}
function drawFlake() {
clearInterval(myInterval);
var myInterval = null;
myInterval = setInterval(function() {
var randX = (Math.floor((Math.random() * $(window).width()) + 1));
var $img = $('<img>');
$img.attr('src','flake.png');
$("#holder").append($img);
$img.css({left: randX, top: 0, position:'absolute'});
}, 2000); //draw a new flake every 2 seconds
update();
}
HTML:
<body onload="drawFlake()">
<div id="holder"></div>
</body>
CSS:
body {
background: white;
}
#holder {
position: relative;
width: 100%;
height: 100%;
}
Related
I have created a JavaScript Slideshow, but I don't know how to add the fade effect. Please tell me how to do it, and please tell in JavaScript only, no jQuery!
Code:
var imgArray = [
'img/slider1.jpg',
'img/slider2.jpg',
'img/slider3.jpg'],
curIndex = 0;
imgDuration = 3000;
function slideShow() {
document.getElementById('slider').src = imgArray[curIndex];
curIndex++;
if (curIndex == imgArray.length) { curIndex = 0; }
setTimeout("slideShow()", imgDuration);
}
slideShow();
Much shorter than Ninja's solution and with hardware accelerated CSS3 animation. http://jsfiddle.net/pdb4kb1a/2/ Just make sure that the transition time (1s) is the same as the first timeout function (1000(ms)).
Plain JS
var imgArray = [
'http://placehold.it/300x200',
'http://placehold.it/200x100',
'http://placehold.it/400x300'],
curIndex = 0;
imgDuration = 3000;
function slideShow() {
document.getElementById('slider').className += "fadeOut";
setTimeout(function() {
document.getElementById('slider').src = imgArray[curIndex];
document.getElementById('slider').className = "";
},1000);
curIndex++;
if (curIndex == imgArray.length) { curIndex = 0; }
setTimeout(slideShow, imgDuration);
}
slideShow();
CSS
#slider {
opacity:1;
transition: opacity 1s;
}
#slider.fadeOut {
opacity:0;
}
As an alternative. If you are trying to make a slider.
The usual approach is to animate a frame out and animate a frame in.
This is what makes the slide effect, and the fade effect work. Your example fades in. Which is fine, but maybe not what you really want once you see it working.
If what you really want is to animate images in and ...OUT you need something a little more complex.
To animate images in and out you must use an image element for each, then flip one out and flip one in. The images need to be placed on top of each other in the case of a fade, if you want to slide you lay them beside each other.
Your slideshow function then works the magic, but before you can do that you need to add all those images in your array into the dom, this is called dynamic dom injection and it's really cool.
Make sure you check the fiddle for the full working demo and code it's linked at the bottom.
HTML
<div id="slider">
// ...we will dynamically add your images here, we need element for each image
</div>
JS
var curIndex = 0,
imgDuration = 3000,
slider = document.getElementById("slider"),
slides = slider.childNodes; //get a hook on all child elements, this is live so anything we add will get listed
imgArray = [
'http://placehold.it/300x200',
'http://placehold.it/200x100',
'http://placehold.it/400x300'];
//
// Dynamically add each image frame into the dom;
//
function buildSlideShow(arr) {
for (i = 0; i < arr.length; i++) {
var img = document.createElement('img');
img.src = arr[i];
slider.appendChild(img);
}
// note the slides reference will now contain the images so we can access them
}
//
// Our slideshow function, we can call this and it flips the image instantly, once it is called it will roll
// our images at given interval [imgDuration];
//
function slideShow() {
function fadeIn(e) {
e.className = "fadeIn";
};
function fadeOut(e) {
e.className = "";
};
// first we start the existing image fading out;
fadeOut(slides[curIndex]);
// then we start the next image fading in, making sure if we are at the end we restart!
curIndex++;
if (curIndex == slides.length) {
curIndex = 0;
}
fadeIn(slides[curIndex]);
// now we are done we recall this function with a timer, simple.
setTimeout(function () {
slideShow();
}, imgDuration);
};
// first build the slider, then start it rolling!
buildSlideShow(imgArray);
slideShow();
Fiddle:
http://jsfiddle.net/f8d1js04/2/
you can use this code
var fadeEffect=function(){
return{
init:function(id, flag, target){
this.elem = document.getElementById(id);
clearInterval(this.elem.si);
this.target = target ? target : flag ? 100 : 0;
this.flag = flag || -1;
this.alpha = this.elem.style.opacity ? parseFloat(this.elem.style.opacity) * 100 : 0;
this.elem.si = setInterval(function(){fadeEffect.tween()}, 20);
},
tween:function(){
if(this.alpha == this.target){
clearInterval(this.elem.si);
}else{
var value = Math.round(this.alpha + ((this.target - this.alpha) * .05)) + (1 * this.flag);
this.elem.style.opacity = value / 100;
this.elem.style.filter = 'alpha(opacity=' + value + ')';
this.alpha = value
}
}
}
}();
this is how to use it
fadeEffect.init('fade', 1, 50) // fade in the "fade" element to 50% transparency
fadeEffect.init('fade', 1) // fade out the "fade" element
Much shorter answer:
HTML:
<div class="js-slideshow">
<img src="[your/image/path]">
<img src="[your/image/path]" class="is-shown">
<img src="[your/image/path]">
</div>
Javascript:
setInterval(function(){
var $container = $('.js-slideshow'),
$currentImage = $container.find('.is-shown'),
currentImageIndex = $currentImage.index() + 1,
imagesLength = $container.find('img').length;
$currentImage.removeClass('is-shown');
$currentImage.next('img').addClass('is-shown');
if ( currentImageIndex == imagesLength ) {
$container.find('img').first().addClass('is-shown');
}
}, 5000)
SCSS
.promo-banner {
height: 300px;
width: 100%;
overflow: hidden;
position: relative;
img {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
z-index: -10;
transition: all 800ms;
&.is-shown {
transition: all 800ms;
opacity: 1;
z-index: 10;
}
}
}
Here is the website with the game/source code and want to try and see if i can pause a block as it falls when i left click it with my mouse but not sure the proper function for it. ( https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/By_example/Raining_rectangles )
You must clearTimeout() to make it paused, I have implemented a toggle on click of box i.e play/pause.
(function() {
"use strict"
window.addEventListener("load", setupAnimation, false);
var gl,
timer,
rainingRect,
scoreDisplay,
missesDisplay,
status,
paused = false;
function setupAnimation(evt) {
window.removeEventListener(evt.type, setupAnimation, false);
if (!(gl = getRenderingContext()))
return;
gl.enable(gl.SCISSOR_TEST);
rainingRect = new Rectangle();
timer = setTimeout(drawAnimation, 17);
document.querySelector("canvas")
.addEventListener("click", playerClick, false);
var displays = document.querySelectorAll("strong");
scoreDisplay = displays[0];
missesDisplay = displays[1];
status = displays[2];
}
var score = 0,
misses = 0;
function drawAnimation() {
gl.scissor(rainingRect.position[0], rainingRect.position[1],
rainingRect.size[0], rainingRect.size[1]);
gl.clear(gl.COLOR_BUFFER_BIT);
rainingRect.position[1] -= rainingRect.velocity;
if (rainingRect.position[1] < 0) {
misses += 1;
missesDisplay.innerHTML = misses;
rainingRect = new Rectangle();
}
// We are using setTimeout for animation. So we reschedule
// the timeout to call drawAnimation again in 17ms.
// Otherwise we won't get any animation.
timer = setTimeout(drawAnimation, 17);
}
function playerClick(evt) {
// We need to transform the position of the click event from
// window coordinates to relative position inside the canvas.
// In addition we need to remember that vertical position in
// WebGL increases from bottom to top, unlike in the browser
// window.
var position = [
evt.pageX - evt.target.offsetLeft,
gl.drawingBufferHeight - (evt.pageY - evt.target.offsetTop),
];
// if the click falls inside the rectangle, we caught it.
// Increment score and create a new rectangle.
var diffPos = [position[0] - rainingRect.position[0],
position[1] - rainingRect.position[1]
];
if (diffPos[0] >= 0 && diffPos[0] < rainingRect.size[0] &&
diffPos[1] >= 0 && diffPos[1] < rainingRect.size[1]) {
score += 1;
scoreDisplay.innerHTML = score;
// rainingRect = new Rectangle();
if (!paused) {
clearTimeout(timer)
paused = true;
status.innerHTML = 'Paused';
} else {
timer = setTimeout(drawAnimation, 17);
paused = false;
status.innerHTML = 'Playing';
}
}
}
function Rectangle() {
// Keeping a reference to the new Rectangle object, rather
// than using the confusing this keyword.
var rect = this;
// We get three random numbers and use them for new rectangle
// size and position. For each we use a different number,
// because we want horizontal size, vertical size and
// position to be determined independently.
var randNums = getRandomVector();
rect.size = [
5 + 120 * randNums[0],
5 + 120 * randNums[1]
];
rect.position = [
randNums[2] * (gl.drawingBufferWidth - rect.size[0]),
gl.drawingBufferHeight
];
rect.velocity = 1.0 + 6.0 * Math.random();
rect.color = getRandomVector();
gl.clearColor(rect.color[0], rect.color[1], rect.color[2], 1.0);
function getRandomVector() {
return [Math.random(), Math.random(), Math.random()];
}
}
function getRenderingContext() {
var canvas = document.querySelector("canvas");
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
var gl = canvas.getContext("webgl") ||
canvas.getContext("experimental-webgl");
if (!gl) {
var paragraph = document.querySelector("p");
paragraph.innerHTML = "Failed to get WebGL context." +
"Your browser or device may not support WebGL.";
return null;
}
gl.viewport(0, 0,
gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
return gl;
}
})();
<style>
body {
text-align: center;
}
canvas {
display: block;
width: 280px;
height: 210px;
margin: auto;
padding: 0;
border: none;
background-color: black;
}
button {
display: block;
font-size: inherit;
margin: auto;
padding: 0.6em;
}
</style>
<p>You caught
<strong>0</strong>.
You missed
<strong>0</strong>
Status
<strong>Playing</strong>.</p>
<canvas>Your browser does not seem to support
HTML5 canvas.</canvas>
As you can see in the code the function drawAnimation() is calling itself every 17ms using setTimeout() JavaScript function (and this is what creates steady animation).
function drawAnimation() {
.
.
.
timer = setTimeout(drawAnimation, 17);
}
In order to pause/stop the animation you would need to use JavaScript function clearTimeout(timer). Since you want to stop/pause the animation on click event you could just reuse the function playerClick (evt) { ... } from the code you already have and put the function clearTimeout(timer) there.
function playerClick (evt) {
.
.
.
clearTimeout(timer);
}
If you want to be able to continue with animation after you have paused it you'll need to implement some switch-logic (pause if it is already playing, play if it is already paused) inside your function playerClick (evt) or to use timers to continue the animation after some time, for example.
I'm trying to make an image that moves to the right on my website. When you click the image, it should move to the left. For now, this doesn't happen, any ideas? If possible, in pure Javascript and no Jquery ;)
Also, if you click the image for a second time, it should move to the right again. Every consecutive time, the image should move to the other side. I guess this would be best with a for-loop?
<script type"text/javascript">
window.onload = init;
var winWidth = window.innerWidth - movingblockobject.scrollWidth; //get width of window
var movingblock = null //object
movingblock.onclick = moveBlockLeft();
function init() {
movingblock = document.getElementById('movingblockobject'); //get object
movingblock.style.left = '0px'; //initial position
moveBlockRight(); //start animiation
}
function moveBlockRight() {
if (parseInt(movingblock.style.left) < winWidth) { // stop function if element touches max window width
movingblock.style.left = parseInt(movingblock.style.left) + 10 + 'px'; //move right by 10px
setTimeout(moveBlockRight,20); //call moveBlockRight in 20 msec
} else {
return;
}
}
function moveBlockLeft () {
movingblock.style.right = parseInt(movingblock.style.right) + 10 + 'px'
}
</script>
Please first go through the Basics of javascript before trying out something .
window.onload = init;
var winWidth = window.innerWidth;
var movingblock = null;
var intervalid = null;
var isLeft = false;
function init() {
console.log('Init');
movingblock = document.getElementById('movingblockobject');
movingblock.style.left = '0px';
intervalid = setInterval(function() {
moveBlock(true);
}, 2000);
movingblock.onclick = function() {
moveBlock(false);
};
}
function moveBlock(isSetInterval) {
if (!isSetInterval)
isLeft = !isLeft;
if (parseInt(movingblock.style.left) < winWidth) {
if (isLeft)
movingblock.style.left = parseInt(movingblock.style.left) - 10 + 'px';
else
movingblock.style.left = parseInt(movingblock.style.left) + 10 + 'px';
} else {
movingblock.style.left = '0px';
}
}
function moveBlockLeft() {
clearInterval(intervalid);
movingblock.style.right = parseInt(movingblock.style.right) + 10 + 'px';
intervalid = setInterval(moveBlockRight, 20);
}
<div id="movingblockobject" style="width:50px;height:50px;border:solid;position: absolute;">
var movingblock = null
this are mistakes you have delclared it as null and next line you are binding click event.Also for assigning click event you should assign the name of the function.
movingblock.onclick = moveBlockLeft;
above is basic bug there are lot like the above.I feel Self learning is much better for basics
try yourself.
try the above it will work but please try yourself
You should CSS3 transition, works like a charm. Just toggle a class "right"
HTML:
<html>
<head>
<style>
#movingblockobject{
width: 40px;
padding: 10px;
position: fixed;
height:10px;
left:0px;
-webkit-transition: left 2s; /* For Safari 3.1 to 6.0 */
transition: left 2s;
}
#movingblockobject.right{
left:200px;
}
</style>
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script>
$( document ).ready(function() {
$('#movingblockobject').on('click', function (e) {
$('#movingblockobject').toggleClass("right");
});
});
</script>
</head>
<body>
<div id="movingblockobject" class="demo">add image here</div>
</body>
</html>
The following code has me confused. My goal is to fade an HTML element from one opacity level to another, over a period of time. Below is my dimScreen() method, used to create a darkened overlay and fade it in.
var overlay;
function dimScreen()
{
if(!overlay)
{
overlay = document.createElement('div');
overlay.setAttribute('id', 'overlay');
overlay.style.width = '100%';
overlay.style.height = '100%';
overlay.style.zindex = '1000';
overlay.style.background = '#000013';
overlay.style.position = 'fixed';
overlay.style.left = '0';
overlay.style.top = '0';
overlay.style.opacity = '.0';
document.body.appendChild(overlay);
fade('overlay', 0, 75, 200);
}
}
Here is my working fade function:
function fade(eID, startOpacity, stopOpacity, duration)
{
var speed = Math.round(duration / 100);
var timer = 0;
if (startOpacity < stopOpacity)
{ // fade in
for (var i=startOpacity; i<=stopOpacity; i++)
{
setTimeout("setOpacity('"+eID+"',"+i+")", timer * speed);
timer++;
} return;
}
for (var i=startOpacity; i>=stopOpacity; i--)
{ // fade out
setTimeout("setOpacity('"+eID+"',"+i+")", timer * speed);
timer++;
}
}
And my working setOpacity:
function setOpacity(eID, opacityLevel)
{
var eStyle = document.getElementById(eID).style;
eStyle.opacity = opacityLevel / 100;
eStyle.filter = 'alpha(opacity='+opacityLevel+')';
}
I would like to, however, change my fade() function to user a closure in the form of:
setTimeout(function(){setOpacity(eID,i)}, timer * speed);
I could then pass in the actual overlay div, instead of the id 'overlay'. When I do this, however, rather than animating a gradual fade-in of the overlay div, it just goes right to the last opacity value with no transition. Why does this happen?
I have a feeling this is something simple that I am missing because I've been looking at it for so long. Any help would be appreciated!
It's too late and still too hot to think much here right now. (2.30am, 28°C)
Forgive me if my explanation falls short of expectations.
Basically, because you construct text strings to pass to setTimeout, each call gets the correct value for i. Since to pass an actual element, you can't use the string trick, you end up using the same value of i for each call to setOpacity.
As your question title indicates you understand, you need to use closures to get it to work right. I can't find(only followed 2 or 3 links) a good tute/S.O question that explains it in a way that seems relevant and clear.
Hope the code will be of use.
var overlay;
function dimScreen()
{
if(!overlay)
{
overlay = document.createElement('div');
overlay.setAttribute('id', 'overlay');
overlay.style.width = '100%';
overlay.style.height = '100%';
overlay.style.zindex = '1000';
overlay.style.background = '#000013';
overlay.style.position = 'fixed';
overlay.style.left = '0';
overlay.style.top = '0';
overlay.style.opacity = '.0';
document.body.appendChild(overlay);
myFade(overlay, 0, 75, 2000);
}
}
function myFade(element, startOpacity, stopOpacity, duration)
{
var speed = Math.round(duration / 100);
var timer = 0;
if (startOpacity < stopOpacity)
{ // fade in
for (var i=startOpacity; i<=stopOpacity; i++)
{
(
function()
{
var myI = i;
setTimeout(function(){mySetOpacity(element,myI)}, timer * speed);
}
)()
timer++;
}
}
else
for (var i=startOpacity; i>=stopOpacity; i--)
{ // fade out
for (var i=startOpacity; i<=stopOpacity; i++)
{
(
function()
{
var myI = i;
setTimeout(function(){mySetOpacity(element,myI)}, timer * speed);
}
)()
timer++;
}
}
}
function mySetOpacity(el, opacityLevel)
{
var eStyle = el.style;
eStyle.opacity = opacityLevel / 100;
eStyle.filter = 'alpha(opacity='+opacityLevel+')';
}
I've built a very basic jQuery plugin that essentially positions a sprite image left by a set amount every x milliseconds to create an animation effect. The plugin at this stage is very basic and only has a few options, and it works pretty well.
Apart from that fact that it only fires once! I have multiple instance of the animation on one page and they all fire, but only ever once each.
Now I'm not expert on Javascript and only just managed to cobble this together but here's the code anyhow:
// Animation Plugin
(function($){
$.fn.anime = function(customOptions) {
// Default Options
var defaultOptions = {
slideWidth : 100,
frames : 10,
speed : 40,
minCycles : 1,
stopFrame : 0
};
// Set options to default
var options = defaultOptions;
// Merge custom options with defaults using the setOptions func
setOptions(customOptions);
// Merge current options with the custom option
function setOptions(customOptions) {
options = $.extend(options, customOptions);
};
return this.each(function() {
// Initialize the animation object
var $elem = $('img', this);
var frameCount = 0;
var currentSlideWidth = options.slideWidth;
var intervalID = null;
var cycleCount = 1;
var animate = function() {
if (frameCount < (options.frames -1)) {
$elem.css('left', '-' + currentSlideWidth + 'px');
frameCount++;
currentSlideWidth += options.slideWidth;
}
else {
if (cycleCount < options.minCycles)
{
frameCount = 0;
currentSlideWidth = options.slideWidth;
$elem.css('left', '-' + currentSlideWidth + 'px');
cycleCount++;
}
else
{
window.clearInterval(intervalID);
$elem.css('left', '0px');
}
}
cycleCount = 1;
};
$(this).bind('mouseover', function(){
var intervalID = window.setInterval(animate, options.speed);
});
});
};
})(jQuery);
The code used to call the actual plugin on a dom element is:
$('#animeBolt').anime({
frames: 50,
slideWidth: 62,
minCycles: 1,
speed: 30,
});
This is the html it is called on:
<div class="anime" id="animeBolt">
<img src="_assets/img/anime-bolt.png" alt="Lightning Bolt" width="3100" height="114">
</div>
And finally the css:
.anime {
position: absolute;
overflow: hidden; }
.anime img {
position: absolute;
left: 0;
top: 0; }
#animeBolt {
top: 2669px;
left: 634px;
width: 62px;
height: 116px; }
How do I get the plugin to fire repeatedly?
I've created and modified jsfiddle example using your code. It's working http://jsfiddle.net/9Yz9j/16/
I've change a couple of things:
added clearInterval on mouseover to preven multiple overlapping intervals
moved intervalID variable to outside of each function, and removed var keyword from mousover handler so the script will remember intervalID set on last mouseover
reseting the frameCount, cycleCount and currentSlideWidth variables on animation end (that was actually a clue thing to get animation going more than just once)
Hope that helps