Image flickers when mouse moves in HTML canvas - javascript

I already looked in these thread 1 and thread 2, but I still got the flickering when the mouse move.
My code:
function draw(){
var img = new Image();
img.src = "/Sample/Icons/sample.png";
img.onload = function () {
ctx.drawImage(img, X1, Y1, 25, 25);
};
}
Hopefully someone can give me an idea or solution on how to solve my flickering problem.

I'm assuming you're calling draw for each mousemove.
Mousemove events occur about 30 times a second so there is not enough time to load an image inside a mousemove handler.
Instead, load the image once at the start of your app.
Then ctx.drawImage has enough time to draw that preloaded image during each mousemove event.

Related

canvas - Where do I put clearRect to refresh the animation?

I'm lost and could use a little help.
I am trying to get the apex of the curve to follow the mouse, but cannot find where I should refresh nor understand why.
function animate(){
requestAnimationFrame(animate);
canvas = document.querySelector('canvas');
c = canvas.getContext('2d');
//c.clearRect(0,0, canvas.width,canvas.height);
$( "#canvas" ).mousemove(function( event ) {
topWave.draw(0, 300, event.pageX, 50, $(window).width(), 300);
});
}
Here is a codepen - https://codepen.io/anon/pen/xpvaee
Any guidance appreciated.
Animation, rendering, and IO events.
You must separate the mouse events from the rendering as the mouse fires events at a different rate than the display is updated.
You should not query the DOM inside mouse or animation events. You should only query the DOM when you need to. At the start of the application, and when there are changes that will effect the state, such as resize events
requestAnimationFrame (rAF) is synced with the display rate (60 times a second). It does not matter where in the animation function you put rAF.
You render in order of visibility, background first then to the top most object last.
jQuery is slow, and 99.99% of the time it is easier to use the standard API. Try to avoid using jQuery, its an old dinosaur past its use by date. Using it is preventing you from learning how best to use the DOM.
Thus from the points above your code should look more like. (with no jQuery)
// start the animation
requestAnimationFrame(animate); // this will fire when the setup code below has
// has executed
// get the DOM object
const canvas = document.querySelector('canvas');
// get the 2D context
const ctx = canvas.getContext('2d');
// create mouse object
const mouse = { x : 0, y : 0 };
// create mouse move event listener
canvas.addEventListener("mousemove",(event) => {
// each time mouse is moved update the mouse position
mouse.x = event.clientX;
mouse.y = event.clientY;
});
// Via rAF this function is called once every 1/60 of a second.
// The rate may change if you do too much rendering, or is the browser is
// busy doing something else.
function animate(){
// first thing to draw is the background, in this case that is clear
ctx.clearRect(0, 0, canvas.width, canvas.height);
// then draw your wave using the current mouse position
// innerWidth (and innerHeight) is built in global value
// same as $("window").width() but a zillion times faster
topWave.draw(0, 300, mouse.y, 50, innerWidth, 300);
// it does not matter where in this function you put rAF
// I like to put it at the bottom of the function
requestAnimationFrame(animate);
}

Why is my sprite blurred when using requestAnimationFrame to move it?

I created a basic 2D game using pure JavaScript. My problem is when the sprite stops moving it is sometimes blurred sometimes not. I use requestAnimationFrame to move the sprite and keydown/keyup events trigger moving. When keyup is triggered the sprite stops moving and the default tile is set however sometimes it is showing blurred.
https://arpadvas.github.io/untitled_game_project/
Since you didn't posted an minimal code example, and that I don't want to go through the raw code you linked to, this will stay as a guess (an educated one).
Generally, this happens when you draw your sprites on floating coordinates.
Since there is no way to draw on half a pixel, the pixel being the smallest unit in canvas, to smoothen drawings, the browser will by default create antialias artifacts, turning some pixels less opaque so that your eyes think it is on half a pixel.
While this usually works well with realistic photographs, it doesn't at all with pixel-art.
The solution then is either to round all your coordinates, or if you are lazy, to set the imageSmoothingEnabled property of your context.
var img = new Image();
img.onload = draw;
function draw(){
i = .316252;
blurred.width = round.width = noAntiAlias.width = img.width +20;
blurred.height = round.height = noAntiAlias.height = img.height +20;
blurred.getContext('2d').drawImage(img, 10+i, 20+i);
round.getContext('2d').drawImage(img, 10, 20);
var nA = noAntiAlias.getContext('2d');
nA.mozImageSmoothingEnabled = nA.msImageSmoothingEnabled = nA.webkitImageSmoothingEnabled = nA.imageSmoothingEnabled = false;
noAntiAlias.getContext('2d').drawImage(img, 10+i, 20+i);
};
img.src = "https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png";
<canvas id="blurred"></canvas>
<canvas id="round"></canvas>
<canvas id="noAntiAlias"></canvas>
Ps : this made me realize that somehow my FF doesn't smooth this particular image I used... If someone can confirm in comments, I'd be glad to dig into this further if needed.

