お問い合わせ
  • Tech

ただのグラフで終わらせない Chart.js 活用術 — カスタム背景レイヤー+折れ線+ズーム操作を SvelteKit で作り込んだ

Chart.js のカスタム描画で、背景・アイコン・ズームを盛り込んだ気温グラフを SvelteKit で作った話。

何を作ったのか

まずは完成したものから。

作ったのは「ある1日の気温が、時間とともにどう変わるか」を表すグラフです。ただの折れ線グラフではなく、次のような要素を盛り込みました。

  • 背景の色帯 … 「寒い」「快適」「暑い」などの温度ゾーンを、背景の色で塗り分けています。今の気温が”快適な範囲”にあるのか一目でわかります。
  • 2本の折れ線 … 「屋内の気温」と「屋外の気温」を別々の線で描き、見比べられるようにしました。
  • 天気アイコン … 各時間に、その時の天気(晴れ・曇り・雨・雪)の小さな絵を表示しています。
  • マウス操作 … マウスのホイールで拡大、ドラッグで範囲を選んでズーム、線にカーソルを合わせるとその時刻の詳しい情報が出ます。

使った道具立てはとてもシンプルです。

  • SvelteKit / Svelte 5(画面を作るための仕組み)
  • Chart.js(グラフを描くためのライブラリ)
  • chartjs-plugin-zoom(Chart.js にマウス操作を足す公式の追加部品)

ポイントは、グラフ専用の特別なライブラリを追加で入れていないこと。基本は Chart.js ひとつで、作れました。

なぜ Chart.js だけで足りるのか

「背景を塗り分けたり、アイコンを乗せたり…、ライブラリ標準でできるの?」と思うかもしれません。答えは「半分は標準機能で、残り半分はちょっとした”自作の追加部品”で」です。

やりたいことを分類すると、こうなります。

やりたいこと どうやって実現したか
折れ線を描く・情報を吹き出しで出す Chart.js の標準機能
マウスで拡大・移動する 公式の追加部品(プラグイン)を入れるだけ
背景を温度ゾーンで塗り分ける 自作の追加部品で、背景に直接お絵描き
線の上に天気アイコンを乗せる 標準機能に「画像」を渡すだけ

この記事でいちばん伝えたいのは、表の3行目です。Chart.js には「描画のすきまに、自分で好きな絵を足し込める仕組み」が用意されています。これを使えば、ライブラリが標準で用意していない見た目も、後から自由に付け足せるのです。

以下、特に工夫した「3つのヤマ場」を順番に紹介します。

ヤマ場① 背景を温度ゾーンで塗り分ける

やりたかったこと

「気温18〜26℃なら快適、それ以下は寒い、それ以上は暑い」——この”温度の区分け”を、グラフの背景の色で表したいと思いました。こうすると、線がどのゾーンを通っているかが直感的にわかります。

ところが、これは Chart.js の標準メニューには載っていません。そこで「自作の追加部品(プラグイン)」の出番です。

どう解決したか

Chart.js は、グラフを描く途中の決まったタイミングで「ここで何かしたい人いますか?」と声をかけてくれます。今回は「線やアイコンを描く”直前”」というタイミングをつかまえて、背景に色のついた長方形を自分で描きました。線より先に描くことで、ちゃんと”背景”として下に敷かれます。

// 快適度ゾーン(寒い〜暑い)を背景に直接描く追加部品
const comfortZonePlugin = {
  id: 'comfortZones',
  // 「線やアイコンを描く直前」に呼ばれる
  beforeDatasetsDraw(chart) {
    const { ctx, chartArea, scales } = chart;
    const yScale = scales.y;

    for (const zone of COMFORT_ZONES) {
      // 「26℃」が画面の上から何ピクセルの位置か、を計算してもらう
      const yTop = yScale.getPixelForValue(zone.to);
      const yBottom = yScale.getPixelForValue(zone.from);
      // その範囲を、ゾーンの色で塗りつぶす
      ctx.fillStyle = zone.color;
      ctx.fillRect(chartArea.left, yTop, chartArea.right - chartArea.left, yBottom - yTop);
    }
  }
};

ここで効いているのが getPixelForValue という機能です。「26℃って、画面上だとどこ?」を Chart.js に聞くと、ピクセル位置で答えてくれます。これを使うと、気温の数字さえ指定すれば、あとは正しい高さに勝手に塗ってくれるわけです。

うれしい副作用として、後で出てくる「ズームで拡大」をしても、背景の帯は気温の位置にぴったり追従します。拡大するたびに「26℃は今どこ?」を聞き直して塗っているので、線とズレないのです。

ゾーンの定義はこんなふうに、別ファイルにまとめてあります(色や範囲を変えたいときはここだけ直せばOK)。

