Chart.js 1.xのグラフを2.xで動作させたい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,769

masahiro.o

score 12

前提・実現したいこと

現在Chart.js 2.1.3 で開発しているシステムの改修を行っているのですが
仕様変更でグラフの横幅が広くなったものがあり、スクロールバーでスクロールさせたいという要望があり
調べていたのですがChart.js 1.xで動作するサンプルを発見して内容も理解できたのですが
2.xで動作させようとするとなくなってしまったオブジェクトがあるようで動作しませんでした。
いろいろ試行錯誤しているのですが、本家のサイトにも情報が少なく知見がある方がいらっしゃれば教えて頂きたいと思い投稿しました。

Chart.js 1.x で操作するソース(html)

<!DOCTYPE html>
<html lang="js">
    <head>
        <title>MIX CHART TEST</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="css/style.css" rel="stylesheet">
    </head>
    <body>

        <div class="chartWrapper">
            <div class="chartAreaWrapper">
                <canvas id="myChart" height="300" width="1200"></canvas>
            </div>
            <canvas id="myChartAxis" height="300" width="0"></canvas>
        </div>

        <script type="text/javascript" src="https://rawgit.com/nnnick/Chart.js/v1.0.2/Chart.min.js"></script>
        <script>

            var ctx = document.getElementById("myChart").getContext("2d");

            var data = {
                labels: ["January", "February", "March", "April", "May", "June", "July"],
                datasets: [
                    {
                        label: "My First dataset",
                        fillColor: "rgba(220,220,220,0.2)",
                        strokeColor: "rgba(220,220,220,1)",
                        pointColor: "rgba(220,220,220,1)",
                        pointStrokeColor: "#fff",
                        pointHighlightFill: "#fff",
                        pointHighlightStroke: "rgba(220,220,220,1)",
                        data: [65, 59, 80, 81, 56, 55, 40]
                    },
                    {
                        label: "My Second dataset",
                        fillColor: "rgba(151,187,205,0.2)",
                        strokeColor: "rgba(151,187,205,1)",
                        pointColor: "rgba(151,187,205,1)",
                        pointStrokeColor: "#fff",
                        pointHighlightFill: "#fff",
                        pointHighlightStroke: "rgba(151,187,205,1)",
                        data: [28, 48, 40, 19, 86, 27, 90]
                    }
                ]
            };

            new Chart(ctx).Bar(data, {
                onAnimationComplete: function () {
                    var sourceCanvas = this.chart.ctx.canvas;
                    var copyWidth = this.scale.xScalePaddingLeft - 5;

                    console.log(this);

                    // the +5 is so that the bottommost y axis label is not clipped off
                    // we could factor this in using measureText if we wanted to be generic
                    var copyHeight = this.scale.endPoint + 5;
                    var targetCtx = document.getElementById("myChartAxis").getContext("2d");
                    targetCtx.canvas.width = copyWidth;
                    targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth, copyHeight, 0, 0, copyWidth, copyHeight);
                }
            });

        </script>
    </body>
</html>
style.css
.chartWrapper {
    position: relative;
}

.chartWrapper > canvas {
    position: absolute;
    left: 0;
    top: 0;
    pointer-events:none;
}

.chartAreaWrapper {
    width: 600px;
    overflow-x: scroll;
}

Chart.js 2.xで試しているソース(html)

<!DOCTYPE html>
<html lang="js">
    <head>
        <title>MIX CHART TEST</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="css/style.css" rel="stylesheet">
    </head>
    <body>

        <div class="chartWrapper">
            <div class="chartAreaWrapper">
                <canvas id="myChart" height="300" width="1200"></canvas>
            </div>
            <canvas id="myChartAxis" height="300" width="0"></canvas>
        </div>

        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.min.js"></script>
        <!--<script type="text/javascript" src="https://rawgit.com/nnnick/Chart.js/v1.0.2/Chart.min.js"></script>-->

        <script>
            var data = {
                labels: ["January", "February", "March", "April", "May", "June", "July"],
                datasets: [
                    {
                        label: "My First dataset",
                        fillColor: "rgba(220,220,220,0.2)",
                        strokeColor: "rgba(220,220,220,1)",
                        pointColor: "rgba(220,220,220,1)",
                        pointStrokeColor: "#fff",
                        pointHighlightFill: "#fff",
                        pointHighlightStroke: "rgba(220,220,220,1)",
                        data: [65, 59, 80, 81, 56, 55, 40]
                    },
                    {
                        label: "My Second dataset",
                        fillColor: "rgba(151,187,205,0.2)",
                        strokeColor: "rgba(151,187,205,1)",
                        pointColor: "rgba(151,187,205,1)",
                        pointStrokeColor: "#fff",
                        pointHighlightFill: "#fff",
                        pointHighlightStroke: "rgba(151,187,205,1)",
                        data: [28, 48, 40, 19, 86, 27, 90]
                    }
                ]
            };

            var complexChartOption = {
                responsive: true,
                scales: {
                    yAxes: [{
                        id: "y-axis-1",
                        type: "linear", 
                        position: "left",
                        ticks: {
                            max: 0.2,
                            min: 0,
                            stepSize: 0.1
                        },
                    }, {
                        id: "y-axis-2",
                        type: "linear", 
                        position: "right",
                        ticks: {
                            max: 1.5,
                            min: 0,
                            stepSize: .5
                        },
                        gridLines: {
                            drawOnChartArea: false, 
                        },
                    }],
                },
                animation: {
                    duration: 2000,
                    onComplete: function(data) {
                        console.log('onAnimationComplete Start');

                        // var _this = myBar;
                        // var chartInstance = _this.chart;
                        // var ctx = chartInstance.ctx;

                        console.log(this);
                        // console.log(_this);

                        // var sourceCanvas = _this.chart.ctx.canvas;
                        // var copyWidth = _this.scale.xScalePaddingLeft - 5;
                        // // the +5 is so that the bottommost y axis label is not clipped off
                        // // we could factor this in using measureText if we wanted to be generic
                        // var copyHeight = _this.scale.endPoint + 5;
                        // var targetCtx = document.getElementById("myChartAxis").getContext("2d");
                        // targetCtx.canvas.width = copyWidth;
                        // targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth, copyHeight, 0, 0, copyWidth, copyHeight);

                        var getParentIdName = this.chart.canvas.attributes.id.value,
                            targetElement = document.getElementById("myChartAxis"),
                            sourceElement = document.getElementById("myChart"),
                            sourceCanvas = this.chart.ctx.canvas,
                            copyWidth = this.scales["y-axis-1"].width, // we are copying the width of actual chart
                            copyHeight = this.chart.height, // we are copying the width of actual chart
                            targetElementWidth = sourceElement.getContext("2d").canvas.clientWidth,
                            targetElementHeight = sourceElement.getContext("2d").canvas.clientHeight,
                            targetCtx = targetElement.getContext("2d");

                        targetCtx.canvas.width = copyWidth;
                        targetCtx.canvas.height = copyHeight;
                        // targetCtx.drawImage(sourceCanvas, 0, 0, targetElementWidth, targetElementHeight);
                        targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth, copyHeight, 0, 0, copyWidth, copyHeight);

                        console.log('onAnimationComplete End');

                    }
                }            
            };

            window.onload = function() {
                ctx = document.getElementById("myChart").getContext("2d");
                window.myBar = new Chart(ctx, {
                    type: 'bar',
                    data: data,
                    options: complexChartOption,
                });
            };
        </script>
    </body>
