Jquery 画布上弯曲的粗箭头
我试图在画布元素上绘制一个弯曲的粗箭头(超过1px)。但我不知道怎么做。我在canvas元素上画了一个带有笔划的直箭头,当我添加fill选项时,它并没有像箭头一样被锁定,接缝就像它有错误的透视图一样。也许有人知道如何在画布元素上绘制一个厚约5倍的弯曲箭头。您可以使用两个画布上下文图形绘制一个弯曲箭头:Jquery 画布上弯曲的粗箭头,jquery,html,canvas,Jquery,Html,Canvas,我试图在画布元素上绘制一个弯曲的粗箭头(超过1px)。但我不知道怎么做。我在canvas元素上画了一个带有笔划的直箭头,当我添加fill选项时,它并没有像箭头一样被锁定,接缝就像它有错误的透视图一样。也许有人知道如何在画布元素上绘制一个厚约5倍的弯曲箭头。您可以使用两个画布上下文图形绘制一个弯曲箭头: 轴的贝塞尔曲线 箭头的三角形线条 演示: 轴只是上下文的三次贝塞尔曲线: ctx.moveTo(bez.sx,bez.sy); ctx.bezierCurveTo(bez.cx1,bez.c
- 轴的贝塞尔曲线
- 箭头的三角形线条
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$(函数(){});
干得好!是否可以在画布外创建相同的箭头?在潜水舱里或者其他什么地方…?@尼尼塔,当然。您可以使用CSSposition:absolute
将画布放置在Div元素上,并在Div“内部”绘制箭头。您可以使画布覆盖整个页面,并在页面上的任何位置绘制箭头!问题:画布始终是一个B-T-W(大透明窗口)。解决方案:覆盖画布的关键是使其“让开”(不侦听事件),您可以通过设置它的指针事件:无代码>。您也可以考虑SVG,您可以在其中绘制箭头,但不必担心B-T-W.SVG绘图命令与画布绘图命令非常类似,只是更简洁。