質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

90.54%

  • TypeScript

    468questions

    TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

  • canvas

    303questions

    HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

  • Angular

    163questions

canvasで描画したグラフが削除できません

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,386

tnishi

score 5

Angular4を勉強している者です。

TypeScriptにてChart.jsを使ったグラフ描写を実装しています。

<!doctype html>
<html lang="en">
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.min.js"></script>
</head>
<body>
    <canvas id="graph2" width="1050" height="400"></canvas>
</body>
</html>
// グラフ描画
let data = {
    labels: {"1月","2月","3月"},
    datasets: [
    {
           label: "件数",
           fillColor: "rgba(220,220,220,0.5)",
           strokeColor: "rgba(220,220,220,0.8)",
           highlightFill: "rgba(220,220,220,0.75)",
           highlightStroke: "rgba(220,220,220,1)",          
           data: {3, 2, 10} // ★ここは可変データ。通るたびに変化★
     }
     ]
};

let element: HTMLCanvasElement =<HTMLCanvasElement>document.getElementById('graph1');

let myChart = new Chart(ctx, {
                               type: 'bar',
                               data: data
                             });

一回上記の通り実装してグラフは表示されました。
しかし、画面リロードをせず再度上記処理を通した際に、一旦は最新のグラフが表示されるのですが、
1回目に描画した棒グラフの棒があった部分にホバーしたところ、1回目に描画したグラフに切り替わってしまいました。
おそらく裏で残ってしまっていると考えたので、以下の通り処理を追加しました。

// グラフ描画
let data = {
    labels: {"1月","2月","3月"},
    datasets: [
    {
           label: "件数",
           fillColor: "rgba(220,220,220,0.5)",
           strokeColor: "rgba(220,220,220,0.8)",
           highlightFill: "rgba(220,220,220,0.75)",
           highlightStroke: "rgba(220,220,220,1)",          
           data: {3, 2, 10} // ★ここは可変データ。通るたびに変化★
     }
     ]
};

let element: HTMLCanvasElement =<HTMLCanvasElement>document.getElementById('graph1');

// 追加箇所-----------------------------------------------
let ctx = element.getContext("2d");
ctx.clearRect(0,0,element.width,element.height);
ctx.beginPath();
// 追加箇所ここまで-----------------------------------------------

let myChart = new Chart(ctx, {
                               type: 'bar',
                               data: data
                             });

削除してから描画するという形でうまくいくかと思いきや、事態は変わりませんでした。
単純に描いたグラフを削除したいだけなのですが、なぜかうまくいきません。

非常にざっくりした説明で申し訳ございませんが、
canvasに詳しい方、同じような現象にあわれた方いらっしゃいましたらご教示いただけますと幸いです。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

毎回 new Chart(ctx,... としているであれば前のChartが残るのではないでしょうか。
Chart.jsは単純にCanvasにグラフを描くだけでなくアニメーション等も付いています。また、ホバー、クリック等のイベントが設定されるため、Chartへの参照が残ってGCに回収されないのだと思います。

別のグラフに切り替えるには new Chart(ctx,... をクラス変数に入れる等の後でアクセスできるようにして、グラフのデータを入れ替えて myChart.update() のメソッドで切替ができます。

素のJSですが切り替えサンプルです。

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
</head>
<body>
<input type="button" value="graphA" onclick="graphA()">
<input type="button" value="graphB" onclick="graphB()">
<canvas id="graph1"></canvas>
<script>
function chartdata(data) {
  return {
    labels: ["1月","2月","3月"],
    datasets: [
      {
        label: "件数",
        fillColor: "rgba(220,220,220,0.5)",
        strokeColor: "rgba(220,220,220,0.8)",
        highlightFill: "rgba(220,220,220,0.75)",
        highlightStroke: "rgba(220,220,220,1)",
        data: data
      }
    ]
  };
}

let ctx = document.getElementById('graph1').getContext("2d");
let myChart = new Chart(ctx, {type: 'bar', data: chartdata([])});

function graphA() {
  myChart.data = chartdata([3, 2, 10]);
  myChart.update();
}
function graphB() {
  myChart.data = chartdata([6,4,5]);
  myChart.update();
}
</script>
</body>
</html>

TypeScriptサンプルを追加します。
Angular-Cli 1.3.2 (Angular 4.3.6) + Chart.js 2.6.0で動作しています。

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-chart',
  template: '<div><button (click)="clicked($event)">Update</button><canvas id="graph1"></canvas></div>'
})
export class ChartComponent implements OnInit {
  cnt = 0;
  myChart;

