Trying to double the size of a circle onclick(). Doesn't seem to be working?
HTML
<canvas id="drawing" width="600px" height="600px" onclick="resize()"></canvas>
Javascript
window.onload = function() {
canvas=document.getElementById("drawing");
context=canvas.getContext("2d");
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
}
function resize () {
context.fillStyle= "#701be0"; // This changes the rectangle to blue
context.fill();
context.scale(10.5, 2.5);
}
You need to redraw your circle again and also keep in mind that context.scale() will also scale its position so i wouldn't recommend to do it this way. You can just draw a new circle over with bigger radius.
jsFiddle - http://jsfiddle.net/DSFMq/
Here's a jsFiddle for exactly what I needed, in case anyone needs help.
http://jsfiddle.net/elijahmurray/fHv82/1/
x=200;
y=200;
size=100;
radius=30;
function animate() {
reqAnimFrame = window.mozRequestAnimationFrame || //get framerate
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame
;
reqAnimFrame(animate);
if(radius <= 200) {
radius +=3;
} //increase size by 1 per frame
draw();
}
function draw() {
var canvas = document.getElementById("ex1");
var context = canvas.getContext("2d");
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
}
animate();
Related
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();
}
I want to implement hover effect with canvas elements. It works fine, if the canvas is not resized.
Code example: jsFiddle
window.onload = function (e)
{
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// Draw the rectangle
context.beginPath();
context.rect(50,50,100,100);
context.fill();
context.fillStyle = 'red';
// Draw the circle
context.beginPath();
context.arc(450,175, 50, 0,2 * Math.PI, false);
context.fill();
context.fillStyle = 'green';
// Draw the shape
context.beginPath();
context.moveTo(250,100);
context.lineTo(350,175);
context.lineTo(325,215);
context.lineTo(185,195);
context.fill();
canvas.onmousemove = function (e)
{
var canvas = e.target;
var context = canvas.getContext('2d');
// This gets the mouse coordinates (relative to the canvas)
var mouseX = e.clientX;
var mouseY = e.clientY;
// Replay the rectangle path (no need to fill() it) and test it
context.beginPath();
context.rect(50,50,100,100);
if (context.isPointInPath(mouseX, mouseY)) {
canvas.style.cursor = 'pointer';
return;
}
///////////////////////////////////////////////////////////////
// Replay the circle path (no need to fill() it) and test it
context.beginPath();
context.arc(450,175, 50, 0,2 * Math.PI, false);
if (context.isPointInPath(mouseX, mouseY)) {
canvas.style.cursor = 'pointer';
return;
}
///////////////////////////////////////////////////////////////
// Replay the irregular shape path (no need to fill() it) and test it
context.beginPath();
context.moveTo(250,100);
context.lineTo(350,175);
context.lineTo(325,215);
context.lineTo(185,195);
if (context.isPointInPath(mouseX, mouseY)) {
canvas.style.cursor = 'pointer';
return;
}
///////////////////////////////////////////////////////////////
// Return the cursor to the default style
canvas.style.cursor = 'default';
}
}
html, body {
margin: 0;
padding: 0;
}
<canvas id="canvas" width="500" height="500"></canvas>
As soon as you add style="width: 100%; height: 100%;" to the <canvas>
it is not working anymore. I think isPointInPath is using the "unscaled" version of canvas?
EDIT: Some minutes ago I read about testing isPointInPath in a separate canvas element which is not resized and also not visible to the user. Is this the solution? It heards like a performance killer, since for every mousemove you would need to create a canvas, test, and then delete.
Your problem is that you want to set the canvas to 100%.
But you need to request the width and height of the browser.
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
Browser = {
//get the width of the browser
width : window.innerWidth ||
root.clientWidth ||
body.clientWidth,
//get the height of the browser
height : window.innerHeight ||
root.clientHeight ||
body.clientHeight
};
canvas.style.position = "fixed";
canvas.style.left = 0;
canvas.style.top = 0;
canvas.width = Browser.width;
canvas.height = Browser.height;
// Draw the rectangle
context.beginPath();
context.rect(50,50,100,100);
context.fill();
context.fillStyle = 'red';
// Draw the circle
context.beginPath();
context.arc(450,175, 50, 0,2 * Math.PI, false);
context.fill();
context.fillStyle = 'green';
// Draw the shape
context.beginPath();
context.moveTo(250,100);
context.lineTo(350,175);
context.lineTo(325,215);
context.lineTo(185,195);
context.fill();
canvas.onmousemove = function (e)
{
var canvas = e.target;
var context = canvas.getContext('2d');
// This gets the mouse coordinates (relative to the canvas)
var mouseX = e.clientX;
var mouseY = e.clientY;
// Replay the rectangle path (no need to fill() it) and test it
context.beginPath();
context.rect(50,50,100,100);
if (context.isPointInPath(mouseX, mouseY)) {
canvas.style.cursor = 'pointer';
return;
}
///////////////////////////////////////////////////////////////
// Replay the circle path (no need to fill() it) and test it
context.beginPath();
context.arc(450,175, 50, 0,2 * Math.PI, false);
if (context.isPointInPath(mouseX, mouseY)) {
canvas.style.cursor = 'pointer';
return;
}
///////////////////////////////////////////////////////////////
// Replay the irregular shape path (no need to fill() it) and test it
context.beginPath();
context.moveTo(250,100);
context.lineTo(350,175);
context.lineTo(325,215);
context.lineTo(185,195);
if (context.isPointInPath(mouseX, mouseY)) {
canvas.style.cursor = 'pointer';
return;
}
///////////////////////////////////////////////////////////////
// Return the cursor to the default style
canvas.style.cursor = 'default';
}
html, body {
margin: 0;
padding: 0;
}
<canvas id="canvas" width="500" height="500"></canvas>
Perhaps you get a little wiser of how I caught the problem.
Here is my simple Browser object:
Browser = {
runTime: 0,
//Updates Browser Info
Update(time = 0) {
this.runTime = time;
//get the width of the browser
this.width = window.innerWidth ||
root.clientWidth ||
body.clientWidth;
//get the height of the browser
this.height = window.innerHeight ||
root.clientHeight ||
body.clientHeight;
//the center of the browser
this.centerX = this.width / 2;
this.centerY = this.height / 2;
}
}
Call in each frame the Browser.Update() so you can update the size of your browser when it changes.
var requestAnimation = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
function AnimationFrame(time) {
Browser.Update(time);
requestAnimationFrame(AnimationFrame);
}
// To start the loop.
AnimationFrame();
I've been having difficulty with producing crisp shapes on my canvas, I've been taking out code to try and debug it and it seems one of the causes is the fact that's being redrawn. Below is the code without a loop:
var context = $('canvas')[0].getContext('2d');
function draw() {
context.clearRect(0, 0, context.width, context.height);
context.beginPath();
context.arc(100, 100, 50, 0, 2 * Math.PI, false);
context.fillStyle = 'red';
context.fill();
context.lineWidth = 4;
context.strokeStyle = 'darkred';
context.stroke();
}
draw();
<canvas width=200 height=200></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
And here is the same again with the loop:
var context = $('canvas')[0].getContext('2d');
function draw() {
requestAnimationFrame(draw);
context.clearRect(0, 0, context.width, context.height);
context.beginPath();
context.arc(100, 100, 50, 0, 2 * Math.PI, false);
context.fillStyle = 'red';
context.fill();
context.lineWidth = 4;
context.strokeStyle = 'darkred';
context.stroke();
}
function init() {
if (typeof game_loop != "undefined") clearInterval(game_loop);
var game_loop = setInterval(draw, 30);
}
init();
<canvas width=200 height=200></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
For those who do not see what I do in Chrome, here's an image:
It would seem that even putting the line requestAnimationFrame(draw); in the first example causes the same issue.
What am I doing wrong here?
The problem is that you cannot access context.width and context.height. Therefore this will cause the clearRect method to fail and have the circles being drawn over another.
Use canvas.widthand canvas.height.
var canvas = $('canvas')[0]
var context = canvas.getContext('2d');
var game_loop
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.arc(100, 100, 50, 0, 2 * Math.PI, false);
context.fillStyle = 'red';
context.fill();
context.lineWidth = 4;
context.strokeStyle = 'darkred';
context.stroke();
}
function init() {
if (typeof game_loop != "undefined") clearInterval(game_loop);
game_loop = setInterval(requestAnimationFrame.bind(null, draw), 30) // use requestAnimationFrame but limit to 30ms interval - from #JoshuaK
}
init();
<canvas width=200 height=200></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
Also you used both, an interval and the requestAnimationFrame. Which will cause massive lags. Use intervals for anmation only when you have no other option. You could also use this polyfill:
window.requestAnimFrame = function(){
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(func){
window.setTimeout(func, 30);
}
);
}()
If you changed the transformation matrix (for example using scale, rotation, or translation), context.clearRect (0,0, canvas.width, canvas.height) will probably not remove the entire visible part Canvas
The solution? Reset the transformation matrix before clearing the canvas:
// Store the current transformation matrix
context.save();
// Use the identity matrix while clearing the canvas
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvas.width, canvas.height);
// Restore the transform
context.restore();
CanvasRenderingContext2D (the type of context) has no width and height attribute, but it keeps a reference to the canvas it belongs to.
And of course that has width/height, so the minimal change in your code could be:
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
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/
Okay, so I am new to canvas, I am trying to learn. I have created something below that sorta works - JSFiddle demo.
You see in the middle there is a circle, I would like that to be transparent, so, obviously, if you look at the code below there are two paths or objects, whatever they're called, and they overlay each other. Not what I need, obviously.
My question is: how do I have a canvas element/object take over the screen size with a transparent middle showing the background? The goal is to make something like this http://www.jcsuzanne.com/. I will eventually work my way up from a circle to a letter, but for now I am not sure how to make a "mask" with a transparent center.
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;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'rgba(0,0,0,0)';
context.fill();
context.lineWidth = 5;
context.stroke();
context.beginPath();
context.fillStyle = 'rgba(0,0,0,0.5)';
context.fill();
context.fillRect(0,0,window.innerWidth,window.innerHeight);
}
}
You can re-organize the lines a little and use composite mode to "punch" a whole in the overlay:
// fill background first
context.fillStyle = 'rgba(0,0,0,0.5)';
context.fillRect(0,0,window.innerWidth,window.innerHeight);
// define the arc path
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// stroke it
context.lineWidth = 5;
context.stroke();
// make alpha solid (the color doesn't matter)
context.fillStyle = 'rgba(0,0,0,1)';
// change composite mode and fill
context.globalCompositeOperation = 'destination-out';
context.fill();
// reset composite mode to default
context.globalCompositeOperation = 'source-over';
Modified fiddle