LoginSignup
23
20

More than 5 years have passed since last update.

Canvas で矢印を描く

Posted at

はじめに

Canvas である程度汎用的にいろいろな矢印を描くライブラリを作ったので紹介します。

デモ&ライブラリ

最終的にこんなかんじでいろいろな形状の矢印を描くことができるようになりました。

image

使い方

example.html
<script src="https://frogcat.github.io/canvas-arrow/canvas-arrow.js"></script>

...
<script>
var context = canvas.getContext("2d");
context.beginPath();
context.arrow(0, 0, 200, 100, [0, 5, -20, 5, -20, 15]);
context.fill();
</script>

https://frogcat.github.io/canvas-arrow/canvas-arrow.js は CanvasRenderingContext2D の prototype に arrow メソッドを追加します。
arrow メソッドの APIはこんなかんじです。

context.arrow(startX,startY,endX,endY,controlPoints);
  • startX : 始点の X 座標
  • startY : 始点の Y 座標
  • endX : 終点の X 座標
  • endY : 終点の Y 座標
  • controlPoints : 矢印形状を指定するための制御点の配列

controlPoints には [x1,y1,x2,y2,x3,y3...] といったように制御点の X,Y 座標値が格納されます。
座標値の意味は下図のとおり。

image

  • x 座標が正の場合には start からの相対座標、負の場合には end からの相対座標と見なす
  • 終点の真上・真下を指定したい場合には -Number.MIN_VALUE などのとても小さな負の値を指定します

解説

結構短いコードです。

canvas-arrow.js
(function(target) {
  if (!target || !target.prototype)
    return;
  target.prototype.arrow = function(startX, startY, endX, endY, controlPoints) {
    var dx = endX - startX;
    var dy = endY - startY;
    var len = Math.sqrt(dx * dx + dy * dy);
    var sin = dy / len;
    var cos = dx / len;
    var a = [];
    a.push(0, 0);
    for (var i = 0; i < controlPoints.length; i += 2) {
      var x = controlPoints[i];
      var y = controlPoints[i + 1];
      a.push(x < 0 ? len + x : x, y);
    }
    a.push(len, 0);
    for (var i = controlPoints.length; i > 0; i -= 2) {
      var x = controlPoints[i - 2];
      var y = controlPoints[i - 1];
      a.push(x < 0 ? len + x : x, -y);
    }
    a.push(0, 0);
    for (var i = 0; i < a.length; i += 2) {
      var x = a[i] * cos - a[i + 1] * sin + startX;
      var y = a[i] * sin + a[i + 1] * cos + startY;
      if (i === 0) this.moveTo(x, y);
      else this.lineTo(x, y);
    }
  };
})(CanvasRenderingContext2D);
  1. 一旦制御点座標系で矢印のポリゴンを作る
  2. そのポリゴンをアフィン変換して始点・終点座標系に投影する
  3. 結果を moveTo/lineTo で描画

まとめ

Canvas arrow で検索すると http://stackoverflow.com/questions/808826/draw-arrow-on-canvas-tag こんなかんじでソリューションはあるのですが、矢印の形を変えるたびに座標変換やら三角関数やらを考えるのは精神衛生上よくありません。大きなライブラリに依存するのもちょっと、という場合に役に立つかもしれません。

23
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
20