# Displaying text from an API inside the canvas

**URL:** <https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244>\
**Category:** Coding Questions\
**Created:** [May 24, 2021, 4:26am UTC](https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244 "2021-05-24T04:26:36Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Blomer478](https://avatars.discourse-cdn.com/v4/letter/b/58956e/32.png) [@Blomer478](https://discourse.processing.org/u/Blomer478)\
**Post date:** [May 24, 2021, 4:26am UTC](https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244/1 "2021-05-24T04:26:37Z")

</div>

Hi, I’m having trouble getting the text from an API to display on my canvas, I can get it outside of it but I can’t find the way to put it in. I have the API key in my code and I know the variable names are kinda weird. My end goal is tho display the content of 5 news stories with the provider, time, title, description and image in the canvas and then making an image of each one (I think with createImage()) so I can apply somo kind of algorithm to them. I’ve been trying to do this for a couple of days but can’t find the way to do it.

```auto
let url = 'https://api.jornalia.net/api/v1/articles?apiKey=?&providers=Clarin%2CTN%2CPagina12%2CLaNacion%2CInfobae&categories=POLITICA%2CECONOMIA%2CSOCIEDAD'

let h4, h5, h1, P, img;

function setup(){

  loadJSON(url, gotData, 'json');

  createCanvas(windowWidth, windowHeight);

  background(150);

}

function gotData(data){

  for ( let i = 0; i <= 4; i++){

    h4 = data.articles[i].provider.name;

    h5 = data.articles[i].publishedAt;

    h1 = data.articles[i].title;

    P = data.articles[i].description;

    img = data.articles[i].imageUrl;

  }

}

function draw(){

  let news = createElement('h4', h4);

  text(news,20,20);

}

```

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [May 24, 2021, 6:56am UTC](https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244/2 "2021-05-24T06:56:14Z")

</div>

> [@Blomer478](#):
>
> `gotData(data){`

You need to call the function

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [May 24, 2021, 6:57am UTC](https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244/3 "2021-05-24T06:57:01Z")

</div>

Make news a global variable and in gotdata fill it with your data

---

<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:** [May 24, 2021, 8:47am UTC](https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244/4 "2021-05-24T08:47:50Z")

</div>

> [@Chrisir](#):
>
> You need to call the function

It is passed as the second parameter to loadJSON which is the callback function for once data is loaded. So it does not need to be called directly.

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [May 24, 2021, 9:22am UTC](https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244/5 "2021-05-24T09:22:32Z")

</div>

I can’t see where the parameter `data` is initialised. Does that mean it is undefined when you call `gotData`?

---

<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:** [May 24, 2021, 10:10am UTC](https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244/6 "2021-05-24T10:10:26Z")

</div>

There are a few issues going on, but first and foremost is the usage of the [`text()`](https://p5js.org/reference/#/p5/text) function. The text function in p5.js expects a string for its first parameter, not an p5.Element which is what [`createElement()`](https://p5js.org/reference/#/p5/createElement) returns. If you want to format text that you render to the canvas with `text()` you need to use methods like [`textSize()` / `textStyle()` / `textFont()`](https://p5js.org/reference/#group-Typography).

Other issues include:

- You should avoid calling `createElement` and the like in `draw()` unless you disable looping with `noLoop()` unlike text drawn to the canvas, HTML elements created this way are persistent so this would be a huge memory leak.
- Your for loop keeps overwriting all your variables, so you’ll only really capture the data from the 5th article (the one with index 4).
- Calls to draw that happen before the data is loaded will fail because h4 (and the other variables containing article data) have not yet been initialized. Once a call to draw fails, p5.js stops calling it.

Here’s a working example:

```auto
let url = 'https://www.paulwheeler.us/files/example.json';

let h4 = '', h5, h1, P, img;

function setup() {
  createCanvas(windowWidth, windowHeight);
  loadJSON(url, gotData, 'json');
}

function gotData(data){
  print('gotData');
  console.log(data);
  
  for (let i = 0; i < data.articles.length; i++) {
    // This is going to only store the last article
    // information in these variables
    h4 = data.articles[i].provider.name;

    h5 = data.articles[i].publishedAt;

    h1 = data.articles[i].title;

    P = data.articles[i].description;

    img = data.articles[i].imageUrl;
  }
  
  // This creates an HTML element that is separate from your canvas
  let news = createElement('h4', h4);
  
  // By default, an h4 element will be a block element added after your canvas.
  // The position function changes the element to be positioned absolutely
  news.position(0,0);
}

function draw() {
  background(255);
  // The p5.js text function can only take a string.
  // It cannot take an HTML element. if you want HTML-like
  // formatting and layout you either need to use HTML or
  // implement it yourself with p5.js drawing commands.
  text(h4, width / 2, height / 2);
}

```

---

<div class="post-metadata">

**Author:** ![Blomer478](https://avatars.discourse-cdn.com/v4/letter/b/58956e/32.png) [@Blomer478](https://discourse.processing.org/u/Blomer478)\
**Post date:** [May 24, 2021, 6:59pm UTC](https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244/7 "2021-05-24T18:59:27Z")

</div>

Thank you very much! I kept working on it and could put the text inside the canvas but now I’m havieng other problems, I wonder if you’d know how to fix them. First I can’t seem to find a way to put the image below the texI tried changing the img variable, I thought by putting the ’ ’ inside it it would grab the url of the image and load it in in the loadImage function but it didn’t work. The other problem is I don’t know how to display those 4 different sets of texts and images on draw. I tried putting another for loop but couldn’t make it work.

```auto
let url = 'https://api.jornalia.net/api/v1/articles?apiKey=?&providers=Clarin%2CTN%2CPagina12%2CLaNacion%2CInfobae&categories=POLITICA%2CECONOMIA%2CSOCIEDAD'

let prov = '', time= '', title = '', desc = '', img = '';

function setup(){

  loadJSON(url, gotData, 'json');

  createCanvas(windowWidth, windowHeight);

}

function gotData(data){

  for ( let i = 0; i < 4; i++){

   prov= data.articles[i].provider.name;

   time = data.articles[i].publishedAt;

   title = data.articles[i].title;

   desc = data.articles[i].description;

   img = data.articles[i].imageUrl;

  }

}

function draw(){

  background(150);

  for( j = 0; j < 4; j++){

   textSize(16);

   text(prov,10,20);

   textSize(12);

   text(time,10,40);

   textSize(30);

   text(title,10,70);

   textSize(16);

   text(desc,10,100);

   loadImage(img);

   image(img,10,120);

  }

}

```

---

<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:** [May 24, 2021, 10:13pm UTC](https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244/8 "2021-05-24T22:13:11Z")

</div>

Ok, first issue: drawing images.

1. loadImage isn’t instantaneous, so you need to call it and then it will take some time before the image is available
2. you need to store the result (a `p5.Image` instance) returned from `loadImage` in a variable and then pass that `p5.Image` to the `image` function.
3. You don’t want to call `loadImage` in every call to draw, you want to call it once and reuse the result in the draw function.

I would do something like this in `gotData`:

```auto
		imgSrc = data.articles[i].imageUrl;
		img = loadImage(
			imgSrc,
			() => {
				imgLoaded = true;
			}
		);

```

And something like this in your draw function:

```auto
	if (imgLoaded) {
		image(img, 10, 120);
	} else {
		text('Loading...', 10, 120);
	}

```

---

<div class="post-metadata">

**Author:** ![Blomer478](https://avatars.discourse-cdn.com/v4/letter/b/58956e/32.png) [@Blomer478](https://discourse.processing.org/u/Blomer478)\
**Post date:** [May 24, 2021, 10:17pm UTC](https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244/9 "2021-05-24T22:17:38Z")

</div>

thank you so much! I really appreciate all the help! I’ll keep working on it

---

<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:** [May 24, 2021, 10:41pm UTC](https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244/10 "2021-05-24T22:41:49Z")

</div>

Regarding the second issue: displaying multiple articles, the problem is that you are trying to store multiple values (one for each article) in individual variables (i.e. `prov`, `time`, `title`) etc. What you need is arrays which you add items to (or better yet a single array to which you add an object containing the article data). Then you can use a for loop in your draw function to draw each article. However, you also don’t want to draw the articles over top of one another. So you need to determine how you want to arrange the articles and then draw them in different places. The easiest way to accomplish the latter (drawing in different places) is with `push()/translate()/pop()` (recommended viewing: [Transformations (Translate, Rotate, Push/Pop) - Part 1 - Additional Topics Tutorial #9.1 · The Coding Train](https://thecodingtrain.com/Tutorials/9-additional-topics/9.1-transformations-part-1.html)). Here’s a functional example:

```auto
let url = 'https://www.paulwheeler.us/files/example2.json';

let articles = [];

function setup() {
  createCanvas(windowWidth, windowHeight);
  loadJSON(url, gotData, 'json');
}

function gotData(data) {
  print('gotData');
  console.log(data);

  for (let i = 0; i < data.articles.length; i++) {
    let content = {
      prov: data.articles[i].provider.name,
      time: data.articles[i].publishedAt,
      title: data.articles[i].title,
      desc: data.articles[i].description,
      imgSrc: data.articles[i].imageUrl,
      imgLoaded: false
    };

    content.img = loadImage(
      imgSrc,
      () => {
        content.imgLoaded = true;
      }
    );

    articles.push(content);
  }
}

function draw() {
  background(255);

  // Simple hack: assume each article fits in a 200px x 200px sqaure
  let articlesPerRow = floor(width / 200);

  for (let i = 0; i < articles.length; i++) {
    // Save the current drawing position
    push();

    // determine layout position
    let y = floor(i / articlesPerRow) * 200;
    let x = (i % articlesPerRow) * 200;

    // translate to the top left corner of the current article's grid spot
    translate(x, y);

    textSize(16);
    text(articles[i].prov, 10, 20);
    textSize(12);
    text(articles[i].time, 10, 40);
    textSize(30);
    text(articles[i].title, 10, 70);
    textSize(16);
    text(articles[i].desc, 10, 100);

    if (articles[i].imgLoaded) {
      image(articles[i].img, 10, 120);
    } else {
      text('Loading...', 10, 120);
    }

    // Revert back to the previous drawing position
    pop();
  }
}

```

---

<div class="post-metadata">

**Author:** ![Blomer478](https://avatars.discourse-cdn.com/v4/letter/b/58956e/32.png) [@Blomer478](https://discourse.processing.org/u/Blomer478)\
**Post date:** [May 24, 2021, 10:49pm UTC](https://discourse.processing.org/t/displaying-text-from-an-api-inside-the-canvas/30244/11 "2021-05-24T22:49:08Z")

</div>

I really can’t thank you enough, I’ve been trying a lot of things this past couple of days but couldn’t do it, thanks for all the advice! Recently I’ve been watching a lot of videos by the coding train too, I’ll give that one a watch!