  constructor() { }

  ngOnInit() {
    const element = <HTMLCanvasElement>document.getElementById('graph1');
    const ctx = element.getContext('2d');
    this.myChart = new Chart(ctx, {type: 'bar', data: this.chartdata([])});
  }

  private chartdata(newData:Array<number>) {
    return {
      labels: ["1月","2月","3月"],
      datasets: [
        {
          label: "件数",
          fillColor: "rgba(220,220,220,0.5)",
          strokeColor: "rgba(220,220,220,0.8)",
          highlightFill: "rgba(220,220,220,0.75)",
          highlightStroke: "rgba(220,220,220,1)",
          data: newData
        }
      ]
    };
  }

  clicked(event) {
    this.cnt++;
    const newData = ((this.cnt & 1) === 1)
      ? [10, 20, 30]
      : [30, 20, 10];
    this.myChart.data = this.chartdata(newData);
    this.myChart.update();
  }
}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/08/24 10:05

    >shimitei 様

    ご回答いただきありがとうございます。
    いただいたサンプルを動かしたところ、正常に動作しました。

    ただし、TypeScriptでは正常に動作しませんでした。
    (グラフは切り替わりますが、前回表示されたグラフがあった場所にホバーすると前回のグラフに切り替わってしまします)
    実装したTypeScript部分は以下の通りです。

    -------------------------------------------------------------------------------------------------
    // 一旦データを空にする
    let myChart = new Chart(ctx, {type: 'bar', data: this.chartdata(0)});
    let data55: any;
    // データを取得
    data55 = this.chartdata(1);
    myChart = new Chart(ctx, {type: 'bar', data: this.chartdata(1)});
    myChart.update();
    this.cnt ++;

    // これが呼ばれるたびに、返却するデータを切り替える
    chartdata(c) {
    let newData = [];

    // 引数が0の場合はデータを一切いれない
    if (c != 0) {
    if (this.cnt == 1 || this.cnt == 3 || this.cnt == 5 || this.cnt == 7) {
    newData[0] = 10;
    newData[1] = 20;
    newData[2] = 30;
    } else {
    newData[0] = 30;
    newData[1] = 20;
    newData[2] = 10;
    }
    }

    return {
    labels: ["1月","2月","3月"],
    datasets: [
    {
    label: "件数",
    fillColor: "rgba(220,220,220,0.5)",
    strokeColor: "rgba(220,220,220,0.8)",
    highlightFill: "rgba(220,220,220,0.75)",
    highlightStroke: "rgba(220,220,220,1)",
    data: newData
    }
    ]
    };
    }

    -------------------------------------------------------------------------------------------------

    JavaScriptとTypeScriptで挙動が違うということはありますでしょうか。
    勉強不足で申し訳ございません。
    再度ご教示いただけますと幸いです。

    キャンセル

  • 2017/08/25 12:36

    問題なく切り替え可能なTypeScript(Angular4)のサンプルを追加しました。
    質問者さんのコードでうまく切り替えできていない原因は、やはり更新時に毎回new Chartしているためでしょう。

    キャンセル

  • 2017/08/28 11:04

    早々のご回答、誠にありがとうございます。
    ご教示いただきました通りオブジェクトは初期処理で生成し、データの更新は別で行いupdateをすることで前回のグラフが表示されなくなりました。解決です、ありがとうございます。

    今回のポイントとしましては以下の点だと考えております。
    ・オブジェクトを作り直ししていた為、以前のグラフが残っていた。
    ・データを入れなおした後、updateをすれば切り替えられる。
    ・Chart.jsのバージョンが若干古かった(2.3.0を使っていました)

    特に一番上の「オブジェクトを作り直ししていた為、以前のグラフが残っていた。」
    というところは盲点でした。


    Angularの件でまたお伺いすることがあると思いますが、その際は助言いただけますと幸いです。
    今回は丁寧親切かつ分かりやすく解説、またサンプルまでご提示いただきありがとうございました。

    キャンセル

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

  • TypeScript

    468questions

    TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

  • canvas

    303questions

    HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

  • Angular

    163questions