Get the duration of continuous mouse movement - javascript

Track the duration of continuous mouse movements on a webpage. A measurement begins when the cursor starts to move and ends when the cursor has stopped moving on the page. Reporting on duration happens thereafter. THis is what I have and works for while the mouse is moving and while it is stopped. However, I am confused how to track the start time and end time(i.e. the duration period of the mouse moving).
var myDiv = document.getElementById("myDiv");
var timeout;
//var startTime;
document.addEventListener("mousemove", function() {
myDiv.innerHTML = "You are moving";
if (timeout) clearTimeout(timeout);
timeout = setTimeout(mouseStop, 150);
});
function mouseStop() {
myDiv.innerHTML = "Stopped";
//console.log(Math.abs((startTime.getTime() - endTime.getTime())/1000));
}

You can count time on a different timer thread. Once you stop rest the timer.
var myDiv = document.getElementById("myDiv");
var timeout;
var timer = {stopped: true, time: 0};
setInterval(() => {
if (!timer.stopped) {
timer.time++;
}
}, 1000);
document.addEventListener("mousemove", function() {
timer.stopped = false;
myDiv.innerHTML = "You are moving";
if (timeout) clearTimeout(timeout);
timeout = setTimeout(mouseStop, 150);
});
function mouseStop() {
var totalTime = timer.time;
timer = {stopped: true, time: 0};
myDiv.innerHTML = 'Stopped! Total time: ' + totalTime + ' seconds';
}
<div id="myDiv"></div>

Related

When my stopwatch updates with setInterval, it blinks, how to make it smooth?

Hi i made a stopwatch in javascript and every time it updates, it deletes, and then after a second appears again and deletes. So every second it appears and disappears, making it blink. How can i make it appear until the next second updates, making a smooth transition.
Here is my code:
function GameTimer() {
var gameTimeMinutes = 0;
var gameTimeSeconds = 0;
var gameTime = "";
this.addTime = function() {
gameTimeSeconds += 1;
if (gameTimeSeconds < 10) {
gameTime = gameTimeMinutes + " : 0" + gameTimeSeconds;
} else {
gameTime = gameTimeMinutes + " : " + gameTimeSeconds;
}
if (gameTimeSeconds == 60) {
gameTimeSeconds = 0;
gameTimeMinutes++;
}
};
this.draw = function() {
graph.clearRect(0, 0, canvas.width, canvas.height);
var fontSize = 25;
graph.lineWidth = playerConfig.textBorderSize;
graph.fillStyle = playerConfig.textColor;
graph.strokeStyle = playerConfig.textBorder;
graph.miterLimit = 1;
graph.lineJoin = 'round';
graph.textAlign = 'right';
graph.textBaseline = 'middle';
graph.font = 'bold ' + fontSize + 'px sans-serif';
graph.strokeText(gameTime, 100, 30);
graph.fillText(gameTime, 100, 30);
};
this.update = function() {
this.addTime();
this.draw();
}.bind(this);
this.update();
}
var playerConfig = {textBorderSize: "1px", textColor: "black", textBorder: "solid"};
var canvas = document.getElementById("timer");
var graph = canvas.getContext("2d");
var gameTimer = new GameTimer();
setInterval(gameTimer.update, 1000);
<canvas id="timer" width="200" height="100"></canvas>
So just to clarify, i tried changing the interval time to ten seconds, and every ten seconds it appears and disappears, meaning that it is gone for the next ten seconds until it appears and disappears again. It doesn't stay there until the next update.
Thanks!
I believe that the flashing could be a result of setInterval not synchronizing with the screen's refresh rate. If so, requestAnimationFrame may be able to solve this.
This does use unnecessary system resources, but may solve your problem regardless.
Try this:
this.timeUntilUpdate = Date.now();
this.update = function(){
if(Date.now() - this.timeUntilUpdate > 1000){
this.addTime();
this.draw();
}
requestAnimationFrame(this.update);
}
And then at the end replace setInterval(gameTimer.update, 1000); with requestAnimationFrame(GameTimer.update) or possibly just GameTimer.update();

Use JS countdown timer in Canvas with requestAnimationFrame

