Google News Clone

Demo

Today we add to Codernews to provide more content to our users.

What You'll Learn

We need a new page specifically for the cryptocurrencies prices chart.

Start by implementing a way to navigate to this new page from the homepage.

<li class="nav-item">
  <a class="nav-link" href="crypto.html">Crypto</a>
</li>

Negative : When we navigate to crypto.html we see that all the html we wrote in index.html is lost...

Negative : Copying everything from index.html into crypto.html works but introduces the problem of a substantial amount of code duplication.

We want this page to only show Crypto so we'll remove some code while adding different code.

This open source code will help us tremendously in this project.

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script>

Positive : It's using Canvas internally. We know that!

Remove scripts.js because we won't render news to the U.I. on this screen

<script src="js/scripts.js"></script>
<div class="col text-center">
  <h1 id="title" class="mt-5 title">CoderNews</h1>
  <ul id="newsList" class="list-group"></ul>
</div>
<script src="crypto.js"></script>
<canvas id="myChart" width="600" height="400"></canvas>

Let's add the logic to fetching crypto data & rendering the chart into crypto.js.

Make sure to replace YOUR_API_KEY with the one you got from the site.

const cryptoURL =
  "https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?start=1&limit=3&convert=USD&CMC_PRO_API_KEY=YOUR_API_KEY";

We call an api and parse it's response.

async function getCryptoPrices() {
  const response = await fetch(cryptoURL);
  const json = await response.json();
  const coin = json.data[0];

  console.log(coin);
}
getCryptoPrices();
const coin = {
  id: 1,
  name: "Bitcoin",
  symbol: "BTC",
  slug: "bitcoin",
  num_market_pairs: 9852,
  date_added: "2013-04-28T00:00:00.000Z",
  tags: [
    "mineable",
    "pow",
    "sha-256",
    "store-of-value",
    "state-channels",
    "coinbase-ventures-portfolio",
    "three-arrows-capital-portfolio",
    "polychain-capital-portfolio",
  ],
  max_supply: 21000000,
  circulating_supply: 18651531,
  total_supply: 18651531,
  platform: null,
  cmc_rank: 1,
  last_updated: "2021-03-12T07:22:02.000Z",
  quote: {
    USD: {
      price: 56772.22509134523,
      volume_24h: 56146078171.69906,
      percent_change_1h: 0.45440337,
      percent_change_24h: 2.1565927,
      percent_change_7d: 20.01380942,
      percent_change_30d: 22.3897859,
      percent_change_60d: 67.00783825,
      percent_change_90d: 209.20232707,
      market_cap: 1058888916230.2034,
      last_updated: "2021-03-12T07:22:02.000Z",
    },
  },
};

Positive : All APIs are called following the same pattern, Async/Await & Fetch/URL/.json().

Time to use the data with ChartJS.

Notice we call it after we get our data and we pass it an single coin.

async function getCryptoPrices() {
  const response = await fetch(cryptoURL);
  const json = await response.json();
  const coin = json.data[0];
  renderLineGraph(coin);
}

Here we select the canvas then use new Chart and ctx to draw to it.

We also pass it data using a helper function, getHistoricPrices(), which requires a single coins price as an argument.

function renderLineGraph(coin) {
  const ctx = document.getElementById("myChart");
  const price = coin.quote.USD.price;
  const [ninetyAgoPrice] = getHistoricPrices(coin.quote.USD);
  const timeAgo = ["90d", "60d", "30d", "7d", "24h", "1h", "Current"];
  const myChart = new Chart(ctx, {
    type: "line",
    data: {
      labels: timeAgo,
      datasets: [
        {
          label: "Price",
          borderWidth: 1,
          data: getHistoricPrices(coin.quote.USD),
          borderColor: "rgba(255, 99, 132, 1)",
          backgroundColor: "rgba(255, 99, 132, 0.2)",
        },
      ],
    },
    options: {
      tooltips: {
        enabled: true,
        mode: "nearest",
      },
      scales: {
        yAxes: [
          {
            ticks: {
              beginAtZero: false,
              suggestedMax: price,
              suggestedMin: ninetyAgoPrice,
            },
          },
        ],
      },
    },
  });
}
function getHistoricPrices(prices) {
  const {
    percent_change_90d,
    percent_change_60d,
    percent_change_30d,
    percent_change_7d,
    percent_change_24h,
    percent_change_1h,
    price,
  } = prices;

  const ninetyAgoPrice = calculatePriceFromPercentageChange(
    price,
    percent_change_90d
  );
  const sixtyAgoPrice = calculatePriceFromPercentageChange(
    price,
    percent_change_60d
  );
  const thirtyAgoPrice = calculatePriceFromPercentageChange(
    price,
    percent_change_30d
  );
  const sevenAgoPrice = calculatePriceFromPercentageChange(
    price,
    percent_change_7d
  );
  const dayAgoPrice = calculatePriceFromPercentageChange(
    price,
    percent_change_24h
  );
  const hourAgoPrice = calculatePriceFromPercentageChange(
    price,
    percent_change_1h
  );

  return [
    ninetyAgoPrice,
    sixtyAgoPrice,
    thirtyAgoPrice,
    sevenAgoPrice,
    dayAgoPrice,
    hourAgoPrice,
    price,
  ];
}

Unfortunately the data isn't structured how we want it so we need to perform these computations ourselves.

function calculatePriceFromPercentageChange(currentPrice, percentageChange) {
  let denominator;
  let historicPrice;
  if (percentageChange >= 100) {
    percentageChange = percentageChange + 100;
    denominator = percentageChange * 0.01;
    historicPrice = currentPrice / denominator;
  }

  if (percentageChange < 100 && percentageChange > 0) {
    denominator = 1 + percentageChange / 100;
    historicPrice = currentPrice / denominator;
  }

  if (percentageChange < 0) {
    const original = (currentPrice / (100 + percentageChange)) * 100;
    historicPrice = original;
  }
  return historicPrice;
}
var myChart = new Chart(ctx, {
  type: "line",
  data: {
    labels: ["90d", "60d", "30d", "7d", "24h", "1h", "Current"],
    datasets: [
      {
        label: "Price",
        borderWidth: 1,
        borderColor: "rgba(255, 99, 132, 1)",
        data: getHistoricPrices(coin.quote.USD),
        backgroundColor: "rgba(255, 99, 132, 0.2)",
      },
    ],
  },
});

Your technical lead did the heavy lifting for you. See if you can build on the shoulders of giants.