Canvas with moving bubbles over a blurred div

I have a canvas which has bubbles moving randomly, now when i put it on to a div which has a filter
-webkit-filter: blur(50px);
then the canvas bubble movement fps drops down and smoothness reduces.
I am not getting what is the issue.
Version with blurred background : http://freakengineers.com/bubbles/index.php
Version with normal background : http://freakengineers.com/bubbles/index2.php
You can load and blur the image (but I don't know if you can use a built in blur algorithm - I've used StackBlur) in a separate canvas as a sort of buffer, then copy it to your main canvas on each frame. JSFiddle: http://jsfiddle.net/1m8rbt7j/
Add a new <canvas> element to the HTML, load your image into it and then blur the new canvas:
var blurimg = new Image();
blurimg.onload = function() {
var blurcv = document.getElementById('blurcanvas');
blurcv.getContext('2d').drawImage(blurimg,0,0);
stackBlurCanvasRGB('blurcanvas', 0, 0, 1580, 730, 50);
};
blurimg.src = 'http://i.imgur.com/WaMsYBC.jpg';
(I had to use a different image to get around cross-origin rules.)
Then just draw the content of the new canvas to your main canvas at the start of each frame:
context.clearRect(0,0, w,h);
context.drawImage(document.getElementById('blurcanvas'),0,0);
With your versions I get 30 FPS without the blur and 20 FPS with it. I get 30 FPS with the blur in my version.

canvas is cleared on mousedown, sketch.js & jquery 2.0.0

11I'm using sketch.js from here: http://intridea.github.io/sketch.js/ and jquery 2.0.0
On my page, I have a list of images presented like so:
<img src="http://url.to/image"><br><span class="background">click for background</span>
and a canvas, set up like so:
<canvas id="simple_sketch" style="border: 2px solid black;"></canvas>
relevant JavaScript:
var winwidth = 800;
var winheight = 600;
$('#simple_sketch').attr('width', winwidth).attr('height', winheight);
$('#simple_sketch').sketch();
$('.background').on('click', function(event) {
event.preventDefault();
var imgurl = $(this).parent().attr('href');
console.log('imgurl: ' + imgurl);
var n = imgurl.split('/');
var size = n.length;
var file = '../webkort/' + n[size - 1];
var sigCanvas = document.getElementById('simple_sketch');
var context = sigCanvas.getContext('2d');
var imageObj = new Image();
imageObj.src = imgurl;
imageObj.onload = function() {
context.drawImage(this, 0, 0,sigCanvas.width,sigCanvas.height);
};
alert('background changed');
});
Backgrounds are changed just as I want them to, but whenever I click on the canvas, the backgound image is cleared. As per a suggestion on this thread: html5 canvas background image disappear on mousemove I commented out this.el.width = this.canvas.width(); on line 116 of sketch.js, but to no avail.
Any help appreciated!
EDIT: jsfiddle: http://jsfiddle.net/RXFX4/1/
EDIT: Couldn't figure out how to do this with sketch.js, so instead went with jqScribble (link posted in comments) which has the ability to do this as a built-in function instead.
Find this line on the library - sketch.js and delete/comment it out.
this.el.width = this.canvas.width();
Good luck
Assign the url on the image source after the onload event. If the image is already loaded, the event is probably firing before you are hooking it. Which means that your drawImage is never being called.
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(this, 0, 0,sigCanvas.width,sigCanvas.height);
};
imageObj.src = imgurl;
EDIT: I'm going to take a shot in the dark here, since I'm not familiar with sketchjs
I'm thinking that your problem is that you are completely re-render the canvas when you click your 'change background' link. Notice that if you draw, then click the change background, you lose your drawing.
However, notice that once you click again, the background disappears, and you get your original drawing back again. This tells me that sketchjs is keeping track of what has been drawn on it's own in-memory canvas, and then it drops it onto the target. The problem, then, is that when this in-memory canvas is drawn, it completely replaces the contents of the target canvas with it's own.
I notice in some of the sketchjs examples, if you want a background they actually assign the canvas a background style. In your example, you are drawing the background directly onto the canvas. The prior probably works because sketchjs knows to incorporate the background style when it draws. However, it does not know that when you drew your fresh background image, it should be using that.
Can you just change the background style on the canvas element, instead of drawing directly on the canvas?