I'm making a simple canvas- game and I'm using requestAnimationFrame (Paul Irish's version) for the gameloop. I'm using a javascript countdown in the game (showing seconds and 100th of seconds), but it doesn't count down in the right speed. I know this has to do with the refresh- rate of the game, so that the counter updates every frame instead of every 100th second. How do I fix this?
Here's the timer object:
/**
* The timer as an object
*/
function Timer(position, time) {
this.position = position || new Vector(150,210);
this.time = time || 6000;
}
Timer.prototype = {
start: function() {
console.log('start running');
this.initial = this.time; //time in 100'ths of seconds
this.count = this.initial;
this.counter; //10 will run it every 100th of a second
clearInterval(this.counter);
//this.counter = setInterval(this.timer, 10);
this.timer();
},
timer: function() {
//console.log(this.count);
this.count--;
var res = this.count / 100;
//Show counter in canvas
return 'Tid kvar: ' + res.toPrecision(this.count.toString().length) + ' sekunder';
},
draw: function(ct) {
if(this.initial === undefined){this.start();} //Start the timer
ct.save();
if(this.count <=0){ //Remove timer if timer has reached 0
ct.clearRect(this.position.x, this.position.y, Racetrack.innerTrackWidth, Racetrack.innerTrackHeight);
return false;
} else { //draw timer
ct.save();
ct.font = 'bold 3em arial';
ct.fillStyle = 'orange';
ct.fillText(this.timer(), this.position.x, this.position.y);
}
ct.restore();
},
}
And the gameloop and the part calling the timer:
var init = function(canvas) {
timer = new Timer(new Vector(160,210), 3000);
}
var render = function() {
ct.clearRect(0,0,width,height);
ship.draw(ct);
racetrack.draw(ct);
//draw timer or results if timer reached 0
timer.draw(ct) !=false ? timer.draw(ct) : endFrame.draw(ct);
};
var gameLoop = function() {
var now = Date.now();
td = (now - (lastGameTick || now)) / 1000; // Timediff since last frame / gametick
lastGameTick = now;
if(timer.draw(ct) == false) { //stop the game if timer has reached 0.
cancelRequestAnimFrame(gameLoop);
console.log('Time\'s up!');
} else { //Otherwise, keep the game going.
requestAnimFrame(gameLoop);
}
update(td);
render();
};
I've also tried this as timer- object, but debugging this.count shows number the first loop, undefined the second loop and NaN every loop after that (And I'm not sure this will fix the timing issue either way?):
function Timer(position, time) {
this.position = position || new Vector(150,210);
this.time = time || 6000;
}
Timer.prototype = {
start: function() {
console.log('start running');
this.initial = this.time; //time in 100'ths of seconds
this.count = this.initial;
this.counter; //10 will run it every 100th of a second
clearInterval(this.counter);
this.counter = setInterval(this.timer, 10);
this.timer();
},
timer: function() {
console.log(this.count);
this.count--;
},
getTime: function() {
var res = this.count / 100;
return 'Tid kvar: ' + res.toPrecision(this.count.toString().length) + ' sekunder';
},
draw: function(ct) {
if(this.initial === undefined){this.start();} //Start the timer
ct.save();
if(this.count <=0){ //Remove timer if timer has reached 0
ct.clearRect(this.position.x, this.position.y, Racetrack.innerTrackWidth, Racetrack.innerTrackHeight);
return false;
} else { //draw timer
ct.save();
ct.font = 'bold 3em arial';
ct.fillStyle = 'orange';
ct.fillText(this.getTime(), this.position.x, this.position.y);
}
ct.restore();
},
}
Not sure if you are asking to display the time in 1/100 intervals or if the time is inaccurate when using setInterval.
A: setInterval should not be used for timing, as it is far from accurate and gets worse the smaller the interval, and even worse if you have animations running.
B: Browser's refresh at 1/60th of a second. You can force the display to render and present at 1/100 of a second but then depending on the graphics hardware it may never be displayed because the display is scanning pixels elsewhere on the screen at the time. Or you will get shearing when you overwrite the display just as the graphics is being written to the display.
Best way to get a countdown using requestAnimationFrame
var start = true; // flags that you want the countdown to start
var stopIn = 3000; // how long the timer should run
var stopTime = 0; // used to hold the stop time
var stop = false; // flag to indicate that stop time has been reached
var timeTillStop = 0; // holds the display time
// main update function
function update(timer){
if(start){ // do we need to start the timer
stopTime = timer + stopIn; // yes the set the stoptime
start = false; // clear the start flag
}else{ // waiting for stop
if(timer >= stopTime){ // has stop time been reached?
stop = true; // yes the flag to stop
}
}
timeTillStop = stopTime - timer; // for display of time till stop
// log() should be whatever you use to display the time.
log(Math.floor(timeTillStop / 10) ); // to display in 1/100th seconds
if(!stop){
requestAnimationFrame(update); // continue animation until stop
}
}
requestAnimationFrame(update); // start the animation
Forgot to add.
You are never going to get 100th of a second accuracy via that method. You will be on average 7-8 ms out. But unless you make it far more complex that is the best you can do. That 7-8ms average is constant and the same for 2 hours and 1 second and is just determined by the animation refresh time of about 16 odd ms.

