HTML5 canvas dirty rectangle Buggy Issue - javascript

I am using dirty rectangles to animate a tank go around a map. For fair game-play, the tank's torso can travel only in the cardinal directions and it's top cannon (separate from the torso, but attached to it) can also rotate in the cardinal directions.
The issue is that when I use clearRect, it may clear other objects, and obstacles immediate to it. clearRect is called as the tank moves in the certain velocity. Is it possible (without any premade physicsEngine / extermal Gitub API I have to lean), to animate the tank such that, it doesn't clear objects around it?
I've tried multiple canvases too..
How would I overlay multiple canvases, so the animation still shows, but the clearRect in one doesn't affect any object in the other?
Image of sample issue:

There are two (common) options:
Draw the tanks only on a separate canvas so when you clear a tank only that canvas is affected. You can overlay canvases using fixed or absolute positioned elements.
Use a single canvas but redraw everything. You can make the redraw more efficient by using a clipping mask for the region you want to redraw.
1) To overlay canvases:
<div id="canvasContainer">
<canvas id="canvas1" ... ></canvas>
<canvas id="canvas2" ... ></canvas>
</div>
CSS:
#canvasContainer {
position:relative;
}
#canvasContainer > canvas {
position:absolute;
left:0;
top:0;
}
2) To set a clipping mask:
ctx.clearRect(x, y, w, h);
ctx.beginPath();
ctx.rect(x, y, w, h);
ctx.save();
ctx.clip();
/// redraw everything, only clipped region will be updated
ctx.restore();
Of course, if your code/setup allow you can just redraw the area inside the regions you cleared instead of everything but if this is possible depends entirely on the draw logic you have implemented.

Related

HTML5 canvas line width less that 1 pixel

Is there any way to draw a rectangle whose composing lines have width thinner than 1 pixel?
This code works perfectly, as expected:
// context is a HTML5 canvas 2D context
context.lineWidth = 1;
context.strokeStyle = "black";
context.rect(0, 0, 20, 20);
context.stroke();
It draws a nice rectangle.
But, if I try to draw a rectangle with thinner lines:
// See line width
context.lineWidth = 0.5;
context.strokeStyle = "black";
context.rect(0, 0, 20, 20);
context.stroke();
It still draws a rectangle whose borders have 1 pixel width.
I'm dealing with the canvas object here, and not CSS, where you have ways to "simulate" this.
Although it doesn't make much sense, you can acheive that with using a regular 1-pixel line with a 50% scaled canvas (but again it's a 1-pixel rendition, read below). See this snippet:
var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
function scale() {
context.scale(0.5, 0.5);
draw();
}
function draw() {
context.beginPath();
context.moveTo(100, 150);
context.lineTo(450, 50);
context.stroke();
}
draw()
<canvas width="400" height="150"></canvas>
<button onclick="scale()">Scale down</button>
But again, I wonder how you expect the half-pixel line to look on your screen, antialiasing?
Right :) I suppose I was thinking on some way of drawing thinner lines, like, for example, when you use CSS styles. I've looked around and I don't think I can use alternate units.
There's no way to make something that's smaller than the smallest component unit, in our case a pixel. You can mimic the thinner look by transparency, or opacity, or even some sort of antialiasing (which again relies on transparency or the colouring of the neighbouring pixels), but not by trying to go below one pixel.
I agree, there is a sub-pixel rendering mode in browsers, for example, when you work with percentages, but in the end, the browser just renders full pixels with some of the modification I've described above.
And you know if you could render unit smaller than pixels, you'd technically have infinite resolutions on displays. I wish it was possible. :)

How to clear rectangle on Image in Canvas

I need to clear a rectangle Drawn on Image in Canvas with out damage existing image. I can draw small rectangle points and clear that out. But the problem is when I clear rectangle it remains as white small patch on image.
Can someone tell me how to clear a rectangle on image without damage the existing image.
I have used following methods to clear rectangles but didn't work.
1) context.fillStyle ="white";
2) context.clearRect(xCoordinate, yCoordinate, 10, 08);
Thanks in advance!
Canvas doesn't work that way. It's a single layer, its also transparent by default. So with that in mind, you might be able to achieve what you want by simply giving the canvas element a CSS background. That way anything you draw on top of that background can easily be removed and the background will show through.
#backed-canvas{
background-image: url(http://www.placebear.com/300/200);
}
JSFiddle example: https://jsfiddle.net/yLf5erut/
There is one thing you can do.
When create a rectangle on the canvas just get the image data like:
var imgData = context.getImageData(xCoordinate, yCoordinate, 10, 8);
and draw the rectangle.
When clearing out the rectangle just place then image data back like this:
context.putImageData(imgData, xCoordinate, yCoordinate);
I suggest using 2 canvas elements one over another.
So you can have the original image drawn on the bottom canvas with low zIndex, and the top one with highter zIndex can be used to draw / clear whatever needed. This is a common practice, and for more complecated animations you will end up with better performance.

How to remove a drawn arch from canvas

