Why is canvas.arc not working? - javascript

I have this code at the end of a web page:
var canvas = document.getElementByID("canvas");
var ctx = canvas.getContext("2d");
canvas.style.width = $(window).width();
canvas.style.height = $(window).height();
ctx.arc(50, 50, 50, 0, Math.PI * 2, false);
$(window).resize(function () {
canvas.style.width = $(window).width();
canvas.style.height = $(window).height();
console.log("resize");
});
But nothing shows up. I know that the problem is with the arc function because ctx.fillRect(0, 0, 100, 100); works fine.
Any idea what I am doing wrong?
(Yes, I do have JQuery)

You need to use ctx.beginPath() before ctx.arc() and ctx.stroke() afterwards, this tells canvas to clean its buffer before it starts drawing, and to output buffer to the canvas after it finishes. fillRect()/strokeRect() already handles those begin/end tasks for you.

You need to do a path:
var canvas = document.getElementByID("canvas");
var ctx = canvas.getContext("2d");
canvas.style.width = $(window).width();
canvas.style.height = $(window).height();
ctx.beginPath(); // <-- start a path
ctx.arc(50, 50, 50, 0, Math.PI * 2, false); // <-- add the arc to the path
ctx.strokeStyle = "#000000"; // <-- set fill color
ctx.stroke(); // <-- draw the arc
$(window).resize(function () {
canvas.style.width = $(window).width();
canvas.style.height = $(window).height();
console.log("resize");
});

First of all ID in first line needs to be Id.
Then for the arc function there needs to be a ctx.beginPath();
function to start.
after that give it a colour eg. ctx.fillStyle = "Colour You
Want";
then, your arc function ctx.arc(50, 50, 50, 0, Math.PI * 2,
false); as it is
and after that at the end put ctx.fill(); to complete the
process.

Related

Rotate canvas image to anticlockwise in the same canvas

Say we have a canvas:
<canvas id="one" width="100" height="200"></canvas>
var canvas = document.getElementById("one");
var context = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
// Sample graphic
context.beginPath();
context.rect(10, 10, 20, 50);
context.fillStyle = 'yellow';
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();
// create button
var button = document.getElementById("rotate");
button.onclick = function () {
// rotate the canvas 90 degrees each time the button is pressed
rotate();
}
var myImageData, rotating = false;
var rotate = function () {
if (!rotating) {
rotating = true;
// store current data to an image
myImageData = new Image();
myImageData.src = canvas.toDataURL();
myImageData.onload = function () {
// reset the canvas with new dimensions
canvas.width = ch;
canvas.height = cw;
cw = canvas.width;
ch = canvas.height;
context.save();
// translate and rotate
context.translate(cw, ch / cw);
context.rotate(Math.PI / 2);
// draw the previows image, now rotated
context.drawImage(myImageData, 0, 0);
context.restore();
// clear the temporary image
myImageData = null;
rotating = false;
}
}
}
And on a button click the canvas gets rotated -90 degrees anticlockwise (around the centre) and the dimensions of the canvas get also updated, so in a sense, it looks like this afterwards:
I want to rotate a canvas element to the anticlockwise rotation. I have used this code but it's not working as I want.
JavaScript has a built-in rotate() function for canvas context:
context.rotate( angle * Math.PI / 180);
The problem is that the rotation will only affect drawings made AFTER the rotation is done, which means you will need to:
Clear the canvas first: context.clearRect(0, 0, canvas.width, canvas.height);
Rotate the context context.rotate( 270 * Math.PI / 180);
Redraw the graphics
Thus, I recommend wrapping the graphics we want to draw in a function to make it easier to call after every rotation:
function drawGraphics() {
context.beginPath();
context.rect(10, 10, 20, 50);
context.fillStyle = 'yellow';
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();
}

Blur behind transparent box in JavaScript canvas