The difference between interval animation and requestAnimationFrame

What is the difference between those two? requestAnimationFrame should be "intervaled" or invoked cca every 60milisecond on 60fps (depending on screen) and with setInterval you can set delay interval of invokation of function.
Yet i have made simple drawning animation with both , interval and requestAnimationFrame and it seems that interval function is smoother and work properly, while requestAnimation function broke browser (tested on mozilla/chrome and on 2 Pcs).
interval function:
function animate(x) {
var start = new Date();
var id = setInterval(function () {
var timepassed = new Date() - start;
var progress = timepassed / x.duration;
if (progress > 1) {
progress = 1;
}
var delta = x.delta(progress);
x.step(delta);
if (progress == 1) {
clearInterval(id);
}
}, x.delay);
}
requestAnimationFrame function:
function animate(x) {
var start = new Date();
var id = function () {
var timepassed = new Date() - start;
var progress = timepassed / x.duration;
if (progress > 1) {
progress = 1;
}
var delta = x.delta(progress);
x.step(delta);
requestAnimationFrame(id);
if (progress < 1) {
requestAnimationFrame(id);
}
}
requestAnimationFrame(id)
}
function to do drawning
function move(delta) {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
animate({
delay:10,
duration: 4000,
delta: delta,
step: function (delta) {
ctx.clearRect(0, 0, c.width, c.height);
ctx.beginPath();
ctx.strokeStyle="red";
ctx.lineWidth = 15;
ctx.arc(150, 150, 70, 0*Math.PI, delta*(2 * Math.PI));
ctx.font="40px Georgia";
ctx.fillText((delta*100).toFixed(0)+"%",95,150);
ctx.stroke(); ;
}
});
}
move(function(p){return p});
demo for interval : http://jsfiddle.net/Trolstover/5tmu4j6z/
demo for requestAnimationFrame : http://jsfiddle.net/Trolstover/5tmu4j6z/1
just comment out
//requestAnimationFrame(id);
var timepassed = new Date() - start
see this: http://jsfiddle.net/5tmu4j6z/2/
After you call animate setInterval will run starting at the first interval, while requestAnimation will run before the next repaint of your canvas. The reason requestAnimation runs again is because it's recursive.

I want to repeat a process in jquery

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%;
}

Counting how many seconds a user dragging the mouse

