HTML 5个帆布完整的箭头(Html 5 Canvas complete arrowhead)

2019-08-31 07:38发布

我使用的是wPaint插件,我尝试添加一些更多的功能。 我需要的是一个画线,以结束与一个“箭头”。 我已经试过几乎所有我能想到的,但我只能得到一半的箭头(想象<-----,但头只延伸至底部或顶部,但从来没有两个方向。)

这里是画线(与半箭头)的功能:

  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();
  }

任何帮助/想法/提示将是有益的。

谢谢。

Answer 1:

这是如何创建借鉴两端箭头的直线对象

有趣的部分是计算这样的箭头的角度:

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;

剩下的只是画了箭头计算的旋转线和2个三角形

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();
}

这里是代码和一个小提琴: 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>


Answer 2:

这又错了垂直线。 尝试

var line=new Line(50,50,50,275)



Answer 3:

简化版本

关键的区别。 使用Math.atan2消除需要if

这其中还把箭头在线路的两端,而不是过去的行结束

换一种说法

这个

start         end
    |<------->|

本VS

   <|---------|>

 function arrow(ctx, x1, y1, x2, y2, start, end) { var rot = -Math.atan2(x1 - x2, y1 - y2); ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); if (start) { arrowHead(x1, y1, rot); } if (end) { arrowHead(x2, y2, rot + Math.PI); } } function arrowHead(x, y, rot) { ctx.save(); ctx.translate(x, y); ctx.rotate(rot); ctx.beginPath(); ctx.moveTo(0, 0); ctx.lineTo(-5, -12); ctx.lineTo(5, -12); ctx.closePath(); ctx.fill(); ctx.restore(); } // test it ------- var ctx = document.createElement("canvas").getContext("2d"); document.body.appendChild(ctx.canvas); // draw some arrows ctx.save(); ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2); for (var ii = 0; ii <= 12; ++ii) { var u = ii / 12; var color = hsl(u * 360, 1, 0.5); ctx.fillStyle = color; ctx.strokeStyle = color; var a = u * Math.PI; var x = Math.cos(a) * 120; var y = Math.sin(a) * 70; arrow(ctx, -x, -y, x, y, true, true); // draw the end points to see the arrowheads match ctx.fillStyle = "#000"; ctx.fillRect(-x - 1, -y - 1, 3, 3); ctx.fillRect( x - 1, y - 1, 3, 3); } ctx.restore(); function hsl(h, s, l) { return `hsl(${h},${s * 100}%,${l * 100}%)`; } 
 canvas { border: 1px solid black; } 

与上述解决方案的一个问题是,如果你勾芡的线条笔触,将通过箭头捅。 不难解决,但你必须计算在像素线的长度,然后从两边减去箭头的大小。

这样的事情

 function arrow(ctx, x1, y1, x2, y2, start, end) { var dx = x2 - x1; var dy = y2 - y1; var rot = -Math.atan2(dx, dy); var len = Math.sqrt(dx * dx + dy * dy); var arrowHeadLen = 10; ctx.save(); ctx.translate(x1, y1); ctx.rotate(rot); ctx.beginPath(); ctx.moveTo(0, start ? arrowHeadLen : 0); ctx.lineTo(0, len - (end ? arrowHeadLen : 0)); ctx.stroke(); if (end) { ctx.save(); ctx.translate(0, len); arrowHead(ctx); ctx.restore(); } if (start) { ctx.rotate(Math.PI); arrowHead(ctx); } ctx.restore(); } function arrowHead(ctx) { ctx.beginPath(); ctx.moveTo(0, 0); ctx.lineTo(-5, -12); ctx.lineTo(5, -12); ctx.closePath(); ctx.fill(); } // test it ------- var ctx = document.createElement("canvas").getContext("2d"); document.body.appendChild(ctx.canvas); // draw some arrows ctx.save(); ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2); for (var ii = 0; ii < 12; ++ii) { var u = ii / 12; var color = hsl(u * 360, 1, 0.5); ctx.fillStyle = color; ctx.strokeStyle = color; var a = u * Math.PI; var x = Math.cos(a) * 120; var y = Math.sin(a) * 70; arrow(ctx, -x, -y, x, y, true, true); ctx.fillStyle = "#000"; // mark the ends so we can see where they are ctx.fillRect(-x - 1, -y - 1, 3, 3); ctx.fillRect( x - 1, y - 1, 3, 3); } ctx.restore(); function hsl(h, s, l) { return `hsl(${h},${s * 100}%,${l * 100}%)`; } 
 canvas { border: 1px solid black; } 

换句话说,第一溶液吸取这样箭

凡为第二个解决方案借鉴这样的箭头



Answer 4:

至于除了坊间的答案与user1707810评论相结合:

的两个块(开始/结束弧度):

 - ((this.x2 > this.x1)?-90:90)*Math.PI/180;

应改为:

 - ((this.x2 >= this.x1)?-90:90)*Math.PI/180;


Answer 5:

我简单的解决方案

ctx.beginPath(); 
ctx.moveTo(ax,ay);
ctx.lineTo(bx,by);
ctx.stroke();
ctx.closePath();
angle=Math.PI+Math.atan2(by-ay,bx-ax);
angle1=angle+Math.PI/6;
angle2=angle-Math.PI/6;
ctx.beginPath(); 
ctx.moveTo(bx,by);
ctx.arc(bx,by,5,angle1,angle2,true);
ctx.lineTo(bx,by);
ctx.fill();
ctx.closePath();


文章来源: Html 5 Canvas complete arrowhead