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

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

ただいまの
回答率

89.63%

canvasで絵画機能を動的に生成したい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 392

MikMik

score 42

JSで絵画機能を自由に複製できるようにしたいです。
現在ajaxからテンプレートHTMLを読み込んで絵画のHTMLが存在していれば(canvasのタグがあれば)お絵かきができるようにしたいです。

$(document).on("change", "[id=templates_number]", function(){
    略
    $.post("templates.php", {
      data : template_data,
     略
    }, function(data) {
   //dataにhtmlを入れて読み込んでいる
  略
   //タグがcanvasならcanvasのセッティング
  canvas = document.getElementById("canvasタグのid");
   ctx = canvas.getContext('2d');
   undoImages = [];
   pointer = -1;
   canvas.addEventListener('mousemove', draw_canvas);
  略
   });
});


かなりコードを省略して申し訳ないです。フォームのデータ情報をjsonで読み込んでおり、それをループさせてタグのタイプがcanvasだったらそのキャンバスの設定をしたいです。
現在このような形になっています。恐らくこのままだと複数の設定ができないと思います。また、EventListenerはループの中で設定できるのか怪しいです。
JSの経験がまだ浅いので皆様の助言をお待ちしております

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+2

脱初心者レベルの難しい話になります。
もし理解するのが難しければJavaScriptで新しく変数を利用するときはvar(またはlet)を使うことだけ覚えてもらえればよいです。
コードの修正点としてはループ中の変数をlet宣言に直すのと、draw_canvas()関数をループ中で定義するようにすればよいかと思います。

質問文のコードが複数の<canvas>に対応できないのは、ループ中で使用している変数が「グローバル変数」になっているからであると考えられます。このままでは2回目以降の<canvas>タグで前回の値を上書きしてしまいます。
JavaScriptでは新しく変数を使用する際にvarletを用いて変数を宣言するとその変数は「ローカル変数」となり、変数の使用できる範囲を限定して使用することができます。
文法とデータ型 - JavaScript | MDN

質問文のコードを下記のように書き換えることで、変数をローカル変数として使用し、ループによる上書きを回避できると思います。

let canvas = document.getElementById("canvasタグのid");
let ctx = canvas.getContext('2d');
let undoImages = [];
let pointer = -1;

ここで用いたletというのは、forループなどに用いる{ }←この括弧の中だけで使用できる変数を宣言しています。こうすることによって、forループがループされるたびに新しい変数が生成されることになります。
(forループ1回目の変数canvasとループ2回目の変数canvasは別物ということになります。)

注意点として、addEventListener()について、引数に与える関数draw_canvas()forループの{ }の中で定義する必要があります。なぜなら変数canvas{ }の中にしか存在しないからです。
また、関数の中から外へ参照する変数は、関数を定義した時点でのローカル変数になるので、変数canvasはちゃんとループごとの変数になってくれます。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/08/26 10:24

    丁寧にご説明いただきありがとうございます!
    ループ中にvarやletで定義したものは別物になるとは初めて知りました。勉強になります。おかげ様で複数のcanvasを設定できるようになりました。

    キャンセル

  • 2018/08/26 13:34

    勉強になってもらえたようでよかったです。
    補足しておくと、letは波括弧{ }で別物になりますが、varは関数function(){ }で別物になります。(varは波括弧{ }では別物にはならないので、1つの変数をループのたびに上書きすることになってしまいます。) 似てるようで違うので、詳しくは調べてみるとよいでしょう。

    キャンセル

  • 2018/08/26 13:48

    補足の補足失礼します…。
    letはvarの代わりになりますが、varをletの代わりにするのはちょっと手間がかかります。もし古いIEを動作対象外にするのであればvarは使わずすべてletにするのがよいかと思います。 https://caniuse.com/#feat=let

    キャンセル

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

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