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

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

ただいまの
回答率

89.13%

html5のcanvasで絵を描くとき、太くすると線が粗くなってしまう【参考画像あり】

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 3,960

sanset

score 182

イメージ説明
【追記】

hirohiroさん、edo_m18さんのコードで、斜めに線を引くとこうなります。
たしかに修正前のようにスカスカはしませんが、きれいに描画されてないように思います。

イメージ説明
【追記終】

上のイメージのように、線を太い設定のまま書くとこのように粗く表示されてしまいます。
下記が上記のようになってしまうcanvasの設定です。

<canvas width="780" height="400"></canvas>

    var borderWidth = 5;
    var fromX;
    var fromY;
    var drawFlag = false;
    var context = $("canvas").get(0).getContext('2d');
    var pale = '#ff25a8'; //色
    var penWidth = 2; //太さ

    $('canvas').mousedown(function(e) {
        drawFlag = true;
        fromX = e.pageX - $(this).offset().left - borderWidth;
        fromY = e.pageY - $(this).offset().top - borderWidth;
        return false;  // for chrome
    });
 
    $('canvas').mousemove(function(e) {
        if (drawFlag) {
            draw(e);
        }
    });

    $('canvas').on('mouseup', function() {
        drawFlag = false;
    });
 
    $('canvas').on('mouseleave', function() {
        drawFlag = false;
    });
 
    function draw(e) {
        var toX = e.pageX - $('canvas').offset().left - borderWidth;
        var toY = e.pageY - $('canvas').offset().top - borderWidth;
        context.strokeStyle = pale; //色の設定 paleという変数に入れてます。
        context.lineWidth = penWidth; //太さの設定 上記の画像は30
        context.beginPath();
        context.moveTo(fromX, fromY);
        context.lineTo(toX, toY);
        context.stroke();
        context.closePath();

        fromX = toX; //追記
        fromY = toY; //追記
    }


どなたか対処法など、ご教示お願いいたします。
コードで書いて説明していただけるとうれしいです。
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 5

checkベストアンサー

+1

beginPathclosePathを実行しちゃってるからな気がします。
つまり、パスを毎回切っちゃってるためにガタガタしているんですね。

draw関数内ではlineToのみを行い、moveTobeginPathclosePathmousedownmouseup時に行うようにすると綺麗につながると思いますよ。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/08/02 02:24

    ありがとうございます。
    試してみて、上記の画像のように別の問題が出てきてしまいました。

    キャンセル

  • 2015/08/02 16:30 編集

    書かれているコードは最新版ですかね?
    指摘の点が反映されていないようです。

    こちらに上記コードを少し修正して意図した動作になるようにしたものをあげてみました。
    http://jsdo.it/edo_m18/jfjA

    JSであればこうした動くものを提示しやすいので、こうしたサイトを利用して動かないコードを共有するとより早く回答が得られると思いますよ。

    ※ ちなみに変更点は、上記指摘の通り、mouseup、mousedownにbeginPath、closePathを移動したものになります。

    キャンセル

  • 2015/08/13 22:58

    ご連絡遅れて申し訳ありません。
    サンプルのコードまで頂き、とても助かりました。
    何度もご協力頂きありがとうございます。

    キャンセル

0

2はそんなに太くないと思います。
恐らくfromX,Yがmousedownの時の設定で固定されていて、mousemoveイベント時に再設定されていないのが原因ではないでしょうか?
こんな感じ↓
    $('canvas').mousemove(function(e) {
        if (drawFlag) {
            draw(e);
            fromX = e.pageX - $(this).offset().left - borderWidth;
            fromY = e.pageY - $(this).offset().top - borderWidth;
        }
    });
※何度も同じ記述が出てきて格好は悪いですが、とりあえず動作するのではないかと思います。


