Créer un chart Bitcoin avec NuxtJS

Créer un chart Bitcoin avec NuxtJS


Disclaimer : Cet article n'a pas pour objectif de vous apprendre les bonnes pratiques et l'optimisation de votre code, mais de vous permettre d'obtenir un résultat concret le plus rapidement possible.

Le code source est disponible ici 👉 github.com/Icesofty/coingecko-api-nuxt Vous pouvez voir le résultat en Live ici 👉 vigilant-northcutt-b1a5f7.netlify.app

Nous allons voir dans cet article comment récupérer l'historique du cours du Bitcoin via l'API de Coingecko afin de créer notre propre chart Bitcoin.

Nous allons utiliser NuxtJS avec Axios et Lightweight Charts, rien de plus!

Prérequis

Avant de démarrer, j'assume que vous avez déjà installé NodeJS, un éditeur de texte ainsi qu'un terminal sur votre machine.

Nous utiliserons Yarn tout au long de notre projet, si ce n'est pas déjà fait, vous pouvez l'installer globalement via la commande npm install -g yarn

Une connaissance de base de VueJS est recommandée, bien que ce tutoriel soit assez simple à suivre.

1 - Création du projet & configuration

La première étape consiste à créer notre projet NuxtJS

yarn create nuxt-app Bitcoin-Chart

Project Name: Programming language: Javascript Package manager: Yarn UI framework: None Nuxt.js modules: Axios Linting tools: Prettier (mais cela dépendra de votre config et de vos préférences)Testing framework: None Rendering mode: Universal (SSR / SSG) Deployment target: Static Development tools: jsconfig.json Continuous integration: None Version control system: Git

Une fois notre projet créé, nous pouvons nous rendre dans le dossier (cd Bitcoin-Chart ) et lancer notre projet avec la commande yarn dev

Notre page principal (index.vue) se trouve dans le dossier pages. Vous pouvez tout effacer et repartir sur une base propre :

<template\>
 <div\>

 </div\>
</template\>

<script\>
 export default {
 }
</script\>

Nous allons aussi créer un nouveau composant qui sera en charge d'afficher notre chart. Pour cela, nous allons créer un fichier chart.vue dans le dossier components de notre workspace.

Nous allons utiliser le modèle 'Legend' fournis par TradingView pour notre chart, mais nous allons retirer la data présente par défaut dans l'exemple.

À la place, nous allons ajouter un props 'fetchedDataBtc' qui sera notre data récupérée via l'API de Coingecko. Nous allons intégrer ce modèle dans notre composant comme suit :

<template>
  <div></div>
</template>

<script>
export default {
  // Nous récupérons notre props
  props: ['fetchedDataBtc'],
  mounted() {
    let chart = LightweightCharts.createChart(document.body, {
      width: 1200,
      height: 600,
      layout: {
        textColor: '#d1d4dc',
        backgroundColor: '#000000',
      },
      rightPriceScale: {
        scaleMargins: {
          top: 0.3,
          bottom: 0.25,
        },
      },
      crosshair: {
        vertLine: {
          width: 5,
          color: 'rgba(224, 227, 235, 0.1)',
          style: 0,
        },
        horzLine: {
          visible: false,
          labelVisible: false,
        },
      },
      grid: {
        vertLines: {
          color: 'rgba(42, 46, 57, 0)',
        },
        horzLines: {
          color: 'rgba(42, 46, 57, 0)',
        },
      },
    })

    let areaSeries = chart.addAreaSeries({
      topColor: 'rgba(38, 198, 218, 0.56)',
      bottomColor: 'rgba(38, 198, 218, 0.04)',
      lineColor: 'rgba(38, 198, 218, 1)',
      lineWidth: 2,
      crossHairMarkerVisible: false,
    })

    // Nous supprimons la data fictive de l'exemple et la remplaçons par notre props fetchedDataBtc
    areaSeries.setData(this.fetchedDataBtc)

    document.body.style.position = 'relative'

    let legend = document.createElement('div')
    legend.classList.add('legend')
    document.body.appendChild(legend)

    let firstRow = document.createElement('div')
    firstRow.innerText = 'BTC USD'
    firstRow.style.color = 'white'
    legend.appendChild(firstRow)

    function pad(n) {
      let s = '0' + n
      return s.substr(s.length - 2)
    }

    chart.subscribeCrosshairMove((param) => {
      if (param.time) {
        const price = param.seriesPrices.get(areaSeries)
        firstRow.innerText = 'BTC USD' + '  ' + price.toFixed(2)
      } else {
        firstRow.innerText = 'BTC USD'
      }
    })
  },
}
</script>