export const COMFORT_ZONES = [
  { label: '寒い',     from: -5, to: 10, color: 'rgba(59, 130, 246, 0.18)' },
  { label: 'やや寒い', from: 10, to: 18, color: 'rgba(96, 165, 250, 0.12)' },
  { label: '快適',     from: 18, to: 26, color: 'rgba(34, 197, 94, 0.16)' },
  { label: 'やや暑い', from: 26, to: 32, color: 'rgba(251, 146, 60, 0.14)' },
  { label: '暑い',     from: 32, to: 40, color: 'rgba(239, 68, 68, 0.18)' }

ヤマ場② 折れ線の上に天気アイコンを乗せる

やりたかったこと

「7時は晴れ、18時は雨」——こうした天気を、その時刻の線の上に小さな絵で表示したいと思いました。

どう解決したか

Chart.js の折れ線は、各データに「点(マーカー)」を打てます。この点の形は、丸や四角だけでなく、好きな画像にもできます。そこで、天気の絵(SVG というイラスト形式)を画像として読み込み、点の代わりに使いました。

// SVGのイラストを「画像」として読み込んでおく
function loadIcon(src, maxSize) {
return new Promise((resolve) => {
const img = new Image();
img.onload = () => resolve(img);
img.src = src; // 例: '/icons/weather/sunny.svg'
});
}
// 各時刻の天気に対応する画像を並べて、点のスタイルとして渡す
const weatherIcons = dataPoints.map((p) => icons[p.condition]);

const markers = {
data: dataPoints.map((p) => ({ x: p.x, y: p.y + 1.8 })), // 線より少し上にずらす
pointStyle: weatherIcons, // ← 丸の代わりに天気の絵を表示
showLine: false // この系列は線を描かず、絵だけ出す
};

ヤマ場③ マウスで拡大・移動

やりたかったこと

1日分のグラフだと、細かい時間帯(例:朝の数時間だけ)を詳しく見たいことがあります。そこで、マウスでグラフを拡大したり、横に動かしたりできるようにしました。

拡大したイメージ

どう解決したか

これは、ほぼ「設定を書くだけ」で実現できます。chartjs-plugin-zoom という公式の追加部品を入れ、こう設定しました。

zoom: {
  // ドラッグで横方向に移動(Shiftキーを押しながら)
  pan: { enabled: true, mode: 'x', modifierKey: 'shift' },
  zoom: {
    wheel: { enabled: true }, // マウスホイールで拡大・縮小
    pinch: { enabled: true }, // スマホのピンチ操作で拡大・縮小
    drag:  { enabled: true }, // ドラッグした範囲にズーム
    mode: 'x'                 // 横方向(時間軸)だけ動かす
  },
  // 行きすぎ防止: 0〜24時の外には出ない/2時間より狭くしすぎない
  limits: { x: { min: 0, max: 24, minRange: 2 } }
}

たったこれだけで、ホイールでの拡大、ドラッグでの範囲指定ズーム、Shift+ドラッグでの横移動が全部使えるようになります。limits(制限)を付けておくと、「グラフの外までスクロールして真っ白になる」といった事故も防げます。

 

まとめ

グラフライブラリは「決まった形しか作れない不自由なもの」ではありません。標準機能で足りない部分は、描画の途中に自分で絵を足す——この発想ひとつで、できることが一気に広がります。

今回作った要素は、テーマを変えればいろいろな場面で使えます。

  • 背景の色帯 → 「正常/注意/危険」のしきい値表示、目標ライン帯
  • 線+アイコン → イベントの発生地点(リリース、障害、キャンペーン)
  • マウス操作 → 期間の長いデータを、細かく見たいところだけ拡大

気になった方は、ぜひ自分のグラフにも一工夫足してみてください。

ドコドア エンジニア部

ドコドア エンジニア部

Flutterなどの技術を活用し、ユーザーにとって価値ある高品質なモバイルアプリ・Webアプリの開発に取り組んでいます。
このブログでは、アプリ開発の現場で培ったフロントエンド、バックエンド、インフラ構築の知識から生成AI活用のノウハウまで、実践的な情報をアプリ開発に悩む皆様へ向けて発信しています!
【主な技術スタック】 Flutter / Firebase / Svelte / AWS / GCP / OpenAI API

Contact Us

Web制作、Webマーケティング、SFA・MA導入支援に関するお悩みがある方は、お気軽にご相談ください。

お問い合わせ・ご相談

ホームページ制作、マーケティングにおける
ご相談はお気軽にご連絡ください。

資料請求

会社案内や制作実績についての資料を
ご希望の方はこちらから。

お電話でのお問い合わせ

お電話でのご相談も受け付けております。

※コールセンターに繋がりますが、営業時間内は即日
担当より折り返しご連絡をさせて頂きます。

9:00-18:00 土日祝休み

電話する 無料相談はこちら