Javascript 这使人感到困惑

Javascript 这使人感到困惑,javascript,canvas,geometry,Javascript,Canvas,Geometry,因此,我再次谈到环形扇区,这不是我的专长。我可以在画布上很好地使用.arc方法,问题在于需要将我的arc作为路径的一部分 例如: ctx.save(); ctx.arc(centerX, centerY, radius, startAngle, endAngle, true); ctx.stroke(); ctx.restore(); 很好。但现在我需要它作为路径的一部分,所以我有这样的东西: var pointArray = [...]; //this contains all f

因此,我再次谈到环形扇区,这不是我的专长。我可以在画布上很好地使用
.arc
方法,问题在于需要将我的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);
切线坐标的切线快把我逼疯了。另外,我有一个严重的担忧: 这听起来像是用arcTo画的圆弧永远不会覆盖180度或更多的圆,有时我的环形扇形会大于180度

感谢stackoverflow的帮助

更新 好的,我必须在这里做svg画布极性转换,使用coffee脚本,实际的生产代码如下

 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!

虽然我对你的问题/代码不是100%清楚

arcTo()仍然存在浏览器/渲染问题,因此现在请使用arc()。
(请原谅,我现在无法给出详细链接,因为我成了新的firefox 12垃圾的受害者,在我的ff3.6系统中丢失了多年的笔记,在未经批准的更新过程中,它只是删除了这些笔记)

arc()适用于弧度,所以请在wiki上快速阅读Math.PI与弧度的关系,然后快速编写一些公式,将您的度数(或您希望的度数)转换为弧度。
您将执行以下操作:((2*Math.PI)/360)*270)(=3/4圈)
顺便说一下:我没有遇到弧度/单位转换和ECMAscript浮点行为的明显绘图问题

另外,不要忘记beginPath()和closePath()(需要时还有stroke()):不要让画布猜测!!这通常是绘制(闭合)路径的关键

您可能还想看看bezierCurveTo()

更新(TS更新时): 看着你的图片(我猜这是你问题的呈现),我想我看到了你想要的:饼图

这很简单,它们是beginPath()和closePath()之间的两条弧和两条线(以及填充颜色)。
您要做的是使用translate()将原点(点0,0)居中。在你做这件事之前,请仔细阅读如何获得清晰的线条:诀窍是转换为半像素:(x.5,y.5)

然后制作一个“主画布”和一个“临时画布”。对于每一块饼,在干净的临时画布上画一个临时画布(只需设置它的宽度和高度,而不是一些清晰的混乱),然后将这个临时画布放在主画布上。最后渲染/输出主画布。完成了

脚本中的“魔法”(简单的数学)在现有svg路径之间进行转换,我帮不了你,因为我(不好意思承认)在更新的源代码中没有识别出任何javascript

希望这有帮助

更新2:实际上。。如果您能告诉我们您的点/坐标数组的格式。。那真的很有帮助!然后我们就知道你在哪里画画了。
最好的解决方案可能确实是启动一个javascript函数,该函数接受points数组的..
这样,您的coffeescript就可以简单地将您的已知值(数据格式)输出到javascript,而javascript无论如何都是呈现画布(html)所需的

这让我想到。。必须存在画布翻译脚本的现有svg路径。。正确的?也许有人知道一个经过尝试和测试的版本,可以在这里链接/复制它(供将来参考)

更新3: 提示:不要忘记:您可以在绘图模式下旋转画布,也可以在对画布进行分层时旋转画布。

当你旋转时(与上面提到的弧度原理相同),画布将围绕其原点(0,0)旋转,这就是为什么平移(到画布中心+0.5px)对于绘制这些基于圆的形状非常有用

我自己也有这个问题。有一次我把它画在一张纸上,用了一点几何学和三角学,它非常简单

此函数将帮助您计算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或coffee脚本,因此旋转和转换是在绘图功能之外完成的。这是上面的完整代码。我画了一个圆的多个环形截面,但是你可以很容易地修改它,只画一个。基本上,你有一个内半径,一个外半径,你用直线连接它们的起点和终点

切线坐标的切线快把我逼疯了。此外,我还有一个严重的担忧:这听起来像是用arcTo绘制的圆弧永远无法覆盖180度或更多的圆,有时我的环形扇形将大于180度


关于arcTo()函数,您是正确的。它只能生成小于180度的圆弧。大于等于180°的切线永远不会相交,因此arcTo()函数不能有控制点。你可以只画两个或(我会为整个环空画三个)彼此更接近的图。

我最近发现自己对arcTo()方法(实际上应该称为roundedCorner())感到失望。我决定为那些想同时使用cx、cy、r、theta1、theta2表达式的人提供一个通用解决方案:

此处复制了重要的代码位:

/**
   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)
        }
    }
}
/**
如果代码是“move”,那么我们将执行moveTo x0,y0
如果代码是“line”,那么我们将对x0,y0进行lineTo
如果代码是其他代码,我们将假定光标已经位于x0,y0
*/
函数otherArcTo(ctx、cx、cy、r、θ1、θ2、代码)
{
log([cx,cy,r,theta1,theta2,code])
var x0=cx+r*Math.cos(θ1)
变量y0=cy+r*Math.sin(θ1)
如果(代码==“移动”){
ctx.moveTo(x0,y0)
}else if(代码=“行”){
ctx.lineTo(x0,y0)
}
var dTheta=θ2-θ1
var nChunk