Modification nuxt.config.js

À la racine de notre projet, nous allons rajouter Lightweight Charts dans notre nuxt config. Lightweight Charts est une librairie fournie par Tradingview permettant d'afficher des charts. De cette façon, Lightweight Charts sera disponible dans notre projet.

   head: {
    title: 'Bitcoin-chart',
    htmlAttrs: {
      lang: 'en',
    },
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: '' },
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],

    // Nous rajoutons Lightweight Charts via le CDN ici
    script: [
      {
        src:
          'https://unpkg.com/lightweight-charts/dist/lightweight-charts.standalone.production.js',
      },
    ],
  },

2 - Consommation de l'API Coingecko

Nous allons maintenant pouvoir nous concentrer sur notre index.vue et la consomation de l'API afin de récupérer notre historique.

La documentation est très bien faite, mais nous allons utiliser le endpoint suivant pour fetch notre data avec axios :

https://api.coingecko.com/api/v3/coins/bitcoin/market\_chart?vs\_currency=usd&days=300

Ce endpoint récupère les 300 derniers jours du cours du Bitcoin en USD.

Nous allons procéder de la façon suivante :

  • Fetch notre historique
  • Mettre à jour notre data afin de la transmettre à notre composant
  • Afficher le composant uniquement lorsque notre historique est fetch
export default {
  data() {
    return {
      dataBtc: [],
    }
  },

  created() {
    this.$axios
      .get(
        'https://api.coingecko.com/api/v3/coins/bitcoin/market_chart?vs_currency=usd&days=300'
      )
      .then((response) => {
        this.dataBtc = response.data
      })
  },
}

À ce stade, nous pouvons penser que notre dataBtc est correctement mis à jour et prêt à être envoyé dans notre composant. Cependant, si nous reprenons l'exemple donné dans notre template 'Legend', notre Data doit être une Array d'Objects. Chaque objet doit contenir time & value.

[
    ...
    { time: '2018-10-19', value: 26.19 },
    { time: '2018-10-22', value: 25.87 },
    { time: '2018-10-23', value: 25.83 },
    { time: '2018-10-24', value: 25.78 },
    ...
]

Mais l'API nous renvoie la réponse suivante :

{
  "prices": [
    [
      1587600000000,
      7109.995291181778
    ],
    [
      1587686400000,
      7382.793144116689
    ],
    [
      1613500344000,
      63446101403.69392
    ]
  ]
}

Il est donc nécessaire de traiter la réponse reçue via l'API afin que celle-ci soit utilisable dans Lightweight Chart. De plus, nous allons rajouter un switch ('show') qui nous permettra d'afficher notre composant uniquement lorsque notre data est mise à jour.

export default {
  data() {
    return {
      dataBtc: [],
      // Etat initial de notre switch
      show: false,
    }
  },

  created() {
    this.$axios
      .get(
        'https://api.coingecko.com/api/v3/coins/bitcoin/market_chart?vs_currency=usd&days=300'
      )
      .then((response) => {
        let chart = []
        // Data représente notre réponse
        const data = response.data.prices

        // On push dans notre chart chaque element avec la strucutre attendu par Lightweigth Chart
        data.forEach((element) => {
          chart.push({
            time: element[0] / 1000,
            value: element[1],
          })
        })
        // Mise à jour de notre data
        this.dataBtc = chart
        // Une fois notre data mise à jour, nous changeons l'état de notre switch
        this.show = true
      })
  },
}

Maintenant que nous avons correctement modifié notre structure afin de correspondre avec la structure attendu par Lightweight Chart, nous pouvons rajouter notre composant avec un attribut v-if dans notre index.vue et envoyer notre props.

<template>
  <div>
    <Chart v-if="show" :dataBTC="dataBtc" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      dataBtc: [],
      show: false,
    }
  },

  created() {
    this.$axios
      .get(
        'https://api.coingecko.com/api/v3/coins/bitcoin/market_chart?vs_currency=usd&days=300'
      )
      .then((response) => {
        let chart = []
        const data = response.data.prices

        data.forEach((element) => {
          chart.push({
            time: element[0] / 1000,
            value: element[1],
          })
        })
        this.dataBtc = chart
        this.show = true
      })
  },
}
</script>