LoginSignup
23
19

More than 5 years have passed since last update.

Chart.js をサーバーサイドで使う方法

Last updated at Posted at 2018-09-17

Chart.js は、JavaScriptで利用できるメジャーなチャート(グラフ)描画ライブラリーの1つですが、HTML DOM、より正確に言えば HTML5 Canvas API に依存しているため、Node.jsの環境では動作できません。

しかし、Canvas以外への依存は殆ど無いので、Canvas APIさえ用意できれば、サーバーサイド・レンダリング (SSR) が可能となります。

今回は私自作のCanvas API互換ライブラリー red-agate-svg-canvas を使用して、Node.js上でSVGにレンダリングしたいと思います。

今回の全ソースは こちら にあります。

追記 (2018/9/18)

今回説明する以外にchartjs-node等のパッケージを用いてもサーバーサイドでChart.jsを使うことができます。
chartjs-nodeのメリットは、jpegやpngといったラスタイメージ、svg、さらにはpdf出力にも対応しているところですが、それらを実現するためにcairoというネイティブのライブラリーに依存しているため、セットアップは少し面倒となっています。

解説

import { SvgCanvas,
         Rect2D,
         SvgCanvas2DGradient } from 'red-agate-svg-canvas/modules';
import * as ChartJs            from 'chart.js';

// グローバルスコープを取得します。
// もし、Node.jsで動作してるならば、 "g" は "global" オブジェクトになります。
// ブラウザー上ならば、 "g" は "window" オブジェクトになります。
const g = Function('return this')();

// グラフの描画オプションです。
// https://www.chartjs.org/docs/latest/getting-started/usage.html
const opts: any = { /* 中略 */ };


function main() {
    // SvgCanvas は "CanvasRenderingContext2D" と互換のインターフェイスを持っています。
    const ctx = new SvgCanvas();

    // しかしながら、 SvgCanvas には canvas プロパティーがありません。
    // canvas プロパティーには本来、このコンテキストの親となる HTMLCanvasElement が設定されています。
    // Chart.js では、以下のプロパティーのみ存在すれば問題ありません。
    (ctx as any).canvas = {
        width: 800,
        height: 400,
        style: {
            width: '800px',
            height: '400px',
        },
    };

    // SvgCanvas の実装は、ホスト環境のフォント(グリフ)情報にアクセスしません。
    // 文字列のピクセルでの幅を求められるようにするために、フォントの縦横比を手動で設定します。
    ctx.fontHeightRatio = 2;

    // Chart.js には "HTMLCanvasElement" と互換のインターフェイスを持つオブジェクトを渡す必要があります。
    // そのオブジェクトは、"getContext()" メソッドのみを持っていれば問題ありません。
    // "getContext()" は "CanvasRenderingContext2D" と互換のインターフェイスを持つオブジェクトを返さなければなりません。
    const el = { getContext: () => ctx };

    // もし、描画オプションに "devicePixelRatio" を設定しないと、
    // Chart.js は devicePixelRatio を "window" オブジェクトから取得しようとします。
    // その場合、 node.js では window オブジェクトが存在しないため、エラーとなってしまいます。
    opts.options.devicePixelRatio = 1;

    // アニメーションを無効にします。
    opts.options.animation = false;
    opts.options.events = [];
    opts.options.responsive = false;

    // Chart.js は描画設定によっては、グローバルスコープの "CanvasGradient" を参照しようとします。
    // エラーを防ぐために、 SvgCanvas のグラデーションオブジェクトをグローバルスコープに設定します。
    const savedGradient = g.CanvasGradient;
    g.CanvasGradient = SvgCanvas2DGradient;
    try {
        const chart = new ChartJs.Chart(el as any, opts);
    } finally {
        // グローバルスコープを元に戻します。
        if (savedGradient) {
            g.CanvasGradient = savedGradient;
        }
    }

    // SVGとして描画します。
    const svgString = ctx.render(new Rect2D(0, 0 , 800, 400), 'px');
    console.log(svgString);
}

レンダリング結果 (Chromeでの表示結果)

  • SVGイメージはQiitaのエディターでアップロードされないため、Chromeで表示してキャプチャーしました。

バー

1.png

ドーナッツ

2.png

ライン

3.png

エリア

4.png

備考

  • 現状、ビルドには Webpack と babel が必要です。

さいごに

上記のチャートやUML、バーコード・2次元コードをドキュメントに組み込んでHTMLやPDFにレンダリングする
コンソールアプリ Ménneu を公開しました。
後発のアプリですが、併せてご覧いただければと思います。

23
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
19