How can I achieve a blur behind a transparent box (fillStyle = 'rgba(255, 255, 255, 0.2)') in JavaScript canvas? Here's what I've got so far:
var canvas = document.getElementById('draw');
var c = canvas.getContext('2d');
function main() {
c.fillStyle = '#222';
c.fillRect(0, 0, canvas.width, canvas.height);
c.fillStyle = '#000';
c.fillRect(32, 32, 64, 64);
c.fillStyle = 'rgba(255, 255, 255, 0.2)';
c.filter = 'blur(5px)';
c.fillRect(16, 16, 128, 24);
}
But what happens, is instead of blurring the background behind the rectangle, is the rectangle itself is blurred, kind of obviously.
In the final script, I will probably use paths instead of rects.
Context2D filters will be applied only on your new drawings, so to also blur the background, you would actually have to redraw the part of the background you want to be blurred.
Fortunately, canvas can drawImage itself.
var blurredRect = {
x: 80,
y: 80,
height: 200,
width: 200,
spread: 10
};
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
function draw() {
canvas.width = img.width / 2;
canvas.height = img.height / 2;
// first pass draw everything
ctx.drawImage(img, 0,0, canvas.width, canvas.height);
// next drawings will be blurred
ctx.filter = 'blur('+ blurredRect.spread +'px)';
// draw the canvas over itself, cropping to our required rect
ctx.drawImage(canvas,
blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height,
blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height
);
// draw the coloring (white-ish) layer, without blur
ctx.filter = 'none'; // remove filter
ctx.fillStyle = 'rgba(255,255,255,0.2)';
ctx.fillRect(blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height);
}
<canvas id="canvas"></canvas>
But, canvas blur filter is a bit different than CSS one in that it will make the spreading stay inside the drawn area. This means that in our case, we have a 5px border around our rectangle that is less blurred than the center.
To workaround, we can take the whole thing in a different order and play with globalCompositeOperation property*:
var blurredRect = {
x: 80,
y: 80,
height: 200,
width: 200,
spread: 10
};
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
function draw() {
var spread = blurredRect.spread,
ratio = 0.5,
// make our blurred rect spreads
x = blurredRect.x - spread,
y = blurredRect.y - spread,
w = blurredRect.width + (spread * 2),
h = blurredRect.height + (spread * 2);
canvas.width = img.width * ratio;
canvas.height = img.height * ratio;
// this time we will first draw the blurred rect
ctx.filter = 'blur('+ spread +'px)';
// this time we draw from the img directly
ctx.drawImage(img,
x / ratio, y / ratio, w / ratio, h / ratio,
x, y, w, h
);
// now we will want to crop the resulting blurred image to the required one, so we get a clear-cut
ctx.filter = 'none'; // remove filter
// with this mode, previous drawings will be kept where new drawings are made
ctx.globalCompositeOperation = 'destination-in';
ctx.fillStyle = '#000'; // make it opaque
ctx.rect(blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height);
ctx.fill(); // clear-cut done
// reuse our rect to make the white-ish overlay
ctx.fillStyle = 'rgba(255,255,255,0.2)';
// reset gCO to its default
ctx.globalCompositeOperation = 'source-over';
ctx.fill();
// now we will draw behind the our blurred rect
ctx.globalCompositeOperation = 'destination-over';
ctx.drawImage(img, 0,0, canvas.width, canvas.height);
// reset to defaults
ctx.globalCompositeOperation = 'source-over';
}
<canvas id="canvas"></canvas>
But this approach requires that we keep access to the whole background as a drawable thing, in the example above that was just an image, but in real life, this might mean you'd have to do this operation on a second offscreen canvas.
var blurredRect = {
x: 80,
y: 80,
height: 200,
width: 200,
spread: 2
};
var ctx = canvas.getContext('2d');
// create an off-screen canvas
var bCanvas = canvas.cloneNode();
var bCtx = bCanvas.getContext('2d');
var img = new Image();
img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
function draw() {
var spread = blurredRect.spread;
canvas.width = bCanvas.width = img.width / 2;
canvas.height = bCanvas.height = img.height / 2;
// now we have a composed background
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
ctx.font = '40px Impact';
ctx.fillStyle = 'white';
ctx.fillText('..SO BLUR ME..', 120, 282);
// make our clear-cut on the offscreen canvas
bCtx.filter = 'blur(' + spread +'px)';
bCtx.drawImage(canvas,
blurredRect.x - spread, blurredRect.y - spread, blurredRect.width + spread * 2, blurredRect.height + spread * 2,
blurredRect.x - spread, blurredRect.y - spread, blurredRect.width + spread * 2, blurredRect.height + spread * 2
);
// clear-cut
bCtx.filter = 'none';
bCtx.globalCompositeOperation = 'destination-in';
bCtx.beginPath();
bCtx.rect(blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height);
bCtx.fillStyle = '#000';
bCtx.fill();
// white-ish layer
bCtx.globalCompositeOperation = 'source-over';
bCtx.fillStyle = 'rgba(255,255,255,0.2)';
bCtx.fillRect(blurredRect.x, blurredRect.y, blurredRect.width, blurredRect.height);
// now just redraw on the visible canvas
ctx.drawImage(bCanvas, 0,0);
}
<canvas id="canvas"></canvas>
*One may say that instead of an offscreen canvas and gCO we could have used ctx.clip(), but since you said it might a more complex Path than a rect, I will not advise to do so. Indeed, while it would require less code, and maybe use less memory, clipping is just bad with antialiasing, and since you are doing blurring, that will just look plain ugly.

