Can't figure out why HTML Canvas arc fails with a parameter - javascript

I've got a very simple HTML page with a Canvas element.
When I pass the 4th parameter of arc as Math.PI * 2, I get the red circle I expect, but when I try to do the same thing passing 3.1415 * 2, I get no red circle.
I expect that in both cases I would get the same result with a red circle.
const canvas = document.getElementById("solar-canvas");
const context = canvas.getContext("2d", { alpha: false });
context.beginPath();
context.fillStyle = "red";
//const val = Math.PI * 2;
const val = 3.1415 * 2;
context.arc(190,150, 9, 0, val, true);
context.fill();
context.closePath();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Simple Solar System</title>
</head>
<body>xxx
<canvas
id="solar-canvas"
width="380"
height="300"
style="border: 1px solid #aaaaaa"
></canvas>
</body>
</html>

I think what you are experiencing is best seen on an example:
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
let end = 0
function draw() {
context.clearRect(0, 0, 90, 90)
context.beginPath()
context.arc(22, 40, 20, 0, end, true);
context.stroke();
context.beginPath()
context.arc(65, 40, 20, 0, end);
context.fillText(end, 10,10)
context.stroke();
end += 0.05
}
setInterval(draw, 100)
<canvas id="canvas" width="90" height="90"></canvas>
3.1415 * 2 is close to Math.PI * 2 but not exactly the same...
It's not failing just the arc is very small
PI 3.14159265... could be rounded to 3.1416
if you use that in your counterclockwise arc you will get the full circle.
There is some weirdness with that last parameter counterclockwise why with big numbers it keeps deleting the arc that might be an interesting question to look into

Related

Flashing dots on canvas [duplicate]

This question already has answers here:
clearRect not working
(2 answers)
Closed 6 months ago.
I don't see why this code isn't working. It should just draw a white rectangle covering the screen. Then a randomly placed blue dot and wait for the loop to complete. And then repeat the cycle by drawing the white rectangle again and turning off the dot and then redrawing it.
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8"/>
<title>Peripheral vision checker</title>
<script type="application/javascript">
function draw() {
// draw crosshairs
var onFor = 1000;
const intervalID = setInterval(mytimer, onFor);
function mytimer()
{
// draw white rects
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
var x = 1280;//will be equal to window height
var y = 720;//will be equal to window width
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'white';
var xcoor =getRandomInt(x);
var ycoor =getRandomInt(y);
ctx.fillRect(0, 0, x, y);
ctx.fillStyle = 'blue';
var radius = 10;
moveTo(xcoor,ycoor);
ctx.arc(xcoor, ycoor, radius, 0, 2 * Math.PI);
//console.log(xcoor + ' ' + ycoor);//just temporary, to see they work
ctx.fill();
}
}
</script>
</head>
<h1>Peripheral vision checker</h1>
<body onload="draw();">
<canvas id="canvas" width="1280" height="720"></canvas>
</body>
</html>
You need to beginPath then closePath
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<title>Peripheral vision checker</title>
<script type="application/javascript">
function draw() {
// draw crosshairs
var onFor = 1000;
const intervalID = setInterval(mytimer, onFor);
function mytimer() {
// draw white rects
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
var x = 500; //will be equal to window height
var y = 250; //will be equal to window width
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'white';
var xcoor = getRandomInt(x);
var ycoor = getRandomInt(y);
ctx.fillRect(0, 0, x, y);
ctx.fillStyle = 'blue';
var radius = 10;
ctx.beginPath();
moveTo(xcoor, ycoor);
ctx.arc(xcoor, ycoor, radius, 0, 2 * Math.PI);
//console.log(xcoor + ' ' + ycoor);//just temporary, to see they work
ctx.fill();
// no need to:
// ctx.closePath();
}
}
</script>
</head>
<h1>Peripheral vision checker</h1>
<body onload="draw();">
<canvas id="canvas" width="500" height="250"></canvas>
</body>
</html>

How do I make a drawing repeat on canvas?

