所以我再次处理环形部门,这不是我的强项。我可以在画布上使用.arc
方法就好了,问题来自于需要将弧作为路径的一部分。
例如:
ctx.save();
ctx.arc(centerX, centerY, radius, startAngle, endAngle, true);
ctx.stroke();
ctx.restore();
工作正常。但现在我需要它作为路径的一部分,所以我有这样的事情:
var pointArray = [...]; //this contains all four corner points of the annular sector
ctx.save();
ctx.moveTo(pointArray[0].x, pointArray[0].y);
ctx.lineTo(pointArray[1].x, pointArray[1].y); //so that draws one of the flat ends
ctx.arcTo(?, ?, pointArray[2].x pointArray[2].y, radius);
切线坐标的切线让我很生气。另外,我有一个严重的担忧: http://www.dbp-consulting.com/tutorials/canvas/CanvasArcTo.html 使它听起来像是用arc绘制的弧线,它永远不会覆盖180度或更多的圆圈,并且有时我的环形扇区将大于180度。
感谢stackoverflow的优秀几何思想!
更新 好的,所以我必须在这里进行svg canvas inter-polarity,然后使用coffee-script,实际的生产代码如下!
annularSector : (startAngle,endAngle,innerRadius,outerRadius) ->
startAngle = degreesToRadians startAngle+180
endAngle = degreesToRadians endAngle+180
p = [
[ @centerX+innerRadius*Math.cos(startAngle), @centerY+innerRadius*Math.sin(startAngle) ]
[ @centerX+outerRadius*Math.cos(startAngle), @centerY+outerRadius*Math.sin(startAngle) ]
[ @centerX+outerRadius*Math.cos(endAngle), @centerY+outerRadius*Math.sin(endAngle) ]
[ @centerX+innerRadius*Math.cos(endAngle), @centerY+innerRadius*Math.sin(endAngle) ]
]
angleDiff = endAngle - startAngle
largeArc = (if (angleDiff % (Math.PI * 2)) > Math.PI then 1 else 0)
if @isSVG
commands = []
commands.push "M" + p[0].join()
commands.push "L" + p[1].join()
commands.push "A" + [ outerRadius, outerRadius ].join() + " 0 " + largeArc + " 1 " + p[2].join()
commands.push "L" + p[3].join()
commands.push "A" + [ innerRadius, innerRadius ].join() + " 0 " + largeArc + " 0 " + p[0].join()
commands.push "z"
return commands.join(" ")
else
@gaugeCTX.moveTo p[0][0], p[0][1]
@gaugeCTX.lineTo p[1][0], p[1][1]
#@gaugeCTX.arcTo
@gaugeCTX.arc @centerX, @centerY, outerRadius, startAngle, endAngle, false
#@gaugeCTX.moveTo p[2][0], p[2][1]
@gaugeCTX.lineTo p[3][0], p[3][1]
@gaugeCTX.arc @centerX, @centerY, innerRadius, startAngle, endAngle, false
解决方案
@gaugeCTX.moveTo p[0][0], p[0][1]
@gaugeCTX.lineTo p[1][0], p[1][1]
@gaugeCTX.arc @centerX, @centerY, outerRadius, startAngle, endAngle, false
@gaugeCTX.lineTo p[3][0], p[3][1]
@gaugeCTX.arc @centerX, @centerY, innerRadius, endAngle, startAngle, true #note that this arc is set to true and endAngle and startAngle are reversed!
答案 0 :(得分:2)
虽然我的问题/代码不是100%明确的,但
arcTo()仍然存在浏览器/渲染问题,所以现在使用arc() (请原谅我,我现在无法提供详细的链接,因为我成为新的强制firefox 12垃圾的受害者,并且在我的ff3.6驱动系统中丢失了多年的笔记,它在未经批准的更新期间被删除了。) / p>
arc()与弧度一起使用,所以在wiki上快速阅读Math.PI与弧度的关系,然后用一些公式将你的学位(或者你想要的)转换为弧度。
你会做的事情如下:(((2 * Math.PI)/ 360)* 270)(= 3/4圈)
顺便说一句:我没有遇到Radian / Unit转换和ECMAscript浮点行为的明显绘图问题!
另外不要忘记beginPath()和closePath()(以及需要的stroke()):不要让画布猜!这通常是绘制(封闭)路径的关键!!
您可能还想查看bezierCurveTo()。
更新(在TS'更新时): 看着你的照片(我想是你的问题的渲染),我想我看到了你想要的东西:饼图。
这很简单,它们是两条弧线,两条线在beginPath()和closePath()之间(和填充颜色)。
你想要做的是使用translate()将你的原点(点0,0)居中。在你这样做之前,先阅读一下清晰的线条:诀窍是转换为半像素:(x.5,y.5)。
然后制作一个'main-canvas'和一个'temp-canvas'。对于每个馅饼,绘制一个干净的临时画布(只需设置它的宽度和高度而不是一些清晰的mumbo jumbo)并将此临时画布放在主画布上。最后渲染/输出你的主画布。完成。
你的脚本中的'魔术'(普通数学)在我现有的svg-path之间进行翻译我无法帮助你,因为我(羞于承认)在你更新的源代码中不识别任何javascript。
希望这有帮助!
更新2:实际上......如果你能告诉我们你的点/坐标数组的格式......这真的有帮助!然后我们就会知道你在哪里画画。
最好的解决方案可能是制作一个接受你的点数组的javascript函数。
这样你的coffeescript就可以简单地将你已知的值(数据格式)吐出到所需的javascript中,无论如何都需要渲染画布(在html中)。
这让我觉得..必须有现成的svg-path到canvas翻译脚本..对吧?也许有人知道一个经过试验和测试的人,可以在这里链接/复制(以备将来参考)..
更新3: 提示:不要忘记:您可以在绘图模式下旋转画布,也可以在分层画布时旋转画布 当你旋转(它使用上面提到的相同弧度原理)时,画布将围绕它的原点(0,0)旋转,这就是为什么平移(到画布的中心+ 0.5px)对于绘制这些是如此有用的原因基于圆形的形状!!!
答案 1 :(得分:2)
我最近发现自己对arcTo()方法感到失望(真的应该被称为roundedCorner())。我决定为那些想要使用cx,cy,r,theta1,theta2表达式的人提出一个通用的解决方法:
http://www.purplefrog.com/~thoth/art/paisley/arcTo.html
在这里复制了重要的代码:
/**
if code is "move" then we will do a moveTo x0,y0
if code is "line" then we will do a lineTo x0,y0
if code is anything else, we'll assume the cursor is already at x0,y0
*/
function otherArcTo(ctx, cx, cy, r, theta1, theta2, code)
{
console.log([cx,cy,r,theta1, theta2, code])
var x0 = cx + r*Math.cos(theta1)
var y0 = cy + r*Math.sin(theta1)
if (code=="move") {
ctx.moveTo(x0,y0)
} else if (code=="line") {
ctx.lineTo(x0,y0)
}
var dTheta = theta2-theta1
var nChunks = Math.ceil( Math.abs(dTheta) / (0.67*Math.PI) )
if (nChunks <=1) {
var theta3 = theta1 + dTheta/2
var r3 = r/Math.cos(dTheta/2)
var x1 = cx + r3*Math.cos(theta3)
var y1 = cy + r3*Math.sin(theta3)
var x2 = cx + r*Math.cos(theta2)
var y2 = cy + r*Math.sin(theta2)
ctx.arcTo(x1,y1,x2,y2, r)
} else {
for (var i=0; i<nChunks; i++) {
var code2 = null
if (i==0)
code2 = code
otherArcTo(ctx, cx, cy, r,
theta1 + dTheta*i/nChunks,
theta1 + dTheta*(i+1)/nChunks, code2)
}
}
}
答案 2 :(得分:1)
我自己遇到了麻烦。一旦我把它画在一张纸上并使用了一点几何和三角法,它就非常简单了。
此功能可帮助您计算arcTo()函数所需的点数。您可以通过在每个点添加/减去x和y来移动(平移)弧。
function calculateArcPoints(radius, rotation, sectionAngle) {
var halfSectionAngle = sectionAngle / 2;
return {
control: {
x: Math.cos(rotation) * radius / Math.cos(halfSectionAngle),
y: -1 * Math.sin(rotation) * radius / Math.cos(halfSectionAngle)
},
start: {
x: Math.cos(rotation - halfSectionAngle) * radius,
y: -1 * Math.sin(rotation - halfSectionAngle) * radius
},
end: {
x: Math.cos(rotation + halfSectionAngle) * radius,
y: -1 * Math.sin(rotation + halfSectionAngle) * radius
}
};
}
我使用了KineticJS而没有使用SVG或咖啡脚本,因此旋转和平移是在绘图功能之外完成的。这是jsFiddle上的完整代码。我在一个圆圈周围画出了多个环形部分,但你可以很容易地将它修改成只画一个。基本上,你有一个内半径,一个外半径,你在它们的起点和终点用直线连接它们。
切线坐标的切线让我很生气。另外,我有一个严重的问题:http://www.dbp-consulting.com/tutorials/canvas/CanvasArcTo.html听起来像是用arc绘制的弧线,它永远不会覆盖180度或更多的圆圈,有时我的环形扇区将超过180度。
你对arcTo()函数是正确的。它只能产生小于180度的弧。 &gt; = 180°处的切线永远不会相交,因此arcTo()函数不能有控制点。你可以画两个或者(我会做三个整个环)更加相邻。