HTML5 Canvasで動かせる3次ベジェ曲線を描く
HTML5 のキャンバスでは bezierCurveTo メソッドを使ってベジェ曲線を描くことができます。
今回はこれを使って、Illustratorなどのベクトルソフトぽく、制御点を動かして、曲線を変形させられるようにしてみます。
スポンサーリンク
サンプル
先に動作サンプルからどうぞ。Firefox, Chromeで動作確認済み。
(このサイト、HTML5じゃないんですが、まぁ気にしないでください 笑)
けっこうグリグリ動かせていい感じですね!
解説
そんなにむずかしいことはありませんが、簡単にするためにベジェ曲線はBezierCurveクラスにまとめています。
コンストラクタで初期化したあとは、メインループからhitTestメソッドとdrawメソッドを呼び出しています。
ソースコード
JavaScript ソースコードの全文です。こちらからダウンロードすることもできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
function BezierCurve(points) { // points の順番は 始点, 終点, 制御点1, 制御点2 に並べ替える this.points = [ points[0], points[3], points[1], points[2] ]; this.pointColors = ["rgb(0,150,0)", "rgb(0,150,0)", "rgb(0,0,255)", "rgb(0,0,255)"]; this.strokeStyle = "rgba(0,0,0,1)"; this.selectedPoint = -1; this.movingPoint = -1; } BezierCurve.prototype.draw = function(ctx, mouse) { if (this.movingPoint > -1) { // 点の移動中 if (mouse.down) { if (this.movingPoint < 2) { // 始点と終点のときは制御点1/2も同時に動かす var sub = [ this.points[this.movingPoint][0] - mouse.x, this.points[this.movingPoint][1] - mouse.y ]; this.points[this.movingPoint + 2][0] -= sub[0]; this.points[this.movingPoint + 2][1] -= sub[1]; } // 点の移動 this.points[this.movingPoint] = [mouse.x, mouse.y]; } else { this.movingPoint = -1; } } // ベジェ曲線を描く ctx.beginPath(); ctx.moveTo(this.points[0][0], this.points[0][1]); ctx.bezierCurveTo( this.points[2][0], this.points[2][1], this.points[3][0], this.points[3][1], this.points[1][0], this.points[1][1] ); ctx.strokeStyle = this.strokeStyle; ctx.stroke(); // 制御点1/2操作用の線を描く for (var i = 0; i < 2; i++) { ctx.beginPath(); ctx.moveTo(this.points[i + 0][0], this.points[i + 0][1]); ctx.lineTo(this.points[i + 2][0], this.points[i + 2][1]); ctx.strokeStyle = "rgba(0,0,255,0.5)"; ctx.stroke(); } // 点操作用の●を描く for (var i = 3; i >= 0; i--) { ctx.beginPath(); ctx.arc(this.points[i][0], this.points[i][1], 3, 0, Math.PI*2, false); ctx.fillStyle = this.pointColors[i]; ctx.fill(); if (this.selectedPoint == i) { ctx.beginPath(); ctx.arc(this.points[i][0], this.points[i][1], 5, 0, Math.PI*2, false); ctx.strokeStyle = this.pointColors[i]; ctx.stroke(); } } } BezierCurve.prototype.hitTest = function(mouse) { this.selectedPoint = -1; // 各点との当たり判定関数 var hitTestP = function(mousePoint, origin, radius) { if (mouse.x >= (origin[0] - radius) && mouse.x <= (origin[0] + radius) && mouse.y >= (origin[1] - radius) && mouse.y <= (origin[1] + radius)) { return true; } else { return false; } }; for (var i = 0; i < this.points.length; i++) { if (hitTestP(mouse, this.points[i], 5)) { this.selectedPoint = i; if (mouse.down) { // マウスが押されていたら移動モードにする this.movingPoint = i; } return true; } } return false; } // マウス情報 var mouse = { x:0, y:0, down:false }; window.onload = function() { var canvas = document.getElementById('c1'); if ( ! canvas || ! canvas.getContext ) { return false; } var ctx = canvas.getContext('2d'); canvas.onmousemove = function(e){ var rect = e.target.getBoundingClientRect(); mouse.x = (e.clientX - rect.left); mouse.y = (e.clientY - rect.top); }; canvas.onmouseout = function() { mouse.down = false; }; canvas.onmousedown = function() { mouse.down = true; }; canvas.onmouseup = function() { mouse.down = false; }; var curve1 = new BezierCurve([ [10, 20], [200, 20], [300, 300], [550, 300] ]); var timer; var loop = function() { // メインループ ctx.clearRect(0, 0, canvas.width, canvas.height); curve1.hitTest(mouse); curve1.draw(ctx, mouse); ctx.fillText(mouse.x + ", " + mouse.y, 10, 10); clearTimeout(timer); timer = setTimeout(loop, 10); } loop(); }; |
HTMLは例えばこんな感じでOKです。
1 2 3 4 5 6 7 8 9 10 11 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>test</title> <script type="text/javascript" src="bezier.js"></script> </head> <body> <canvas id="c1" width="570" height="315"></canvas> </body> </html> |
最後までお読みいただきありがとうございました m(_ _)m
スポンサーリンク