</html>

試したこと

1.xのソースそのままですと「this.scale」というオブジェクトがないので「this.scale.xScalePaddingLeft」でエラーとなってしまいます。
上のソースは2.xのオブジェクトを目視して作ってみたものですが、エラーは出ないですが動きません…

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

見て頂いた方、検証して頂いた方がいらっしゃったらすいません。自己解決しました。
そもそもcavasのdrawImageメソッドの値を手動で修正しても反映されないので不思議に思って調べていたところ
グラフのオプション「responsive」が「true」だとcavasのサイズ指定を無視してグラフを描画する仕様があることが分かりました。
これを「false」とすることで目的であるスクロールバーの表示はできました。
(v.1でとれている値が取れない課題は残っていますが…)
「responsive」レスポンシブデザイン用のオプションだと思うのですが必要になった場合はcssで以下みたいにすれば対応できるかと思います。

<div class="chart_container">
  <canvas id="myChart" width="320" height="360"></canvas>
</div>

<style>
@media screen and (min-width: 768px) {
  .chart_container {
    width: 640px;
    margin: auto;
  }
}
</style>

V.2.xで動作するソース

<!DOCTYPE html>
<html lang="js">
    <head>
        <title>MIX CHART TEST</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="css/style.css" rel="stylesheet">
    </head>
    <body>

        <div class="chartWrapper">
            <div class="chartAreaWrapper">
                <canvas id="myChart" height="300" width="1200"></canvas>
            </div>
            <canvas id="myChartAxis" height="300" width="0"></canvas>
        </div>

        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.min.js"></script>

        <script>
            var data = {
                labels: ["January", "February", "March", "April", "May", "June", "July"],
                datasets: [
                    {
                        label: "My First dataset",
                        fillColor: "rgba(220,220,220,0.2)",
                        strokeColor: "rgba(220,220,220,1)",
                        pointColor: "rgba(220,220,220,1)",
                        pointStrokeColor: "#fff",
                        pointHighlightFill: "#fff",
                        pointHighlightStroke: "rgba(220,220,220,1)",
                        data: [65, 59, 80, 81, 56, 55, 40]
                    },
                    {
                        label: "My Second dataset",
                        fillColor: "rgba(151,187,205,0.2)",
                        strokeColor: "rgba(151,187,205,1)",
                        pointColor: "rgba(151,187,205,1)",
                        pointStrokeColor: "#fff",
                        pointHighlightFill: "#fff",
                        pointHighlightStroke: "rgba(151,187,205,1)",
                        data: [28, 48, 40, 19, 86, 27, 90]
                    }
                ]
            };

            var complexChartOption = {
                responsive: false,
                animation: {
                    onComplete: function(data) {
                        console.log('onComplete Start');

                        var sourceCanvas = this.chart.ctx.canvas;

                        var getParentIdName = this.chart.canvas.attributes.id.value,
                            targetElement = document.getElementById("myChartAxis"),
                            sourceElement = document.getElementById("myChart"),
                            copyWidth = this.scales["y-axis-0"].width, // we are copying the width of actual chart
                            copyHeight = this.chart.height, // we are copying the width of actual chart
                            targetElementWidth = sourceElement.getContext("2d").canvas.clientWidth,
                            targetElementHeight = sourceElement.getContext("2d").canvas.clientHeight,
                            targetCtx = targetElement.getContext("2d");


                        targetCtx.canvas.width = copyWidth;
                        targetCtx.canvas.height = copyHeight;
                        // targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth, copyHeight, 0, 0, copyWidth, copyHeight);
                        targetCtx.drawImage(sourceCanvas, 0, 0, targetElementWidth, targetElementHeight);

                        console.log('onComplete End');

                    }
                }            
            };

            window.onload = function() {
                ctx = document.getElementById("myChart").getContext("2d");
                window.myBar = new Chart(ctx, {
                    type: 'bar',
                    data: data,
                    options: complexChartOption,
                });
            };
        </script>
    </body>
</html>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る