5

所以我再次处理环形扇区,这不是我的强项。我可以.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 听起来好像用 arcTo 绘制的弧永远无法覆盖 180 度或更多的圆,而且有时会这样我的环形扇区将大于 180 度。

感谢stackoverflow的高级几何头脑的帮助!

更新 好的,所以我必须在这里做 svg canvas inter-polarity,并使用咖啡脚本,实际的生产代码如下!

 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!
4

3 回答 3

2

虽然您的问题/代码对我来说不是 100% 清楚,

arcTo() 仍然存在浏览器/渲染问题,所以现在使用 arc()。
(请原谅我,我现在无法提供详细链接,因为我成为了新的强制 firefox 12 垃圾的受害者,并且在我的 ff3.6 动力系统中丢失了多年的笔记,它在未经批准的更新期间被简单地删除了)。

arc() 适用于弧度,因此请在 wiki 上快速阅读 Math.PI 如何与弧度相关,然后制定一些公式将您的度数(或您可能希望的任何值)转换为弧度。
您将执行以下操作: (((2 * Math.PI) / 360) * 270)     (=3/4 circle)
顺便说一句:我没有遇到弧度/单位转换和 ECMAscript 浮动的明显绘图问题点行为!

也不要忘记 beginPath() 和 closePath() (和 stroke() 在需要的地方):不要让画布猜测!这通常是绘制(封闭)路径的关键!!

您可能还想查看 bezierCurveTo()。

更新(关于 TS 的更新):看着你的图片(我猜这是你的问题的渲染),我想我看到了你想要的:饼图。

这很简单,它们是 beginPath() 和 closePath() (以及填充颜色)之间的 2 条弧线和两条线。
你想要做的是用 translate() 将你的原点(点 0,0)居中。在您执行此操作之前,请阅读有关获得清晰线条的信息:诀窍是转换为半像素:(x.5,y.5)。

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

您脚本中的“魔术”(简单数学)在您现有的 svg-path 之间进行翻译我无法帮助您,因为我(羞于承认)在您更新的源代码中无法识别任何 javascript。

希望这可以帮助!

更新2:实际上..如果你能告诉我们你的点/坐标数组的格式..那真的很有帮助!然后我们会知道你从哪里画到哪里。
最好的解决方案可能确实是创建一个接受您的点数组的 javascript 函数。
这样,​​您的咖啡脚本可以简单地将您的已知值(数据格式)吐出到无论如何渲染画布所需的 javascript(在html).

这让我觉得.. 必须有现有的 svg-path 到画布翻译脚本.. 对吗?也许有人知道一个久经考验的,可以在这里链接/复制它(以供将来参考)..

更新 3: 提示:不要忘记:您可以在绘图模式下旋转画布,也可以在分层画布时旋转画布。
当您旋转时(使用上述相同的弧度原理),画布将围绕其原点 (0,0) 旋转,这就是为什么平移(到画布中心 + 0.5px)对于绘制这些非常有用善良的圆形形状!!!

于 2012-07-24T02:50:51.730 回答
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)
        }
    }
}
于 2015-09-18T15:32:12.380 回答
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 听起来好像用 arcTo 绘制的弧永远无法覆盖 180 度或更多的圆,而且有时会这样我的环形扇区将大于 180 度。

您对 arcTo() 函数是正确的。它只能产生小于 180 度的圆弧。>= 180° 处的切线永远不会相交,因此 arcTo() 函数不能有控制点。您可以只画两个或(我会为整个环形空间画三个)彼此更相邻。

于 2013-03-30T20:30:41.950 回答