0

I'm trying to make it so that when I clicked the button to change the radius size, it would change all the circle's radius size into a random size between 5-10.

I've already tried to draw 2 circles (1 black, 1 blue) and call then tried to change the radius to a new random radius size between 5-10. After adding my function, I cannot see the 2 circles I have drawn. Any feedback is greatly appreciated.

<canvas width="300" height="300" id="myCanvas" style="border: 1px solid black"></canvas>
<button id="changeRadius">Change Size</button>

<script>
var number = Math.min(Math.max(paraseInt(number), 5), 10);
let canvas = document.getElementById("myCanvas");
let ctx = canvas.getContext("2d");
ctx.translate(100,120);
ctx.beginPath(); 
  ctx.arc(0, 0, 10, 0, 2 * Math.PI);
  ctx.fillStyle = "black";
  ctx.fill();
ctx.translate(140,120);
ctx.beginPath(); 
  ctx.arc(0, 0, 10, 0, 2 * Math.PI);
  ctx.fillStyle = "blue";
  ctx.fill();
document.getElementById("changeRadius").onclick = function() {
ctx.clearRect
ctx.translate(100,120);
ctx.beginPath(); 
  ctx.arc(0, 0, "number", 0, 2 * Math.PI);
  ctx.fillStyle = "black";
  ctx.fill();
ctx.translate(140,120);
ctx.beginPath(); 
  ctx.arc(0, 0, "number", 0, 2 * Math.PI);
  ctx.fillStyle = "blue";
  ctx.fill();
if (event.keycode == s){
ctx.translate(100,120);
ctx.beginPath(); 
  ctx.arc(0, 0, 5, 0, 2 * Math.PI);
  ctx.fillStyle = "black";
  ctx.fill();
ctx.translate(140,120);
ctx.beginPath(); 
  ctx.arc(0, 0, 5, 0, 2 * Math.PI);
  ctx.fillStyle = "blue";
  ctx.fill();
}else if (event.keycode == b) {
ctx.translate(100,120);
ctx.beginPath(); 
  ctx.arc(0, 0, 10, 0, 2 * Math.PI);
  ctx.fillStyle = "black";
  ctx.fill();
ctx.translate(140,120);
ctx.beginPath(); 
  ctx.arc(0, 0, 10, 0, 2 * Math.PI);
  ctx.fillStyle = "blue";
  ctx.fill();
}
}
</script>
Michael Kheong
  • 194
  • 1
  • 10
  • You can't change elements drawn to canvas - once added, they become part of the whole. You'd have to redraw it. Or use a library like Fabric, which makes this easier to handle. – Mitya Apr 04 '19 at 10:24
  • I have tried to clear the drawing above and then redraw via my code posted above – Michael Kheong Apr 04 '19 at 10:27

2 Answers2

1

There are many simple mistakes in the code.

1.

Where you call clearRect, you have:

ctx.clearRect

but it needs to be:

ctx.clearRect(x, y, width, height);

where x, y, width and height define the rectangle that you want to clear. To clear the whole canvas, use:

ctx.clearRect(0, 0, canvas.width, canvas.height);

2.

You have misspelled parseInt as paraseInt.

3.

Where you have put "number" as the radius in the calls to ctx.arc... I don't even know what you are trying to achieve. It looks like a placeholder? Anyway, it needs to be an actual number, not just the string "number".

Perhaps you intended to use the variable number that you create at the top and never use?

ctx.arc(0, 0, "number", 0, 2 * Math.PI);

becomes

ctx.arc(0, 0, number, 0, 2 * Math.PI);

