Jquery 画布上弯曲的粗箭头

Jquery 画布上弯曲的粗箭头,jquery,html,canvas,Jquery,Html,Canvas,我试图在画布元素上绘制一个弯曲的粗箭头(超过1px)。但我不知道怎么做。我在canvas元素上画了一个带有笔划的直箭头,当我添加fill选项时,它并没有像箭头一样被锁定,接缝就像它有错误的透视图一样。也许有人知道如何在画布元素上绘制一个厚约5倍的弯曲箭头。您可以使用两个画布上下文图形绘制一个弯曲箭头: 轴的贝塞尔曲线 箭头的三角形线条 演示: 轴只是上下文的三次贝塞尔曲线: ctx.moveTo(bez.sx,bez.sy); ctx.bezierCurveTo(bez.cx1,bez.c

我试图在画布元素上绘制一个弯曲的粗箭头(超过1px)。但我不知道怎么做。我在canvas元素上画了一个带有笔划的直箭头,当我添加fill选项时,它并没有像箭头一样被锁定,接缝就像它有错误的透视图一样。也许有人知道如何在画布元素上绘制一个厚约5倍的弯曲箭头。

您可以使用两个画布上下文图形绘制一个弯曲箭头:

  • 轴的贝塞尔曲线
  • 箭头的三角形线条
演示:

轴只是上下文的三次贝塞尔曲线:

ctx.moveTo(bez.sx,bez.sy);
ctx.bezierCurveTo(bez.cx1,bez.cy1,bez.cx2,bez.cy2,bez.ex,bez.ey);
ctx.lineWidth=5;
ctx.stroke();
ctx.moveTo(0,0);
ctx.lineTo(0,-10);
ctx.lineTo(15,0);
ctx.lineTo(0,10);
ctx.lineTo(0,0);
ctx.translate(bez.ex,bez.ey);
ctx.rotate(endingAngle);
<!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 ctx=canvas.getContext("2d");

    var bez1={sx:50,sy:150,cx1:125,cy1:75,cx2:100,cy2:225,ex:200,ey:130};

    drawCurvedArrow(bez1);

    function drawCurvedArrow(bez){

        // calculate the ending angle of the curve

        var pointNearEnd=getCubicBezierXYatT(
            {x:bez.sx,y:bez.sy},
            {x:bez.cx1,y:bez.cy1},
            {x:bez.cx2,y:bez.cy2},
            {x:bez.ex,y:bez.ey},0.99);
        var dx=bez.ex-pointNearEnd.x;
        var dy=bez.ey-pointNearEnd.y;
        var endingAngle=Math.atan2(dy,dx);

        // draw the arrow shaft

        ctx.moveTo(bez.sx,bez.sy);
        ctx.bezierCurveTo(bez.cx1,bez.cy1,bez.cx2,bez.cy2,bez.ex,bez.ey);
        ctx.lineWidth=5;
        ctx.stroke();

        // draw the arrow head

        var size=ctx.lineWidth;

        ctx.beginPath();
        ctx.save();
        ctx.translate(bez.ex,bez.ey);
        ctx.rotate(endingAngle);
        ctx.moveTo(0,0);
        ctx.lineTo(0,-size*2);
        ctx.lineTo(size*3,0);
        ctx.lineTo(0,size*2);
        ctx.lineTo(0,0);
        ctx.closePath();
        ctx.fill();
        ctx.restore();

    }

    // helper functions

    function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
        var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
        var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
        return({x:x,y:y});
    }

    // cubic helper formula at T distance
    function CubicN(T, a,b,c,d) {
        var t2 = T * T;
        var t3 = t2 * T;
        return a + (-a * 3 + T * (3 * a - a * T)) * T
        + (3 * b + T * (-6 * b + b * 3 * T)) * T
        + (c * 3 - c * 3 * T) * t2
        + d * t3;
    }


}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
箭头只是一个三角形,由命令的上下文线组成:

ctx.moveTo(bez.sx,bez.sy);
ctx.bezierCurveTo(bez.cx1,bez.cy1,bez.cx2,bez.cy2,bez.ex,bez.ey);
ctx.lineWidth=5;
ctx.stroke();
ctx.moveTo(0,0);
ctx.lineTo(0,-10);
ctx.lineTo(15,0);
ctx.lineTo(0,10);
ctx.lineTo(0,0);
ctx.translate(bez.ex,bez.ey);
ctx.rotate(endingAngle);
<!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 ctx=canvas.getContext("2d");

    var bez1={sx:50,sy:150,cx1:125,cy1:75,cx2:100,cy2:225,ex:200,ey:130};

    drawCurvedArrow(bez1);

    function drawCurvedArrow(bez){

        // calculate the ending angle of the curve

        var pointNearEnd=getCubicBezierXYatT(
            {x:bez.sx,y:bez.sy},
            {x:bez.cx1,y:bez.cy1},
            {x:bez.cx2,y:bez.cy2},
            {x:bez.ex,y:bez.ey},0.99);
        var dx=bez.ex-pointNearEnd.x;
        var dy=bez.ey-pointNearEnd.y;
        var endingAngle=Math.atan2(dy,dx);

        // draw the arrow shaft

        ctx.moveTo(bez.sx,bez.sy);
        ctx.bezierCurveTo(bez.cx1,bez.cy1,bez.cx2,bez.cy2,bez.ex,bez.ey);
        ctx.lineWidth=5;
        ctx.stroke();

        // draw the arrow head

        var size=ctx.lineWidth;

        ctx.beginPath();
        ctx.save();
        ctx.translate(bez.ex,bez.ey);
        ctx.rotate(endingAngle);
        ctx.moveTo(0,0);
        ctx.lineTo(0,-size*2);
        ctx.lineTo(size*3,0);
        ctx.lineTo(0,size*2);
        ctx.lineTo(0,0);
        ctx.closePath();
        ctx.fill();
        ctx.restore();

    }

    // helper functions

    function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
        var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
        var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
        return({x:x,y:y});
    }

    // cubic helper formula at T distance
    function CubicN(T, a,b,c,d) {
        var t2 = T * T;
        var t3 = t2 * T;
        return a + (-a * 3 + T * (3 * a - a * T)) * T
        + (3 * b + T * (-6 * b + b * 3 * T)) * T
        + (c * 3 - c * 3 * T) * t2
        + d * t3;
    }


}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
使用上下文的变换(平移+旋转)将箭头定位在轴的末端:

ctx.moveTo(bez.sx,bez.sy);
ctx.bezierCurveTo(bez.cx1,bez.cy1,bez.cx2,bez.cy2,bez.ex,bez.ey);
ctx.lineWidth=5;
ctx.stroke();
ctx.moveTo(0,0);
ctx.lineTo(0,-10);
ctx.lineTo(15,0);
ctx.lineTo(0,10);
ctx.lineTo(0,0);
ctx.translate(bez.ex,bez.ey);
ctx.rotate(endingAngle);
<!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 ctx=canvas.getContext("2d");

    var bez1={sx:50,sy:150,cx1:125,cy1:75,cx2:100,cy2:225,ex:200,ey:130};

    drawCurvedArrow(bez1);

    function drawCurvedArrow(bez){

        // calculate the ending angle of the curve

        var pointNearEnd=getCubicBezierXYatT(
            {x:bez.sx,y:bez.sy},
            {x:bez.cx1,y:bez.cy1},
            {x:bez.cx2,y:bez.cy2},
            {x:bez.ex,y:bez.ey},0.99);
        var dx=bez.ex-pointNearEnd.x;
        var dy=bez.ey-pointNearEnd.y;
        var endingAngle=Math.atan2(dy,dx);

        // draw the arrow shaft

        ctx.moveTo(bez.sx,bez.sy);
        ctx.bezierCurveTo(bez.cx1,bez.cy1,bez.cx2,bez.cy2,bez.ex,bez.ey);
        ctx.lineWidth=5;
        ctx.stroke();

        // draw the arrow head

        var size=ctx.lineWidth;

        ctx.beginPath();
        ctx.save();
        ctx.translate(bez.ex,bez.ey);
        ctx.rotate(endingAngle);
        ctx.moveTo(0,0);
        ctx.lineTo(0,-size*2);
        ctx.lineTo(size*3,0);
        ctx.lineTo(0,size*2);
        ctx.lineTo(0,0);
        ctx.closePath();
        ctx.fill();
        ctx.restore();

    }

    // helper functions

    function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
        var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
        var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
        return({x:x,y:y});
    }

    // cubic helper formula at T distance
    function CubicN(T, a,b,c,d) {
        var t2 = T * T;
        var t3 = t2 * T;
        return a + (-a * 3 + T * (3 * a - a * T)) * T
        + (3 * b + T * (-6 * b + b * 3 * T)) * T
        + (c * 3 - c * 3 * T) * t2
        + d * t3;
    }


}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
您需要曲线末端的角度才能将箭头旋转到正确的角度。

正确的结束角可以这样计算:

var pointNearEnd=getCubicBezierXYatT(
    {x:bez.sx,y:bez.sy},
    {x:bez.cx1,y:bez.cy1},
    {x:bez.cx2,y:bez.cy2},
    {x:bez.ex,y:bez.ey},0.99);
var dx=bez.ex-pointNearEnd.x;
var dy=bez.ey-pointNearEnd.y;
var endingAngle=Math.atan2(dy,dx);

// helper functions

function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
    var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
    var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
    return({x:x,y:y});
}

// cubic helper formula at T distance
function CubicN(T, a,b,c,d) {
    var t2 = T * T;
    var t3 = t2 * T;
    return a + (-a * 3 + T * (3 * a - a * T)) * T
    + (3 * b + T * (-6 * b + b * 3 * T)) * T
    + (c * 3 - c * 3 * T) * t2
    + d * t3;
}
下面是一个完整的代码示例:

ctx.moveTo(bez.sx,bez.sy);
ctx.bezierCurveTo(bez.cx1,bez.cy1,bez.cx2,bez.cy2,bez.ex,bez.ey);
ctx.lineWidth=5;
ctx.stroke();
ctx.moveTo(0,0);
ctx.lineTo(0,-10);
ctx.lineTo(15,0);
ctx.lineTo(0,10);
ctx.lineTo(0,0);
ctx.translate(bez.ex,bez.ey);
ctx.rotate(endingAngle);
<!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 ctx=canvas.getContext("2d");

    var bez1={sx:50,sy:150,cx1:125,cy1:75,cx2:100,cy2:225,ex:200,ey:130};

    drawCurvedArrow(bez1);

    function drawCurvedArrow(bez){

        // calculate the ending angle of the curve

        var pointNearEnd=getCubicBezierXYatT(
            {x:bez.sx,y:bez.sy},
            {x:bez.cx1,y:bez.cy1},
            {x:bez.cx2,y:bez.cy2},
            {x:bez.ex,y:bez.ey},0.99);
        var dx=bez.ex-pointNearEnd.x;
        var dy=bez.ey-pointNearEnd.y;
        var endingAngle=Math.atan2(dy,dx);

        // draw the arrow shaft

        ctx.moveTo(bez.sx,bez.sy);
        ctx.bezierCurveTo(bez.cx1,bez.cy1,bez.cx2,bez.cy2,bez.ex,bez.ey);
        ctx.lineWidth=5;
        ctx.stroke();

        // draw the arrow head

        var size=ctx.lineWidth;

        ctx.beginPath();
        ctx.save();
        ctx.translate(bez.ex,bez.ey);
        ctx.rotate(endingAngle);
        ctx.moveTo(0,0);
        ctx.lineTo(0,-size*2);
        ctx.lineTo(size*3,0);
        ctx.lineTo(0,size*2);
        ctx.lineTo(0,0);
        ctx.closePath();
        ctx.fill();
        ctx.restore();

    }

    // helper functions

    function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
        var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
        var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
        return({x:x,y:y});
    }

    // cubic helper formula at T distance
    function CubicN(T, a,b,c,d) {
        var t2 = T * T;
        var t3 = t2 * T;
        return a + (-a * 3 + T * (3 * a - a * T)) * T
        + (3 * b + T * (-6 * b + b * 3 * T)) * T
        + (c * 3 - c * 3 * T) * t2
        + d * t3;
    }


}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

正文{背景色:象牙;}
#画布{边框:1px纯红;}
$(函数(){
var canvas=document.getElementById(“canvas”);
var ctx=canvas.getContext(“2d”);
变量bez1={sx:50,sy:150,cx1:125,cy1:75,cx2:100,cy2:225,ex:200,ey:130};
绘制曲线箭头(bez1);
函数drawCurvedArrow(bez){
//计算曲线的结束角
var pointNearEnd=getCubicBezierXYatT(
{x:bez.sx,y:bez.sy},
{x:bez.cx1,y:bez.cy1},
{x:bez.cx2,y:bez.cy2},
{x:bez.ex,y:bez.ey},0.99);
var dx=bez.ex pointNearEnd.x;
var dy=bez.ey pointNearEnd.y;
var endingAngle=数学常数2(dy,dx);
//画箭头轴
ctx.moveTo(bez.sx,bez.sy);
ctx.bezierCurveTo(bez.cx1、bez.cy1、bez.cx2、bez.cy2、bez.ex、bez.ey);
ctx.线宽=5;
ctx.stroke();
//画箭头
变量大小=ctx.lineWidth;
ctx.beginPath();
ctx.save();
ctx.translate(bez.ex,bez.ey);
ctx.旋转(端角);
ctx.moveTo(0,0);
ctx.lineTo(0,-尺寸*2);
ctx.lineTo(尺寸*3,0);
ctx.lineTo(0,尺寸*2);
ctx.lineTo(0,0);
ctx.closePath();
ctx.fill();
ctx.restore();
}
//辅助函数
函数getCubicBezierXYatT(开始、控制PT1、控制PT2、结束、T){
var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
变量y=CubicN(T,开始时间y,控制时间1.y,控制时间2.y,结束时间y);
返回({x:x,y:y});
}
//T距离的三次辅助公式
函数CubicN(T,a,b,c,d){
var t2=T*T;
var t3=t2*T;
返回a+(-a*3+T*(3*a-a*T))*T
+(3*b+T*(-6*b+b*3*T))*T
+(c*3-c*3*T)*t2
+d*t3;
}
}); // end$(函数(){});

干得好!是否可以在画布外创建相同的箭头?在潜水舱里或者其他什么地方…?@尼尼塔,当然。您可以使用CSS
position:absolute
将画布放置在Div元素上,并在Div“内部”绘制箭头。您可以使画布覆盖整个页面,并在页面上的任何位置绘制箭头!问题:画布始终是一个B-T-W(大透明窗口)。解决方案:覆盖画布的关键是使其“让开”(不侦听事件),您可以通过设置它的
指针事件:无。您也可以考虑SVG,您可以在其中绘制箭头,但不必担心B-T-W.SVG绘图命令与画布绘图命令非常类似,只是更简洁。