I have been trying to print arc in the html page. How can i remove the already drawn arch from the page?. i have written the below code.
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="1200" height="1000"
style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
/*ctx.beginPath();
ctx.arc(600,500,20, 0.5*Math.PI,2*Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(600,500,40, 0.5*Math.PI,2*Math.PI);
ctx.stroke();
*/
var radius=20;
for (i=0; i<10; i++)
{
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(600,500,radius, 0.5*Math.PI, 2*Math.PI);
ctx.stroke();
radius= radius+30;
}
</script>
</body>
</html>
How can i achieve this?.
Call clearRect method:
ctx.clearRect(0, 0, 1200, 1000)
The four arguments are:
axis-X of left top corner of the area to wipe
axis-Y of left top corner of the area to wipe
width of the area to wipe
height of the area to wipe
So with this method, you could wipe either the whole canvas or just a certain part of it.
If you want to remove the whole previously drawn image please take a look at the other anwers. In the comments OP made it clear that this is not what he was trying to achieve. So instead I will answer the intended question:
How do I un-stroke a path?
A bitmap is not a vector graphic. You cannot simply remove or modify things you've drawn previously. By drawing on a canvas you modify the pixel color values of its image data. If you need to undo things you have to maintain a separate data structure with the relevant data yourself.
For example you could create a copy of the image data before drawing something. Then you could return to this snapshot afterwards. HTMLCanvasElement#toDataURL returns the complete image as an url which you can use as the src of an image. Later you can draw this image on the canvas to revert all subsequent changes. HTMLCanvasElement#toBlob does about the same but it returns a blob. This might consume less memory but it's a little more inconvenient to use. The most convenient method is CanvasRenderingContext2D#getImageData. You can even use it to copy only a small part of the image. This is useful if you have a big canvas but only modify pixels in a small region.
Another way to make modifications undoable is by maintaining a detailed list of your steps. For example whenever you draw an arc you store the exact parameters as one entry in the list. steps.push({type: 'stroke', style: 'rgb(0,0,0)', shapes: [{type: 'arc', x: 600, y: 500, radius: radius, from: 0.5 * Math.PI, to: 2 * Math.PI}]}) You can remove, rearrange or modify the elements in this list any way you like and have all necessary information to draw the resulting image from scratch. Basically you've implemented just another vector graphic library.

Division / sub-canvas

I have few coordinates in an XML file. They are lines, circles and arcs. I am reading them in a data structure and then trying to plot them on a canvas. What i am trying to figure out is how to divide the canvas into sub canvases. e.g suppose my canvas is
<canvas id="myCanvas" width="800" height="600" role="img">
Your browser does not support the canvas element.
</canvas>
What I am trying to achieve is how to make an imaginary window of width and height of 200px starting from say x1=200px on canvas and y1=250. And draw the image I have only in that box.
I have managed to scale down the image based on the imaginary box but cannot get around the concept of how to draw only in that imaginary box. The points are randomly distributed.
There are other ways to achieve this but the one you'll probably find most useful in this context is to use translation and a clip mask:
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
/// for simplicity, save current settings
ctx.save();
/// move coordinate system to the upper left corner of isolated region
ctx.translate(offsetX, offsetY);
/// create a clipping mask by using a simple rectangle
ctx.beginPath();
ctx.rect(0, 0, width, height);
/// define the last path (rectangle) as clipping mask
ctx.clip();
/// ... draw other things into this region from offset 0...
ctx.restore(); /// done and back to full canvas
By moving the whole coordinate system to the upper left corner of your region you can use offsets relative to the new isolated area. By adding a clip mask anything drawn outside the region will be clipped.
You will need to do this for each region one by one.
Another way is to add an offset to all drawing points. For example:
ctx.lineTo(x + offsetX, y + offsetY);
where offsetX/Y is the upper left corner of the region.
However, it will get more complicated if you need clipping - not a huge issue with images as you can define the destination region but for lines and and other path operation you will need to clip yourself by using interpolation etc.
Here is a live demo demonstrating this:
Fiddle (updated link)
The demo sets up a canvas and context and then fills the whole with a red color.
Then if sets the clipping and mask and translate it.
We now have a "virtual canvas" and the other graphic is intact
We now fill the region with the same fill operation but with blue. Now we can see only this regions is filled even the size is outside the actual region
Then we remove the clip and draw a line as evidence that we are now back in full mode

HTML5/Javascript - How to get the coordinates of a shape/image on the canvas?

Say I drew a rectangle on the canvas. Surely there is some sort of built in method to get the XY coordinates, and dimensions of that rectangle? But after some googling I came up with nothing. And just to clarify, I am not talking about the coordinates of the canvas element itself, but rather a shape/image that is drawn unto the canvas.
Any help is appreciated.
If you're talking about a 2D canvas drawing, then the drawing maps 1:1 with screen coordinates, so it is just location of <canvas> + location of the drawing.
To clarify, drawing on a <canvas> basically just changes the pixels of the canvas - after you draw to it, you can't reference the drawn object the same way you can reference an html element.
Canvas is 2D table (Array) of numbers (= pixels = colors). When drawing into canvas, you are just editing this table. When you draw into canvas (= change numbers in table), what should be the coordinates of your adjustment?
If you are drawing rectangles only and you can define the coordinates for your rectangle, you must know your coordinates inside a program, because you have just drawn it.
If you want your image to be separated into some "objects" (shapes), you should use SVG.
Basically, you should be using canvas as a means to output graphics to the screen and the rest of your logic goes straight into the JavaScript that powers your game/application. The best way to go about making something like this is to create objects and assign properties to them; in its simplest form that can look like this:
function Player(x, y)
{
this.x = x;
this.y = y;
}
var examplePlayerObject = new Player(20, 20);
By extending this object via prototyping you can create multiple copies of an object that has the exact same functions; such as draw. Drawing the player in this instance could just be a red square that is 20px*20px.
Player.prototype.draw = function()
{
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = 'red';
context.fillRect(this.x, this.y, 20, 20);
}
Then, you should have an update step with some means of clearing what is on the screen and redrawing the parts which have changed.
function animationStep()
{
examplePlayerObject.x++;
examplePlayerObject.y++;
examplePlayerObject.draw();
}
This animation step should run each frame; look into requestAnimationFrame for smooth animation. Paul Irish has a good shim for older browsers. Add in requestAnimationFrame(animationStep) at the end of that function and you will have a red square moving slowly across the screen. Good luck!

Categories