(notice no " characters)

4.

You never actually update the value of number, so even the above won't do anything.

Community
  • 1
  • 1
Mat
  • 6,694
  • 7
  • 35
  • 39
0

Michael, your question has been on SO for some time but hopefully this answer might still be useful to you as well as others still learning JavaScript. Once I addressed basic syntax issues listed by Mat, the missing circles became visible. At that point I discovered three things.

  1. images drawn on your canvas may not appear where you expect them.

  2. a variable declared and initialised as number in your first statement does not generate a valid number let alone a random number.

  3. your code has if and if else statements that will not do anything without an event handler.


#1

Your code uses ctx.arc() to draw a basic circle and ctx.translate() to move it into position on the canvas. With ctx.translate() two parameters x and y determine how far to move the circle; x is the distance to move in the horizontal direction; y is the distance to move in the vertical direction.

The problem is that you no longer know the position coordinates on the canvas after the move. For this reason the origin needs to be reset before proceeding to the next ctx.translate() operation.

To reset the origin use CanvasRenderingContext2D.setTransform()e.g.

ctx.setTransform(1, 0, 0, 1, 0, 0);

from Mozilla MDN

The CanvasRenderingContext2D.setTransform() method of the Canvas 2D API resets (overrides) the current transformation to the identity matrix, and then invokes a transformation described by the arguments of this method. This lets you scale, rotate, translate (move), and skew the context.

This API is designed for animated drawing with a variety of methods for transforming 2D shapes dynamically. For the purposes of your code it is enough to understand that by clearing the identity matrix you restore 0,0 (the canvas origin) as the reference for x and y values used in any drawing operation that follows. Before you use ctx.translate() reset the origin. Watch the difference this will make when the code launches.

effect of origin reset at launch

without / with

Whenever a new image is drawn the entire canvas must first be cleared using ctx.clearRect()and it is important to reset the origin before doing so. Click the 'Change Size' button in each example to see that the entire screen is cleared with an origin reset. Without a reset the origin of the cleared rectangle will align with the centre of the last circle drawn i.e. the cleared rectangle eats into the lower right quadrant of the circle.

effect of origin reset on clearing the canvas

without / with


#2

The second problem can be demonstrated by inserting alert(number) following the first instruction. When the code runs, alert reports a NaN message (i.e. not a number). Also, random values lie within a range from 0.0 to 1.0 but for your purposes can be scaled to a range from 5.0 to 10.0 (for more see here and here).

The code below shows getNewRadius(), a function that generates a random number whenever the 'Change Size' button is clicked. Before the function is called constants and variables are declared and initialised. Every time the function is called, i.e. with every mouse click, it returns a new random value of radius which is then passed as an argument to the next drawing function.

For clarity I renamed your variable number to the more self-explanatory radius and replaced magic numbers in your code with some aptly named constant or var.


#3

Statements within the scope of your if and else if tests will never be executed. Testable values are potentially created at runtime by a keyboard event (i.e. event.keycode). But in your code no handler has been set up to listen for such an event. Moreoever, Mozilla MDN advises that keyCode is obsolete and makes the following recommendation

MDN Warning: This attribute is deprecated; you should use KeyboardEvent.key instead, if available.

For a more comprehensive summary of keyboard event options see here.

The code below includes a basic function called setMaxOrMinRadius(e) that allows maximum or minimum radius values to be selected by typing on a keyboard. In keeping with your initial code, typing s will select minRadius, typing b will select maxRadius. This function will only be recognised if a key is pressed and the event listener has been initialised. If the event listener detects a keystroke it will now be able to switch to the function and recognise which key has been pressed.

Acknowledgement

This answer is a collaborative effort between fellow retiree and former colleague Bob Douglas and myself. We have been learning JavaScript together for two months. We welcome suggestions for improvement.

Code

<canvas width="300" height="300" id="myCanvas" style="border: 1px solid black"></canvas>
<button id="changeRadius">Change Size</button>

<script>
const maxRadius     = 10;
const minRadius     = 5;
var range           = maxRadius - minRadius;
var radius          = maxRadius;

let canvas          = document.getElementById("myCanvas");
let ctx             = canvas.getContext("2d");

    document.addEventListener('keydown', setMaxOrMinRadius);

    drawCircles(maxRadius);

    document.getElementById("changeRadius").onclick = function() {
    clearCanvas();
    radius          = getNewRadius();
    drawCircles(radius);
}

function setMaxOrMinRadius(e) {
clearCanvas();
switch (e.which) {
    case 83:                                // type 's'
        drawCircles(minRadius);
    break;

    case 66:                                // type 'b'
        drawCircles(maxRadius);
    break;
    }
}

function getNewRadius() {
    var radius      = (Math.random() * minRadius) + range;
    return radius;
}

function drawCircles(radius) {
    drawBlueCircle(radius);
    drawBlackCircle(radius);
}

function clearCanvas(){
    ctx.setTransform(1, 0, 0, 1, 0, 0);     // reset origin
    ctx.clearRect(0, 0, canvas.width, canvas.height);
}

function drawBlackCircle (radius) {
    ctx.setTransform(1, 0, 0, 1, 0, 0);     // reset origin
    ctx.translate(100,120);
    ctx.beginPath();
    ctx.arc(0, 0, radius, 0, 2 * Math.PI);
    ctx.fillStyle   = "black";
    ctx.fill();
}

function drawBlueCircle (radius) {
    ctx.setTransform(1, 0, 0, 1, 0, 0);     // reset origin
    ctx.translate(140,120);
    ctx.beginPath();
    ctx.arc(0, 0, radius, 0, 2 * Math.PI);
    ctx.fillStyle   = "blue";
    ctx.fill();
}

Greg
  • 1,750
  • 2
  • 29
  • 56