我试图用绿色填充在画布(由二次曲线和贝塞尔曲线制成)中绘制的面孔。在第一个贝塞尔曲线之后,我使用moveTo并将其直接指向曲线的端点(是的,有点多余),然后再创建下一条曲线(二次曲线)。做完整个脸后,我使用填充。脸部用绿色填充一部分脸部,但在中间留下一个白色三角形。当我删除了前面提到的多余的moveTo()时,但是整个形状都按预期的绿色填充。有人可以解释吗?
我的想法/尝试:
因为三角形的点与两条相交的曲线之间的点相同,所以我首先认为是因为这些曲线没有接触,然后回过头来固定了该点。
moveTo()在贝塞尔曲线的端点上方创建一个“新点”,所以实际上是相交的新点和下一条曲线,而不是贝塞尔曲线和下一条曲线?
咨询:
我查看了Mozilla开发人员网络对moveTo()的Canvas教程的解释,并在此处使用诸如“ moveTo()”,“。fill()”,“相邻曲线”,“相邻贝塞尔曲线”之类的关键字进行搜索。我找到了this,但这并不是我想要的。
HTML代码:
<!DOCTYPE html>
<html>
<head>
<title>FACE</title>
</head>
<body>
<canvas id = 'canvas' height = '900' width = '900'></canvas>
<script src = 'face.js'></script>
</body>
</html>
JavaScript代码在这里
var canvas = document.getElementById('canvas'); <br>
var context = canvas.getContext('2d');<br><br>
function greenHeadFront()
{
var rightHeadx = 110.5;
var rightHeady = 80;
var leftHeadx = 40.5;
var leftHeady = 80;
context.moveTo(leftHeadx, leftHeady);
context.bezierCurveTo(leftHeadx+6, leftHeady-40, rightHeadx-6, rightHeady-40, rightHeadx, rightHeady); //TOP OF HEAD
context.moveTo(rightHeadx, rightHeady);
context.quadraticCurveTo( 115 , 100 , rightHeadx, rightHeady+30);//RIGHT CHEEK
context.bezierCurveTo (100 , 114, 129, 152, 75, 131); //RIGHT CHIN
context.moveTo(leftHeadx,leftHeady);
context.quadraticCurveTo(35, 100, leftHeadx, leftHeady+30);//LEFT CHEEK
context.bezierCurveTo(53, 120, 23, 148, 75, 131); //LEFT CHIN
context.fillStyle = 'rgb(0,156,0)';
context.fill();
context.stroke();
}
greenHeadFront();
先感谢您!!
最佳答案
第一件事:不要使用硬编码的常量,这可能会引起麻烦。
另一件事,不要犹豫使用上下文转换来简化您的绘图代码。
最后,如果您使用简单易懂的参数,您的代码将更容易(重复)使用:例如,您可以提供要绘制的图形的边界框的左上角的x,y和宽度/高度。
因此,下面我编写了未经测试的代码,只是为了向您展示如何更清晰地重写您的绘图代码。
想法是平移到图形的左上角,然后缩放上下文,以便您只能使用0.0到1.0之间的坐标来进行绘制。
同样,不要犹豫在函数中命名常量,以后可以选择一些常量作为函数参数。
function greenHeadFront(x, y, width, height )
{
context.save();
context.translate(x,y);
context.scale(width, height);
// !! required !!
context.beginPath();
// now all coordinates are beetween (0,0) (top-left)
// and (1.0,1.0) (bottom-right)
var cheekHeight = 0.1 ;
context.moveTo(0.5, 1 - cheekHeight); // move to center middle point.
context.quadraticCurveTo( ??);//RIGHT CHEEK
context.bezierCurveTo (??); //RIGHT CHIN
context.bezierCurveTo( ?? ); //TOP OF HEAD
context.bezierCurveTo(??); //LEFT CHIN
context.quadraticCurveTo(??);//LEFT CHEEK
context.fillStyle = 'rgb(0,156,0)';
context.fill();
context.strokeStyle='#000';
context.lineWidth=0.01;
context.stroke();
context.strokeRect(0,0,1,1); // for debug
context.restore();
}
greenHeadFront( ?? );
现在对于三角形问题,这是预期的行为:每次调用moveTo时,您都在创建一个新的子路径,因此您的图形现在是由几个子路径构建的,当您调用fill()时,这些子路径都将被填充。这些子路径并不能覆盖您要填充的所有表面。