As the title says, it works perfectly fine on Chrome. But in Safari, it just sets the page to the desired top and and left position. Is this the expected behaviour? Is there a way to make it work nicely?
Use smoothscroll polyfill (solution for all browsers), easy applicable and lightweight dependency:
https://github.com/iamdustan/smoothscroll
Once you install it via npm or yarn, add it to your main .js, .ts file (one which executes first)
import smoothscroll from 'smoothscroll-polyfill';
// or if linting/typescript complains
import * as smoothscroll from 'smoothscroll-polyfill';
// kick off the polyfill!
smoothscroll.polyfill();
Behavior options aren't fully supported in IE/Edge/Safari, so you'd have to implement something on your own. I believe jQuery has something already, but if you're not using jQuery, here's a pure JavaScript implementation:
function SmoothVerticalScrolling(e, time, where) {
var eTop = e.getBoundingClientRect().top;
var eAmt = eTop / 100;
var curTime = 0;
while (curTime <= time) {
window.setTimeout(SVS_B, curTime, eAmt, where);
curTime += time / 100;
}
}
function SVS_B(eAmt, where) {
if(where == "center" || where == "")
window.scrollBy(0, eAmt / 2);
if (where == "top")
window.scrollBy(0, eAmt);
}
And if you need horizontal scrolling:
function SmoothHorizontalScrolling(e, time, amount, start) {
var eAmt = amount / 100;
var curTime = 0;
var scrollCounter = 0;
while (curTime <= time) {
window.setTimeout(SHS_B, curTime, e, scrollCounter, eAmt, start);
curTime += time / 100;
scrollCounter++;
}
}
function SHS_B(e, sc, eAmt, start) {
e.scrollLeft = (eAmt * sc) + start;
}
And an example call is:
SmoothVerticalScrolling(myelement, 275, "center");
For a more comprehensive list of methods for smooth scrolling, see my answer here.
window.requestAnimationFrame can be used to perform smooth scrolling in an exact amount of time.
For smooth vertical scrolling, the following function can be used. Note that horizontal scrolling can be done in much the same manner.
/*
#param time: the exact amount of time the scrolling will take (in milliseconds)
#param pos: the y-position to scroll to (in pixels)
*/
function scrollToSmoothly(pos, time) {
var currentPos = window.pageYOffset;
var start = null;
if(time == null) time = 500;
pos = +pos, time = +time;
window.requestAnimationFrame(function step(currentTime) {
start = !start ? currentTime : start;
var progress = currentTime - start;
if (currentPos < pos) {
window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos);
} else {
window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time));
}
if (progress < time) {
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
});
}
Demo:
/*
#param time: the exact amount of time the scrolling will take (in milliseconds)
#param pos: the y-position to scroll to (in pixels)
*/
function scrollToSmoothly(pos, time) {
var currentPos = window.pageYOffset;
var start = null;
if(time == null) time = 500;
pos = +pos, time = +time;
window.requestAnimationFrame(function step(currentTime) {
start = !start ? currentTime : start;
var progress = currentTime - start;
if (currentPos < pos) {
window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos);
} else {
window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time));
}
if (progress < time) {
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
});
}
document.querySelector('button').addEventListener('click', function(e){
scrollToSmoothly(500, 1500);
});
html, body {
height: 1000px;
}
<button>Scroll to y-position 500px in 1500ms</button>
For more complex cases, the SmoothScroll.js library can be used, which handles smooth scrolling both vertically and horizontally, scrolling inside other container elements, different easing behaviors, scrolling relatively from the current position, and more. It also supports most browsers that do not have native smooth scrolling.
var easings = document.getElementById("easings");
for(var key in smoothScroll.easing){
if(smoothScroll.easing.hasOwnProperty(key)){
var option = document.createElement('option');
option.text = option.value = key;
easings.add(option);
}
}
document.getElementById('to-bottom').addEventListener('click', function(e){
smoothScroll({yPos: 'end', easing: easings.value, duration: 2000});
});
document.getElementById('to-top').addEventListener('click', function(e){
smoothScroll({yPos: 'start', easing: easings.value, duration: 2000});
});
<script src="https://cdn.jsdelivr.net/gh/LieutenantPeacock/SmoothScroll#1.2.0/src/smoothscroll.min.js" integrity="sha384-UdJHYJK9eDBy7vML0TvJGlCpvrJhCuOPGTc7tHbA+jHEgCgjWpPbmMvmd/2bzdXU" crossorigin="anonymous"></script>
<!-- Taken from one of the library examples -->
Easing: <select id="easings"></select>
<button id="to-bottom">Scroll To Bottom</button>
<br>
<button id="to-top" style="margin-top: 5000px;">Scroll To Top</button>
The workarounds above all make up for the lack of Safari support for behaviors.
It's still necessary to detect when a workaround is needed.
This little function will detect if smooth scrolling is supported by the browser. It returns false on Safari, true on Chrome and Firefox:
// returns true if browser supports smooth scrolling
const supportsSmoothScrolling = () => {
const body = document.body;
const scrollSave = body.style.scrollBehavior;
body.style.scrollBehavior = 'smooth';
const hasSmooth = getComputedStyle(body).scrollBehavior === 'smooth';
body.style.scrollBehavior = scrollSave;
return hasSmooth;
};
const pre = document.querySelector('pre');
// returns true if browser supports smooth scrolling
const supportsSmoothScrolling = () => {
const body = document.body;
const scrollSave = body.style.scrollBehavior;
body.style.scrollBehavior = 'smooth';
const hasSmooth = getComputedStyle(body).scrollBehavior === 'smooth';
body.style.scrollBehavior = scrollSave;
return hasSmooth;
};
const supported = supportsSmoothScrolling();
pre.innerHTML = `supported: ${ (supported) ? 'true' : 'false'}`;
<h3>
Testing if 'scrollBehavior smooth' is supported
</h3>
<pre></pre>
Update
Test of Safari Technology Preview, Release 139 (Safari 15.4) shows support for scrollBehavior smooth, so we may expect to see support in 15.4.
The solution with the smoothest performance, especially if you want to incorporate easing is to use requestAnimationFrame:
const requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
const step = (timestamp) => {
window.scrollBy(
0,
1, // or whatever INTEGER you want (this controls the speed)
);
requestAnimationFrame(step);
};
requestAnimationFrame(step);
if you want to later cancel the scroll, you need to have a reference to your requestAnimationFrame (do this everywhere you use requestAnimationFrame(step)):
this.myRequestAnimationFrame = requestAnimationFrame(step);
const cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
cancelAnimationFrame(this.myRequestAnimationFrame);
Now what if you want to use easing with your scroll and take timeouts between scroll actions?
create an array of 60 elements (requestAnimationFrame usually calls 60 times per second. It's technically whatever the refresh rate of the browser is, but 60 is the most common number.) We are going to fill this array non-linearly then use those numbers to control how much to scroll at each step of requestAnimationFrame:
let easingPoints = new Array(60).fill(0)
choose an easing function. Let's say we're doing a cubic ease-out:
function easeCubicOut(t) {
return --t * t * t + 1;
}
create a dummy array and fill it with data piped through the easing function. You'll see why we need this in a moment:
// easing function will take care of decrementing t at each call (too lazy to test it at the moment. If it doesn't, just pass it a decrementing value at each call)
let t = 60;
const dummyPoints = new Array(60).fill(0).map(()=> easeCubicOut(t));
const dummyPointsSum = dummyPoints.reduce((a, el) => {
a += el;
return a;
}, 0);
map easingPoints using the help of each dummyPoint ratio to dummyPointsSum:
easingPoints = easingPoints.map((el, i) => {
return Math.round(MY_SCROLL_DISTANCE * dummyPoints[i] / dummyPointsSum);
});
in your scroll function, we'll make a few adjustments:
const requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
let i = 0;
const step = (timestamp) => {
window.scrollBy(
0,
easingPoints[i],
);
if (++i === 60) {
i = 0;
return setTimeout(() => {
this.myRequestAnimationFrame = requestAnimationFrame(step);
}, YOUR_TIMEOUT_HERE);
}
};
this.myRequestAnimationFrame = requestAnimationFrame(step);
A simple jQuery fix that works for Safari:
$('a[href*="#"]').not('[href="#"]').not('[href="#0"]').click(function (t) {
if (location.pathname.replace(/^\//, "") == this.pathname.replace(/^\//, "") && location.hostname == this.hostname) {
var e = $(this.hash);
e = e.length ? e : $("[name=" + this.hash.slice(1) + "]"), e.length && (t.preventDefault(), $("html, body").animate({
scrollTop: e.offset().top
}, 600, function () {
var t = $(e);
if (t.focus(), t.is(":focus")) return !1;
t.attr("tabindex", "-1"), t.focus()
}))
}
});
Combining the answers of George Daniel and terrymorse, the following can be used for all the browser's support using native JavaScript.
As, Chrome, Firefox supports CSS, scroll-behavior: smooth; for the browsers which don't support this property, we can add below.
HTML:
<a onclick="scrollToSection(event)" href="#section">
Redirect On section
</a>
<section id="section">
Section Content
</section>
CSS:
body {
scroll-behavior: smooth;
}
JavaScript:
function scrollToSection(event) {
if (supportsSmoothScrolling()) {
return;
}
event.preventDefault();
const scrollToElem = document.getElementById("section");
SmoothVerticalScrolling(scrollToElem, 300, "top");
}
function supportsSmoothScrolling() {
const body = document.body;
const scrollSave = body.style.scrollBehavior;
body.style.scrollBehavior = 'smooth';
const hasSmooth = getComputedStyle(body).scrollBehavior === 'smooth';
body.style.scrollBehavior = scrollSave;
return hasSmooth;
};
function SmoothVerticalScrolling(element, time, position) {
var eTop = element.getBoundingClientRect().top;
var eAmt = eTop / 100;
var curTime = 0;
while (curTime <= time) {
window.setTimeout(SVS_B, curTime, eAmt, position);
curTime += time / 100;
}
}
function SVS_B(eAmt, position) {
if (position == "center" || position == "")
window.scrollBy(0, eAmt / 2);
if (position == "top")
window.scrollBy(0, eAmt);
}
Another possible solution with an "ease-out" effect.
Inspired by some of the answers given earlier,
a key difference is in using "pace" instead of specifying a duration, I found that calculating the length of each step based on a fixed pace creates a smooth "ease-out" effect as the number of steps increases as the scroll approaches the destination point.
Hopefully the code below is easy to understand.
function smoothScrollTo(destination) {
//check if browser supports smooth scroll
if (window.CSS.supports('scroll-behavior', 'smooth')) {
window.scrollTo({ top: destination, behavior: 'smooth' });
} else {
const pace = 200;
let prevTimestamp = performance.now();
let currentPos = window.scrollY;
// #param: timestamp is a "DOMHightResTimeStamp", check on MDN
function step(timestamp) {
let remainingDistance = currentPos < destination ? destination - currentPos : currentPos - destination;
let stepDuration = timestamp - prevTimestamp;
let numOfSteps = pace / stepDuration;
let stepLength = remainingDistance / numOfSteps;
currentPos = currentPos < destination ? currentPos + stepLength : currentPos - stepLength;
window.scrollTo({ top: currentPos });
prevTimestamp = timestamp;
if (Math.floor(remainingDistance) >= 1) window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
}
}
This is my first contribution on SO after years of benefiting from this great community. Constructive criticism is highly appreciated.
Thanks to T.Dayya, I had combined few answers on that topic and here is ts module with
extension function scrollSmoothIntoView.
export default {}
declare global {
interface Element {
scrollSmoothIntoView(): void;
}
}
Element.prototype.scrollSmoothIntoView = function()
{
const t = 45;
const tstep = 6.425/t;
const dummyPoints = new Array(t).fill(0).map((t, i) => circ(i * tstep));
const dummyPointsSum = dummyPoints.reduce((a, el) => { a += el; return a;}, 0);
const _window: any = window;
const _elem: any = getScrollParent(this);
const scroll_distance: any = (this as any).offsetTop - (!_elem.parentElement ? _window.scrollY : 0);
let easingPoints = new Array(t).fill(0)
easingPoints = easingPoints.map((el, i) => {
return Math.round(scroll_distance * dummyPoints[i] / dummyPointsSum);
});
const requestAnimationFrame = _window.requestAnimationFrame ||
_window.mozRequestAnimationFrame ||
_window.webkitRequestAnimationFrame ||
_window.msRequestAnimationFrame;
let i = 0;
const step = (timestamp:any) => {
_elem.scrollBy(0, easingPoints[i]);
if (++i < t)
setTimeout(() => { requestAnimationFrame(step) }, 2);
};
window.requestAnimationFrame(()=>requestAnimationFrame(step));
}
function getScrollParent(element: any, includeHidden?: any):any {
var style = getComputedStyle(element);
var excludeStaticParent = style.position === "absolute";
var overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;
if (style.position === "fixed") return document.body;
for (var parent = element; (parent = parent.parentElement);) {
style = getComputedStyle(parent);
if (excludeStaticParent && style.position === "static") {
continue;
}
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent;
}
return document.body;
}
function circ(t:any) {
return 1+Math.cos(3+t);
}
Using html_element.scrollSmoothIntoView().
I am trying to make an image to fade out and then in. The problem is that when I use two functions, the image doesn't fade out but it immediately disappears. Is there anyone with amazing JavaScript skills to solve my problem?
Please do not tell me about jQuery because I already know how to do it using it, I only need to improve my JavaScript skills.
PS: I need also to understand why it doesn't work and how to make it work with as much details please.
Here is my code:
var el = document.getElementById("img1");
el.addEventListener("click", function() {
function fadeOut() {
el.style.opacity = 1;
function fade(){
var val = el.style.opacity;
if ((val -= .01) > 0){
el.style.opacity = val;
requestAnimationFrame(fade);
}
}
fade();
};
function fadeIn() {
el.style.opacity = 0;
function fade1() {
var val = el.style.opacity;
if ((val += .01) < 1){
el.style.opacity = val;
requestAnimationFrame(fade1);
}
}
fade1();
};
fadeIn();
fadeOut();
});
Thank you!
Still not the prettiest, but I have made just the minimum changes to your code to make it work: http://codepen.io/rlouie/pen/BzjZmK
First, you're assigning the opacity value back and forth repeatedly for no reason, which makes the code confusing to follow and also results in string concatenation instead of addition or subtraction, I have simplified this. Second, the functions were named the opposite of what they did, also confusing and fixed by me here. Finally, you ran both functions one after the other, so the second function set opacity to zero and then broke. Instead, I use a promise in your first function and resolve it when the animation completes.
That way the second function does not run until after the first one has completed animating.
var el = document.getElementById("img1");
el.addEventListener("click", function() {
function fadeOut() {
return new Promise(function (resolve, reject) {
let opacity = 1;
function fade(){
if ((opacity -= .01) > 0){
el.style.opacity = opacity;
requestAnimationFrame(fade);
} else {
resolve();
}
}
fade();
});
};
function fadeIn() {
let opacity = 0;
function fade1() {
if ((opacity += .01) < 1){
el.style.opacity = opacity;
requestAnimationFrame(fade1);
}
}
fade1();
};
fadeOut().then(fadeIn);
});
My proposal is:
start animation with fadein
when fadein finishes start the fadeout
var el = null;
function fadeIn(timestamp) {
var val = (+el.style.opacity == 0) ? 1 : +el.style.opacity;
if ((val -= .005) > 0) {
el.style.opacity = val;
window.requestAnimationFrame(fadeIn);
} else {
window.requestAnimationFrame(fadeOut);
}
}
function fadeOut(timestamp) {
var val = (+el.style.opacity == 0) ? 1 : +el.style.opacity;
if ((val += .005) < 1) {
el.style.opacity = val;
window.requestAnimationFrame(fadeOut);
}
};
window.onload = function () {
el = document.getElementById('img1');
el.addEventListener('click', function(e) {
window.requestAnimationFrame(fadeIn);
});
}
<img id="img1" src="http://www.loc.gov/pictures/static/data/highsm/banner.jpg">
Voor de fade in:
Function FadeIn() {
var milli = 3000; //duration
el = yourelement;
el.style.opacity = 1;
var a = 1 / (milli / 1000 * 16); //the -x
FadeIn_loop(a);
}
Function FadeIn_loop(a) {
if (el.style.opacity > 0.01) {
el.style.opacity = el.style.opacity - a;
setTimeout("FadeIn(" + el + ")", 16); //about 1/60 a second
} else {
el.style.opacity = 0;
}
}
Same thing for fade out, succes!
In your code are many things that does'nt seem to be right. First of get all those functions out of each other otherwise requestAnimationframe cant find the functions.
var depth = 0;
var moving = false;
var answers = new Array();
var qNo = 0;
var rangeCarousel;
var productCarousel;
var ih, iw, orient;
var sidebarOpen = false;
var focused = "range";
var currentRange = 0;
$(document).ready(function () {
document.getElementById('intro').addEventListener('click', clickHandler);
document.getElementById('q1').addEventListener('click', clickHandler);
document.getElementById('q2').addEventListener('click', clickHandler);
document.getElementById('q3').addEventListener('click', clickHandler);
document.getElementById('q4').addEventListener('click', clickHandler);
document.getElementById('intro').addEventListener('webkitTransitionEnd', transitionEnd);
document.getElementById('intro').addEventListener('transitionend', transitionEnd);
document.getElementById('intro').addEventListener('transition', transitionEnd);
});
function clickHandler(e) {
if ((qNo < 4) && (e.target.id != 'intro')) {
qNo++;
if (!moving) {
depth -= 100;
document.getElementById('intro').style.top = (depth + '%');
document.getElementById('q1').style.top = (depth + '%');
document.getElementById('q2').style.top = (depth + '%');
document.getElementById('q3').style.top = (depth + '%');
document.getElementById('q4').style.top = (depth + '%');
moving = true;
}
} else if (qNo == 4) {
var c = e.target.parentNode.classList[0];
switch (c) {
case 'one':
window.open("test.html","_self");
break;
case 'two':
window.open("test.html","_self");
break;
case 'three':
window.open("test.html","_self");
break;
case 'four':
window.open("test.html","_self");
break;
}
}
}
function transitionEnd() {
moving = false;
}
i m trying to create a quiz where users clicks on the images then loads the answer. It works fine on ie11 but i also need to make it work on ie10. I cant see any errors or anything to show me whats wrong
Any help or suggestion will be great
Some old IE does not support target property. You can use e.srcElement which is an alias of target as an alias of target
((e.target || e.srcElement).id) === "intro"
& also use it to find the parentNode
Side Note :As mentioned in comment section you can use jquery as which will also reduce the number of lines in your code beside efficiently handling events
You can also use jquery multiple selector instead of writing same lines of code for attaching event to every selector.
$('sel1 ,selector2 , selector 3 ...').click(function(event){.. rest of code})
I have a fade in function im trying to understand better. It works fine when I set up the
My question is if I have 8 links that already have the separate ID and class names how can I attach this function to each clickable link?
Is there a function to getElementbyClass or something and then just add the class to all my links?
here is my javascript:
var done = true,
fading_div = document.getElementById('fading_div'),
fade_in_button = document.getElementById('fade_in'),
fade_out_button = document.getElementById('fade_out');
function function_opacity(opacity_value) {
fading_div.style.opacity = opacity_value / 100;
fading_div.style.filter = 'alpha(opacity=' + opacity_value + ')';
}
function function_fade_out(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'none';
done = true;
}
}
function function_fade_in(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'block';
}
if (opacity_value == 100) {
done = true;
}
}
// fade in button
fade_in_button.onclick = function () {
if (done && fading_div.style.opacity !== '1') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_in(x)
};
})(i), i * 10);
}
}
};
// fade out button
fade_out_button.onclick = function () {
if (done && fading_div.style.opacity !== '0') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_out(x)
};
})(100 - i), i * 10);
}
}
};
Correcting the answer from BLiu1:
var fadeDivs = document.getElementsByClassName('fade');
for (var i=0, i<fadeDivs.length, i++){
// do stuff to all fade-divs by accessing them with "fadeDivs[i].something"
}
Have you considered using a javascript library like jQuery to manage this. They have some extensive, very easy to use "selectors" that allow you to easily get access to elements in the DOM and animate them with things like "fade ins" and "slides", etc. If you need more animations there are tons of plugins available for this. It also helps to deal with browser compatibility challenges too.
If you want to rely on pure JavaScript, you can use the document.getElementsByClassName() function defined here, but that function is only defined in IE9 and above as well as Safari, Chrome, FF, and Opera.
As said in the comments, there is a getElementsByClassName() method. Here is how you would use it.
for(var i=0; i<document.getElementsByClassName("fade").length; i++ ){
/*apply fade in function*/
}
I'm not sure whether getElementsByClassName() can detect one class name at a time. You might need regex for that.
I am trying to make images that move around the screen that do something when they are clicked. I am using setInterval to call a function to move the images. Each image has the onclick attribute set. The problem is that the clicks are not registering.
If I take out the setInterval and just keep the images still, then the clicks do register.
My code is here (html, css, JavaScript): https://jsfiddle.net/contini/nLc404x7/4/
The JavaScript is copied here:
var smiley_screen_params = {
smiley_size : 100, // needs to agree with width/height from css file
num_smilies: 20
}
var smiley = {
top_position : 0,
left_position : 0,
jump_speed : 2,
h_direction : 1,
v_direction : 1,
intvl_speed : 10, // advance smiley every x milliseconds
id : "smiley"
}
function randomise_direction(s) {
var hd = parseInt(Math.random()*2);
var vd = parseInt(Math.random()*2);
if (hd === 0)
s.h_direction = -1;
if (vd === 0)
s.v_direction = -1;
}
function plotSmiley(sp /* sp = smiley params */) {
var existing_smiley = document.getElementById(sp.id);
if (existing_smiley !== null)
// delete existing smiley so we can move it
document.getElementById("smileybox").removeChild(existing_smiley);
var smiley_to_plot = document.createElement('img');
smiley_to_plot.setAttribute('src', "http://i.imgur.com/C0BiXJx.png");
smiley_to_plot.setAttribute('id', sp.id);
smiley_to_plot.setAttribute('onclick', "my_click_count()");
smiley_to_plot.style.position = 'absolute';
smiley_to_plot.style.top = sp.top_position + "px";
smiley_to_plot.style.left = sp.left_position + "px";
document.getElementById("smileybox").appendChild(smiley_to_plot);
}
function random_direction_change() {
var r = parseInt(Math.random()*200);
if (r===0)
return true;
else
return false;
}
function moveFace(sp_array /* sp_array = smiley params array */) {
var i;
var sp;
for (i=0; i < sp_array.length; ++i) {
// move ith element
sp = sp_array[i];
if (
(sp.h_direction > 0 && sp.left_position >= smiley_screen_params.width - smiley_screen_params.smiley_size) ||
(sp.h_direction < 0 && sp.left_position <= 0) ||
(random_direction_change())
) {
sp.h_direction = -sp.h_direction; // hit left/right, bounce off (or random direction change)
}
if (
(sp.v_direction > 0 && sp.top_position >= smiley_screen_params.height - smiley_screen_params.smiley_size) ||
(sp.v_direction < 0 && sp.top_position <= 0) ||
(random_direction_change())
) {
sp.v_direction = -sp.v_direction; // hit top/bottom, bounce off (or random direction change)
}
sp.top_position += sp.v_direction * sp.jump_speed;
sp.left_position += sp.h_direction * sp.jump_speed;
plotSmiley(sp);
}
}
if (typeof Object.create !== 'function') {
Object.create = function(o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
function generateFaces() {
var smilies = new Array();
var s;
var i;
var css_smileybox=document.getElementById("smileybox");
var sb_style = getComputedStyle(css_smileybox, null);
// add info to the screen params
smiley_screen_params.width = parseInt(sb_style.width);
smiley_screen_params.height = parseInt(sb_style.height);
// create the smileys
for (i=0; i < smiley_screen_params.num_smilies; ++i) {
s = Object.create(smiley);
s.id = "smiley" + i;
s.top_position = parseInt(Math.random() * (smiley_screen_params.height - smiley_screen_params.smiley_size)),
s.left_position = parseInt(Math.random() * (smiley_screen_params.width - smiley_screen_params.smiley_size)),
randomise_direction(s);
smilies.push(s);
}
setInterval( function(){ moveFace(smilies) }, smiley.intvl_speed );
}
var click_count=0;
function my_click_count() {
++click_count;
document.getElementById("mg").innerHTML = "Number of clicks: " + click_count;
}
generateFaces();
The generateFaces() will generate parameters (for example, coordinates of where they are placed) for a bunch of smiley face images. The setInterval is within this function, and calls the moveFace function to make the smiley faces move at a fixed interval of time. moveFace computes the new coordinates of each smiley face image and then calls plotSmiley to plot each one on the screen in its new location (removing it from the old location). The plotSmiley sets the onclick attribute of each image to call a dummy function just to see if the clicks are registering.
Thanks in advance.
This is not a complete answer but it could give you some perspective to improve your code.
First of all, your idea of deleting the existing img so wrong. If it does exist, all you need is to just change its position so instead of this
if (existing_smiley !== null)
// delete existing smiley so we can move it
document.getElementById("smileybox").removeChild(existing_smiley);
you should do something like this:
if (existing_smiley !== null)
var smiley_to_plot = existing_smiley;
else {
var smiley_to_plot = document.createElement('img');
smiley_to_plot.setAttribute('src', "http://i.imgur.com/C0BiXJx.png");
smiley_to_plot.setAttribute('id', sp.id);
smiley_to_plot.style.position = 'absolute';
document.getElementById("smileybox").appendChild(smiley_to_plot);
smiley_to_plot.addEventListener('click', my_click_count);
}
smiley_to_plot.style.top = sp.top_position + "px";
smiley_to_plot.style.left = sp.left_position + "px";
As you can see new image is only being added if it's not already there. Also notice that adding events by using .setAttribute('onclick', "my_click_count()"); is not a good way to do. You should use .addEventListener('click', my_click_count); like I did.
Like I said this is not a complete answer but at least this way they response to the click events now.
FIDDLE UPDATE
Good luck!