I've got a canvas that includes images, I'm re-drawing 1 pixel lower each time to give the effect of falling. I've got the images in an array and I just place them 1 pixel lower without recreating the image.
Is it possible to add a border dynamically to images that reach a certain point and if so, how?
Yes, all you have to do is draw a path outside the image and call ctx.stroke() to make the border.
So say the image has the coordinates x and y, with a width and height of w and h, you just do:
ctx.rect(x, y, w, h);
ctx.stroke();
Want a different colored border?
ctx.strokeStyle = 'blue';
Thicker?
ctx.lineWidth = 5;
If you know your images' size and location and as you draw them you probably do, You can use the .rect canvas method to draw a rectangle around the image.
Related
I am making annotations on images using a jpeg image and rectangles that I am drawing onto the image. I can then transfer the image to a canvas, and, using a for-loop, I can grab the bounds of the rectangular divs that I had drawn on the image to re-draw on the canvas.
The problem arises when I have multiple rectangles because the opacity decreases on each subsequent rectangle due to the fact that they are being layered, as such: `
function drawRectangleToCanvas(left, top, width, height, canvas, context, opacity) {
context.globalCompositeOperation='destination-over';
context.strokeStyle = 'rgba(0,255,130,0.7)';
context.fillStyle = 'rgba(0,0,255,'+opacity+')';
context.rect(left, top, width, height);
context.setLineDash([2,1]);
context.lineWidth = 2;
context.fill();
context.stroke();
}
From my understanding, the context.globalCompositeOperation='destination-over' causes the rectangles to be placed onto the image like slices of bread. With each rectangle that is drawn on the div, the opacities overlap, causing the opacity to increase by a factor of, in this case, 0.1. This is what the issue looks like: Canvas with layered rectangles and opacity problems.
How can I just add all the rectangles without this opacity issue? I call this method for each and every rectangle that I have, so I didn't know if I could put all the rectangles in an array or what. Any suggestions to fix this would be helpful.
EDIT: The darkest rectangle is the first one to be drawn, just to add some information.
Not completely sure what you want but you can leave out the calls to the stroke and fill methods until you have defined all the rectangles.
// Not much left to do in the function but just here to illustrate
// that creating the rectangles should be put together
function drawRectangleToCanvas(left, top, width, height, canvas, context){
context.rect(left, top, width, height);
}
context.globalCompositeOperation='destination-over';
context.strokeStyle = 'rgba(0,255,130,0.7)';
context.fillStyle = 'rgba(0,0,255,'+opacity+')';
context.setLineDash([2,1]);
context.lineWidth = 2;
context.beginPath();
while(??? ){
// loop and define all the rectangles
drawRectangleToCanvas(... //
}
// once all the rectangles are defined
// call the fill and stroke to render them
context.fill();
context.stroke();
This will stop them compounding the alpha values
after trying a few ways to preserve a background under a canvas drawing a moving rectangle (animation code not reproduced), here is my best try :
canvas {background-image:url('background.png');}
var x,y, pixels;
function draw() {
if(pixels) {
context.putImageData(pixels,x,y);
}
x = //calculate new X
y = //calculate new Y
pixels = context.getImageData(x, y, 10, 10);
context.fillStyle = 'red';
context.fillRect(x, y, 10, 10);
}
My first question is : why won't replacing the first two lines of draw() with :
context.fillStyle = 'rgba(10,10,10,0)';
context.fillRect(x,y,10,10);
work to clear the previously drawn pixels?
And my second question is : is there really no better way than get and putImageData(), which are very labor-intensive?
EDIT: in particular is there a div containing the background image trick that would maybe work without the get and putImageData calls?
Thanks!
By default, whatever you draw gets drawn on top of each other, instead of being replaced.
Use context.clearRect(x,y,10,10); instead.
There is also the context.globalCompositeOperation property, which could be set to "destination-out" before using fillRect .. but you're better off with clearRect.
I am trying to draw a sharp thin rectangle using canvas control.I want the canvas background to get loaded with an image and in foreground with some text .
Though i am able to set the color and text they are somehow appearing blurred.Is there a way to fix this issue ?
And i want to apply an image as background image for each canvas rectangle i will draw.These rectangels will appear a in a div control.So wherever there is a canvas rectangle i want its background image to be filled with the image i choose.entire div will not be filled with canvas rectangles but only half of it.Is there a way whether we can have one image for all the canvas rectangles i will draw or do ineed to draw it for every rectangle ?
html:
<div id="divBoard" >
<canvas id="canvasBoard" />
</div>
javascript:
canvas = document.getElementById("canvasBoard");
if (canvas.getContext) {
var context = canvas.getContext("2d");
}
context.fillStyle = "green";
context.fillRect(x, y, width,height);
context.font = "5px tahoma";
context.fillStyle = "black";
context.fillText("cell"+i, x, y + width);
this is the image displayed after executing my code
I have experienced the same issue with fonts not rendering as sharply on a canvas. In my project I did a workaround by placing the font in a separate DIV and overlaying it on the canvas using an appropriate z-index. This approach worked very well for me.
Have you tried adding 0.5 to x and y? The html5 canvas uses antialiasing so if you want "crisp" lines, you need to draw "in between" the pixels.
You will find a good explanation on how this works in mozilla developer reference page for lineWidth
PS. also see this question
I'm trying to draw a circle and then have an image follow the circle around. Later I want to rotate and move the image around with respect to the circle drawn. The problem I'm facing is that when I try to rotate the image it won't rotate. It also doesn't show me an error in the console. I have functions allowing me to move the circle around and the image moves with it, I just can't seem to rotate the image.
Here is the code:
draw: function(){
//draw self on canvas;
//intended only to be called from update, should never
//need to be deliberately called
ctx = this.context;
ctx.save();
ctx.fillStyle="#000000";
ctx.beginPath();
//void arc(double x, double y,
// double radius, double startAngle, double endAngle,
// optional boolean anticlockwise = false);
ctx.arc(this.x,this.y,this.size,0,Math.PI*2,true);
ctx.closePath();
ctx.fill();
//ctx.translate(this.x, this.y);
ctx.rotate(this.imgAngle);
//draw the hammer
ctx.drawImage(this.hammer,this.hammerX,this.hammerY,100,100)
ctx.rotate(Math.PI/2);
ctx.restore();
},
Live Demo
Try changing your code to the following. You need to perform the rotation before drawing. You can translate the canvas to the entities position and then draw the image at x:0,y:0 to get the effect you desire. Note I did 0-50,0-50 because that puts the point of origin in the center since the width and height are 100. Meaning your image will rotate around its center rather than around its corner.
//draw the hammer
ctx.translate(this.hammerX, this.hammerY);
ctx.rotate(this.imgAngle);
ctx.drawImage(this.hammer,0-50,0-50,100,100);
The rotation will only affect drawings made AFTER the rotation is done.
You could try moving the rotate calls to just before the object that needs to be rotated?
I am using an HTML canvas and javascript and I need to clear all of the pixels underneath a shape created by closing a path (for example, I am using flot, and I want to make rounded corners, and to do this, I first need to remove the square corners by drawing a curve on top of the corner to remove the desired pixels).
Right now, I am doing this by just filling the shape with the same color as the background, which can imitate what I want to do, but, it is not ideal as it makes it impossible to place the chart on top of non-solid backgrounds without seeing the square corners. I know that there is a clearRect method that would do what I want to do, but with only rectangles, I need to do it with any closed shape. Is it possible, and if so, how would I do it?
brainjam's code was heading in the right direction, but didn't fully solve the problem. Here's the solution:
context.save();
context.globalCompositeOperation = 'copy';
context.fillStyle = 'rgba(0,0,0,0)';
//draw shape to cover up stuff underneath
context.fill();
context.restore();
Here's an example of a function that will clear a circle from a canvas:
var clearCircle = function(x, y, radius)
{
context.save();
context.globalCompositeOperation = 'destination-out';
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fill();
context.restore();
};
I think what you want is a clipping region, defined by the clip() function. The latter takes a bunch of paths. Here's an example.
This is a little different from what you are specifically asking (which is to remove pixels after drawing them), but actually not drawing the pixels in the first place is probably better, if I understand your requirements correctly.
Edit: I now think I understand that what you want to do is clear pixels to transparent black. To do that, after having defined your paths, do something like this:
context.fillStyle = 'rgba(0,0,0,0)';
context.fill();
The first statement sets the fill color to transparent black.
Use globalCompositeOperation = 'destination-out' instead of 'copy', it will erase all pixels of the shape in the canvas.
See all kinds of composition here
very usefull !