How about the below? Here all the rendering comes in one setInterval function and the mouse event just updates parameters associated with each particle. These parameters are used by the rendering function whenever it is called. This allows you to introduce the "gradual" effect you were looking for. Also you don't have to worry about clearing tiny pieces of the canvas as the setInterval function clears everything and redraws everything based on values that were either initially set or what the mouse event set.
I added a an x0 and y0 property to the particle object to let it know where it should return to if it has been moved by the mouse event. deltaY and deltaX let us know how much to increment each coordinate element by.
Here is my fiddle: https://jsfiddle.net/kotman12/5p9tko50/
var canvas = document.getElementById("scene");
var ctx = canvas.getContext("2d");
var particles = [];
function drawScene(){
canvas.width = png.width+200;
canvas.height = png.height+200;
//canvas.addEventListener("mouseover", doMouseOver, false);
canvas.addEventListener('mousemove', move, false);
//canvas.addEventListener('mouseout', doMouseOut, false);
//canvas.addEventListener('click', doClick, false);
ctx.drawImage(png, 0, 0);
var data = ctx.getImageData(0, 0, png.width, png.height);
ctx.clearRect(0,0,canvas.width, canvas.height);
for (var y = 0, y2 = data.height; y < y2; y=y+4) {
for (var x = 0, x2 = data.width; x < x2; x=x+4) {
if (data.data[(y * 4 * data.width) + (x * 4) + 3] > 128) {
var particle = {
x : x+100,
y : y+100,
y0: y+100,
x0: x+100,
xDelta: 0,
yDelta: 0
};
particles.push(particle);
}
}
}
console.log(particles);
ctx.fillStyle = "White";
var renderStuff = setInterval(function() {
ctx.clearRect(0,0,canvas.width, canvas.height);
for(var i=0, j=particles.length;i<j;i++){
var particle = particles[i];
ctx.save();
// ctx.rotate((Math.PI/180)*2);
// ctx.translate(100, 100);
if(Math.sqrt(Math.pow(particle.x-particle.x0,2)+Math.pow(particle.y-particle.y0, 2)) > 1){
particle.x += particle.xDelta/200;
particle.y += particle.yDelta/200;
}else{
particle.x = particle.x0;
particle.y = particle.y0;
}
ctx.fillRect(particle.x, particle.y, 2, 2);
// ctx.restore();
}
}, 1);
}
function move(e){
// madami k hover hast
// console.log(2);
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
//ctx.clearRect(0,0,canvas.width, canvas.height);
/*for(var i=0, j=particles.length;i<j;i++){
ctx.clearRect(particles[i].x, particles[i].y, 2, 2);
}*/
for(var i=0, j=particles.length;i<j;i++){
var xDistance = particles[i].x - mouseX;
var yDistance = particles[i].y - mouseY;
var distance = Math.sqrt(xDistance * xDistance + yDistance * yDistance);
if (distance < 20) {
angle = Math.atan2(yDistance,xDistance);
particles[i].x += Math.cos(angle) * distance;
particles[i].y += Math.sin(angle) * distance;
particles[i].yDelta = particles[i].y0 - particles[i].y;
particles[i].xDelta = particles[i].x0 - particles[i].x;
}
/* else if(Math.abs(particle.x-particle.x0) > .01){
particle.x += particle.xDelta/400;
particle.y += particle.yDelta/400;
}*/
//ctx.fillRect(particles[i].x, particles[i].y, 2, 2);
}
}