I need to make some repetitions but I'm not really sure how to make it, when the user clicks the button "Part one" it should display the pig drawing every 100 pixels to the right and when the user clicks parte two it should display a circle of pigs in the center of the canvas but it has to delete the function that part one did.
can someone help me please?
"use strict";
let ctx;
function setup() {
let canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
drawPig();
}
function drawPig() {
ctx.fillStyle = "pink"
ctx.beginPath();
ctx.arc(25, 40, 15, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.arc(40, 25, 10, 0, 2 * Math.PI);
ctx.fill();
ctx.fillRect(45, 20, 10, 10);
ctx.fillStyle = "black"
ctx.beginPath();
ctx.arc(42, 18, 1.5, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.moveTo(35, 50);
ctx.lineTo(50, 60);
ctx.moveTo(35, 50);
ctx.lineTo(35, 62);
ctx.moveTo(15, 50);
ctx.lineTo(5, 60);
ctx.moveTo(15, 50);
ctx.lineTo(15, 60);
ctx.stroke();
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Repetitions</title>
<script src="javascript.js" type="text/javascript"></script>
</head>
<body onload="setup()">
<h1>Repeat</h1>
<canvas id="myCanvas" height="500" width="500" style="border: 1px solid black"></canvas>
<br>
<button onclick="firstPart"> First Part</button>
<button onclick="secondPart">Second Part</button>
</body>
</html>
You can use CanvasRenderingContext2D.translate:
for (int i=0; i<ctx.canvas.width; i+=100){
for (int j=0; j=ctx.canvas.height; j+=100){
ctx.translate(i,j);
drawPig();
ctx.translate(-i,-j);
}
}
This will draw a pig every 100 px. You could use a similar function do draw something else.
As for clearing the canvas, you can use ctx.clearRect(clearRect(0, 0, canvas.width, canvas.height); to set all pixels to 0 alpha black. You can also use this function to clear only part of the canvas if you so desire.

I need to stack multiple randomly colored rectangles in html canvas

I want to have hella stacked rectangles that go to the center of the canvas and have them all randomly colored, but my code is wrong and isn't working.
Here is the code i have:
var ctx = canvas.getContext("2d");
var cornerpad = 0;
var rectwidth = 790;
var rectheight = 590;
function drawrectangles() {
ctx.beginPath;
ctx.rect(cornerpad, cornerpad, rectwidth, rectheight);
ctx.fillStyle = 'hsl(' + 360 * Math.random() + ', 50%, 50%)'
ctx.fill();
ctx.closePath;
}
while(rectheight > 5) {
rectheight =- 10;
rectwidth =- 10;
cornerpad++;
drawrectangles();
}
I am pretty sure I made the while loop wrong since the random color works and the drawing rectangles works. Please help and explain what I did wrong
You had some mistakes in your code. First of all, you have rectheight =- 10; instead of rectheight -= 10. Your line of code is actually equivalent to rectheight = -10, so you are just setting both of the variables to -10, not decrementing them by 10.
Then, you used fill instead of fillRect. There is a fine difference between them, you may read more here or here. fillRect is a "stand-alone" command that draws and fills a rectangle. So if you issue multiple fillRect commands with multiple fillStyle commands, each new rect will be filled with the preceeding fillstyle.
For a nicer effect, I recommend using strokeRect instead of rect, but that's your decision. Also, you may want to play with the condition from the while, to actually make them appear centered.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
var cornerpad = 0;
var rectwidth = 790;
var rectheight = 590;
function drawrectangles() {
ctx.beginPath();
ctx.rect(cornerpad, cornerpad, rectwidth, rectheight);
ctx.fillStyle = 'hsl(' + 360 * Math.random() + ', 50%, 50%)';
ctx.fill();
ctx.stroke();
}
while (rectheight > 5) {
rectheight -= 10;
rectwidth -= 10;
cornerpad += 10;
//console.log(`(h, w)=(${rectheight}, ${rectwidth})`);
drawrectangles();
}
canvas {
border: 1px dotted black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/canvasjs/1.7.0/canvasjs.js"></script>
<canvas id="canvas" width="790" height="590">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
Edit:
I added a version that draws them much nicer, check it out :)
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
var cornerpad = 0;
var rectwidth = 600;
var rectheight = 400;
var middleLine = rectheight / 2;
function drawrectangles() {
ctx.strokeRect(cornerpad, cornerpad, rectwidth, rectheight);
ctx.fillStyle = 'hsl(' + 360 * Math.random() + ', 50%, 50%)'
ctx.fillRect(cornerpad, cornerpad, rectwidth, rectheight);
}
while (cornerpad < middleLine) {
rectheight -= 20;
rectwidth -= 20;
cornerpad += 10;
//console.log(`(h, w)=(${rectheight}, ${rectwidth})`);
drawrectangles();
}
canvas {
border: 1px dotted black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/canvasjs/1.7.0/canvasjs.js"></script>
<canvas id="canvas" width="600" height="400">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
Cheers!
Edit 2:
Because I was too absorbed by the =- 10 thing, I forgot to point out to actually use beginPath and closePath as functions and to call them as ctx.beginPath() and ctx.closePath(). Thanks to Kaiido for pointing that out and for the two working additional jsfiddles.
I believe your problem is laying in this expressions =- what you mean is -=. what you are doing now is setting rectheight value to -10 instead of reducing it by 10, thus your while loop just gets executed once.
You missed some closing brackets and had the =- around the wrong way. I also change the rect to fill straight away.
var ctx = canvas.getContext("2d");
var cornerpad = 0;
var rectwidth = 790;
var rectheight = 590;
function drawrectangles() {
ctx.fillStyle = 'hsl(' + 360 * Math.random() + ', 50%, 50%)'
ctx.fillRect(cornerpad, cornerpad, rectwidth, rectheight);
}
while(rectheight > 5) {
rectheight -= 10;
rectwidth -= 10;
cornerpad++;
drawrectangles();
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<canvas id='canvas' height=590 width=790></canvas>
</body>
</html>

Set canvas object in motion using requestAnimationFrame

I am beginning my study in motion, using requestAnimationFrame. I wanted to put a circle on the canvas and then set that circle into motion with a click of a button. I have achieved it, accidentally, with the following code. But I don’t get it. What I was expecting to see with this code was a circle painted on the canvas, then another circle painted on top of that circle when the button was pressed. The first circle would remain on the screen, in stationary position, while the other circle went into motion. Again, I have accidentally achieved what I was going for, but I don’t want to build off this because it seems so wrong. What do I need to do to correct my code so that the circle appears on screen, then is set in motion with the button click?
<script>
var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d');
// Creates a ball in location (but why does it disappear?)
c.beginPath();
c.lineWidth = 5;
c.arc(145, 100, 75, 0, Math.PI * 2, true);
c.stroke();
var y = 100;
function ballDrop(){
requestAnimationFrame(ballDrop);
c.clearRect(0, 0, 300, 800);
// Create Ball
c.beginPath();
c.lineWidth = 5;
c.arc(145, y, 75, 0, Math.PI * 2, true);
c.stroke();
y += 1;
}
</script>
Your code performs as expected because:
1. You draw an initial circle on the canvas
2. You click a button which executes ballDrop
3. Within ballDrop you clear the context draw area, which removes all previous paints. This is why your original circle is gone.
A few notes:
* You don't need to keep setting lineWidth unless you plan on changing it for that context
* You should move requestAnimationFrame to the end of your function. This is mostly for clarity, as requestAnimationFrame is asynchronous (like setTimeout) so functionality won't really be affected.
Example https://jsfiddle.net/m503wa4g/6/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<canvas width="300" height="300"></canvas>
<button onclick="ballDrop()">Drop</button>
<script>
var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d');
// Creates a ball in location (but why does it disappear?)
c.beginPath();
c.lineWidth = 5;
c.arc(145, 100, 75, 0, Math.PI * 2, true);
c.stroke();
var y = 100;
function ballDrop() {
c.clearRect(0, 0, 300, 800);
// Create Ball
c.beginPath();
c.arc(145, y, 75, 0, Math.PI * 2, true);
c.stroke();
y += 1;
requestAnimationFrame(ballDrop);
}
</script>
</body>
</html>
function ballDrop(){
// start the animation that runs forever
requestAnimationFrame(ballDrop);
// clear the canvas so nothing is on the canvas
// this is why the circle disappears
c.clearRect(0, 0, 300, 800);
// Create first Ball again so it doesn't disappear
c.beginPath();
c.lineWidth = 5;
c.arc(145, 100, 75, 0, Math.PI * 2, true);
c.stroke();
// Create Dropping Ball that is 1 pixel down (y+=1)
c.beginPath();
c.lineWidth = 5;
c.arc(145, y, 75, 0, Math.PI * 2, true);
c.stroke();
y += 1;
}

Setting true colors to a canvas border stroke?

I have this simple code of setting rectangle.
I'm stroking its border with a black color.
However , I dont see any black here but gray.
<!doctype html>
<html lang="en">
<canvas id="canvas" width=300 height=300></canvas>
<script>
function draw()
{
ctx.beginPath();
ctx.strokeStyle = "#000000";
ctx.strokeRect(rect.x, rect.y, rect.w, rect.h);
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
var rect = {
x: 10,
y: 10,
w: 40,
h: 100
};
draw();
</script>
</html>
Question :
What am I doing wrong and how can I set the color to be as I define ?
When you create a canvas line, it will make a line passing through the points you declared, and with a width of lineWidth. If the line is between 2 pixels (for example when you create a line passing through borders, meaning you choose integer values for x and y) it will dissolve the color to balance the 2 pixels your line is crossing, in this case 50% to the pixel on the left, and 50% to the pixel on the right, resulting in a greyish color.
Adding .5 to your x and y makes the line always stay in 1 pixel
<!doctype html>
<html lang="en">
<canvas id="canvas" width=300 height=300></canvas>
<script>
function draw()
{
ctx.beginPath();
ctx.strokeStyle = "#000000";
ctx.strokeRect(rect.x, rect.y, rect.w, rect.h);
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
var rect = {
x: 10.5,
y: 10.5,
w: 40,
h: 100
};
draw();
</script>
</html>
If you run the snippet you'll see that the lines are straight black, and occupying only 1 pixel in width. I just added .5 to your x and y

Categories

Resources