Search code examples
htmlcanvashtml5-canvas

Html 5 Canvas complete arrowhead


I'm using the wPaint plugin and I am attempting to add a few more features. What I need is a drawn line to end with an "arrowhead". I have tried just about everything I could think of, but I can only get half of the arrow ( imagine <-----, but the head only extends to the bottom or the top, but never both directions.)

Here is the function for drawing the line (with the half arrowhead):

  drawArrowMove: function(e, _self)
  {
        var xo = _self.canvasTempLeftOriginal;
        var yo = _self.canvasTempTopOriginal;

        if(e.pageX < xo) { e.x = e.x + e.w; e.w = e.w * -1}
        if(e.pageY < yo) { e.y = e.y + e.h; e.h = e.h * -1}

        _self.ctxTemp.lineJoin = "round";
        _self.ctxTemp.beginPath();
        _self.ctxTemp.moveTo(e.x, e.y);
        _self.ctxTemp.lineTo(e.x + e.w, e.y + e.h);

        _self.ctxTemp.closePath();
        _self.ctxTemp.moveTo(e.x, e.y);

        _self.ctxTemp.lineTo(15,10);                   
        _self.ctxTemp.stroke();
  }

Any help/ideas/tips would be helpful.

Thanks.


Solution

  • This is how to create a line object that draws arrowheads on both ends

    The interesting part is calculating the angle of the arrowheads like this:

    var startRadians=Math.atan((this.y2-this.y1)/(this.x2-this.x1));
    startRadians+=((this.x2>=this.x1)?-90:90)*Math.PI/180;
    
    var endRadians=Math.atan((this.y2-this.y1)/(this.x2-this.x1));
    endRadians+=((this.x2>=this.x1)?90:-90)*Math.PI/180;
    

    The rest is just drawing the line and 2 triangles for arrowheads the calculated rotations

    Line.prototype.drawArrowhead=function(ctx,x,y,radians){
        ctx.save();
        ctx.beginPath();
        ctx.translate(x,y);
        ctx.rotate(radians);
        ctx.moveTo(0,0);
        ctx.lineTo(5,20);
        ctx.lineTo(-5,20);
        ctx.closePath();
        ctx.restore();
        ctx.fill();
    }
    

    Here is code and a Fiddle: http://jsfiddle.net/m1erickson/Sg7EZ/

    <!doctype html>
    <html>
    <head>
    <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    
    <style>
        body{ background-color: ivory; }
        canvas{border:1px solid red;}
    </style>
    
    <script>
    $(function(){
    
        var canvas=document.getElementById("canvas");
        var context=canvas.getContext("2d");
    
        function Line(x1,y1,x2,y2){
            this.x1=x1;
            this.y1=y1;
            this.x2=x2;
            this.y2=y2;
        }
        Line.prototype.drawWithArrowheads=function(ctx){
    
            // arbitrary styling
            ctx.strokeStyle="blue";
            ctx.fillStyle="blue";
            ctx.lineWidth=1;
    
            // draw the line
            ctx.beginPath();
            ctx.moveTo(this.x1,this.y1);
            ctx.lineTo(this.x2,this.y2);
            ctx.stroke();
    
            // draw the starting arrowhead
            var startRadians=Math.atan((this.y2-this.y1)/(this.x2-this.x1));
            startRadians+=((this.x2>this.x1)?-90:90)*Math.PI/180;
            this.drawArrowhead(ctx,this.x1,this.y1,startRadians);
            // draw the ending arrowhead
            var endRadians=Math.atan((this.y2-this.y1)/(this.x2-this.x1));
            endRadians+=((this.x2>this.x1)?90:-90)*Math.PI/180;
            this.drawArrowhead(ctx,this.x2,this.y2,endRadians);
    
    
        }
        Line.prototype.drawArrowhead=function(ctx,x,y,radians){
            ctx.save();
            ctx.beginPath();
            ctx.translate(x,y);
            ctx.rotate(radians);
            ctx.moveTo(0,0);
            ctx.lineTo(5,20);
            ctx.lineTo(-5,20);
            ctx.closePath();
            ctx.restore();
            ctx.fill();
        }
    
        // create a new line object
        var line=new Line(50,50,150,150);
        // draw the line
        line.drawWithArrowheads(context);
    
    }); // end $(function(){});
    </script>
    
    </head>
    
    <body>
        <canvas id="canvas" width=300 height=300></canvas>
    </body>
    </html>