2

I have read that you can make an array of anything. In my efforts to go forth in my studies of javaScript/canvas, I set out to create an array of shapes. The idea is to have an array of three circles. Math.floor will be used to grab one element/circle and display it on the canvas. I put together code that, well, makes sense to me... I've created an array, I have filled the array, I am grabbing a random element from the array... I have not yet reached the point of having to display it on the canvas, because not matter my approach, all three circles are always on the canvas. It would be so cool to grasp this concept. Can you tell me why this code doesn't work? Thank you in advance.

 <script>
        var canvas = document.getElementById("canvas");
        var c = canvas.getContext("2d");

        var objects = [];
        objects[0] = 
            [c.beginPath(),
            c.lineWidth = 5,
            c.strokeStyle = 'red',
            c.arc(200, 200, 50, 0, Math.PI * 2, false),
            c.stroke()];

        objects[1] = 
            [c.beginPath(),
            c.lineWidth = 5,
            c.strokeStyle = 'dimgray',
            c.arc(600, 200, 50, 0, Math.PI * 2, false),
            c.stroke()];

        objects[2] = 
            [c.beginPath(),
            c.lineWidth = 5,
            c.strokeStyle = 'purple',
            c.arc(1000, 200, 50, 0, Math.PI * 2, false),
            c.stroke()];

        for (var i = 0; i < objects.length; i++) {
            objects[i] = Math.floor(Math.random() * 3);}    

</script>
3
  • 1
    It doesn't work because you're actually creating an array of arrays that are return values of arbitrary JavaScript expression statements. Maybe if you want to save the directions like a "recipe for a shape", wrap them in a function and assign them to the objects indices? but then it should probably be functions Commented Apr 11, 2018 at 20:13
  • 1
    Well, you can’t store lines of code in an array. c.arc(600, 200, 50, 0, Math.PI * 2, false) will execute that method, then return undefined. The array stores the result undefined. Commented Apr 11, 2018 at 20:14
  • On to functions it is. Thank you. Commented Apr 11, 2018 at 20:42

2 Answers 2

3

You should make a function drawCircle which takes a canvas and a color as arguments

const drawCircle = (canvas, color = "red") =>
{
  canvas.beginPath ()
  canvas.lineWidth = 5
  canvas.strokeStyle = color
  canvas.arc (95, 50, 40, 0, 2 * Math.PI)
  canvas.stroke ()
}

const getCanvas = (id) =>
  document.getElementById(id).getContext("2d")

drawCircle (getCanvas('canvas-1')) // default "red"
drawCircle (getCanvas('canvas-2'), 'dimgray')
drawCircle (getCanvas('canvas-3'), 'purple')
<canvas id="canvas-1"></canvas>
<canvas id="canvas-2"></canvas>
<canvas id="canvas-3"></canvas>

We could add additional parameters for position, radius, and line width, but then how would we know which order to pass them in? A better option would be to pass a descriptor object with default values.

const drawCircle = (canvas, descriptor = {}) =>
{
  const { x = 95
        , y = 50
        , radius = 40
        , lineWidth = 5
        , color = "red"
        } = descriptor

  canvas.beginPath ()
  canvas.lineWidth = lineWidth
  canvas.strokeStyle = color
  canvas.arc (x, y, radius, 0, 2 * Math.PI)
  canvas.stroke ()
}

const getCanvas = (id) =>
  document.getElementById(id).getContext("2d")

drawCircle (getCanvas('canvas-1')) // default styles
drawCircle (getCanvas('canvas-2'), { color: 'dimgray' })
drawCircle (getCanvas('canvas-3'), { color: 'purple', radius: 10 })
<canvas id="canvas-1"></canvas>
<canvas id="canvas-2"></canvas>
<canvas id="canvas-3"></canvas>

Above, we use a named parameter descriptor but we could also could've inlined it. Because the descriptor contains so many properties, the readability suffers a bit and makes the previous version of our function a little nicer.

const drawCircle = (canvas, { x=95, y=50, radius=40, lineWidth=5, color="red" } = {}) => {
  canvas.beginPath ()
  canvas.lineWidth = lineWidth
  canvas.strokeStyle = color
  canvas.arc (x, y, radius, 0, 2 * Math.PI)
  canvas.stroke ()
}

Now, using drawCircle you could create presets, like

const FatPurpleCircle = canvas =>
  drawCircle (canvas, { color: "purple", lineWidth: 10 })

const SmallBlueCircle = canvas =>
  drawCircle (canvas, { color: "blue", radius: 5 })

And you could have an array of these presets called circles. Given a function sample that returns a random element of an array, we can select a random circle function, and use it to draw its contents on a supplied canvas

const circles =
  [ FatPurpleCircle, SmallBlueCircle, ... ]

const sample = (arr = []) => {
  const size = arr.length
  const rand = Math.floor (Math.random () * size)
  return arr[rand]
}

const drawRandomCircle =
  sample (circles)

drawRandomCircle (getCanvas('canvas-1'))
Sign up to request clarification or add additional context in comments.

Comments

0

One option you have is to store each "canvas" in a function, which are then all stored in an array. This will end up having close to the same format that you had previously, but via a different method. @Patrick Roberts mentioned a similar method in his comment.

var objects = [
  function() { 
    var canvas = document.getElementById("canvas-1");
    var c = canvas.getContext("2d");
    c.beginPath();
    c.lineWidth = 5;
    c.strokeStyle = 'red';
    c.arc(95,50,40,0,2*Math.PI);
    c.stroke();
  },
  function() {
    var canvas = document.getElementById("canvas-2");
    var c = canvas.getContext("2d");
    c.beginPath();
    c.lineWidth = 5;
    c.strokeStyle = 'dimgray';
    c.arc(95,50,40,0,2*Math.PI);
    c.stroke();
  },
  function() {
    var canvas = document.getElementById("canvas-3");
    var c = canvas.getContext("2d");
    c.beginPath();
    c.lineWidth = 5;
    c.strokeStyle = 'purple';
    c.arc(95,50,40,0,2*Math.PI);
    c.stroke();
  }
];

objects[0]();
objects[2]();
objects[1]();

Here is a Codepen demonstrating this implementation.

As to why it doesn't work, @Xofox explained it very well in his comment:

[...] you can’t store lines of code in an array. c.arc(600, 200, 50, 0, Math.PI * 2, false) will execute that method, then return undefined. The array stores the result undefined.

3 Comments

While this works, unfortunately it doesn't make sense as a program
Ya, I focused more on the "array of canvas objects" than I did actually implementing this code so it would be production ready. +1 to your answer!
Thank you, gentlemen. I am a bit confused, though. I look at Chase's answer and it appears to be right where I want to be...An array of objects has been created. From there I was wanting to use Math.random() to randomly display an index from the array. (And eventually, have all objects displayed and left with an empty array). But, it is mentioned that this doesn't make the most sense. What I can't figure out is, as to why? Do you not have to use an array to accomplish what I am wanting to do? If I can't iterate through an array, how can each individual element be displayed at random?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.