【WIP】よく聴く曲ランキングを画像生成してみる(土台だけ)

「直近1週間でよく聴いた10曲」として、下記のような形式で、時折ツイートしています。
今は、AWS LambdaからLast.fmのAPIを叩き、情報を取得しています。とりあえずなので、ツイートする機能は無く、取得するところまでしか作れていません・・・。

直近1週間でよく聴いた10曲
1. 新世界 - 南條愛乃
2. Daybreak Age - シャイニーカラーズ
3. Forever Friends - Leaders ver. - AiRBLUE Leaders
4. Daybreak Age (Off Vocal) - シャイニーカラーズ
5. 虹の行方 - シャイニーカラーズ
6. 虹の行方 (Off Vocal) - シャイニーカラーズ
7. CRYST@LOUD - 天海春香、渋谷 凛、伊吹 翼、天道 輝、八宮めぐる from THE IDOLM@STER M@STERS OF IDOL WORLD!!!!! 2023
8. Luminous Witches - 藤澤慶昌
9. 蒼穹のファンファーレ - FictionJunction
10. GR@TITUDE - ミリオンライブ!Ver. - MILLIONSTARS

ネットで調べていると、下記のように画像でランキングを作っている記事を見つけました。
今回は、「ランキング表を画像で作る」ところを、仮の形で作りましたので、メモです。 zenn.dev

完成イメージ

My Favorite Songs (1month)

流れ

手順1: 背景用画像を用意

背景用画像

手順2: canvas要素を用意

HTML

<canvas id="rankingCanvas" width="640" height="1280"></canvas>

※背景用画像と同じサイズで作成します。

JavaScript

const canvas = document.getElementById("rankingCanvas");
const ctx = canvas.getContext("2d");

参考ドキュメント
キャンバス API - Web API | MDN
CanvasRenderingContext2D - Web API | MDN

手順3: 背景画像を描画

function drawImage() {
  const image = new Image();
  image.onload = function () {
    ctx.drawImage(image, 0, 0);
  };
  image.src = "background.png";
}

上記 関数を呼び出し。

drawImage();

このタイミングで、背景用画像が画面上に表示されます。

手順4: 仮のランキングデータを用意する

const rankingData = {
  tracks: [
    {
      trackName: "1曲目",
      artistName: "アーティスト名",
    },
    {
      trackName: "2曲目",
      artistName: "アーティスト名",
    },
    {
      trackName: "3曲目",
      artistName: "アーティスト名",
    },
    {
      trackName: "4曲目",
      artistName: "アーティスト名",
    },
    {
      trackName: "5曲目",
      artistName: "アーティスト名",
    },
    {
      trackName: "6曲目",
      artistName: "アーティスト名",
    },
    {
      trackName: "7曲目",
      artistName: "アーティスト名",
    },
    {
      trackName: "8曲目",
      artistName: "アーティスト名",
    },
    {
      trackName: "9曲目",
      artistName: "アーティスト名",
    },
    {
      trackName: "10曲目",
      artistName: "アーティスト名",
    },
  ],
};

手順5: ランキングデータを画像の上に描画する

let trackTextX = 100;
let trackTextY = 150;
let artistTextX = 100;
let artistTextY = 190;

function textRendering() {
  for (var i = 0; i < rankingData.tracks.length; i++) {
    let trackName = rankingData.tracks[i].trackName;
    let artistName = rankingData.tracks[i].artistName;

    ctx.font = "28px Arial";
    ctx.fillStyle = "black";
    ctx.textAlign = "left";
    ctx.fillText(trackName, trackTextX, trackTextY);

    ctx.font = "18px Arial";
    ctx.fillStyle = "black";
    ctx.textAlign = "left";
    ctx.fillText(artistName, artistTextX, artistTextY);

    trackTextY += 115; // 灰色1行文の高さ
    artistTextY += 115; // 灰色1行文の高さ
  }
}

drawImage関数内、image.onloadの箇所を下記に修正。
画像を読み込み後に、画像描画を行ない、更にテキストを描画します。

image.onload = function () {
  ctx.drawImage(image, 0, 0);
  textRendering(); // ここを追加
};

参考ドキュメント
CanvasRenderingContext2D: font property - Web APIs | MDN
CanvasRenderingContext2D: fillStyle property - Web APIs | MDN
CanvasRenderingContext2D: textAlign property - Web APIs | MDN
CanvasRenderingContext2D: fillText() method - Web APIs | MDN

気づき・課題

  • 固定要素は、今回のように背景用画像として用意しても良さそう。
    • 最初、背景画像の要素もCanvasで生成しようとしていた。
  • 曲名やアーティスト名が長い場合、「完成イメージ」のように、はみ出てしまう。
    • 解決策としては、折り返しや文字サイズの縮小など?
  • サーバーサイドでCanvas要素を利用する場合、「Automattic/node-canvas: Node canvas is a Cairo backed Canvas implementation for NodeJS.」などのライブラリが必要となる。