2013-04-15 85 views
3

我使用的是wPaint插件,我试图添加一些更多的功能。我需要的是以“箭头”结尾的画线。我已经尝试过所有我能想到的事情,但我只能得到一半的箭头(想象一下< -----,但头部只能延伸到底部或顶部,但从不是两个方向。)Html 5画布完整箭头

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

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

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

谢谢。

回答

11

这是如何创建绘制箭头,两端

有趣的部分是计算的箭镞这样的角度线对象:

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> 
+0

完美。谢谢 ! – Kisaragi

+0

Brillant!非常感谢! –

+0

请确保你签出@PierreDuc's anwer并用'((this.x2> = this.x1)替换'((this.x2> this.x1)? - 90:90)* Math.PI/180;'' ?-90:90)* Math.PI/180;' - 即使用大于或等于 – ElDog

5

这对于垂直线是错误的。 尝试

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

2

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

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

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

应更改为:

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

简化版本

关键区别。使用Math.atan2消除了if

这其中还把箭头在线路的两端,而不是以往的线路

结束换句话说

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

需要对此

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

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

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

top arrow

凡作为第二溶液绘制的箭头这样

bottom arrow