Changing canvas for drawing lines - javascript

I found this in a stackoverflow question on how to draw in canvas http://jsfiddle.net/ArtBIT/kneDX/ but I want it to draw lines continuously without the circles but smooth lines. The code to be changed is below:
ctx.fillCircle = function(x, y, radius, fillColor) {
this.fillStyle = fillColor;
this.beginPath();
this.moveTo(x, y);
this.arc(x, y, radius, 0, Math.PI * 2, false);
this.fill();
};

You can use Bresenham's line algorithm to find all the points between the mouse start and end, and then fill the points between using fillRect. The reason you need to use the line algorithm is because if a user moves the mouse too fast you wont get solid lines, but lines with gaps. I modified your function quite a bit to do this. You can also pass a line thickness value to change how large you want the stroke to be. Note the same could be applied using arcs I just prefer rect
Live Demo
(function() {
// Creates a new canvas element and appends it as a child
// to the parent element, and returns the reference to
// the newly created canvas element
function createCanvas(parent, width, height) {
var canvas = {};
canvas.node = document.createElement('canvas');
canvas.context = canvas.node.getContext('2d');
canvas.node.width = width || 100;
canvas.node.height = height || 100;
parent.appendChild(canvas.node);
canvas.lastX = 0;
canvas.lastY = 0;
return canvas;
}
function init(container, width, height, fillColor) {
var canvas = createCanvas(container, width, height);
var ctx = canvas.context;
// define a custom fillCircle method
ctx.fillCircle = function(x1, y1, x2, y2, fillColor, lineThickness) {
this.fillStyle = fillColor;
var steep = (Math.abs(y2 - y1) > Math.abs(x2 - x1));
if (steep) {
var x = x1;
x1 = y1;
y1 = x;
var y = y2;
y2 = x2;
x2 = y;
}
if (x1 > x2) {
var x = x1;
x1 = x2;
x2 = x;
var y = y1;
y1 = y2;
y2 = y;
}
var dx = x2 - x1,
dy = Math.abs(y2 - y1),
error = 0,
de = dy / dx,
yStep = -1,
y = y1;
if (y1 < y2) {
yStep = 1;
}
for (var x = x1; x < x2; x++) {
if (steep) {
this.fillRect(y, x, lineThickness, lineThickness);
} else {
this.fillRect(x, y, lineThickness, lineThickness);
}
error += de;
if (error >= 0.5) {
y += yStep;
error -= 1.0;
}
}
};
ctx.clearTo = function(fillColor) {
ctx.fillStyle = fillColor;
ctx.fillRect(0, 0, width, height);
};
ctx.clearTo(fillColor || "#ddd");
// bind mouse events
canvas.node.onmousemove = function(e) {
if (!canvas.isDrawing) {
return;
}
mouseX = e.pageX - this.offsetLeft;
mouseY = e.pageY - this.offsetTop;
ctx.fillCircle(mouseX,mouseY,canvas.lastX,canvas.lastY,"#000",1);
canvas.lastX = mouseX;
canvas.lastY = mouseY;
};
canvas.node.onmousedown = function(e) {
canvas.isDrawing = true;
canvas.lastX = e.pageX - this.offsetLeft;
canvas.lastY = e.pageY - this.offsetTop;
};
canvas.node.onmouseup = function(e) {
canvas.isDrawing = false;
};
}
var container = document.getElementById('canvas');
init(container, 200, 200, '#ddd');
})();​
​

If i understand,you need this: http://www.html5canvastutorials.com/tutorials/html5-canvas-lines/
This script draw a line from 0,0 to mouse.
window.event.clientX = mouse x coordinate
window.event.clientY = mouse y coordinate
<script>
context.beginPath();
context.moveTo(0,0);
context.lineTo(window.event.clientX,window.event.clientY);
context.stroke();
</script>

Related

How to draw parallel rectangles with rubber-band in canvas

