# Cant call from an Array on createGraphics canvas

**URL:** <https://discourse.processing.org/t/cant-call-from-an-array-on-creategraphics-canvas/35434>\
**Category:** Coding Questions\
**Created:** [February 25, 2022, 12:21am UTC](https://discourse.processing.org/t/cant-call-from-an-array-on-creategraphics-canvas/35434 "2022-02-25T00:21:24Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![chriscorey](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chriscorey/32/7390_2.png) [@chriscorey](https://discourse.processing.org/u/chriscorey)\
**Post date:** [February 25, 2022, 12:21am UTC](https://discourse.processing.org/t/cant-call-from-an-array-on-creategraphics-canvas/35434/1 "2022-02-25T00:21:24Z")

</div>

Project Goal: I’d like to create a simple drawing program that randomly cycles through an array of shapes which the user has to place one at a time. I have a simple version built but when I try to draw something from an array onto my createGraphics canvas I get a TypeError “Cannot read properties of undefined (reading ‘0’)”.

I’m using createGraphics so that I can see where the shape will be drawn before clicking the mouse to draw it onto the canvas. Is there a better approach for this or am I just making a small error with the arrays, variables, or syntax?

> **[p5.js Web Editor](https://editor.p5js.org/cmcfaa/sketches/56Ho8uCQp)**
>
> A web editor for p5.js, a JavaScript library with the goal of making coding accessible to artists, designers, educators, and beginners.

Problem Area  
illustration.circle(mouseX, mouseY, 50);  
illustration.shapes0;

````auto
let illustration;
let shapes = [s1];

function setup() {
  createCanvas(400, 400);
  illustration = createGraphics(width, height);
  illustration.clear();
}

function draw() {
  background(0);
  shapes[0]();
  
  image(illustration, 0, 0);
}

function mousePressed() {
  illustration.noFill();
  illustration.stroke(255);
  illustration.circle(mouseX, mouseY, 50);
  illustration.shapes[0]();
}

function s1() {
  noFill();
  stroke(255);
  circle(mouseX, mouseY, 50);
}
}```
````

---

<div class="post-metadata">

**Author:** ![KumuPaul](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kumupaul/32/13072_2.png) [@KumuPaul](https://discourse.processing.org/u/KumuPaul)\
**Post date:** [February 25, 2022, 12:28am UTC](https://discourse.processing.org/t/cant-call-from-an-array-on-creategraphics-canvas/35434/2 "2022-02-25T00:28:56Z")

</div>

It’s not clear why you think this would work:

```javascript
illustration.shapes[0]();

```

Nor why you think this would be able to draw to both the main canvas and your `p5.Graphics`:

```javascript
function s1() {
  noFill();
  stroke(255);
  circle(mouseX, mouseY, 50);
}

```

Even if you fixed the fact that `illustration.shapes` is undefined by doing something like `illustration.shapes = shapes;` this still wouldn’t do what you want. All of the functions referenced in the `s1` function (`noFill`, `stroke`, and `circle`) are global functions that draw to the main canvas. In order to change this you would need to make the function support specifying an explicit target:

```javascript
function s1(g) {
  if (!g) {
    g = window;
  }
  g.noFill();
  g.stroke(255);
  g.circle(mouseX, mouseY, 50);
}

```

Then when you call your shape functions, specify the target as an argument:

```auto
shapes[0](illustration);

```

---

<div class="post-metadata">

**Author:** ![chriscorey](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chriscorey/32/7390_2.png) [@chriscorey](https://discourse.processing.org/u/chriscorey)\
**Post date:** [February 25, 2022, 1:02am UTC](https://discourse.processing.org/t/cant-call-from-an-array-on-creategraphics-canvas/35434/3 "2022-02-25T01:02:25Z")

</div>

Thanks KumuPaul. I appreciate the feedback.

Maybe this a more direct way to ask the question.  
I want the functionality from the new sketch below but I want to be able to see the shapes on the canvas before I click to place them. Should I be using the createGraphics approach for a transparent layer to draw on or is there a better way to go about it?

> **[p5.js Web Editor](https://editor.p5js.org/cmcfaa/sketches/56Ho8uCQp)**
>
> A web editor for p5.js, a JavaScript library with the goal of making coding accessible to artists, designers, educators, and beginners.

```auto
let shapes = [s1, s2, s3];
let index = 0;

function setup() {
  createCanvas(400, 400);
  background(0);
}

function draw() {
}

function mousePressed() {
  shapes[index]();
  index++;
  if (index >= shapes.length){
    index = 0;
  }
}

function s1() {
  circle(mouseX, mouseY, 75);
}

function s2() {
  square(mouseX, mouseY, 50);
}

function s3() {
  ellipse(mouseX, mouseY, 50, 200);
}

```

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [February 25, 2022, 4:07am UTC](https://discourse.processing.org/t/cant-call-from-an-array-on-creategraphics-canvas/35434/4 "2022-02-25T04:07:57Z")

</div>

One possible approach:

```auto
let shapes = [s1, s2, s3];
let pg;
let sel;
let selection = 0;
let _x = 0;
let _y = 80;
let _w = 400;
let _h = 320;

function setup() { 
  createCanvas(400, 400);
  pg = createGraphics(50,50);
  background(209);
  textAlign(CENTER);
  sel = createSelect();
  sel.position(80, 10);
  sel.option('Shapes...');
  sel.option('circle');
  sel.option('square');
  sel.option('ellipse');
  sel.changed(selectShape);  
}

function draw() {
}

function mousePressed() {
  if(mouseX >= _x && mouseX <= _x + _w && mouseY >= _y && mouseY <= _y + _h){
   shapes[selection]();
  }
}

function selectShape(){
  let item = sel.value();
  switch(item){
    case 'circle': previewCircle(); selection = 0; break;     
    case 'square': previewSquare(); selection = 1; break;     
    case 'ellipse': previewEllipse(); selection = 2; break;     
  }
}

function previewCircle(){
  pg.background(255);
  pg.circle(25,25,25);
  image(pg,0,0);
}

function previewSquare(){
  pg.background(255);
  pg.square(5,5,25);
  image(pg,0,0);
}

function previewEllipse(){
  pg.background(255);
  pg.ellipse(25,25,25,50);
  image(pg,0,0);
}

function s1() {
  fill(255, 0, 0);
  circle(mouseX, mouseY, 75);  
}

function s2() {
  fill(0, 255, 0);
  square(mouseX, mouseY, 50);
}

function s3() {
  fill(0, 0, 255);
  ellipse(mouseX, mouseY, 50, 200);
}

```

---

<div class="post-metadata">

**Author:** ![KumuPaul](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kumupaul/32/13072_2.png) [@KumuPaul](https://discourse.processing.org/u/KumuPaul)\
**Post date:** [February 25, 2022, 8:19pm UTC](https://discourse.processing.org/t/cant-call-from-an-array-on-creategraphics-canvas/35434/5 "2022-02-25T20:19:23Z")

</div>

> [@chriscorey](#):
>
> Should I be using the createGraphics approach for a transparent layer to draw on or is there a better way to go about it?

I think your approach of using a separate `p5.Graphics` object to draw the shapes to on click is perfectly reasonable. The important thing is to understand the fundamentals of JavaScript: assigning a function to an object and then invoking it does not change the meaning of global symbols, it only changes the meaning of the `this` keyword. Which is why in my code sample I suggest passing the `p5.Graphics` as an argument to your functions.

https://editor.p5js.org/Kumu-Paul/full/KU8_v5xMx