Draw a cross at the mouses location on a canvas, non persistently

I have this bound to the mousemove event of my canvas:
function(e){
var contDiv = $('#current_system_map');
var offset = contDiv.offset();
x = e.clientX-offset.left;
y = e.clientY-offset.top;
context.beginPath();
context.moveTo(0,y);
context.lineTo(595,y);
context.moveTo(x,0);
context.lineTo(x,595);
context.strokeStyle = "rgb(255,255,255)";
context.stroke();
}
and it works fine, to a point. The drawn cross is persistent, so when the mouse moves a new cross is drawn but the old one remains. I've tried essentially re-drawing the canvas but that cause the cross to be laggy and remain quite away behind the mouse.
So i need to know how to draw the cross and make it dis-appear without having to re-draw everything on the canvas
http://jsfiddle.net/PgKEt/2/
This is the best that I can do.
If you try to use setInterval and such to animate it, it will keep redrawing even when it does not need to. So by doing this, you essentially only redraw when the mouse moves, and only draw 2 lines, instead of whatever content you want it on top.
In addition, if you have any detection such as mousedown and such, it has to be on whatever canvas is on the top, otherwise it will not detect them anymore.
Usually if you draw something on the canvas you will have to redrawn the canvas contents to erase it. I suggest you use an image element as a cursor and position it absolutely above the
Or you could try the old trick and draw the cursor in the canvas with globalCompositeOperation='xor', then draw it again in the same place to erase it. Afterwards you will need to restore globalCompositeOperation to source-over.
This approach works fast enough for me in Firefox 3.6.8 to do in a mousemove event. Save the image before you draw the crosshair and then restore it to erase:
To save:
savedImage = new Image()
savedImage.src = canvas.toDataURL("image/png")
The to restore:
ctx = canvas.getContext('2d')
ctx.drawImage(savedImage,0,0)
If you do not want to store it persistently, you can also take a look at SVG.
Try
ctx.clearRect(0,0,YourCanvasHeight,YourCanvasWidth);
In my case I implemented a circle and every time the user clicks inside it, this instruction returns and deletes the previous points.
This is the complete code:
function getMousePosition(canvas, event) {
let rect = canvas.getBoundingClientRect();
let x = event.offsetX; //event.clientX - rect.left;
let y = event.offsetY; //event.clientY - rect.top;
drawPoint(canvas,x,y);
};
function drawPoint(canvas,x,y) {
if (canvas.getContext){
var ctx = canvas.getContext('2d');
ctx.clearRect(0,0,200,200);
ctx.beginPath();
ctx.arc(x, y, 5, 0, 2 * Math.PI);
ctx.fillStyle = "white";
ctx.fill();
}
};
$(document).ready(function(){
let canvasElem = document.getElementById("circle");
canvasElem.addEventListener("click", function(e)
{
getMousePosition(canvasElem, e);
});
});

Categories

Resources