canvas rotate img horizontally

I am working on animation optimisation and i wanted to try out canvas to see how it performs but i am not experienced well in canvas and i dont know how to prepare concept of this kind of animation.
this is the gif that shows how animation should rotate like:
this is my current code of js:
var cvs = document.getElementById('coin-spin'),
ctx = cvs.getContext('2d'),
w = cvs.width = 400,
h = cvs.height = 400,
cx = w / 2,
cy = h / 2,
a = 0;
var img = new Image();
var loop = function() {
// BG
ctx.fillStyle = '#ccc';
ctx.fillRect(0, 0, w, h);
// draw image
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(Math.PI / 180 * a);
ctx.translate(-cx, -cy);
ctx.drawImage(img, cx - (img.width / 2), cy - (img.height / 2));
ctx.restore();
// axis
ctx.strokeStyle = '#000';
ctx.beginPath();
ctx.moveTo(cx, 0);
ctx.lineTo(cx, h);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, cy);
ctx.lineTo(w, cy);
ctx.stroke();
//mod angle
a++;
window.requestAnimationFrame(loop);
};
img.onload = function() {
loop();
};
img.src = 'https://image.ibb.co/gqkeXx/coin.png';
and the working demo on fiddle.
Could someone show how to add to the code so the image would rotate horizontally like on the gif?
EDIT ----
I added the spin, as it was also something to do, but still struggling on how to rotate it.
To get around the problem of rotating the object along two axes (faking one by mapping width to a sine wave), you can use an offscreen canvas to render the coin rotating around one axis, then render that canvas applying the second rotation ;
//make an offscreen canvas for rendering the coin rotating around one axis
var offscreenCanvas = document.createElement('canvas');
var cvs = document.getElementById('coin-spin'),
ctx = cvs.getContext('2d'),
w = cvs.width = 400,
h = cvs.height = 400,
cx = w / 2,
cy = h / 2,
a = 0;
var img = new Image();
var frameCount = 0;
var loop = function() {
frameCount++;
// BG
ctx.fillStyle = '#ccc';
ctx.fillRect(0, 0, w, h);
offscreenContext.fillStyle = '#ccc';
offscreenContext.fillRect(0, 0, w, h);
//determine how wide to render the offscreen canvas so we can fake
//rotation around the second axis
var imgRenderWidth = offscreenCanvas.width * Math.sin(frameCount/10.0)
//render the coin rotating around one axis to the offscreen canvas
offscreenContext.save();
offscreenContext.translate(img.width/2, img.height/2);
offscreenContext.rotate(Math.PI / 180 * a);
offscreenContext.translate((0-img.width)/2, (0-img.height)/2);
offscreenContext.drawImage(img, 0,0);
offscreenContext.restore();
// draw offscreen canvas to the screen with our precalculated width
ctx.save();
ctx.drawImage(offscreenCanvas, cx - (imgRenderWidth / 2), cy - (offscreenCanvas.height / 2), imgRenderWidth, offscreenCanvas.height);
ctx.restore();
// axis
ctx.strokeStyle = '#000';
ctx.beginPath();
ctx.moveTo(cx, 0);
ctx.lineTo(cx, h);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, cy);
ctx.lineTo(w, cy);
ctx.stroke();
//mod angle
a++;
window.requestAnimationFrame(loop);
};
//once the image has loaded, we know what size our offscreen canvas needs to be
img.onload = function() {
offscreenCanvas.width = img.width;
offscreenCanvas.height = img.height;
loop();
};
img.src = 'https://image.ibb.co/gqkeXx/coin.png';
//prepare the offscreen context so we can render to it later
var offscreenContext = offscreenCanvas.getContext('2d');
https://jsfiddle.net/ay3h5vuo/

