在HTML5画布中绘制箭头曲线

5

我正在尝试画出下面的三个箭头。我可以正确地绘制顶部,但我无法正确地绘制另外两个箭头头部。我正在使用HTML5 Canvas来绘制这些箭头。

enter image description here

问题出现在我的arcTo调用中。由于某种原因,我无法获得正确的曲线。也许我应该使用Bezier曲线?有谁能告诉我我应该使用哪些HTML5/Javascript函数来产生上面的箭头头部?

你能提供一个如何实现上述箭头头部的示例吗?

这是JSFiddle显示了错误的链接:http://jsfiddle.net/hJX8X/

<canvas id="testCanvas" width="400px" height="400px">

</canvas>
<script type="text/javascript">
<!--
    var canvas = document.getElementById("testCanvas");
    var dc     = canvas.getContext("2d");

    // Points which are correct (when I draw straight lines its a perfect arrow
    var width    = 400;
    var height   = 100;
    var arrowW   = 0.35 * width;
    var arrowH   = 0.75 * height;
    var p1       = {x: 0,              y: (height-arrowH)/2};
    var p2       = {x: (width-arrowW), y: (height-arrowH)/2};
    var p3       = {x: (width-arrowW), y: 0};
    var p4       = {x: width,          y: height/2};
    var p5       = {x: (width-arrowW), y: height};
    var p6       = {x: (width-arrowW), y: height-((height-arrowH)/2)};
    var p7       = {x: 0,              y: height-((height-arrowH)/2)};

    dc.clearRect(0, 0, canvas.width, canvas.height);
    dc.fillStyle = "#FF0000";

    dc.beginPath();

    dc.moveTo(p1.x, p1.y);
    dc.lineTo(p2.x, p2.y);
    dc.lineTo(p3.x, p3.y);      
    dc.moveTo(p3.x, p3.y);
    dc.arcTo(p3.x, p3.y, p4.x, p4.y, 50);
    dc.moveTo(p4.x, p4.y);
    dc.arcTo(p4.x, p4.y, p5.x, p5.y, 50);
    dc.moveTo(p5.x, p5.y);
    dc.lineTo(p6.x, p6.y);
    dc.lineTo(p7.x, p7.y);

    dc.closePath();
    dc.fill();

    /* Draw arrow without curves
    dc.moveTo(p1.x, p1.y);
    dc.lineTo(p2.x, p2.y);
    dc.lineTo(p3.x, p3.y);      
    dc.lineTo(p4.x, p4.y);  
    dc.lineTo(p5.x, p5.y);
    dc.lineTo(p6.x, p6.y);
    dc.lineTo(p7.x, p7.y);
    */
-->
</script>

你能提供一个期望结果的示例(图片)吗? - rkmax
@rkmax,我现在发布了一个JSFiddle,展示了我的尝试,箭头太矮了。 - sazr
1个回答

9
所以我们有了这条画箭头的路径。我已经做了注释:
dc.moveTo(p1.x, p1.y);
dc.lineTo(p2.x, p2.y); // end of main block
dc.lineTo(p3.x, p3.y); // topmost point     
dc.lineTo(p4.x, p4.y); // endpoint 
dc.lineTo(p5.x, p5.y); // bottommost point 
dc.lineTo(p6.x, p6.y); // end at bottom point 
dc.lineTo(p7.x, p7.y);

我们希望尽可能保持相似,只是我们想以不同于直线的方式到达终点(和返回)。除了第一个命令,我们绝对不想使用任何moveTo命令。那样会使事情变得混乱并且难以理解。我也建议避免使用arcTo,除非你确实需要弧的一部分(比如在饼图中),因为与其他路径命令相比,它相当复杂。
所以我们将使用二次曲线,它们类似于beziers但只有一个控制点,使它们非常简单。它们通过指定控制点来起作用,例如这个(在左侧)
因此,我们采取完全相同的箭头代码并插入两个二次bezier曲线制作一个细长的箭头。我们希望控制点"内部"接近箭头质点,使得二次曲线向内弯曲。
dc.moveTo(p1.x, p1.y);
dc.lineTo(p2.x, p2.y); // end of main block
dc.lineTo(p3.x, p3.y); // topmost point
// control point is based on p3 (topmost point)
dc.quadraticCurveTo(p3.x + 20, p3.y + 30, p4.x, p4.y); // endpoint 
// control point is based on p5 (bottommost point)
dc.quadraticCurveTo(p5.x + 20, p5.y - 30, p5.x, p5.y); // bottommost point 
dc.lineTo(p6.x, p6.y); // end at bottom point 
dc.lineTo(p7.x, p7.y);

如果是一个粗的线条,我们将控制点放置在与顶部和底部点相同高度,并且大致与终点相同的X位置:

dc.beginPath();
// Draw arrow without curves
dc.moveTo(p1.x, p1.y);
dc.lineTo(p2.x, p2.y); // end of main block
dc.lineTo(p3.x, p3.y); // topmost point
// control point is based on p3 (topmost point)
dc.quadraticCurveTo(p3.x + 120, p3.y, p4.x, p4.y); // endpoint 
// control point is based on p5 (bottommost point)
dc.quadraticCurveTo(p5.x + 120, p5.y, p5.x, p5.y); // bottommost point 
dc.lineTo(p6.x, p6.y); // end at bottom point 
dc.lineTo(p7.x, p7.y);

现场演示:http://jsfiddle.net/Yp7DM/


我实际上是在寻找您在原始帖子中提到的第一个箭头。您能分享一下相关代码吗? - Fandango68

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接