I am trying to draw a group of shapes using canvas.
I have referenced below SO threads:
Draw a parallel line
How to draw parallel line using three.js?
but not able to figure out how to calculate points for the rectangles parallel in as we stretch the line.
Any reference for stretching shapes with canvas is appreciated.
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var canvasx = $(canvas).offset().left;
var canvasy = $(canvas).offset().top;
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
// grid parameters
var gridSpacing = 20; // pixels
var gridWidth = 1;
//var gridColor = "#f1f1f1";
var gridColor = "lightgray";
/** */
var originX = 0;
/** */
var originY = 0;
drawGrid();
//Mousedown
$(canvas).on('mousedown', function(e) {
last_mousex = parseInt(e.clientX-canvasx);
last_mousey = parseInt(e.clientY-canvasy);
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
mousedown = false;
});
//Mousemove
$(canvas).on('mousemove', function(e) {
mousex = parseInt(e.clientX-canvasx);
mousey = parseInt(e.clientY-canvasy);
if(mousedown) {
ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
drawGrid();
ctx.setLineDash([5, 15]);
ctx.beginPath();
ctx.moveTo(last_mousex,last_mousey);
ctx.lineTo(mousex,mousey);
//ctx.lineTo(mousex,mousey);
ctx.strokeStyle = 'blue';
ctx.lineDashOffset = 2;
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
startx = last_mousex;
starty = last_mousey;
drawPolygon([last_mousex, mousex, mousex, last_mousex, last_mousex],
[last_mousey-10, mousey-10, mousey-60, last_mousey-60],true, 'gray', false, 'black', 2);
drawPolygon([last_mousex, mousex, mousex, last_mousex, last_mousex],
[last_mousey+10, mousey+10, mousey+60, last_mousey+60],true, 'gray', false, 'black', 2);
}
//Output
$('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});
/** */
function drawLine(startX, startY, endX, endY, width, color) {
// width is an integer
// color is a hex string, i.e. #ff0000
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.stroke();
}
function drawPolygon(xArr, yArr, fill, fillColor, stroke, strokeColor, strokeWidth) {
// fillColor is a hex string, i.e. #ff0000
fill = fill || false;
stroke = stroke || false;
ctx.beginPath();
ctx.moveTo(xArr[0], yArr[0]);
for (var i = 1; i < xArr.length; i++) {
ctx.lineTo(xArr[i], yArr[i]);
}
ctx.closePath();
if (fill) {
ctx.fillStyle = fillColor;
ctx.fill();
}
if (stroke) {
ctx.lineWidth = strokeWidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
}
//console.log(xArr);
//console.log(yArr);
}
/** returns n where -gridSize/2 < n <= gridSize/2 */
function calculateGridOffset(n) {
if (n >= 0) {
return (n + gridSpacing / 2.0) % gridSpacing - gridSpacing / 2.0;
} else {
return (n - gridSpacing / 2.0) % gridSpacing + gridSpacing / 2.0;
}
}
/** */
function drawGrid() {
var offsetX = calculateGridOffset(-originX);
var offsetY = calculateGridOffset(-originY);
var width = canvas.width;
var height = canvas.height;
for (var x = 0; x <= (width / gridSpacing); x++) {
drawLine(gridSpacing * x + offsetX, 0, gridSpacing * x + offsetX, height, gridWidth, gridColor);
}
for (var y = 0; y <= (height / gridSpacing); y++) {
drawLine(0, gridSpacing * y + offsetY, width, gridSpacing * y + offsetY, gridWidth, gridColor);
}
}
canvas {
cursor: crosshair;
border: 1px solid #000000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="500"></canvas>
<div id="output"></div>
I'm guessing this is what you wanted.
Instead of trying to manually draw your line rotated, instead, move the origin of the canvas to the start of the line,
// save the canvas state
ctx.save();
// move origin to start of line
ctx.translate(last_mousex, last_mousey);
then rotate the origin so it points toward the end of the line in the positive X direction
// compute direction of line from start to end
const dx = mousex - last_mousex;
const dy = mousey - last_mousey;
const angle = Math.atan2(dy, dx);
// rotate to point to end of line
ctx.rotate(angle);
then compute the length of the line from the start to the end
// compute length of line
const length = Math.sqrt(dx * dx + dy * dy);
and just draw an arrow in the positive x direction of that length
ctx.setLineDash([5, 15]);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(length, 0);
ctx.strokeStyle = 'blue';
ctx.lineDashOffset = 2;
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
drawPolygon([0, length, length, 0, 0],
[-10, -10, -60, -60],true, 'gray', false, 'black', 2);
drawPolygon([0, length, length, 0, 0],
[+10, +10, +60, +60],true, 'gray', false, 'black', 2);
// restore the canvas state
ctx.restore();
while we're at it your code for calculating the mouse position didn't work if the page is scrolled. This will get the mouse position relative to the pixels in the canvas.
const rect = canvas.getBoundingClientRect();
mousex = (e.clientX - rect.left) * canvas.width / canvas.clientWidth;
mousey = (e.clientY - rect.top ) * canvas.height / canvas.clientHeight;
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
// grid parameters
var gridSpacing = 20; // pixels
var gridWidth = 1;
//var gridColor = "#f1f1f1";
var gridColor = "lightgray";
/** */
var originX = 0;
/** */
var originY = 0;
drawGrid();
//Mousedown
$(canvas).on('mousedown', function(e) {
const rect = canvas.getBoundingClientRect();
last_mousex = (e.clientX - rect.left) * canvas.width / canvas.clientWidth;
last_mousey = (e.clientY - rect.top ) * canvas.height / canvas.clientHeight;
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
mousedown = false;
});
//Mousemove
$(canvas).on('mousemove', function(e) {
const rect = canvas.getBoundingClientRect();
mousex = (e.clientX - rect.left) * canvas.width / canvas.clientWidth;
mousey = (e.clientY - rect.top ) * canvas.height / canvas.clientHeight;
if(mousedown) {
ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
drawGrid();
// save the canvas state
ctx.save();
// move origin to start of line
ctx.translate(last_mousex, last_mousey);
// compute direction of line from start to end
const dx = mousex - last_mousex;
const dy = mousey - last_mousey;
const angle = Math.atan2(dy, dx);
// rotate to point to end of line
ctx.rotate(angle);
// compute length of line
const length = Math.sqrt(dx * dx + dy * dy);
ctx.setLineDash([5, 15]);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(length, 0);
ctx.strokeStyle = 'blue';
ctx.lineDashOffset = 2;
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
drawPolygon([0, length, length, 0, 0],
[-10, -10, -60, -60],true, 'gray', false, 'black', 2);
drawPolygon([0, length, length, 0, 0],
[+10, +10, +60, +60],true, 'gray', false, 'black', 2);
// restore the canvas state
ctx.restore();
}
//Output
$('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});
/** */
function drawLine(startX, startY, endX, endY, width, color) {
// width is an integer
// color is a hex string, i.e. #ff0000
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.stroke();
}
function drawPolygon(xArr, yArr, fill, fillColor, stroke, strokeColor, strokeWidth) {
// fillColor is a hex string, i.e. #ff0000
fill = fill || false;
stroke = stroke || false;
ctx.beginPath();
ctx.moveTo(xArr[0], yArr[0]);
for (var i = 1; i < xArr.length; i++) {
ctx.lineTo(xArr[i], yArr[i]);
}
ctx.closePath();
if (fill) {
ctx.fillStyle = fillColor;
ctx.fill();
}
if (stroke) {
ctx.lineWidth = strokeWidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
}
//console.log(xArr);
//console.log(yArr);
}
/** returns n where -gridSize/2 < n <= gridSize/2 */
function calculateGridOffset(n) {
if (n >= 0) {
return (n + gridSpacing / 2.0) % gridSpacing - gridSpacing / 2.0;
} else {
return (n - gridSpacing / 2.0) % gridSpacing + gridSpacing / 2.0;
}
}
/** */
function drawGrid() {
var offsetX = calculateGridOffset(-originX);
var offsetY = calculateGridOffset(-originY);
var width = canvas.width;
var height = canvas.height;
for (var x = 0; x <= (width / gridSpacing); x++) {
drawLine(gridSpacing * x + offsetX, 0, gridSpacing * x + offsetX, height, gridWidth, gridColor);
}
for (var y = 0; y <= (height / gridSpacing); y++) {
drawLine(0, gridSpacing * y + offsetY, width, gridSpacing * y + offsetY, gridWidth, gridColor);
}
}
canvas {
cursor: crosshair;
border: 1px solid #000000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="500"></canvas>
<div id="output"></div>

Making mouse position (0, 0) the center of the canvas

So I've recently been messing around with html5 canvas and trying to figure out how to make a particle system. While it does work I want to make vx = mouse coordinates(specifically x) but they start from the center.
What I mean by this is basically if the cursor is in the center of the canvas then vx would be equal to 0 and if the cursor is to the right from the center of the canvas it have positive mouse coordinates (and if the cursor is to the left from the center of canvas it have negative mouse coordinates).
Once that is accomplished I would just do p.speed += p.vx
Here is my javascript:
window.onload = function(){
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var W = window.innerWidth, H = window.innerHeight;
canvas.width = W;
canvas.height = H;
var particles = [];
var particle_count = 100;
for(var i = 0; i < particle_count; i++)
{
particles.push(new particle());
}
function particle()
{
this.vx = -1 + Math.random() * 2;
this.speed = {x: 0, y: -15+Math.random()*10};
this.location = {x: W/2, y: H/2};
this.radius = 5+Math.random()*10;
this.life = 20+Math.random()*10;
this.remaining_life = this.life;
this.r = Math.round(Math.random()*255);
this.g = Math.round(Math.random()*55);
this.b = Math.round(Math.random()*5);
}
function draw()
{
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "black";
ctx.fillRect(0, 0, W, H);
ctx.globalCompositeOperation = "lighter";
for(var i = 0; i < particles.length; i++)
{
var p = particles[i];
ctx.beginPath();
p.opacity = Math.round(p.remaining_life/p.life*100)/100
var gradient = ctx.createRadialGradient(
p.location.x, p.location.y, 0, p.location.x, p.location.y, p.radius);
gradient.addColorStop(0, "rgba("+p.r+", "+p.g+", "+p.b+", "+p.opacity+")");
gradient.addColorStop(0.5, "rgba("+p.r+", "+p.g+", "+p.b+", "+p.opacity+")");
gradient.addColorStop(1, "rgba("+p.r+", "+p.g+", "+p.b+", 0)");
ctx.fillStyle = gradient;
ctx.arc(p.location.x, p.location.y, p.radius, Math.PI*2, false);
ctx.fill();
p.remaining_life--;
p.radius--;
p.location.x += p.speed.x += p.vx;
p.location.y += p.speed.y;
if(p.remaining_life < 0 || p.radius < 0) {
particles[i] = new particle();
}
}
}
setInterval(draw, 33); }
Here is my codepen.
You need to translate context to move origin to center.
You also need to reverse the translation on the mouse coordinates as they will still be relative to the upper-left corner (assuming the coordinates are corrected to be relative to canvas).
Example:
var cx = canvas.width * 0.5;
var cy = canvas.height * 0.5;
ctx.translate(cx, cy); // translate globally once
For each mouse coordinate compensate with the translated position:
var pos = getMousePosition(evt); // see below
var x = pos.x - cx;
var y = pos.y - cy;
To adjust mouse position:
function getMousePosition(evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
}
}

Better line selection than using Bresenham algorithm?

I'm drawing lines on an HTML canvas, and use a less precise 2d-array (representing blocks of 10x10 pixels) in which I 'draw' lines with Bresenham's algorithm to store line-ids, so I can use that array to see which line is selected.
This works, but I would like it to be more accurate - not in the 10x10 size that I use (I like that I don't exactly have to click on the line), but when I draw a representation of that array over my actual canvas, I see that there are a lot of the 10x10 blocks not filled, even though the line is crossing them:
Is there a better solution to this? What I want is to catch ALL grid blocks that the actual line passes through.
Without seeing your code, I think you made a rounding error while filling the lookup table using the Bresenham algorithm or you scaled the coordinates before running the algorithm.
This jsFiddle shows what I came up with and the squares are perfectly aligned.
HTML
<canvas id="myCanvas"></canvas>
CSS
#myCanvas {
width: 250px;
height: 250px;
}
JavaScript
var $canvas = $("#myCanvas"),
ctx = $canvas[0].getContext("2d");
ctx.canvas.width = $canvas.width();
ctx.canvas.height = $canvas.height();
function Grid(ctx) {
this._ctx = ctx;
this._lines = [];
this._table = [];
this._tableScale = 10;
this._createLookupTable();
}
Grid.prototype._createLookupTable = function() {
this._table = [];
for (var y = 0; y < Math.ceil(ctx.canvas.height / this._tableScale); y++) {
this._table[y] = [];
for (var x = 0; x < Math.ceil(ctx.canvas.width / this._tableScale); x++)
this._table[y][x] = null;
}
};
Grid.prototype._updateLookupTable = function(line) {
var x0 = line.from[0],
y0 = line.from[1],
x1 = line.to[0],
y1 = line.to[1],
dx = Math.abs(x1 - x0),
dy = Math.abs(y1 - y0),
sx = (x0 < x1) ? 1 : -1,
sy = (y0 < y1) ? 1 : -1,
err = dx - dy;
while(true) {
this._table[Math.floor(y0 / 10)][Math.floor(x0 / 10)] = line;
if ((x0 == x1) && (y0 == y1)) break;
var e2 = 2 * err;
if (e2 >- dy) { err -= dy; x0 += sx; }
if (e2 < dx) { err += dx; y0 += sy; }
}
};
Grid.prototype.hitTest = function(x, y) {
var ctx = this._ctx,
hoverLine = this._table[Math.floor(y / 10)][Math.floor(x / 10)];
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
this._lines.forEach(function(line) {
line.draw(ctx, line === hoverLine ? "red" : "black");
});
};
Grid.prototype.drawLookupTable = function() {
ctx.beginPath();
for (var y = 0; y < this._table.length; y++)
for (var x = 0; x < this._table[y].length; x++) {
if (this._table[y][x])
ctx.rect(x * 10, y * 10, 10, 10);
}
ctx.strokeStyle = "rgba(0, 0, 0, 0.2)";
ctx.stroke();
};
Grid.prototype.addLine = function(line) {
this._lines.push(line);
this._updateLookupTable(line);
};
Grid.prototype.draw = function() {
var ctx = this._ctx;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
this._lines.forEach(function(line) {
line.draw(ctx);
});
};
function Line(x0, y0, x1, y1) {
this.from = [ x0, y0 ];
this.to = [ x1, y1];
}
Line.prototype.draw = function(ctx, style) {
ctx.beginPath();
ctx.moveTo(this.from[0], this.from[1]);
ctx.lineTo(this.to[0], this.to[1]);
ctx.strokeStyle = style || "black";
ctx.stroke();
};
var grid = new Grid(ctx);
grid.addLine(new Line(80, 10, 240, 75));
grid.addLine(new Line(150, 200, 50, 45));
grid.addLine(new Line(240, 10, 20, 150));
grid.draw();
grid.drawLookupTable();
$canvas.on("mousemove", function(e) {
grid.hitTest(e.offsetX, e.offsetY);
grid.drawLookupTable();
});
Your best option is to treat the mouse-cursor-position as a small circle (f.e. with a 5px radius) and check if the line intersects with the circle.
Use the math as explained in this Q&A
JavaScript
A simple function to detect intersection would be:
function lineCircleIntersects(x1, y1, x2, y2, cx, cy, cr) {
var dx = x2 - x1,
dy = y2 - y1,
a = dx * dx + dy * dy,
b = 2 * (dx * (x1 - cx) + dy * (y1 - cy)),
c = cx * cx + cy * cy,
bb4ac;
c += x1 * x1 + y1 * y1;
c -= 2 * (cx * x1 + cy * y1);
c -= cr * cr;
bb4ac = b * b - 4 * a * c;
return bb4ac >= 0; // true: collision, false: no collision
}
See it working in this jsFiddle, but note that this function will also return true if the cursor is on the slope of the line outside [x1, y1], [x2, y2]. I'll leave this up to you :)
You can also try line-circle-collision library on github which should give you what you want.

How to move the square to the destination?

How to move the square to the destination? Square moves one pixel only when click the mouse? Sorry for my english.
window.onload = function(){
var x = 50;
var y = 50;
var c = document.getElementById("game");
var ctx = c.getContext("2d");
init();
draw();
function init()
{
document.addEventListener("click",paint,false);
}
function paint(e)
{
if(x<e.clientX) x++;
}
function draw()
{
ctx.clearRect(x-1,y,1,15);
ctx.fillStyle = "blue";
ctx.fillRect(x,y,15,15);
window.requestAnimationFrame(draw);
}
}
Here is one way to do it, adapted from this article that I wrote a few months back.
The following is the piece to get it working
var tx = targetX - x,
ty = targetY - y,
dist = Math.sqrt(tx*tx+ty*ty);
velX = (tx/dist)*thrust;
velY = (ty/dist)*thrust;
We need to get the difference between the current position and targeted position (clicked area), we then get the distance, and make the velocity for x and y equal to the difference divided by the total distance multiplied by the speed of the object.
Full working example and code
Live demo
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 500,
height = 500,
mX = width/2,
mY = height/2;
canvas.width = width;
canvas.height = height;
canvas.addEventListener("click", function (e) {
mX = e.pageX;
mY = e.pageY;
});
var Ball = function (x, y, radius, color) {
this.x = x || 0;
this.y = y || 0;
this.radius = radius || 10;
this.speed = 5;
this.color = color || "rgb(255,0,0)";
this.velX = 0;
this.velY = 0;
}
Ball.prototype.update = function (x, y) {
// get the target x and y
this.targetX = x;
this.targetY = y;
// We need to get the distance this time around
var tx = this.targetX - this.x,
ty = this.targetY - this.y,
dist = Math.sqrt(tx * tx + ty * ty);
/*
* we calculate a velocity for our object this time around
* divide the target x and y by the distance and multiply it by our speed
* this gives us a constant movement speed.
*/
this.velX = (tx / dist) * this.speed;
this.velY = (ty / dist) * this.speed;
// Stop once we hit our target. This stops the jittery bouncing of the object.
if (dist > this.radius / 2) {
// add our velocities
this.x += this.velX;
this.y += this.velY;
}
};
Ball.prototype.render = function () {
ctx.fillStyle = this.color;
ctx.beginPath();
// draw our circle with x and y being the center
ctx.arc(this.x - this.radius / 2, this.y - this.radius / 2, this.radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
};
var ball1 = new Ball(width / 2, height / 2, 10);
function render() {
ctx.clearRect(0, 0, width, height);
ball1.update(mX, mY);
ball1.render();
requestAnimationFrame(render);
}
render();

How to get smooth mouse events for a canvas "drawing style" app?

I'm trying to make smooth mouse movements across the screen for a drawing style app. More specifically its a "Powder toy". What this means is, it draws pixel by pixel so I cant do some line trickery. I was initially thinking of checking mouse down and mouse up then put something in my game "update" loop to make it draw pixels to the screen but that didnt work out when I found I couldn't directly get the mouse X and mouse Y without the events firing.
So does anyone know a way of smooth mouse movements, the way I have at the moment uses the mousemove event which causes this:
http://img1.uploadscreenshot.com/images/orig/9/26119184415-orig.jpg
(Notice how the pixels are spread apart)
Thank you,
Looks like your doing a world of sand clone so I imagine you need rects. I used Bresenham's line algorithm to plot the points. Basically onmousedown it starts painting. Then onmousemove it compares the current coordinates with the last coordinates and plots all of the points between.
Live Demo
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
painting = false,
lastX = 0,
lastY = 0;
canvas.width = canvas.height = 600;
ctx.fillRect(0, 0, 600, 600);
canvas.onmousedown = function(e) {
if (!painting) {
painting = true;
} else {
painting = false;
}
ctx.fillStyle = "#ffffff";
lastX = e.pageX - this.offsetLeft;
lastY = e.pageY - this.offsetTop;
};
canvas.onmousemove = function(e) {
if (painting) {
mouseX = e.pageX - this.offsetLeft;
mouseY = e.pageY - this.offsetTop;
// find all points between
var x1 = mouseX,
x2 = lastX,
y1 = mouseY,
y2 = lastY;
var steep = (Math.abs(y2 - y1) > Math.abs(x2 - x1));
if (steep){
var x = x1;
x1 = y1;
y1 = x;
var y = y2;
y2 = x2;
x2 = y;
}
if (x1 > x2) {
var x = x1;
x1 = x2;
x2 = x;
var y = y1;
y1 = y2;
y2 = y;
}
var dx = x2 - x1,
dy = Math.abs(y2 - y1),
error = 0,
de = dy / dx,
yStep = -1,
y = y1;
if (y1 < y2) {
yStep = 1;
}
for (var x = x1; x < x2; x++) {
if (steep) {
ctx.fillRect(y, x, 1, 1);
} else {
ctx.fillRect(x, y, 1, 1);
}
error += de;
if (error >= 0.5) {
y += yStep;
error -= 1.0;
}
}
lastX = mouseX;
lastY = mouseY;
}
}

Categories