I have a function where the user sort of "scratching" a surface when he drags the mouse over it, reviling content underneath this surface. I want to count how many seconds he dragged the mouse, and when he reaches 5 seconds - do something. If he lets go after, for example, 3 seconds, the count should stop and resume from 3d second when he resumes dragging. I tried to do it with setInterval and add 1 to seconds counter every 1000 ms, but no matter what I've tried - I'm either getting some crazy numbers in the counter or it just stays on 0. Here's my code:
var interval, info;
var totalSeconds = 0;
function init()
{
...more vars declaration and initialization
function scratchOff(x, y)
{
mainctx.save();
mainctx.beginPath();
mainctx.arc(x,y,radius,0,Math.PI*2,false);
mainctx.clip();
mainctx.drawImage(bottomImage, 0, 0);
mainctx.restore();
}
$('#overlay').mousedown(function(e){
isMouseDown = true;
var relX = e.pageX;
var relY = e.pageY;
scratchOff(relX, relY, true);
});
$('#overlay').mousemove(function(e){
var relX = e.pageX;
var relY = e.pageY;
overlayctx.clearRect(0,0,canvasWidth,canvasHeight);
overlayctx.drawImage(coinImage, relX-radius, relY-radius);
if (isMouseDown) {
scratchOff(relX, relY, false);
countSeconds(); // - THIS CALLS FOR THE FUNCTION THAT IS SUPPOSED
// TO COUNT SECONDS ONCE THE USER STARTS DRAGGING THE MOUSE
}
});
$('#overlay').mouseup(function(e){
isMouseDown = false;
clearInterval(interval);
});
var mainctx = $('canvas')[0].getContext('2d');
var radius = 10;
topImage.onload = function(){
mainctx.drawImage(topImage, 0, 0);
};
topImage.src = "images/oie_canvas.png";
}
// THIS IS THE FUNCTION THAT'S SUPPOSED TO COUNT SECONDS
function countSeconds() {
interval = setInterval(function(){
totalSeconds = totalSeconds++;
info.innerHTML = totalSeconds;
if(totalSeconds >= 5) clearInterval(interval);
}, 1000);
}
How can I make it work?
You would start a timer of 1 sec, which monitor your isMouseDown flag and start counting, when you reach 5 sec you go for your action, no need to call the countSeconds every time.
Here is an example:
EDITED
$(function() {
setInterval(function(){
if(isMouseDown) {
totalSeconds++;
}
if(totalSeconds== 5) {
//do your action;
totalSeconds = 0;
}
info.innerHTML = totalSeconds;
}, 1000);
} );
var isMouseDown = false;
function init()
{
... your code
}
EDITED 2
Full Example
var topImage = new Image();
var bottomImage = new Image();
var coinImage = new Image();
bottomImage.src = "http://i58.tinypic.com/2i093ia.jpg";
coinImage.src = "http://i61.tinypic.com/30acmtt.png";
var info;
var interval;
var totalSeconds = 0;
$(function() {
setInterval(function(){
if(isMouseDown) {
totalSeconds++;
}
if(totalSeconds== 5) {
alert("5 sec");
totalSeconds = 0;
}
info.innerHTML = totalSeconds;
}, 1000);
} );
var isMouseDown = false;
function init()
{
var canvasWidth = $('#myCanvas').width();
var canvasHeight = $('#myCanvas').height();
$('body').append('<canvas id="overlay" width="'+canvasWidth+'" height="'+canvasHeight+'" />');
var overlayctx = $('canvas')[1].getContext('2d');
overlayctx.drawImage(coinImage, 0,0);
info = document.getElementById('info');
function scratchOff(x, y)
{
mainctx.save();
mainctx.beginPath();
mainctx.arc(x,y,radius,0,Math.PI*2,false);
mainctx.clip();
mainctx.drawImage(bottomImage, 0, 0);
mainctx.restore();
}
$('#overlay').mousedown(function(e){
isMouseDown = true;
var relX = e.pageX;
var relY = e.pageY;
scratchOff(relX, relY, true);
});
$('#overlay').mousemove(function(e){
var relX = e.pageX;
var relY = e.pageY;
overlayctx.clearRect(0,0,canvasWidth,canvasHeight);
overlayctx.drawImage(coinImage, relX-radius, relY-radius);
if (isMouseDown) {
scratchOff(relX, relY, false);
countSeconds();
}
});
$('#overlay').mouseup(function(e){
isMouseDown = false;
clearInterval(interval);
});
var mainctx = $('canvas')[0].getContext('2d');
var radius = 10;
topImage.onload = function(){
mainctx.drawImage(topImage, 0, 0);
};
topImage.src = "http://i61.tinypic.com/xpzbx0.png";
}

Categories