block by armollica 41d62fdffa9c4172662c

Line Arrow

Full Screen

Drawing an arrowhead on a line in canvas. Move mouse to move line. Similar to a marker tag in SVG.

index.html

<html>
<head>
  <title>Line Arrow</title>
</head>
<body>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
  var width = 960,
      height = 500,
      arrowLength = 10;

  var canvas = d3.select("body").append("canvas")
    .attr("width", width)
    .attr("height", height);

  var context = canvas.node().getContext("2d");

  var origin = {x: width/2, y: height/2};

  draw(width/4, height/4);
  canvas
    .on("mousemove", function() {
      var mouse = d3.mouse(this);
      var d = truncateVector([origin, {x: mouse[0], y: mouse[1]}], .8)[1];
      draw(d.x, d.y);
    });

  function draw(x, y) {
    var endPoint = {x, y},
        arrowData = getArrowData([origin, endPoint]);

    context.clearRect(0, 0, width, height);
    path(context, [origin, endPoint]);
    path(context, [endPoint, arrowData.left]);
    path(context, [endPoint, arrowData.right]);
  }

  function path(context, data) {
    context.beginPath();
    context.moveTo(data[0].x, data[0].y);
    data.slice(1).forEach(function(d) {
      context.lineTo(d.x, d.y);
    });
    context.stroke();
    context.closePath();
  }

  function truncateVector(data, c) {
    var x0 = data[0].x, y0 = data[0].y,
        x1 = data[1].x, y1 = data[1].y,
        endPoint = {
          x: x0 + (x1-x0)*c,
          y: y0 + (y1-y0)*c
        };
    return [data[0], endPoint];
  }

  function getArrowData(data) {
    var data = data.slice(-2),
        x0 = data[0].x, y0 = data[0].y,
        x1 = data[1].x, y1 = data[1].y,
        t = Math.atan2(y1-y0, x1-x0),
        dt = Math.PI*(3/4);
    return {
      right: {
        x: arrowLength * Math.cos(t + dt) + x1,
        y: arrowLength * Math.sin(t + dt) + y1
      },
      left: {
        x: arrowLength * Math.cos(t - dt) + x1,
        y: arrowLength * Math.sin(t - dt) + y1
      }
    };
  }
</script>
</body>
</html>