修正コードを追記します。これでどうでしょう?
    var borderWidth = 5;
    var fromX;
    var fromY;
    var drawFlag = false;
    var context = $("canvas").get(0).getContext('2d');
    var pale = '#ff25a8'; //色
    var penWidth = 20; //太さ

    $('canvas').mousedown(function(e) {
        drawFlag = true;
        fromX = e.pageX - $(this).offset().left - borderWidth;
        fromY = e.pageY - $(this).offset().top - borderWidth;
        context.beginPath(); //追加
        context.moveTo(fromX, fromY); //追加
        context.strokeStyle = pale; //追加
        context.lineWidth = penWidth; //追加
        return false;  // for chrome
    });
 
    $('canvas').mousemove(function(e) {
        if (drawFlag) {
            draw(e);
        }
    });

    $('canvas').on('mouseup', function() {
        drawFlag = false;
        context.closePath(); //追加
    });
 
    $('canvas').on('mouseleave', function() {
        drawFlag = false;
        context.closePath(); //追加
    });
 
    function draw(e) {
        var toX = e.pageX - $('canvas').offset().left - borderWidth;
        var toY = e.pageY - $('canvas').offset().top - borderWidth;
        // context.strokeStyle = pale; 削除
        // context.lineWidth = penWidth; 削除
        // context.beginPath(); 削除
        // context.moveTo(fromX, fromY); 削除
        context.lineTo(toX, toY);
        context.stroke();
        fromX = toX; //追加
        fromY = toY; //追加
        // context.closePath(); 削除
    }
  });

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/08/02 02:19

    恐らくそれは、linetoを使っているとはいえポイントの集まりにしかならないからです。
    本当に滑らかな線にするには、ポイントを一定時間サンプリングして、それらを最小二乗法などで高次関数化し、ベジェやBスプライン曲線なんかに落とし込むしかないと思います。
    参考ページ:http://gihyo.jp/design/serial/01/createjs/0010#sec2_pd

    キャンセル

  • 2015/08/02 02:24 編集

    mousedownのcontext.beginPath();の下に
    context.lineJoin = "bevel";
    を追加すると多少マシになりました

    キャンセル

  • 2015/08/13 23:00

    ご連絡遅れて申し訳ありません。
    参考URL、とても助かりました。
    非常に心苦しいですが、
    先に同じようにして解説頂いた方がいらっしゃったので、そちらの方をベストアンサーにさせていただきました。申し訳ございません。
    また何かございましたらよろしくお願い致します。

    キャンセル

0

context.beginPath();
context.moveTo(fromX, fromY);
context.lineTo(toX, toY);
context.closePath();
context.stroke();
closePath()の後に,stroke()ではないでしょうか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/08/02 02:23

    ありがとうございます。
    直してみましたが改善されませんでした。

    キャンセル

0

ごり押し。非推奨。
    var borderWidth = 5;
    var fromX;
    var fromY;
    var drawFlag = false;
    var context = $("canvas").get(0).getContext('2d');
    var pale = '#ff25a8'; //色
    var penWidth = 30; //太さ

    $('canvas').mousedown(function(e) {
        drawFlag = true;
        fromX = e.pageX - $(this).offset().left - borderWidth;
        fromY = e.pageY - $(this).offset().top - borderWidth;
        return false;  // for chrome
    });
 
    $('canvas').mousemove(function(e) {
        if(!drawFlag)return
        setTimeout(function (){draw(e)},0);
        setTimeout(function (){draw(e)},10);
        setTimeout(function (){draw(e)},20);
        setTimeout(function (){draw(e)},30);
        setTimeout(function (){draw(e)},40);
        setTimeout(function (){draw(e)},50);
    });

    $('canvas').on('mouseup', function() {
        drawFlag = false;
    });
 
    $('canvas').on('mouseleave', function() {
        drawFlag = false;
    });
 
    function draw(e) {
        var toX = e.pageX - $('canvas').offset().left - borderWidth;
        var toY = e.pageY - $('canvas').offset().top - borderWidth;
        context.strokeStyle = pale; //色の設定 paleという変数に入れてます。
        context.lineWidth = penWidth; //太さの設定 上記の画像は30
        context.beginPath();
        /*
        context.fillStyle=pale;
        context.arc(toX,toY,(penWidth/10)|0,0,Math.PI*2,false);
        context.fill();
        */
        context.moveTo(fromX, fromY);
        context.lineTo(toX, toY);
        context.stroke();
        context.closePath();
        fromX=toX;
        fromY=toY;
    }

質問本文のコードで
fromX=toX;
fromY=toY;
が抜けていませんか?
(質問の本題とは関係ないですが挙動が全く違うため念のため)

コードを変えた点としてはsetTimeout()を使い時間差で複数回実行されるようにしているだけです。
円をマウス座標に描画する方法も考えられますが、マウスを高速で動かした場合に円と円の間に隙間が空くため、今回は使用していません。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/08/02 02:36

    ご丁寧にありがとうございます。
    試してみて、すばやく描くと滑らかに描画されますが、ゆっくり描くとやはり上記の画像のようになってしまいます。

    キャンセル

0

直線ではなく曲線で書くようにすれば改善されます。
http://jsdo.it/oao_oao/sRaI

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/08/13 22:59

    ご連絡遅れて申し訳ありません。
    サンプルのコードまで頂き、とても助かりました。
    非常に心苦しいですが、
    先に同じようにして解説頂いた方がいらっしゃったので、そちらの方をベストアンサーにさせていただきました。申し訳ございません。
    また何かございましたらよろしくお願い致します。

    キャンセル

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

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