Canvas use a letter instead of a shape?

I have written up an example, being new to canvas I need help transforming a basic circle into a letter.
Fiddle
Here is the code you will see in the fiddle. Note the circle drawing is what is in the center of the canvas, I am trying to use a letter like B with a cool font in place of the circle, I am just not sure how to implement this.
So just imagine where the circle is a letter being in that spot, still transparent with a rectangle overlaying the image with the color rgba(255,255,255,0.7).
var canvas = document.getElementById('c');
// resize the canvas to fill browser window dynamically
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
/**
* Your drawings need to be inside this function otherwise they will be reset when
* you resize the browser window and the canvas goes will be cleared.
*/
drawStuff();
}
resizeCanvas();
function drawStuff() {
if (canvas.getContext) {
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = 70;
// Full rectangle
context.fillStyle = 'rgba(255,255,255,0.7)';
context.fillRect(0, 0, window.innerWidth, window.innerHeight);
// Inner circle
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// Add a letter instead of a circle?
// Hmm
context.fillStyle = 'rgba(0,0,0,1)';
context.globalCompositeOperation = 'destination-out';
context.fill();
}
}
why not
context.fillStyle = 'rgba(0,0,0,1)';
context.strokeStyle = "#F00";
context.font = "bold 60pt Arial";
context.globalCompositeOperation = 'destination-out';
context.fillText("B", 20, 50);
http://jsfiddle.net/pqD87/
Here again with centering
context.fillStyle = 'rgba(0,0,0,1)';
context.globalCompositeOperation = 'destination-out';
context.textAlign = 'center';
context.font="150px Times";
context.fillText("A",centerX,centerY+40);
http://jsfiddle.net/x4BuF/1/

Whole canvas is being rotated?

I am just trying my hands at HTML5's most talked feature i.e canvas. There are 2 rectangles and I only want to rotate 1st and keep the 2nd one as it is. Problem is when the below code runs my whole canvas is rotated and both rectangles are rotated. I can't even find any API where I can get reference to the object that I have drawn and rotate only that specific object instead of the whole context.
Code:
<script type="text/javascript">
var context;
var radian = 0.01;
var w, h;
$(document).ready(function () {
w = document.width;
h = document.height;
var canvas = $('#canvas');
context = canvas[0].getContext('2d');
canvas[0].width = w;
canvas[0].height = h;
setInterval(startAnim, 200);
});
function startAnim() {
context.clearRect(0, 0, w, h);
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(0,0,0)';
context.fillRect(0, 0, w, h);
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(255,255,0)';
context.rotate(radian);
context.strokeRect(400, 300, 200, 200);
context.fillRect(400, 300, 200, 200);
context.fillStyle = 'rgb(0,255,255)';
context.fillRect(500, 400, 200, 200);
radian += 0.01;
}
</script>
How can I prevent this from happening?
Finally, I have resolved the issue on my own by trial and error. This is the code:
<script type="text/javascript">
var context;
var radian = 0.01;
var w, h;
$(document).ready(function () {
w = document.width;
h = document.height;
var canvas = $('#canvas');
context = canvas[0].getContext('2d');
canvas[0].width = w;
canvas[0].height = h;
setInterval(startAnim, 100);
});
function startAnim() {
context.save();
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(0,0,0)';
context.fillRect(0, 0, w, h);
context.rotate(radian);
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(255,255,0)';
context.strokeRect(400, 300, 200, 200);
context.fillRect(400, 300, 200, 200);
context.restore();
context.fillStyle = 'rgb(0,255,255)';
context.fillRect(500, 400, 200, 200);
radian += 0.1;
}
</script>
As I understand you have to clear the whole canvas and redraw everything, between each frame. Keep the data for the rectangles in memory. Do the context.clearRect(0, 0, w, h); between each frame, then draw the rectangles again with there new altered properties.

Categories