This program runs. But, as you can, see there is an artifact when the square turns over. The matrix values must be represented, and this representation should also bee seen depending on an angle. Is there any way to archieve good visualization. Why is this happening to my code?
var canvas=document.getElementById('canvas');
var ctx=canvas.getContext('2d');
var x=100;
var y=100;
var width=200;
var height=200;
var radianAngle=0;
Rotar();
var array = new Array2D(200,200);
function Array2D(NumOfRows,NumOfCols)
{
var k=new Array(NumOfRows);
for (i = 0; i < k.length; ++i)
k[i] = new Array(NumOfCols);
return k;
}
function Rotar(){
//Borramos
ctx.clearRect(0,0,canvas.width,canvas.height);
//Salvamos el estado
ctx.save();
// Transladamos su centro de gravedad
ctx.translate(x+width/2,y+height/2);
//Otra mⳍ
ctx.rotate(radianAngle);
var array = new Array2D(200,200);
for(i=0; i<200; i++)
{
for(j=0;j<200; j++)
{
array[i][j]=i+j;
var r,g,b;
r = array[i][j];
g=50;
b=50;
//La parte de dibujo
ctx.fillStyle = "rgba("+r+","+g+","+b+",100)";
ctx.fillRect( i, j, 1, 1 );
}
}
ctx.restore();
}
$("#test").click(function(){
radianAngle+=Math.PI/60;
// call rotateSquare
Rotar();
});
body {
background: #dddddd;
}
#canvas {
background: #eeeeee;
border: thin solid #aaaaaa;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" height="500" width="500"></canvas>
<button id="test">Rotate</button><br>
Rotar();
});
This is a typical rounding issue : You rotate the context, then iterate on (x,y) in [0,199]. But while drawing the small one pixel wide rectangles, they won't fit perfectly one pixel, so the renderer has to 'diffuse' the color on several real device pixels, and that goes with a rounding error since r,g,b are only stored on 8 bits. Add to this the error on the coordinates of the tiny rectangles -that will be rasterized on up to 4 pixels-, and you have the grid you're seing.
When doing such transform, the rule is to rasterize : iterate the pixels of the destination and find where they originate in the source, not the other way around.
So a simple way do that : find the bounding box of the rotated rect, iterate in this BBox, and if a point is in the rect compute its color.
Or build an algorithm that rasterize the rect (most easy would be to use triangles, see here for an example of a triangle rasterization i played with : http://jsfiddle.net/gamealchemist/5cnkr2s5/ )
But... for what you are drawing here most simple and way faster is to build a linear gradient, use it as the fillStyle, and draw the whole rectangle in a single fillRect call. In other words : let the canvas (and, behind the scene, the GPU) do the math for you.
var grad = ctx.createLinearGradient(0,0,200,200);
grad.addColorStop(0,'#000');
grad.addColorStop(1,'#F00');
ctx.fillStyle = grad;
//
ctx.save();
ctx.clearRect( ... );
ctx.translate ( the upper left point) ;
ctx.rotate ( some angle );
ctx.fillRect(0, 0, 200, 200);
ctx.restore();
most simple example here (click 'run' several times, angle is randomized ):
http://jsfiddle.net/gamealchemist/j57msxr5/11/
(Rq : You can have an idea of the speed up of using the context2D by comparing the triangle rasterization i mentioned above with the same work done by the context2D : http://jsfiddle.net/gamealchemist/zch3gdrx/ )
Related
I'm making a JavaScript game engine - demo - and I'm wondering which of these options would be the least expensive for drawing on canvas:
Have a condition to check if an object's x and y coords are within the height and width ranges.
Draw the objects regardless, although many won't appear.
The first option would require comparing four or so many variables, for each object and each animation loop. I'm wondering if that would be less expensive than drawing all objects regardless.
The actual game will have a number of objects that have x and y coords, with canvas that centres around the human player on a larger game map.
I use requestAnimationFrame to do the draw loop. I'm also not using any frameworks.
Offscreen drawings are ignored by the GPU and therefore take less time to render (ummm--not render!). However the CPU will still process the drawing commands so offscreen drawings are not "free".
But you have a second performance hit. You are drawing every circle in its own path:
ctx.beginPath();
ctx.arc(p.x,p.y,p.r,0,PI2);
ctx.fillStyle=p.color;
ctx.fill();
It's more efficient to draw all commonly colored arcs in a single (multi-circle) path:
ctx.fillStyle='red';
ctx.beginPath();
for(var i=0;i<len;i++){
var p=players[i];
if(p.color=='red'){
ctx.moveTo(p.x,p.y);
ctx.arc(p.x,p.y,p.r,0,PI2);
}
}
ctx.fill();
Here's a highly non-optimized set of perf tests showing:
Drawing on-screen circles with individual beginPath paths.
Drawing off-screen circles with individual beginPath paths.
Drawing on-screen circles with 1 multiple-circle path per color.
Drawing off-screen circles with 1 multiple-circle path per color.
On my modest development computer these are the perf results:
Onscreen / individual paths: 1050ms
Offscreen / individual paths: 427ms
Onscreen / one path per color: 528ms
Offscreen / one path per color: 220ms
highly non-optimized perf tests:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var colors=['red','green','blue','gold'];
var playersOnscreen=[];
var playersOffscreen=[];
for(var c=0;c<colors.length;c++){
var color=colors[c];
for(var p=0;p<100;p++){
playersOnscreen.push({x:50,y:50,r:10,color:color});
}
}
for(var c=0;c<colors.length;c++){
var color=colors[c];
for(var p=0;p<100;p++){
playersOffscreen.push({x:-50,y:50,r:10,color:color});
}
}
var count=100;
var t1=performance.now();
for(var i=0;i<count;i++){ drawIndividualPaths(playersOnscreen); }
var t2=performance.now();
for(var i=0;i<count;i++){ drawIndividualPaths(playersOffscreen); }
var t3=performance.now();
for(var i=0;i<count;i++){ drawColorPaths(playersOnscreen); }
var t4=performance.now();
for(var i=0;i<count;i++){ drawColorPaths(playersOffscreen); }
var t5=performance.now();
alert('onscreen/individual='+parseInt(t2-t1)+', offscreen/individual='+parseInt(t3-t2)+', onscreen/by color='+parseInt(t4-t3)+', offscreen/by color='+parseInt(t5-t4));
function drawIndividualPaths(players){
var len=players.length;
var PI2=Math.PI*2;
for(var i=0;i<len;i++){
var p=players[i];
ctx.beginPath();
ctx.arc(p.x,p.y,p.r,0,PI2);
ctx.fillStyle=p.color;
ctx.fill();
}
}
function drawColorPaths(players){
var len=players.length;
var PI2=Math.PI*2;
var clen=colors.length;
for(var c=0;c<clen;c++){
var color=colors[c];
ctx.fillStyle=color;
ctx.beginPath();
for(var i=0;i<len;i++){
var p=players[i];
if(p.color==color){
ctx.moveTo(p.x,p.y);
ctx.arc(p.x,p.y,p.r,0,PI2);
}
}
ctx.fill();
}
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<h2>Please wait for perf tests to complete</h2>
<canvas id="canvas" width=300 height=300></canvas>
im using a canvas to visualize a small game of mine.
Basicly i have two objects that represent space ships, each of them has a "Location" array which holds the ships current x/y.
According to these arrays, i drawImage on the canvas (totalw/h is 300/300 fyi).
Now, for the difficult part.
i want to draw animations (gunfire) on that canvas. basicly from ship1 x/y to ship2 x/y.
For the animation function itself, im passing an effects object that holds 3 Arrays, shooter.location[x, y], target.location[x, y] and a third array that holds where the EFFECT is currently at [x, y].
this.animateEffects = function(effects){
var shooter = effects.shooter;
var target = effects.target;
var current = effects.current;
var canvas = document.getElementById("effects");
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.fillStyle = "red";
context.arc(current[0], current[1], 5, 0, 2*Math.PI);
effects.current[0]++
effects.current[1]++
context.fill();
if (current == target){
console.log("ding");
this.end()
}
}
My "problem" is that im, if possible at all, looking for a smart way to determine (for each frame) if effects[x, y] should go ++ or -- or a combination of the two, depending on where the "moving" ships are located at (at the time, the shooting started).
Any advise or hints are appreciated.
You can fire a bullet from shooter to target using linear interpolation.
Calculate the difference in the original X & Y positions of the shooter and target.
// save the starting position of the bullet (== shooter's original position)
// (these original X & Y are needed in the linear interpolation formula)
bulletOriginalX=shooter.x;
bulletOriginalY=shooter.y;
// calc the delta-X & delta-Y of the shooter & target positions
// (these deltas are needed in the linear interpolation formula)
dx=target.x-shooter.x;
dy=target.y-shooter.y;
Move the bullet towards the target using the interpolation formula
// where percent == the percent you want the bullet to be between
// it's starting & ending positions
// (between starting shooter & starting target positions)
currentBulletX=bulletOriginalX+dx*percent;
currentBulletY=bulletOriginalY+dy*percent;
Here's an example:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
shooter={x:50,y:50};
target={x:100,y:100};
effect={x:50,y:50,dx:0,dy:0,pct:0,speedPct:0.25};
draw();
fire();
$('#test').click(function(){
moveEffect();
draw();
});
function fire(){
effect.x=shooter.x;
effect.y=shooter.y;
effect.dx=target.x-shooter.x;
effect.dy=target.y-shooter.y;
effect.pct=0;
}
function moveEffect(){
effect.pct+=effect.speedPct;
}
function draw(){
ctx.clearRect(0,0,cw,ch);
ctx.beginPath();
ctx.arc(shooter.x,shooter.y,15,0,Math.PI*2);
ctx.closePath();
ctx.strokeStyle='green';
ctx.stroke();
ctx.beginPath();
ctx.arc(target.x,target.y,15,0,Math.PI*2);
ctx.closePath();
ctx.strokeStyle='red';
ctx.stroke();
if(effect.pct>1){return;}
var x=effect.x+effect.dx*effect.pct;
var y=effect.y+effect.dy*effect.pct;
ctx.beginPath();
ctx.arc(x,y,3,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle='black';
ctx.fill();
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id=test>Animate 1 frame</button>
<br><canvas id="canvas" width=300 height=300></canvas>
I have the following code to draw shapes (mainly used for rectangles) but the HTML5 drawing functions seem to draw borders with their thickness centered on the lines specified. I would like to have a border outside the surface of the shape and I'm at a loss.
Path.prototype.trace = function(elem, closePath) {
sd.context.beginPath();
sd.context.moveTo(this.getStretchedX(0, elem.width), this.getStretchedY(0, elem.height));
sd.context.lineCap = "square";
for(var i=1; i<this.points.length; ++i) {
sd.context.lineTo(this.getStretchedX(i, elem.width), this.getStretchedY(i, elem.height));
}
if(closePath) {
sd.context.lineTo(this.getStretchedX(0, elem.width), this.getStretchedY(0, elem.height));
}
}
getStrechedX and getStretchedY return the coordinates of the nth vertex once the shape is applied to a set element width, height and offset position.
Thanks to Ken Fyrstenberg's answer I've got it working for a rectangle, but this solution can sadly not apply to other shapes.
http://jsfiddle.net/0zq9mrch/
Here I drew two "wide" borders, one subtracting half the lineWidth to every position, another one adding. It doesn't work (as expected) because it's only going to put the thick lines above and to the left in one case, under and to the right in another - not "outside" the shape. You can also see a white area around the slope.
I tried working out how I could get the vertices to manually draw the path for the thick border (using fill() instead of stroke()).
But it turns out I still end up with the same problem: how to programatically determine if an edge is inside or outside. This would require some trigonometry and a heavy algorithm. For the purpose of my current work, this is too much trouble. I wanted to use this to draw a map of a building. The room walls need to be drawn outside the given dimensions, but I'll stick to standalone sloped walls for now.
Solution
You can solve this by drawing two lines:
First line with line thickness as intended
Second line contracted with 50% of the outer line width
To contract, add 50% to x and y, subtract line-width (or 2x 50%) from width and height.
Example
var ctx = document.querySelector("canvas").getContext("2d");
var lineWidth = 20;
var lw50 = lineWidth * 0.5;
// outer line
ctx.lineWidth = lineWidth; // intended line width
ctx.strokeStyle = "#975"; // color for main line
ctx.strokeRect(40, 40, 100, 100); // full line
// inner line
ctx.lineWidth = 2; // inner line width
ctx.strokeStyle = "#000"; // color for inner line
ctx.strokeRect(40 + lw50, 40 + lw50, 100 - lineWidth, 100 - lineWidth);
<canvas></canvas>
Complex shapes
For more complex shapes you will have to calculate the path manually. This is a little bit more complex and perhaps too broad for SO. You have to consider things like tangents, angle at bends, intersections and so forth.
One way to "cheat" is to:
draw the main line at full thickness to canvas
then use reuse the path as a clipping mask
change composite mode to destination-atop
draw the shape offset in various direction
restore clipping
change color and reuse path again for the main line.
The offset value below will determine the thickness of the inner line while the directions will determine resolution.
var ctx = document.querySelector("canvas").getContext("2d");
var lineWidth = 20;
var offset = 0.5; // line "thickness"
var directions = 8; // increase to increase details
var angleStep = 2 * Math.PI / 8;
// shape
ctx.lineWidth = lineWidth; // intended line width
ctx.strokeStyle = "#000"; // color for inner line
ctx.moveTo(50, 100); // some random shape
ctx.lineTo(100, 20);
ctx.lineTo(200, 100);
ctx.lineTo(300, 100);
ctx.lineTo(200, 200);
ctx.lineTo(50, 100);
ctx.closePath();
ctx.stroke();
ctx.save()
ctx.clip(); // set as clipping mask
ctx.globalCompositeOperation = "destination-atop"; // draws "behind" existing drawings
for(var a = 0; a < Math.PI * 2; a += angleStep) {
ctx.setTransform(1,0,0,1, offset * Math.cos(a), offset * Math.sin(a));
ctx.drawImage(ctx.canvas, 0, 0);
}
ctx.restore(); // removes clipping, comp. mode, transforms
// set new color and redraw same path as previous
ctx.strokeStyle = "#975"; // color for inner line
ctx.stroke();
<canvas height=250></canvas>
I'm late to the party, but here's an alternate way to "outside stroke" a complex path.
It uses a PathObject to simplify the process of creating the outside stroke.
The PathObject saves all the commands and arguments used to define your complex path.
This PathObject can also replay the commands--and can thereby redefine/redraw the saved path.
The PathObject class is re-usable. You can use it to save any path (simple or complex) that you need to redraw.
Html5 Canvas will soon have its own Path2D object built into the context, but my example below has a cross-browser polyfill that can be used until the Path2D object is implemented.
An illustration of a cloud with a silver lining applied using an outside stroke.
"Here's how it's done..."
Create a PathObject that can save all the commands and arguments used to define your complex path. This PathObject can also replay the commands--and can thereby redefine the saved path. Html5 Canvas will soon have its own Path2D object built into the context, but my example below is a cross-browser polyfill that can be used until the Path2D object is implemented.
Save a complex path using the PathObject.
Play the path commands on the main canvas and fill/stroke as desired.
Play the path commands on a temporary in-memory canvas.
On the temporary canvas:
Set a context.lineWidth of twice your desired outside stroke width and do the stroke.
Set globalCompositeOperation='destination-out' and fill. This will cause the inside of the complex path to be cleared and made transparent.
Draw the temporary canvas onto the main canvas. This causes your existing complex path on the main canvas to get the "outside stroke" from the in-memory canvas.
Here's example code and a Demo:
function log(){console.log.apply(console,arguments);}
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvas1=document.getElementById("canvas1");
var ctx1=canvas1.getContext("2d");
// A "class" that remembers (and can replay) all the
// commands & arguments used to define a context path
var PathObject=( function(){
// Path-related context methods that don't return a value
var methods = ['arc','beginPath','bezierCurveTo','clip','closePath',
'lineTo','moveTo','quadraticCurveTo','rect','restore','rotate',
'save','scale','setTransform','transform','translate','arcTo'];
var commands=[];
var args=[];
function PathObject(){
// add methods plus logging
for (var i=0;i<methods.length;i++){
var m = methods[i];
this[m] = (function(m){
return function () {
if(m=='beginPath'){
commands.length=0;
args.length=0;
}
commands.push(m);
args.push(arguments);
return(this);
};}(m));
}
};
// define/redefine the path by issuing all the saved
// path commands to the specified context
PathObject.prototype.definePath=function(context){
for(var i=0;i<commands.length;i++){
context[commands[i]].apply(context, args[i]);
}
}
//
PathObject.prototype.show=function(){
for(var i=0;i<commands.length;i++){
log(commands[i],args[i]);
}
}
//
return(PathObject);
})();
var x=75;
var y=100;
var scale=0.50;
// define a cloud path
var path=new PathObject()
.beginPath()
.save()
.translate(x,y)
.scale(scale,scale)
.moveTo(0, 0)
.bezierCurveTo(-40, 20, -40, 70, 60, 70)
.bezierCurveTo(80, 100, 150, 100, 170, 70)
.bezierCurveTo(250, 70, 250, 40, 220, 20)
.bezierCurveTo(260, -40, 200, -50, 170, -30)
.bezierCurveTo(150, -75, 80, -60, 80, -30)
.bezierCurveTo(30, -75, -20, -60, 0, 0)
.restore();
// fill the blue sky on the main canvas
ctx.fillStyle='skyblue';
ctx.fillRect(0,0,canvas.width,canvas.height);
// draw the cloud on the main canvas
path.definePath(ctx);
ctx.fillStyle='white';
ctx.fill();
ctx.strokeStyle='black';
ctx.lineWidth=2;
ctx.stroke();
// draw the cloud's silver lining on the temp canvas
path.definePath(ctx1);
ctx1.lineWidth=20;
ctx1.strokeStyle='silver';
ctx1.stroke();
ctx1.globalCompositeOperation='destination-out';
ctx1.fill();
// draw the silver lining onto the main canvas
ctx.drawImage(canvas1,0,0);
body{ background-color: ivory; }
canvas{border:1px solid red;}
<h4>Main canvas with original white cloud + small black stroke<br>The "outside silver lining" is from the temp canvas</h4>
<canvas id="canvas" width=300 height=300></canvas>
<h4>Temporary canvas used to create the "outside stroke"</h4>
<canvas id="canvas1" width=300 height=300></canvas>
im using a canvas to visualize a small game of mine.
Basicly i have two objects that represent space ships, each of them has a "Location" array which holds the ships current x/y.
According to these arrays, i drawImage on the canvas (totalw/h is 300/300 fyi).
Now, for the difficult part.
i want to draw animations (gunfire) on that canvas. basicly from ship1 x/y to ship2 x/y.
For the animation function itself, im passing an effects object that holds 3 Arrays, shooter.location[x, y], target.location[x, y] and a third array that holds where the EFFECT is currently at [x, y].
this.animateEffects = function(effects){
var shooter = effects.shooter;
var target = effects.target;
var current = effects.current;
var canvas = document.getElementById("effects");
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.fillStyle = "red";
context.arc(current[0], current[1], 5, 0, 2*Math.PI);
effects.current[0]++
effects.current[1]++
context.fill();
if (current == target){
console.log("ding");
this.end()
}
}
My "problem" is that im, if possible at all, looking for a smart way to determine (for each frame) if effects[x, y] should go ++ or -- or a combination of the two, depending on where the "moving" ships are located at (at the time, the shooting started).
Any advise or hints are appreciated.
You can fire a bullet from shooter to target using linear interpolation.
Calculate the difference in the original X & Y positions of the shooter and target.
// save the starting position of the bullet (== shooter's original position)
// (these original X & Y are needed in the linear interpolation formula)
bulletOriginalX=shooter.x;
bulletOriginalY=shooter.y;
// calc the delta-X & delta-Y of the shooter & target positions
// (these deltas are needed in the linear interpolation formula)
dx=target.x-shooter.x;
dy=target.y-shooter.y;
Move the bullet towards the target using the interpolation formula
// where percent == the percent you want the bullet to be between
// it's starting & ending positions
// (between starting shooter & starting target positions)
currentBulletX=bulletOriginalX+dx*percent;
currentBulletY=bulletOriginalY+dy*percent;
Here's an example:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
shooter={x:50,y:50};
target={x:100,y:100};
effect={x:50,y:50,dx:0,dy:0,pct:0,speedPct:0.25};
draw();
fire();
$('#test').click(function(){
moveEffect();
draw();
});
function fire(){
effect.x=shooter.x;
effect.y=shooter.y;
effect.dx=target.x-shooter.x;
effect.dy=target.y-shooter.y;
effect.pct=0;
}
function moveEffect(){
effect.pct+=effect.speedPct;
}
function draw(){
ctx.clearRect(0,0,cw,ch);
ctx.beginPath();
ctx.arc(shooter.x,shooter.y,15,0,Math.PI*2);
ctx.closePath();
ctx.strokeStyle='green';
ctx.stroke();
ctx.beginPath();
ctx.arc(target.x,target.y,15,0,Math.PI*2);
ctx.closePath();
ctx.strokeStyle='red';
ctx.stroke();
if(effect.pct>1){return;}
var x=effect.x+effect.dx*effect.pct;
var y=effect.y+effect.dy*effect.pct;
ctx.beginPath();
ctx.arc(x,y,3,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle='black';
ctx.fill();
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id=test>Animate 1 frame</button>
<br><canvas id="canvas" width=300 height=300></canvas>
How do you draw with alpha = 0 to an HTML5 Canvas? Imagine I'm making a photoshop clone, I have a layer that's solid red. I pick the eraser tool and draw with. It draws in rgba(0,0,0,0) letting me see through to the background. How do I do this in HTML5 Canvas?
Here's some code.
var rand = function(v) {
return Math.random() * v;
};
var canvas = document.getElementsByTagName("canvas")[0];
var ctx = canvas.getContext("2d");
// fill the canvas with black
ctx.fillStyle = "red";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Erase some circles (draw them in 0,0,0,0);
ctx.fillStyle = "rgba(0,0,0,0)";
ctx.globalCompositeOperation = "copy";
for (var ii = 0; ii < 5; ++ii) {
ctx.beginPath();
ctx.arc(rand(canvas.width), rand(canvas.height),
rand(50) + 20, 0, 360, false);
ctx.fill();
}
/*
source-over
source-in
source-out
source-atop
destination-over
destination-in
destination-out
destination-atop
lighter
darker
copy
xor
*/
canvas {
margin: 10px;
border: 1px solid black;
background-color: yellow;
}
<div>Want red with yellow circles</div>
<canvas></canvas>
This doesn't work. All canvas operations are considered to be infinitely large which means drawing each circle (arc) with globalCompositeOperation set to "copy" effectively erases everything outside of each circle.
I might be able to setup clipping to match the circle but ideally I'd like to be able to erase with an anti-aliased circle, same as a photoshop brush.
You'll want to use:
ctx.fillStyle = "rgba(0,0,0,1)"; // (Drawing with 0 alpha pretty much means doing nothing)
ctx.globalCompositeOperation = "destination-out";
Working Example
Keep in mind to save the previous globalCompositeOperation and restore it, or transparency won't work properly, later on.
The problem is that "Drawing with alpha=0 on a canvas just overlays a invisible layer of "ink", by default.
If you have to erase fluently, so when the mouse was clicked and moved this line should be erased, this might be a solution:
var canvas = document.getElementById("myCanvas");
var eraseWidth = 5;
$("#myCanvas").mousedown(function(canvas){ //the mousedown (writing) handler, this handler does not draw, it detects if the mouse is down (see mousemove)
x = canvas.pageX-this.offsetLeft;
y = canvas.pageY-this.offsetTop;
});
$("#myCanvas").mousemove(function(canvas){
context.beginPath();
var x2 = x-(eraseWidth/2); //x2 is used to center the erased rectangle at the mouse point
var y2 = y-(eraseWidth/2); //y2 is used to center the erased rectangle at the mouse point
context.clearRect(x2, y2, eraseWidth, eraseWidth); //clear the rectangle at the mouse point (x2 and y2)
context.closePath();
};
basically what this does is clear a rectangle when the mouse is moved, everytime the mousehandler sends a mousemove event and uses the x and y coordinates for the center of the canvas to clear the recangle. the result is a cleared (erased) line.
ok, you can see the rectangles if you move too fast, but my project was a concept, so it did the trick for me ;)
If you're working on something akin to a photoshop clone, then it's probably best for you to create a canvas for each layer. I think that would greatly simplify everything for you, while giving you better performance in return.